## Push Constants for Robot Animation

This page was last updated: February 17, 2020

Click here to see a 3-minute MP4

### Project Description

• Starting with the basic cube found in the original sample program, use Push Constants to give three robot arms different colors, give them different X scale factors, and animate them while looking connected.

• The appearance of the 3-arm robot is shown here.

• The Time-based animation will no longer be a global rotation. Instead, it will be changing 3 robot arm angles of rotation: Θ1, Θ2, Θ3.

• Make Arm #2 rotate twice as fast as Arm #1, and make Arm #3 rotate twice as fast as Arm #2. Watch out for temporal aliasing!

• Other than that, keep the keyboard keys doing what they used to do. Lighting is especially handy.

• Feel free to add more keyboard inputs to control more things.

• This is inherently a 2½D project. Feel free to do it in 3D.

• Typically robot arms stay the same color and stay the same size throughout their lifetime, but, in this case, feel free to make them change based on Time. Laws of Physics are optional here. The only aspect that is non-negotiable is that the arms must stay connected to each other.

• As a reminder, GLM gives you rotates and translates like this:
```
glm::mat4 m = glm::mat4( 1. );					// [I]
m = glm::translate( m, glm::vec3(tx, ty, tz)  );		// [T]
m = glm::rotate( m, radians, glm::vec3(ax, ay, az) );		// [T] * [R]
```

• You won't need glm::scale( ) because you will do the arm scaling in the vertex shader.

### Keyboard Keys

 'l' (ell) Toggle lighting on and off Esc, 'q' Exit the program

Feel free to add more keyboard inputs if you want.

### Robot Arm Transformations

The theory behind the derivation of these equations can be found here.

 [M1/G] = [T1/G] * [RΘ1] [M2/G] = [T1/G] * [RΘ1] * [T2/1] * [RΘ2] = [M1/G] * [M2/1] [M3/G] = [T1/G] * [RΘ1] * [T2/1] * [RΘ2] * [T3/2] * [RΘ3] = [M1/G] * [M2/1] * [M3/2]

### Example Code

```**************************************************************

layout( push_constant ) uniform arm
{
mat4  armMatrix;
vec3  armColor;
float armScale;		// scale factor in x
} RobotArm

**************************************************************

vec3 bVertex = aVertex;

// do to bVertex just what the cube needs to become a robot arm:
bVertex.x += 1.;
bVertex.x *= RobotArm.armScale;
bVertex = vec3(  RobotArm.armMatrix * vec4( bVertex, 1. )  );

// now do to bVertex what the cube needed before when it was just a cube (lighting, transformation):
???

**************************************************************
**************************************************************

struct arm
{
glm::mat4 armMatrix;
glm::vec3 armColor;
float     armScale;	// scale factor in x
};

**************************************************************

struct arm	Arm1, Arm2, Arm3;

**************************************************************

Arm1.armMatrix = glm::mat4( 1. );
Arm1.armColor  = ?????
Arm1.armScale  = ?????

Arm2.armMatrix = glm::mat4( 1. );
Arm2.armColor  = ?????
Arm2.armScale  = ?????

Arm3.armMatrix = glm::mat4( 1. );
Arm3.armColor  = ?????
Arm3.armScale  = ?????

**************************************************************

VkPushConstantRange			vpcr[1];
vpcr[0].offset = 0;
vpcr[0].size = sizeof( struct arm );		// 80 bytes

VkPipelineLayoutCreateInfo		vplci;
. . .
vplci.pushConstantRangeCount = 1;
vplci.pPushConstantRanges = vpcr;

**************************************************************

vkCmdBeginRenderPass( CommandBuffers[nextImageIndex], IN &vrpbi, IN VK_SUBPASS_CONTENTS_INLINE );
vkCmdBindPipeline( CommandBuffers[nextImageIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, GraphicsPipeline );
vkCmdBindDescriptorSets( CommandBuffers[nextImageIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, GraphicsPipelineLayout, 0, 4,
DescriptorSets, 0, (uint32_t *)nullptr );

vkCmdBindVertexBuffers( CommandBuffers[nextImageIndex], 0, 1, buffers, offsets );

// provide the information for Arm1:
vkCmdPushConstants( CommandBuffers[nextImageIndex], GraphicsPipelineLayout, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0,
sizeof(struct arm), &Arm1 );

// draw the cube, which will become Arm1:
vkCmdDraw( CommandBuffers[nextImageIndex], vertexCount, instanceCount, firstVertex, firstInstance );

// provide the information for Arm2:
vkCmdPushConstants( CommandBuffers[nextImageIndex], GraphicsPipelineLayout, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0,
sizeof(struct arm), &Arm2 );

// draw the cube, which will become Arm2:
vkCmdDraw( CommandBuffers[nextImageIndex], vertexCount, instanceCount, firstVertex, firstInstance );

// provide the information for Arm3:
vkCmdPushConstants( CommandBuffers[nextImageIndex], GraphicsPipelineLayout, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0,
sizeof(struct arm), &Arm3 );

// draw the cube, which will become Arm3:
vkCmdDraw( CommandBuffers[nextImageIndex], vertexCount, instanceCount, firstVertex, firstInstance );

**************************************************************
```

### Turn-in:

Use the Teach system to turn in your: