2016-02-16 15:07:25 +01:00
/*
* Vulkan Example - Skeletal animation
*
* Copyright ( C ) 2016 by Sascha Willems - www . saschawillems . de
*
* This code is licensed under the MIT license ( MIT ) ( http : //opensource.org/licenses/MIT)
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
# include <vector>
# define GLM_FORCE_RADIANS
2016-03-08 21:52:40 +01:00
# define GLM_FORCE_DEPTH_ZERO_TO_ONE
2016-02-16 15:07:25 +01:00
# include <glm/glm.hpp>
# include <glm/gtc/matrix_transform.hpp>
# include <glm/gtc/type_ptr.hpp>
2017-02-11 12:35:18 +01:00
# include <assimp/Importer.hpp>
# include <assimp/scene.h>
# include <assimp/postprocess.h>
# include <assimp/cimport.h>
2016-02-16 15:07:25 +01:00
# include <vulkan/vulkan.h>
# include "vulkanexamplebase.h"
2016-10-30 18:13:49 +01:00
# include "vulkanbuffer.hpp"
2017-02-11 12:35:18 +01:00
# include "VulkanTexture.hpp"
# include "VulkanModel.hpp"
2016-02-16 15:07:25 +01:00
# define VERTEX_BUFFER_BIND_ID 0
# define ENABLE_VALIDATION false
// Vertex layout used in this example
struct Vertex {
glm : : vec3 pos ;
glm : : vec3 normal ;
glm : : vec2 uv ;
glm : : vec3 color ;
// Max. four bones per vertex
float boneWeights [ 4 ] ;
uint32_t boneIDs [ 4 ] ;
} ;
2017-02-11 12:35:18 +01:00
// Vertex layout for the models
vks : : VertexLayout vertexLayout = vks : : VertexLayout ( {
vks : : VERTEX_COMPONENT_POSITION ,
vks : : VERTEX_COMPONENT_NORMAL ,
vks : : VERTEX_COMPONENT_UV ,
vks : : VERTEX_COMPONENT_COLOR ,
vks : : VERTEX_COMPONENT_DUMMY_VEC4 ,
vks : : VERTEX_COMPONENT_DUMMY_VEC4 ,
} ) ;
2016-05-14 20:03:29 +02:00
2016-05-14 21:19:52 +02:00
// Maximum number of bones per mesh
// Must not be higher than same const in skinning shader
# define MAX_BONES 64
// Maximum number of bones per vertex
# define MAX_BONES_PER_VERTEX 4
2016-02-16 15:07:25 +01:00
2016-05-14 21:19:52 +02:00
// Skinned mesh class
2016-02-16 15:07:25 +01:00
2016-05-14 21:19:52 +02:00
// Per-vertex bone IDs and weights
struct VertexBoneData
{
std : : array < uint32_t , MAX_BONES_PER_VERTEX > IDs ;
std : : array < float , MAX_BONES_PER_VERTEX > weights ;
2016-02-16 15:07:25 +01:00
2016-05-14 21:19:52 +02:00
// Ad bone weighting to vertex info
void add ( uint32_t boneID , float weight )
2016-02-16 15:07:25 +01:00
{
2016-05-14 21:19:52 +02:00
for ( uint32_t i = 0 ; i < MAX_BONES_PER_VERTEX ; i + + )
2016-02-16 15:07:25 +01:00
{
2016-05-14 21:19:52 +02:00
if ( weights [ i ] = = 0.0f )
2016-02-16 15:07:25 +01:00
{
2016-05-14 21:19:52 +02:00
IDs [ i ] = boneID ;
weights [ i ] = weight ;
return ;
2016-02-16 15:07:25 +01:00
}
}
}
2016-05-14 21:19:52 +02:00
} ;
2016-02-16 15:07:25 +01:00
2016-05-14 21:19:52 +02:00
// Stores information on a single bone
struct BoneInfo
{
aiMatrix4x4 offset ;
aiMatrix4x4 finalTransformation ;
2016-02-16 15:07:25 +01:00
2016-05-14 21:19:52 +02:00
BoneInfo ( )
2016-02-16 15:07:25 +01:00
{
2016-05-14 21:19:52 +02:00
offset = aiMatrix4x4 ( ) ;
finalTransformation = aiMatrix4x4 ( ) ;
} ;
} ;
2016-02-16 15:07:25 +01:00
2016-05-14 21:19:52 +02:00
class SkinnedMesh
{
public :
// Bone related stuff
// Maps bone name with index
std : : map < std : : string , uint32_t > boneMapping ;
// Bone details
std : : vector < BoneInfo > boneInfo ;
// Number of bones present
uint32_t numBones = 0 ;
// Root inverese transform matrix
aiMatrix4x4 globalInverseTransform ;
// Per-vertex bone info
std : : vector < VertexBoneData > bones ;
// Bone transformations
std : : vector < aiMatrix4x4 > boneTransforms ;
2016-05-14 21:40:58 +02:00
// Modifier for the animation
2016-05-14 21:19:52 +02:00
float animationSpeed = 0.75f ;
2016-05-14 21:40:58 +02:00
// Currently active animation
aiAnimation * pAnimation ;
2016-05-14 21:19:52 +02:00
// Vulkan buffers
2017-02-11 12:35:18 +01:00
vks : : Model vertexBuffer ;
// Store reference to the ASSIMP scene for accessing properties of it during animation
Assimp : : Importer Importer ;
const aiScene * scene ;
2016-02-16 15:07:25 +01:00
2016-05-14 21:40:58 +02:00
// Set active animation by index
void setAnimation ( uint32_t animationIndex )
{
2017-02-11 12:35:18 +01:00
assert ( animationIndex < scene - > mNumAnimations ) ;
pAnimation = scene - > mAnimations [ animationIndex ] ;
2016-05-14 21:40:58 +02:00
}
2016-03-06 20:15:05 +01:00
// Load bone information from ASSIMP mesh
2017-02-11 12:35:18 +01:00
void loadBones ( const aiMesh * pMesh , uint32_t vertexOffset , std : : vector < VertexBoneData > & Bones )
2016-02-16 15:07:25 +01:00
{
for ( uint32_t i = 0 ; i < pMesh - > mNumBones ; i + + )
{
uint32_t index = 0 ;
2016-05-14 21:19:52 +02:00
2016-05-14 20:03:29 +02:00
assert ( pMesh - > mNumBones < = MAX_BONES ) ;
2016-02-16 15:07:25 +01:00
std : : string name ( pMesh - > mBones [ i ] - > mName . data ) ;
2016-05-14 21:19:52 +02:00
if ( boneMapping . find ( name ) = = boneMapping . end ( ) )
2016-02-16 15:07:25 +01:00
{
// Bone not present, add new one
2016-05-14 21:19:52 +02:00
index = numBones ;
numBones + + ;
2016-02-16 15:07:25 +01:00
BoneInfo bone ;
2016-05-14 21:19:52 +02:00
boneInfo . push_back ( bone ) ;
boneInfo [ index ] . offset = pMesh - > mBones [ i ] - > mOffsetMatrix ;
boneMapping [ name ] = index ;
2016-02-16 15:07:25 +01:00
}
else
{
2016-05-14 21:19:52 +02:00
index = boneMapping [ name ] ;
2016-02-16 15:07:25 +01:00
}
for ( uint32_t j = 0 ; j < pMesh - > mBones [ i ] - > mNumWeights ; j + + )
{
2017-02-11 12:35:18 +01:00
uint32_t vertexID = vertexOffset + pMesh - > mBones [ i ] - > mWeights [ j ] . mVertexId ;
2016-02-16 15:07:25 +01:00
Bones [ vertexID ] . add ( index , pMesh - > mBones [ i ] - > mWeights [ j ] . mWeight ) ;
}
}
2016-05-14 21:19:52 +02:00
boneTransforms . resize ( numBones ) ;
}
// Recursive bone transformation for given animation time
void update ( float time )
{
2017-02-11 12:35:18 +01:00
float TicksPerSecond = ( float ) ( scene - > mAnimations [ 0 ] - > mTicksPerSecond ! = 0 ? scene - > mAnimations [ 0 ] - > mTicksPerSecond : 25.0f ) ;
2016-05-14 21:19:52 +02:00
float TimeInTicks = time * TicksPerSecond ;
2017-02-11 12:35:18 +01:00
float AnimationTime = fmod ( TimeInTicks , ( float ) scene - > mAnimations [ 0 ] - > mDuration ) ;
2016-05-14 21:19:52 +02:00
aiMatrix4x4 identity = aiMatrix4x4 ( ) ;
2017-02-11 12:35:18 +01:00
readNodeHierarchy ( AnimationTime , scene - > mRootNode , identity ) ;
2016-05-14 21:19:52 +02:00
for ( uint32_t i = 0 ; i < boneTransforms . size ( ) ; i + + )
{
boneTransforms [ i ] = boneInfo [ i ] . finalTransformation ;
}
2016-02-16 15:07:25 +01:00
}
2017-02-11 12:35:18 +01:00
~ SkinnedMesh ( )
{
vertexBuffer . vertices . destroy ( ) ;
vertexBuffer . indices . destroy ( ) ;
}
2016-05-14 21:19:52 +02:00
private :
2016-02-16 15:07:25 +01:00
// Find animation for a given node
const aiNodeAnim * findNodeAnim ( const aiAnimation * animation , const std : : string nodeName )
{
for ( uint32_t i = 0 ; i < animation - > mNumChannels ; i + + )
{
const aiNodeAnim * nodeAnim = animation - > mChannels [ i ] ;
if ( std : : string ( nodeAnim - > mNodeName . data ) = = nodeName )
{
return nodeAnim ;
}
}
return nullptr ;
}
// Returns a 4x4 matrix with interpolated translation between current and next frame
aiMatrix4x4 interpolateTranslation ( float time , const aiNodeAnim * pNodeAnim )
{
aiVector3D translation ;
if ( pNodeAnim - > mNumPositionKeys = = 1 )
{
translation = pNodeAnim - > mPositionKeys [ 0 ] . mValue ;
}
else
{
uint32_t frameIndex = 0 ;
for ( uint32_t i = 0 ; i < pNodeAnim - > mNumPositionKeys - 1 ; i + + )
{
if ( time < ( float ) pNodeAnim - > mPositionKeys [ i + 1 ] . mTime )
{
frameIndex = i ;
break ;
}
}
aiVectorKey currentFrame = pNodeAnim - > mPositionKeys [ frameIndex ] ;
aiVectorKey nextFrame = pNodeAnim - > mPositionKeys [ ( frameIndex + 1 ) % pNodeAnim - > mNumPositionKeys ] ;
2016-05-14 21:19:52 +02:00
2016-02-16 15:07:25 +01:00
float delta = ( time - ( float ) currentFrame . mTime ) / ( float ) ( nextFrame . mTime - currentFrame . mTime ) ;
const aiVector3D & start = currentFrame . mValue ;
const aiVector3D & end = nextFrame . mValue ;
translation = ( start + delta * ( end - start ) ) ;
}
aiMatrix4x4 mat ;
aiMatrix4x4 : : Translation ( translation , mat ) ;
return mat ;
}
// Returns a 4x4 matrix with interpolated rotation between current and next frame
aiMatrix4x4 interpolateRotation ( float time , const aiNodeAnim * pNodeAnim )
{
aiQuaternion rotation ;
2016-05-14 21:19:52 +02:00
if ( pNodeAnim - > mNumRotationKeys = = 1 )
2016-02-16 15:07:25 +01:00
{
rotation = pNodeAnim - > mRotationKeys [ 0 ] . mValue ;
}
else
{
uint32_t frameIndex = 0 ;
for ( uint32_t i = 0 ; i < pNodeAnim - > mNumRotationKeys - 1 ; i + + )
{
if ( time < ( float ) pNodeAnim - > mRotationKeys [ i + 1 ] . mTime )
{
frameIndex = i ;
break ;
}
}
aiQuatKey currentFrame = pNodeAnim - > mRotationKeys [ frameIndex ] ;
aiQuatKey nextFrame = pNodeAnim - > mRotationKeys [ ( frameIndex + 1 ) % pNodeAnim - > mNumRotationKeys ] ;
float delta = ( time - ( float ) currentFrame . mTime ) / ( float ) ( nextFrame . mTime - currentFrame . mTime ) ;
const aiQuaternion & start = currentFrame . mValue ;
const aiQuaternion & end = nextFrame . mValue ;
aiQuaternion : : Interpolate ( rotation , start , end , delta ) ;
rotation . Normalize ( ) ;
}
aiMatrix4x4 mat ( rotation . GetMatrix ( ) ) ;
return mat ;
}
// Returns a 4x4 matrix with interpolated scaling between current and next frame
aiMatrix4x4 interpolateScale ( float time , const aiNodeAnim * pNodeAnim )
{
aiVector3D scale ;
2016-05-14 21:19:52 +02:00
if ( pNodeAnim - > mNumScalingKeys = = 1 )
2016-02-16 15:07:25 +01:00
{
scale = pNodeAnim - > mScalingKeys [ 0 ] . mValue ;
}
else
{
uint32_t frameIndex = 0 ;
for ( uint32_t i = 0 ; i < pNodeAnim - > mNumScalingKeys - 1 ; i + + )
{
if ( time < ( float ) pNodeAnim - > mScalingKeys [ i + 1 ] . mTime )
{
frameIndex = i ;
break ;
}
}
aiVectorKey currentFrame = pNodeAnim - > mScalingKeys [ frameIndex ] ;
aiVectorKey nextFrame = pNodeAnim - > mScalingKeys [ ( frameIndex + 1 ) % pNodeAnim - > mNumScalingKeys ] ;
float delta = ( time - ( float ) currentFrame . mTime ) / ( float ) ( nextFrame . mTime - currentFrame . mTime ) ;
const aiVector3D & start = currentFrame . mValue ;
const aiVector3D & end = nextFrame . mValue ;
scale = ( start + delta * ( end - start ) ) ;
}
aiMatrix4x4 mat ;
aiMatrix4x4 : : Scaling ( scale , mat ) ;
return mat ;
}
// Get node hierarchy for current animation time
void readNodeHierarchy ( float AnimationTime , const aiNode * pNode , const aiMatrix4x4 & ParentTransform )
{
std : : string NodeName ( pNode - > mName . data ) ;
aiMatrix4x4 NodeTransformation ( pNode - > mTransformation ) ;
const aiNodeAnim * pNodeAnim = findNodeAnim ( pAnimation , NodeName ) ;
if ( pNodeAnim )
{
// Get interpolated matrices between current and next frame
aiMatrix4x4 matScale = interpolateScale ( AnimationTime , pNodeAnim ) ;
aiMatrix4x4 matRotation = interpolateRotation ( AnimationTime , pNodeAnim ) ;
aiMatrix4x4 matTranslation = interpolateTranslation ( AnimationTime , pNodeAnim ) ;
2016-05-14 20:03:29 +02:00
NodeTransformation = matTranslation * matRotation * matScale ;
2016-02-16 15:07:25 +01:00
}
aiMatrix4x4 GlobalTransformation = ParentTransform * NodeTransformation ;
2016-05-14 21:19:52 +02:00
if ( boneMapping . find ( NodeName ) ! = boneMapping . end ( ) )
2016-02-16 15:07:25 +01:00
{
2016-05-14 21:19:52 +02:00
uint32_t BoneIndex = boneMapping [ NodeName ] ;
boneInfo [ BoneIndex ] . finalTransformation = globalInverseTransform * GlobalTransformation * boneInfo [ BoneIndex ] . offset ;
2016-02-16 15:07:25 +01:00
}
for ( uint32_t i = 0 ; i < pNode - > mNumChildren ; i + + )
{
readNodeHierarchy ( AnimationTime , pNode - > mChildren [ i ] , GlobalTransformation ) ;
}
}
2016-05-14 21:19:52 +02:00
} ;
class VulkanExample : public VulkanExampleBase
{
public :
struct {
2017-02-09 21:55:35 +01:00
vks : : Texture2D colorMap ;
vks : : Texture2D floor ;
2016-05-14 21:19:52 +02:00
} textures ;
2016-06-14 18:12:47 +02:00
SkinnedMesh * skinnedMesh = nullptr ;
2016-05-14 21:19:52 +02:00
struct {
2016-10-30 18:13:49 +01:00
vk : : Buffer mesh ;
vk : : Buffer floor ;
} uniformBuffers ;
2016-05-14 21:19:52 +02:00
struct {
glm : : mat4 projection ;
glm : : mat4 model ;
2016-08-18 18:52:50 +02:00
glm : : mat4 view ;
2016-05-14 21:19:52 +02:00
glm : : mat4 bones [ MAX_BONES ] ;
glm : : vec4 lightPos = glm : : vec4 ( 0.0f , - 250.0f , 250.0f , 1.0 ) ;
glm : : vec4 viewPos ;
} uboVS ;
2016-02-16 15:07:25 +01:00
2016-05-14 21:19:52 +02:00
struct {
glm : : mat4 projection ;
glm : : mat4 model ;
2016-08-18 18:52:50 +02:00
glm : : mat4 view ;
2016-05-14 21:19:52 +02:00
glm : : vec4 lightPos = glm : : vec4 ( 0.0 , 0.0f , - 25.0f , 1.0 ) ;
glm : : vec4 viewPos ;
glm : : vec2 uvOffset ;
} uboFloor ;
struct {
VkPipeline skinning ;
VkPipeline texture ;
} pipelines ;
struct {
2017-02-11 12:35:18 +01:00
vks : : Model floor ;
} models ;
2016-05-14 21:19:52 +02:00
VkPipelineLayout pipelineLayout ;
VkDescriptorSet descriptorSet ;
VkDescriptorSetLayout descriptorSetLayout ;
struct {
VkDescriptorSet skinning ;
VkDescriptorSet floor ;
} descriptorSets ;
float runningTime = 0.0f ;
VulkanExample ( ) : VulkanExampleBase ( ENABLE_VALIDATION )
2016-02-16 15:07:25 +01:00
{
2016-05-14 21:19:52 +02:00
zoom = - 150.0f ;
zoomSpeed = 2.5f ;
rotationSpeed = 0.5f ;
rotation = { - 182.5f , - 38.5f , 180.0f } ;
2016-06-04 13:35:52 +02:00
enableTextOverlay = true ;
2016-05-14 21:19:52 +02:00
title = " Vulkan Example - Skeletal animation " ;
cameraPos = { 0.0f , 0.0f , 12.0f } ;
}
2016-02-16 15:07:25 +01:00
2016-05-14 21:19:52 +02:00
~ VulkanExample ( )
{
// Clean up used Vulkan resources
// Note : Inherited destructor cleans up resources stored in base class
vkDestroyPipeline ( device , pipelines . skinning , nullptr ) ;
2016-08-18 18:52:50 +02:00
vkDestroyPipeline ( device , pipelines . texture , nullptr ) ;
2016-05-14 21:19:52 +02:00
vkDestroyPipelineLayout ( device , pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayout , nullptr ) ;
2016-02-16 15:07:25 +01:00
2017-02-09 21:55:35 +01:00
textures . colorMap . destroy ( ) ;
textures . floor . destroy ( ) ;
2016-05-14 21:19:52 +02:00
2016-10-30 18:13:49 +01:00
uniformBuffers . mesh . destroy ( ) ;
uniformBuffers . floor . destroy ( ) ;
2016-05-14 21:19:52 +02:00
2017-02-11 12:35:18 +01:00
models . floor . destroy ( ) ;
2016-05-14 21:19:52 +02:00
delete ( skinnedMesh ) ;
}
void buildCommandBuffers ( )
{
VkCommandBufferBeginInfo cmdBufInfo = vkTools : : initializers : : commandBufferBeginInfo ( ) ;
VkClearValue clearValues [ 2 ] ;
clearValues [ 0 ] . color = { { 0.0f , 0.0f , 0.0f , 0.0f } } ;
clearValues [ 1 ] . depthStencil = { 1.0f , 0 } ;
VkRenderPassBeginInfo renderPassBeginInfo = vkTools : : initializers : : renderPassBeginInfo ( ) ;
renderPassBeginInfo . renderPass = renderPass ;
renderPassBeginInfo . renderArea . offset . x = 0 ;
renderPassBeginInfo . renderArea . offset . y = 0 ;
renderPassBeginInfo . renderArea . extent . width = width ;
renderPassBeginInfo . renderArea . extent . height = height ;
renderPassBeginInfo . clearValueCount = 2 ;
renderPassBeginInfo . pClearValues = clearValues ;
for ( int32_t i = 0 ; i < drawCmdBuffers . size ( ) ; + + i )
2016-02-16 15:07:25 +01:00
{
2016-05-14 21:19:52 +02:00
renderPassBeginInfo . framebuffer = frameBuffers [ i ] ;
2016-05-30 20:57:38 +02:00
VK_CHECK_RESULT ( vkBeginCommandBuffer ( drawCmdBuffers [ i ] , & cmdBufInfo ) ) ;
2016-05-14 21:19:52 +02:00
vkCmdBeginRenderPass ( drawCmdBuffers [ i ] , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
VkViewport viewport = vkTools : : initializers : : viewport ( ( float ) width , ( float ) height , 0.0f , 1.0f ) ;
vkCmdSetViewport ( drawCmdBuffers [ i ] , 0 , 1 , & viewport ) ;
VkRect2D scissor = vkTools : : initializers : : rect2D ( width , height , 0 , 0 ) ;
vkCmdSetScissor ( drawCmdBuffers [ i ] , 0 , 1 , & scissor ) ;
VkDeviceSize offsets [ 1 ] = { 0 } ;
// Skinned mesh
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 0 , 1 , & descriptorSet , 0 , NULL ) ;
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelines . skinning ) ;
2017-02-11 12:35:18 +01:00
vkCmdBindVertexBuffers ( drawCmdBuffers [ i ] , VERTEX_BUFFER_BIND_ID , 1 , & skinnedMesh - > vertexBuffer . vertices . buffer , offsets ) ;
vkCmdBindIndexBuffer ( drawCmdBuffers [ i ] , skinnedMesh - > vertexBuffer . indices . buffer , 0 , VK_INDEX_TYPE_UINT32 ) ;
vkCmdDrawIndexed ( drawCmdBuffers [ i ] , skinnedMesh - > vertexBuffer . indexCount , 1 , 0 , 0 , 0 ) ;
2016-05-14 21:19:52 +02:00
// Floor
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 0 , 1 , & descriptorSets . floor , 0 , NULL ) ;
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelines . texture ) ;
2017-02-11 12:35:18 +01:00
vkCmdBindVertexBuffers ( drawCmdBuffers [ i ] , VERTEX_BUFFER_BIND_ID , 1 , & models . floor . vertices . buffer , offsets ) ;
vkCmdBindIndexBuffer ( drawCmdBuffers [ i ] , models . floor . indices . buffer , 0 , VK_INDEX_TYPE_UINT32 ) ;
vkCmdDrawIndexed ( drawCmdBuffers [ i ] , models . floor . indexCount , 1 , 0 , 0 , 0 ) ;
2016-05-14 21:19:52 +02:00
vkCmdEndRenderPass ( drawCmdBuffers [ i ] ) ;
2016-05-30 20:57:38 +02:00
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
2016-02-16 15:07:25 +01:00
}
}
// Load a mesh based on data read via assimp
void loadMesh ( )
{
2016-05-14 21:19:52 +02:00
skinnedMesh = new SkinnedMesh ( ) ;
2017-02-11 12:35:18 +01:00
std : : string filename = getAssetPath ( ) + " models/goblin.dae " ;
2016-03-25 21:08:59 +01:00
# if defined(__ANDROID__)
2017-02-11 12:35:18 +01:00
// Meshes are stored inside the apk on Android (compressed)
// So they need to be loaded via the asset manager
AAsset * asset = AAssetManager_open ( androidApp - > activity - > assetManager , filename . c_str ( ) , AASSET_MODE_STREAMING ) ;
assert ( asset ) ;
size_t size = AAsset_getLength ( asset ) ;
assert ( size > 0 ) ;
void * meshData = malloc ( size ) ;
AAsset_read ( asset , meshData , size ) ;
AAsset_close ( asset ) ;
skinnedMesh - > scene = skinnedMesh - > Importer . ReadFileFromMemory ( meshData , size , 0 ) ;
free ( meshData ) ;
# else
skinnedMesh - > scene = skinnedMesh - > Importer . ReadFile ( filename . c_str ( ) , 0 ) ;
2016-03-25 21:08:59 +01:00
# endif
2016-05-14 21:40:58 +02:00
skinnedMesh - > setAnimation ( 0 ) ;
2016-02-16 15:07:25 +01:00
// Setup bones
// One vertex bone info structure per vertex
2017-02-11 12:35:18 +01:00
uint32_t vertexCount ( 0 ) ;
for ( uint32_t m = 0 ; m < skinnedMesh - > scene - > mNumMeshes ; m + + ) {
vertexCount + = skinnedMesh - > scene - > mMeshes [ m ] - > mNumVertices ;
} ;
skinnedMesh - > bones . resize ( vertexCount ) ;
2016-02-16 15:07:25 +01:00
// Store global inverse transform matrix of root node
2017-02-11 12:35:18 +01:00
skinnedMesh - > globalInverseTransform = skinnedMesh - > scene - > mRootNode - > mTransformation ;
2016-05-14 21:19:52 +02:00
skinnedMesh - > globalInverseTransform . Inverse ( ) ;
2016-02-16 15:07:25 +01:00
// Load bones (weights and IDs)
2017-02-11 12:35:18 +01:00
uint32_t vertexBase ( 0 ) ;
for ( uint32_t m = 0 ; m < skinnedMesh - > scene - > mNumMeshes ; m + + ) {
aiMesh * paiMesh = skinnedMesh - > scene - > mMeshes [ m ] ;
if ( paiMesh - > mNumBones > 0 ) {
skinnedMesh - > loadBones ( paiMesh , vertexBase , skinnedMesh - > bones ) ;
2016-02-16 15:07:25 +01:00
}
2017-02-11 12:35:18 +01:00
vertexBase + = skinnedMesh - > scene - > mMeshes [ m ] - > mNumVertices ;
2016-02-16 15:07:25 +01:00
}
// Generate vertex buffer
std : : vector < Vertex > vertexBuffer ;
2017-02-11 12:35:18 +01:00
// Iterate through all meshes in the file and extract the vertex information used in this demo
vertexBase = 0 ;
for ( uint32_t m = 0 ; m < skinnedMesh - > scene - > mNumMeshes ; m + + ) {
for ( uint32_t v = 0 ; v < skinnedMesh - > scene - > mMeshes [ m ] - > mNumVertices ; v + + ) {
2016-02-16 15:07:25 +01:00
Vertex vertex ;
2017-02-11 12:35:18 +01:00
vertex . pos = glm : : make_vec3 ( & skinnedMesh - > scene - > mMeshes [ m ] - > mVertices [ v ] . x ) ;
vertex . normal = glm : : make_vec3 ( & skinnedMesh - > scene - > mMeshes [ m ] - > mNormals [ v ] . x ) ;
vertex . uv = glm : : make_vec2 ( & skinnedMesh - > scene - > mMeshes [ m ] - > mTextureCoords [ 0 ] [ v ] . x ) ;
vertex . color = ( skinnedMesh - > scene - > mMeshes [ m ] - > HasVertexColors ( 0 ) ) ? glm : : make_vec3 ( & skinnedMesh - > scene - > mMeshes [ m ] - > mColors [ 0 ] [ v ] . r ) : glm : : vec3 ( 1.0f ) ;
2016-02-16 15:07:25 +01:00
// Fetch bone weights and IDs
2017-02-11 12:35:18 +01:00
for ( uint32_t j = 0 ; j < MAX_BONES_PER_VERTEX ; j + + ) {
vertex . boneWeights [ j ] = skinnedMesh - > bones [ vertexBase + v ] . weights [ j ] ;
vertex . boneIDs [ j ] = skinnedMesh - > bones [ vertexBase + v ] . IDs [ j ] ;
2016-02-16 15:07:25 +01:00
}
vertexBuffer . push_back ( vertex ) ;
}
2017-02-11 12:35:18 +01:00
vertexBase + = skinnedMesh - > scene - > mMeshes [ m ] - > mNumVertices ;
2016-02-16 15:07:25 +01:00
}
2016-10-30 18:13:49 +01:00
VkDeviceSize vertexBufferSize = vertexBuffer . size ( ) * sizeof ( Vertex ) ;
2016-02-16 15:07:25 +01:00
// Generate index buffer from loaded mesh file
std : : vector < uint32_t > indexBuffer ;
2017-02-11 12:35:18 +01:00
for ( uint32_t m = 0 ; m < skinnedMesh - > scene - > mNumMeshes ; m + + ) {
2016-10-30 18:13:49 +01:00
uint32_t indexBase = static_cast < uint32_t > ( indexBuffer . size ( ) ) ;
2017-02-11 12:35:18 +01:00
for ( uint32_t f = 0 ; f < skinnedMesh - > scene - > mMeshes [ m ] - > mNumFaces ; f + + ) {
for ( uint32_t i = 0 ; i < 3 ; i + + )
{
indexBuffer . push_back ( skinnedMesh - > scene - > mMeshes [ m ] - > mFaces [ f ] . mIndices [ i ] + indexBase ) ;
}
2016-02-16 15:07:25 +01:00
}
}
2016-10-30 18:13:49 +01:00
VkDeviceSize indexBufferSize = indexBuffer . size ( ) * sizeof ( uint32_t ) ;
2017-02-11 12:35:18 +01:00
skinnedMesh - > vertexBuffer . indexCount = static_cast < uint32_t > ( indexBuffer . size ( ) ) ;
2016-02-16 15:07:25 +01:00
2017-01-07 20:46:28 +01:00
struct {
VkBuffer buffer ;
VkDeviceMemory memory ;
} vertexStaging , indexStaging ;
// Create staging buffers
// Vertex data
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_TRANSFER_SRC_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
vertexBufferSize ,
& vertexStaging . buffer ,
& vertexStaging . memory ,
vertexBuffer . data ( ) ) ) ;
// Index data
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_TRANSFER_SRC_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
indexBufferSize ,
& indexStaging . buffer ,
& indexStaging . memory ,
indexBuffer . data ( ) ) ) ;
// Create device local buffers
// Vertex buffer
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT ,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ,
2017-02-11 12:35:18 +01:00
& skinnedMesh - > vertexBuffer . vertices ,
vertexBufferSize ) ) ;
2017-01-07 20:46:28 +01:00
// Index buffer
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT ,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ,
2017-02-11 12:35:18 +01:00
& skinnedMesh - > vertexBuffer . indices ,
indexBufferSize ) ) ;
2017-01-07 20:46:28 +01:00
// Copy from staging buffers
VkCommandBuffer copyCmd = VulkanExampleBase : : createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
VkBufferCopy copyRegion = { } ;
copyRegion . size = vertexBufferSize ;
vkCmdCopyBuffer (
copyCmd ,
vertexStaging . buffer ,
2017-02-11 12:35:18 +01:00
skinnedMesh - > vertexBuffer . vertices . buffer ,
2017-01-07 20:46:28 +01:00
1 ,
& copyRegion ) ;
copyRegion . size = indexBufferSize ;
vkCmdCopyBuffer (
copyCmd ,
indexStaging . buffer ,
2017-02-11 12:35:18 +01:00
skinnedMesh - > vertexBuffer . indices . buffer ,
2017-01-07 20:46:28 +01:00
1 ,
& copyRegion ) ;
VulkanExampleBase : : flushCommandBuffer ( copyCmd , queue , true ) ;
vkDestroyBuffer ( device , vertexStaging . buffer , nullptr ) ;
vkFreeMemory ( device , vertexStaging . memory , nullptr ) ;
vkDestroyBuffer ( device , indexStaging . buffer , nullptr ) ;
vkFreeMemory ( device , indexStaging . memory , nullptr ) ;
2016-02-16 15:07:25 +01:00
}
2016-10-30 18:13:49 +01:00
void loadAssets ( )
2016-05-14 20:03:29 +02:00
{
2017-02-09 21:55:35 +01:00
textures . colorMap . loadFromFile ( getAssetPath ( ) + " textures/goblin_bc3.ktx " , VK_FORMAT_BC3_UNORM_BLOCK , vulkanDevice , queue ) ;
textures . floor . loadFromFile ( getAssetPath ( ) + " textures/trail_bc3.ktx " , VK_FORMAT_BC3_UNORM_BLOCK , vulkanDevice , queue ) ;
2017-02-11 12:35:18 +01:00
models . floor . loadFromFile ( getAssetPath ( ) + " models/plane_z.obj " , vertexLayout , 512.0f , vulkanDevice , queue ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorPool ( )
{
// Example uses one ubo and one combined image sampler
std : : vector < VkDescriptorPoolSize > poolSizes =
{
2016-05-14 20:03:29 +02:00
vkTools : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 2 ) ,
vkTools : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 2 ) ,
2016-02-16 15:07:25 +01:00
} ;
VkDescriptorPoolCreateInfo descriptorPoolInfo =
vkTools : : initializers : : descriptorPoolCreateInfo (
poolSizes . size ( ) ,
poolSizes . data ( ) ,
2 ) ;
2016-05-14 21:40:58 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSetLayout ( )
{
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings =
{
// Binding 0 : Vertex shader uniform buffer
vkTools : : initializers : : descriptorSetLayoutBinding (
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
VK_SHADER_STAGE_VERTEX_BIT ,
0 ) ,
// Binding 1 : Fragment shader combined sampler
vkTools : : initializers : : descriptorSetLayoutBinding (
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
VK_SHADER_STAGE_FRAGMENT_BIT ,
1 ) ,
} ;
VkDescriptorSetLayoutCreateInfo descriptorLayout =
vkTools : : initializers : : descriptorSetLayoutCreateInfo (
setLayoutBindings . data ( ) ,
setLayoutBindings . size ( ) ) ;
2016-05-14 21:40:58 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorLayout , nullptr , & descriptorSetLayout ) ) ;
2016-02-16 15:07:25 +01:00
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
vkTools : : initializers : : pipelineLayoutCreateInfo (
& descriptorSetLayout ,
1 ) ;
2016-05-14 21:40:58 +02:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pPipelineLayoutCreateInfo , nullptr , & pipelineLayout ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSet ( )
{
VkDescriptorSetAllocateInfo allocInfo =
vkTools : : initializers : : descriptorSetAllocateInfo (
descriptorPool ,
& descriptorSetLayout ,
1 ) ;
2016-05-14 21:40:58 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSet ) ) ;
2016-02-16 15:07:25 +01:00
VkDescriptorImageInfo texDescriptor =
vkTools : : initializers : : descriptorImageInfo (
textures . colorMap . sampler ,
textures . colorMap . view ,
VK_IMAGE_LAYOUT_GENERAL ) ;
std : : vector < VkWriteDescriptorSet > writeDescriptorSets =
{
// Binding 0 : Vertex shader uniform buffer
vkTools : : initializers : : writeDescriptorSet (
2016-05-14 20:03:29 +02:00
descriptorSet ,
2016-02-16 15:07:25 +01:00
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
0 ,
2016-10-30 18:13:49 +01:00
& uniformBuffers . mesh . descriptor ) ,
2016-02-16 15:07:25 +01:00
// Binding 1 : Color map
vkTools : : initializers : : writeDescriptorSet (
descriptorSet ,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
1 ,
& texDescriptor )
} ;
vkUpdateDescriptorSets ( device , writeDescriptorSets . size ( ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
2016-05-14 20:03:29 +02:00
// Floor
2016-05-30 20:57:38 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSets . floor ) ) ;
2016-05-14 20:03:29 +02:00
texDescriptor . imageView = textures . floor . view ;
texDescriptor . sampler = textures . floor . sampler ;
writeDescriptorSets . clear ( ) ;
// Binding 0 : Vertex shader uniform buffer
writeDescriptorSets . push_back (
vkTools : : initializers : : writeDescriptorSet (
descriptorSets . floor ,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
0 ,
2016-10-30 18:13:49 +01:00
& uniformBuffers . floor . descriptor ) ) ;
2016-05-14 20:03:29 +02:00
// Binding 1 : Color map
writeDescriptorSets . push_back (
vkTools : : initializers : : writeDescriptorSet (
descriptorSets . floor ,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
1 ,
& texDescriptor ) ) ;
vkUpdateDescriptorSets ( device , writeDescriptorSets . size ( ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
2016-02-16 15:07:25 +01:00
}
void preparePipelines ( )
{
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
vkTools : : initializers : : pipelineInputAssemblyStateCreateInfo (
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ,
0 ,
VK_FALSE ) ;
VkPipelineRasterizationStateCreateInfo rasterizationState =
vkTools : : initializers : : pipelineRasterizationStateCreateInfo (
VK_POLYGON_MODE_FILL ,
VK_CULL_MODE_BACK_BIT ,
VK_FRONT_FACE_CLOCKWISE ,
0 ) ;
VkPipelineColorBlendAttachmentState blendAttachmentState =
vkTools : : initializers : : pipelineColorBlendAttachmentState (
0xf ,
VK_FALSE ) ;
VkPipelineColorBlendStateCreateInfo colorBlendState =
vkTools : : initializers : : pipelineColorBlendStateCreateInfo (
1 ,
& blendAttachmentState ) ;
VkPipelineDepthStencilStateCreateInfo depthStencilState =
vkTools : : initializers : : pipelineDepthStencilStateCreateInfo (
VK_TRUE ,
VK_TRUE ,
VK_COMPARE_OP_LESS_OR_EQUAL ) ;
VkPipelineViewportStateCreateInfo viewportState =
vkTools : : initializers : : pipelineViewportStateCreateInfo ( 1 , 1 , 0 ) ;
VkPipelineMultisampleStateCreateInfo multisampleState =
vkTools : : initializers : : pipelineMultisampleStateCreateInfo (
VK_SAMPLE_COUNT_1_BIT ,
0 ) ;
std : : vector < VkDynamicState > dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT ,
VK_DYNAMIC_STATE_SCISSOR
} ;
VkPipelineDynamicStateCreateInfo dynamicState =
vkTools : : initializers : : pipelineDynamicStateCreateInfo (
dynamicStateEnables . data ( ) ,
dynamicStateEnables . size ( ) ,
0 ) ;
2016-05-14 20:03:29 +02:00
// Skinned rendering pipeline
2016-02-16 15:07:25 +01:00
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
VkGraphicsPipelineCreateInfo pipelineCreateInfo =
vkTools : : initializers : : pipelineCreateInfo (
pipelineLayout ,
renderPass ,
0 ) ;
pipelineCreateInfo . pInputAssemblyState = & inputAssemblyState ;
pipelineCreateInfo . pRasterizationState = & rasterizationState ;
pipelineCreateInfo . pColorBlendState = & colorBlendState ;
pipelineCreateInfo . pMultisampleState = & multisampleState ;
pipelineCreateInfo . pViewportState = & viewportState ;
pipelineCreateInfo . pDepthStencilState = & depthStencilState ;
pipelineCreateInfo . pDynamicState = & dynamicState ;
2017-02-11 12:35:18 +01:00
pipelineCreateInfo . stageCount = static_cast < uint32_t > ( shaderStages . size ( ) ) ;
2016-02-16 15:07:25 +01:00
pipelineCreateInfo . pStages = shaderStages . data ( ) ;
2017-02-11 12:35:18 +01:00
// Shared vertex inputs
// Binding description
VkVertexInputBindingDescription vertexInputBinding =
vkTools : : initializers : : vertexInputBindingDescription ( VERTEX_BUFFER_BIND_ID , sizeof ( Vertex ) , VK_VERTEX_INPUT_RATE_VERTEX ) ;
// Attribute descriptions
// Describes memory layout and shader positions
std : : vector < VkVertexInputAttributeDescription > vertexInputAttributes = {
vkTools : : initializers : : vertexInputAttributeDescription ( VERTEX_BUFFER_BIND_ID , 0 , VK_FORMAT_R32G32B32_SFLOAT , 0 ) , // Location 0: Position
vkTools : : initializers : : vertexInputAttributeDescription ( VERTEX_BUFFER_BIND_ID , 1 , VK_FORMAT_R32G32B32_SFLOAT , sizeof ( float ) * 3 ) , // Location 1: Normal
vkTools : : initializers : : vertexInputAttributeDescription ( VERTEX_BUFFER_BIND_ID , 2 , VK_FORMAT_R32G32_SFLOAT , sizeof ( float ) * 6 ) , // Location 2: Texture coordinates
vkTools : : initializers : : vertexInputAttributeDescription ( VERTEX_BUFFER_BIND_ID , 3 , VK_FORMAT_R32G32B32_SFLOAT , sizeof ( float ) * 8 ) , // Location 3: Color
vkTools : : initializers : : vertexInputAttributeDescription ( VERTEX_BUFFER_BIND_ID , 4 , VK_FORMAT_R32G32B32A32_SFLOAT , sizeof ( float ) * 11 ) , // Location 4: Bone weights
vkTools : : initializers : : vertexInputAttributeDescription ( VERTEX_BUFFER_BIND_ID , 5 , VK_FORMAT_R32G32B32A32_SINT , sizeof ( float ) * 15 ) , // Location 5: Bone IDs
} ;
VkPipelineVertexInputStateCreateInfo vertexInputState = vkTools : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
vertexInputState . vertexBindingDescriptionCount = 1 ;
vertexInputState . pVertexBindingDescriptions = & vertexInputBinding ;
vertexInputState . vertexAttributeDescriptionCount = static_cast < uint32_t > ( vertexInputAttributes . size ( ) ) ;
vertexInputState . pVertexAttributeDescriptions = vertexInputAttributes . data ( ) ;
pipelineCreateInfo . pVertexInputState = & vertexInputState ;
// Skinned mesh rendering pipeline
shaderStages [ 0 ] = loadShader ( getAssetPath ( ) + " shaders/skeletalanimation/mesh.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getAssetPath ( ) + " shaders/skeletalanimation/mesh.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2016-05-14 21:40:58 +02:00
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCreateInfo , nullptr , & pipelines . skinning ) ) ;
2016-05-14 20:03:29 +02:00
2017-02-11 12:35:18 +01:00
// Environment rendering pipeline
2016-05-14 20:03:29 +02:00
shaderStages [ 0 ] = loadShader ( getAssetPath ( ) + " shaders/skeletalanimation/texture.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getAssetPath ( ) + " shaders/skeletalanimation/texture.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2016-05-30 20:57:38 +02:00
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCreateInfo , nullptr , & pipelines . texture ) ) ;
2016-02-16 15:07:25 +01:00
}
// Prepare and initialize uniform buffer containing shader uniforms
void prepareUniformBuffers ( )
{
2016-10-30 18:13:49 +01:00
// Mesh uniform buffer block
vulkanDevice - > createBuffer (
2016-02-16 15:07:25 +01:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-06-04 13:35:52 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-10-30 18:13:49 +01:00
& uniformBuffers . mesh ,
sizeof ( uboVS ) ) ;
// Map persistant
VK_CHECK_RESULT ( uniformBuffers . mesh . map ( ) ) ;
2016-02-16 15:07:25 +01:00
2016-10-30 18:13:49 +01:00
// Floor uniform buffer block
vulkanDevice - > createBuffer (
2016-05-14 20:03:29 +02:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-06-04 13:35:52 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-10-30 18:13:49 +01:00
& uniformBuffers . floor ,
sizeof ( uboFloor ) ) ;
// Map persistant
VK_CHECK_RESULT ( uniformBuffers . floor . map ( ) ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 20:03:29 +02:00
updateUniformBuffers ( true ) ;
}
void updateUniformBuffers ( bool viewChanged )
{
if ( viewChanged )
{
2016-10-30 18:13:49 +01:00
uboVS . projection = glm : : perspective ( glm : : radians ( 60.0f ) , ( float ) width / ( float ) height , 0.1f , 1024.0f ) ;
2016-05-14 20:03:29 +02:00
glm : : mat4 viewMatrix = glm : : translate ( glm : : mat4 ( ) , glm : : vec3 ( 0.0f , 0.0f , zoom ) ) ;
viewMatrix = glm : : rotate ( viewMatrix , glm : : radians ( 90.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) ) ;
viewMatrix = glm : : scale ( viewMatrix , glm : : vec3 ( 0.025f ) ) ;
2016-08-18 18:52:50 +02:00
uboVS . view = viewMatrix * glm : : translate ( glm : : mat4 ( ) , glm : : vec3 ( cameraPos . x , - cameraPos . z , cameraPos . y ) * 100.0f ) ;
uboVS . view = glm : : rotate ( uboVS . view , glm : : radians ( rotation . x ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) ) ;
uboVS . view = glm : : rotate ( uboVS . view , glm : : radians ( rotation . z ) , glm : : vec3 ( 0.0f , 1.0f , 0.0f ) ) ;
uboVS . view = glm : : rotate ( uboVS . view , glm : : radians ( - rotation . y ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) ) ;
2016-05-14 20:03:29 +02:00
uboVS . viewPos = glm : : vec4 ( 0.0f , 0.0f , - zoom , 0.0f ) ;
uboFloor . projection = uboVS . projection ;
2016-08-18 18:52:50 +02:00
uboFloor . view = viewMatrix ;
uboFloor . model = glm : : translate ( glm : : mat4 ( ) , glm : : vec3 ( cameraPos . x , - cameraPos . z , cameraPos . y ) * 100.0f ) ;
2016-05-14 20:03:29 +02:00
uboFloor . model = glm : : rotate ( uboFloor . model , glm : : radians ( rotation . x ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) ) ;
uboFloor . model = glm : : rotate ( uboFloor . model , glm : : radians ( rotation . z ) , glm : : vec3 ( 0.0f , 1.0f , 0.0f ) ) ;
uboFloor . model = glm : : rotate ( uboFloor . model , glm : : radians ( - rotation . y ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) ) ;
uboFloor . model = glm : : translate ( uboFloor . model , glm : : vec3 ( 0.0f , 0.0f , - 1800.0f ) ) ;
uboFloor . viewPos = glm : : vec4 ( 0.0f , 0.0f , - zoom , 0.0f ) ;
}
2016-02-16 15:07:25 +01:00
// Update bones
2016-05-14 21:19:52 +02:00
skinnedMesh - > update ( runningTime ) ;
for ( uint32_t i = 0 ; i < skinnedMesh - > boneTransforms . size ( ) ; i + + )
2016-06-04 13:35:52 +02:00
{
2016-05-14 21:19:52 +02:00
uboVS . bones [ i ] = glm : : transpose ( glm : : make_mat4 ( & skinnedMesh - > boneTransforms [ i ] . a1 ) ) ;
2016-02-16 15:07:25 +01:00
}
2016-10-30 18:13:49 +01:00
uniformBuffers . mesh . copyTo ( & uboVS , sizeof ( uboVS ) ) ;
2016-05-14 20:03:29 +02:00
// Update floor animation
2016-10-30 18:13:49 +01:00
uboFloor . uvOffset . t - = 0.25f * skinnedMesh - > animationSpeed * frameTimer ;
uniformBuffers . floor . copyTo ( & uboFloor , sizeof ( uboFloor ) ) ;
2016-02-16 15:07:25 +01:00
}
2016-06-04 13:35:52 +02:00
void draw ( )
{
VulkanExampleBase : : prepareFrame ( ) ;
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VulkanExampleBase : : submitFrame ( ) ;
}
2016-02-16 15:07:25 +01:00
void prepare ( )
{
VulkanExampleBase : : prepare ( ) ;
2016-10-30 18:13:49 +01:00
loadAssets ( ) ;
2016-02-16 15:07:25 +01:00
loadMesh ( ) ;
prepareUniformBuffers ( ) ;
setupDescriptorSetLayout ( ) ;
preparePipelines ( ) ;
setupDescriptorPool ( ) ;
setupDescriptorSet ( ) ;
buildCommandBuffers ( ) ;
prepared = true ;
}
virtual void render ( )
{
if ( ! prepared )
return ;
draw ( ) ;
if ( ! paused )
{
2016-05-14 21:19:52 +02:00
runningTime + = frameTimer * skinnedMesh - > animationSpeed ;
2016-05-14 20:03:29 +02:00
vkDeviceWaitIdle ( device ) ;
updateUniformBuffers ( false ) ;
2016-02-16 15:07:25 +01:00
}
}
virtual void viewChanged ( )
{
2016-05-14 20:03:29 +02:00
vkDeviceWaitIdle ( device ) ;
updateUniformBuffers ( true ) ;
2016-02-16 15:07:25 +01:00
}
2016-05-14 21:19:52 +02:00
void changeAnimationSpeed ( float delta )
{
skinnedMesh - > animationSpeed + = delta ;
2016-06-04 13:35:52 +02:00
}
virtual void keyPressed ( uint32_t keyCode )
{
switch ( keyCode )
{
2016-08-11 13:15:49 +02:00
case KEY_KPADD :
2016-06-04 13:35:52 +02:00
case GAMEPAD_BUTTON_R1 :
changeAnimationSpeed ( 0.1f ) ;
break ;
2016-08-11 13:15:49 +02:00
case KEY_KPSUB :
2016-06-04 13:35:52 +02:00
case GAMEPAD_BUTTON_L1 :
changeAnimationSpeed ( - 0.1f ) ;
break ;
}
}
virtual void getOverlayText ( VulkanTextOverlay * textOverlay )
{
if ( skinnedMesh ! = nullptr )
{
std : : stringstream ss ;
ss < < std : : setprecision ( 2 ) < < std : : fixed < < skinnedMesh - > animationSpeed ;
# if defined(__ANDROID__)
textOverlay - > addText ( " Animation speed: " + ss . str ( ) + " (Buttons L1/R1 to change) " , 5.0f , 85.0f , VulkanTextOverlay : : alignLeft ) ;
# else
textOverlay - > addText ( " Animation speed: " + ss . str ( ) + " (numpad +/- to change) " , 5.0f , 85.0f , VulkanTextOverlay : : alignLeft ) ;
# endif
}
2016-05-14 21:19:52 +02:00
}
2016-02-16 15:07:25 +01:00
} ;
2016-10-30 18:13:49 +01:00
VULKAN_EXAMPLE_MAIN ( )