diff --git a/data/shaders/glsl/skeletalanimation/mesh.frag b/data/shaders/glsl/skeletalanimation/mesh.frag deleted file mode 100644 index 4b652205..00000000 --- a/data/shaders/glsl/skeletalanimation/mesh.frag +++ /dev/null @@ -1,24 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColorMap; - -layout (location = 0) in vec3 inNormal; -layout (location = 1) in vec3 inColor; -layout (location = 2) in vec2 inUV; -layout (location = 3) in vec3 inViewVec; -layout (location = 4) in vec3 inLightVec; - -layout (location = 0) out vec4 outFragColor; - -void main() -{ - vec4 color = texture(samplerColorMap, inUV) * vec4(inColor, 1.0); - - vec3 N = normalize(inNormal); - vec3 L = normalize(inLightVec); - vec3 V = normalize(inViewVec); - vec3 R = reflect(-L, N); - vec3 diffuse = max(dot(N, L), 0.1) * vec3(1.0) * inColor; - vec3 specular = pow(max(dot(R, V), 0.0), 32.0) * vec3(0.5); - outFragColor = vec4(diffuse * color.rgb + specular, 1.0); -} \ No newline at end of file diff --git a/data/shaders/glsl/skeletalanimation/mesh.frag.spv b/data/shaders/glsl/skeletalanimation/mesh.frag.spv deleted file mode 100644 index 9fb3b8a6..00000000 Binary files a/data/shaders/glsl/skeletalanimation/mesh.frag.spv and /dev/null differ diff --git a/data/shaders/glsl/skeletalanimation/mesh.vert b/data/shaders/glsl/skeletalanimation/mesh.vert deleted file mode 100644 index b634de07..00000000 --- a/data/shaders/glsl/skeletalanimation/mesh.vert +++ /dev/null @@ -1,49 +0,0 @@ -#version 450 - -layout (location = 0) in vec3 inPos; -layout (location = 1) in vec3 inNormal; -layout (location = 2) in vec2 inUV; -layout (location = 3) in vec3 inColor; -layout (location = 4) in vec4 inBoneWeights; -layout (location = 5) in ivec4 inBoneIDs; - -#define MAX_BONES 64 - -layout (binding = 0) uniform UBO -{ - mat4 projection; - mat4 view; - mat4 model; - mat4 bones[MAX_BONES]; - vec4 lightPos; - vec4 viewPos; -} ubo; - -layout (location = 0) out vec3 outNormal; -layout (location = 1) out vec3 outColor; -layout (location = 2) out vec2 outUV; -layout (location = 3) out vec3 outViewVec; -layout (location = 4) out vec3 outLightVec; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - -void main() -{ - mat4 boneTransform = ubo.bones[inBoneIDs[0]] * inBoneWeights[0]; - boneTransform += ubo.bones[inBoneIDs[1]] * inBoneWeights[1]; - boneTransform += ubo.bones[inBoneIDs[2]] * inBoneWeights[2]; - boneTransform += ubo.bones[inBoneIDs[3]] * inBoneWeights[3]; - - outColor = inColor; - outUV = inUV; - - gl_Position = ubo.projection * ubo.view * ubo.model * boneTransform * vec4(inPos.xyz, 1.0); - - vec4 pos = ubo.model * vec4(inPos, 1.0); - outNormal = mat3(boneTransform) * inNormal; - outLightVec = ubo.lightPos.xyz - pos.xyz; - outViewVec = ubo.viewPos.xyz - pos.xyz; -} \ No newline at end of file diff --git a/data/shaders/glsl/skeletalanimation/mesh.vert.spv b/data/shaders/glsl/skeletalanimation/mesh.vert.spv deleted file mode 100644 index 8f45b833..00000000 Binary files a/data/shaders/glsl/skeletalanimation/mesh.vert.spv and /dev/null differ diff --git a/data/shaders/glsl/skeletalanimation/texture.frag b/data/shaders/glsl/skeletalanimation/texture.frag deleted file mode 100644 index 4b01cdc6..00000000 --- a/data/shaders/glsl/skeletalanimation/texture.frag +++ /dev/null @@ -1,28 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColorMap; - -layout (location = 0) in vec2 inUV; -layout (location = 1) in vec3 inNormal; -layout (location = 2) in vec3 inViewVec; -layout (location = 3) in vec3 inLightVec; - -layout (location = 0) out vec4 outFragColor; - -void main() -{ - vec4 color = texture(samplerColorMap, inUV); - - float distSqr = dot(inLightVec, inLightVec); - vec3 lVec = inLightVec * inversesqrt(distSqr); - - const float attInvRadius = 1.0/5000.0; - float atten = max(clamp(1.0 - attInvRadius * sqrt(distSqr), 0.0, 1.0), 0.0); - - // Fake drop shadow - const float shadowInvRadius = 1.0/2500.0; - float dropshadow = max(clamp(1.0 - shadowInvRadius * sqrt(distSqr), 0.0, 1.0), 0.0); - - outFragColor = vec4(color.rgba * (1.0 - dropshadow)); - outFragColor.rgb *= atten; -} \ No newline at end of file diff --git a/data/shaders/glsl/skeletalanimation/texture.frag.spv b/data/shaders/glsl/skeletalanimation/texture.frag.spv deleted file mode 100644 index 334dcfa4..00000000 Binary files a/data/shaders/glsl/skeletalanimation/texture.frag.spv and /dev/null differ diff --git a/data/shaders/glsl/skeletalanimation/texture.vert b/data/shaders/glsl/skeletalanimation/texture.vert deleted file mode 100644 index 88328eba..00000000 --- a/data/shaders/glsl/skeletalanimation/texture.vert +++ /dev/null @@ -1,36 +0,0 @@ -#version 450 - -layout (location = 0) in vec3 inPos; -layout (location = 1) in vec3 inNormal; -layout (location = 2) in vec2 inUV; - -layout (binding = 0) uniform UBO -{ - mat4 projection; - mat4 view; - mat4 model; - vec4 lightPos; - vec4 viewPos; - vec2 uvOffset; -} ubo; - -layout (location = 0) out vec2 outUV; -layout (location = 1) out vec3 outNormal; -layout (location = 2) out vec3 outViewVec; -layout (location = 3) out vec3 outLightVec; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - -void main() -{ - outUV = inUV + ubo.uvOffset; - vec4 pos = vec4(inPos, 1.0); - gl_Position = ubo.projection * ubo.view * ubo.model * vec4(pos); - - outNormal = inNormal; - outLightVec = ubo.lightPos.xyz - pos.xyz; - outViewVec = ubo.viewPos.xyz - pos.xyz; -} diff --git a/data/shaders/glsl/skeletalanimation/texture.vert.spv b/data/shaders/glsl/skeletalanimation/texture.vert.spv deleted file mode 100644 index a8d7b980..00000000 Binary files a/data/shaders/glsl/skeletalanimation/texture.vert.spv and /dev/null differ diff --git a/data/shaders/hlsl/skeletalanimation/mesh.frag b/data/shaders/hlsl/skeletalanimation/mesh.frag deleted file mode 100644 index 4117babb..00000000 --- a/data/shaders/hlsl/skeletalanimation/mesh.frag +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2020 Google LLC - -Texture2D textureColorMap : register(t1); -SamplerState samplerColorMap : register(s1); - -struct VSOutput -{ -[[vk::location(0)]] float3 Normal : NORMAL0; -[[vk::location(1)]] float3 Color : COLOR0; -[[vk::location(2)]] float2 UV : TEXCOORD0; -[[vk::location(3)]] float3 ViewVec : TEXCOORD1; -[[vk::location(4)]] float3 LightVec : TEXCOORD2; -}; - -float4 main(VSOutput input) : SV_TARGET -{ - float4 color = textureColorMap.Sample(samplerColorMap, input.UV) * float4(input.Color, 1.0); - - float3 N = normalize(input.Normal); - float3 L = normalize(input.LightVec); - float3 V = normalize(input.ViewVec); - float3 R = reflect(-L, N); - float3 diffuse = max(dot(N, L), 0.1) * float3(1.0, 1.0, 1.0) * input.Color; - float3 specular = pow(max(dot(R, V), 0.0), 32.0) * float3(0.5, 0.5, 0.5); - return float4(diffuse * color.rgb + specular, 1.0); -} \ No newline at end of file diff --git a/data/shaders/hlsl/skeletalanimation/mesh.frag.spv b/data/shaders/hlsl/skeletalanimation/mesh.frag.spv deleted file mode 100644 index 3a546e2a..00000000 Binary files a/data/shaders/hlsl/skeletalanimation/mesh.frag.spv and /dev/null differ diff --git a/data/shaders/hlsl/skeletalanimation/mesh.vert b/data/shaders/hlsl/skeletalanimation/mesh.vert deleted file mode 100644 index 1a1d6b57..00000000 --- a/data/shaders/hlsl/skeletalanimation/mesh.vert +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2020 Google LLC - -struct VSInput -{ -[[vk::location(0)]] float3 Pos : POSITION0; -[[vk::location(1)]] float3 Normal : NORMAL0; -[[vk::location(2)]] float2 UV : TEXCOORD0; -[[vk::location(3)]] float3 Color : COLOR0; -[[vk::location(4)]] float4 BoneWeights : TEXCOORD1; -[[vk::location(5)]] int4 BoneIDs : TEXCOORD2; -}; - -#define MAX_BONES 64 - -struct UBO -{ - float4x4 projection; - float4x4 view; - float4x4 model; - float4x4 bones[MAX_BONES]; - float4 lightPos; - float4 viewPos; -}; - -cbuffer ubo : register(b0) { UBO ubo; } - -struct VSOutput -{ - float4 Pos : SV_POSITION; -[[vk::location(0)]] float3 Normal : NORMAL0; -[[vk::location(1)]] float3 Color : COLOR0; -[[vk::location(2)]] float2 UV : TEXCOORD0; -[[vk::location(3)]] float3 ViewVec : TEXCOORD1; -[[vk::location(4)]] float3 LightVec : TEXCOORD2; -}; - -VSOutput main(VSInput input) -{ - VSOutput output = (VSOutput)0; - float4x4 boneTransform = ubo.bones[input.BoneIDs[0]] * input.BoneWeights[0]; - boneTransform += ubo.bones[input.BoneIDs[1]] * input.BoneWeights[1]; - boneTransform += ubo.bones[input.BoneIDs[2]] * input.BoneWeights[2]; - boneTransform += ubo.bones[input.BoneIDs[3]] * input.BoneWeights[3]; - - output.Color = input.Color; - output.UV = input.UV; - - output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, mul(boneTransform, float4(input.Pos.xyz, 1.0))))); - - float4 pos = mul(ubo.model, float4(input.Pos, 1.0)); - output.Normal = mul((float3x3)(boneTransform), input.Normal); - output.LightVec = ubo.lightPos.xyz - pos.xyz; - output.ViewVec = ubo.viewPos.xyz - pos.xyz; - return output; -} \ No newline at end of file diff --git a/data/shaders/hlsl/skeletalanimation/mesh.vert.spv b/data/shaders/hlsl/skeletalanimation/mesh.vert.spv deleted file mode 100644 index 00c7c226..00000000 Binary files a/data/shaders/hlsl/skeletalanimation/mesh.vert.spv and /dev/null differ diff --git a/data/shaders/hlsl/skeletalanimation/texture.frag b/data/shaders/hlsl/skeletalanimation/texture.frag deleted file mode 100644 index 75af0820..00000000 --- a/data/shaders/hlsl/skeletalanimation/texture.frag +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2020 Google LLC - -Texture2D textureColorMap : register(t1); -SamplerState samplerColorMap : register(s1); - -struct VSOutput -{ -[[vk::location(0)]] float2 UV : TEXCOORD0; -[[vk::location(1)]] float3 Normal : NORMAL0; -[[vk::location(2)]] float3 ViewVec : TEXCOORD1; -[[vk::location(3)]] float3 LightVec : TEXCOORD2; -}; - -float4 main(VSOutput input) : SV_TARGET -{ - float4 color = textureColorMap.Sample(samplerColorMap, input.UV); - - float distSqr = dot(input.LightVec, input.LightVec); - float3 lVec = input.LightVec * rsqrt(distSqr); - - const float attInvRadius = 1.0/5000.0; - float atten = max(clamp(1.0 - attInvRadius * sqrt(distSqr), 0.0, 1.0), 0.0); - - // Fake drop shadow - const float shadowInvRadius = 1.0/2500.0; - float dropshadow = max(clamp(1.0 - shadowInvRadius * sqrt(distSqr), 0.0, 1.0), 0.0); - - float4 outFragColor = float4(color.rgba * (1.0 - dropshadow)); - outFragColor.rgb *= atten; - return outFragColor; -} \ No newline at end of file diff --git a/data/shaders/hlsl/skeletalanimation/texture.frag.spv b/data/shaders/hlsl/skeletalanimation/texture.frag.spv deleted file mode 100644 index 0fc23090..00000000 Binary files a/data/shaders/hlsl/skeletalanimation/texture.frag.spv and /dev/null differ diff --git a/data/shaders/hlsl/skeletalanimation/texture.vert b/data/shaders/hlsl/skeletalanimation/texture.vert deleted file mode 100644 index 1b22deb6..00000000 --- a/data/shaders/hlsl/skeletalanimation/texture.vert +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2020 Google LLC - -struct VSInput -{ -[[vk::location(0)]] float3 Pos : POSITION0; -[[vk::location(1)]] float3 Normal : NORMAL0; -[[vk::location(2)]] float2 UV : TEXCOORD0; -}; - -struct UBO -{ - float4x4 projection; - float4x4 view; - float4x4 model; - float4 lightPos; - float4 viewPos; - float2 uvOffset; -}; - -cbuffer ubo : register(b0) { UBO ubo; } - -struct VSOutput -{ - float4 Pos : SV_POSITION; -[[vk::location(0)]] float2 UV : TEXCOORD0; -[[vk::location(1)]] float3 Normal : NORMAL0; -[[vk::location(2)]] float3 ViewVec : TEXCOORD1; -[[vk::location(3)]] float3 LightVec : TEXCOORD2; -}; - -VSOutput main(VSInput input) -{ - VSOutput output = (VSOutput)0; - output.UV = input.UV + ubo.uvOffset; - float4 pos = float4(input.Pos, 1.0); - output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, pos))); - - output.Normal = input.Normal; - output.LightVec = ubo.lightPos.xyz - pos.xyz; - output.ViewVec = ubo.viewPos.xyz - pos.xyz; - return output; -} diff --git a/data/shaders/hlsl/skeletalanimation/texture.vert.spv b/data/shaders/hlsl/skeletalanimation/texture.vert.spv deleted file mode 100644 index b979972b..00000000 Binary files a/data/shaders/hlsl/skeletalanimation/texture.vert.spv and /dev/null differ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b7f68bb4..03d7c5cb 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -100,7 +100,6 @@ set(EXAMPLES shadowmapping shadowmappingomni shadowmappingcascade - skeletalanimation specializationconstants sphericalenvmapping ssao diff --git a/examples/skeletalanimation/skeletalanimation.cpp b/examples/skeletalanimation/skeletalanimation.cpp deleted file mode 100644 index 708cc14d..00000000 --- a/examples/skeletalanimation/skeletalanimation.cpp +++ /dev/null @@ -1,1021 +0,0 @@ -/* -* 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 -#include -#include -#include -#include -#include - -#define GLM_FORCE_RADIANS -#define GLM_FORCE_DEPTH_ZERO_TO_ONE -#include -#include -#include - -#include -#include -#include -#include - -#include -#include "vulkanexamplebase.h" -#include "VulkanBuffer.hpp" -#include "VulkanTexture.hpp" -#include "VulkanModel.hpp" - -#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]; -}; - -// 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, -}); - -// 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 - -// Skinned mesh class - -// Per-vertex bone IDs and weights -struct VertexBoneData -{ - std::array IDs; - std::array weights; - - // Ad bone weighting to vertex info - void add(uint32_t boneID, float weight) - { - for (uint32_t i = 0; i < MAX_BONES_PER_VERTEX; i++) - { - if (weights[i] == 0.0f) - { - IDs[i] = boneID; - weights[i] = weight; - return; - } - } - } -}; - -// Stores information on a single bone -struct BoneInfo -{ - aiMatrix4x4 offset; - aiMatrix4x4 finalTransformation; - - BoneInfo() - { - offset = aiMatrix4x4(); - finalTransformation = aiMatrix4x4(); - }; -}; - -class SkinnedMesh -{ -public: - // Bone related stuff - // Maps bone name with index - std::map boneMapping; - // Bone details - std::vector boneInfo; - // Number of bones present - uint32_t numBones = 0; - // Root inverese transform matrix - aiMatrix4x4 globalInverseTransform; - // Per-vertex bone info - std::vector bones; - // Bone transformations - std::vector boneTransforms; - - // Modifier for the animation - float animationSpeed = 0.75f; - // Currently active animation - aiAnimation* pAnimation; - - // Vulkan buffers - vks::Model vertexBuffer; - - // Store reference to the ASSIMP scene for accessing properties of it during animation - Assimp::Importer Importer; - const aiScene* scene; - - // Set active animation by index - void setAnimation(uint32_t animationIndex) - { - assert(animationIndex < scene->mNumAnimations); - pAnimation = scene->mAnimations[animationIndex]; - } - - // Load bone information from ASSIMP mesh - void loadBones(const aiMesh* pMesh, uint32_t vertexOffset, std::vector& Bones) - { - for (uint32_t i = 0; i < pMesh->mNumBones; i++) - { - uint32_t index = 0; - - assert(pMesh->mNumBones <= MAX_BONES); - - std::string name(pMesh->mBones[i]->mName.data); - - if (boneMapping.find(name) == boneMapping.end()) - { - // Bone not present, add new one - index = numBones; - numBones++; - BoneInfo bone; - boneInfo.push_back(bone); - boneInfo[index].offset = pMesh->mBones[i]->mOffsetMatrix; - boneMapping[name] = index; - } - else - { - index = boneMapping[name]; - } - - for (uint32_t j = 0; j < pMesh->mBones[i]->mNumWeights; j++) - { - uint32_t vertexID = vertexOffset + pMesh->mBones[i]->mWeights[j].mVertexId; - Bones[vertexID].add(index, pMesh->mBones[i]->mWeights[j].mWeight); - } - } - boneTransforms.resize(numBones); - } - - // Recursive bone transformation for given animation time - void update(float time) - { - float TicksPerSecond = (float)(scene->mAnimations[0]->mTicksPerSecond != 0 ? scene->mAnimations[0]->mTicksPerSecond : 25.0f); - float TimeInTicks = time * TicksPerSecond; - float AnimationTime = fmod(TimeInTicks, (float)scene->mAnimations[0]->mDuration); - - aiMatrix4x4 identity = aiMatrix4x4(); - readNodeHierarchy(AnimationTime, scene->mRootNode, identity); - - for (uint32_t i = 0; i < boneTransforms.size(); i++) - { - boneTransforms[i] = boneInfo[i].finalTransformation; - } - } - - ~SkinnedMesh() - { - vertexBuffer.vertices.destroy(); - vertexBuffer.indices.destroy(); - } - -private: - // 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]; - - 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; - - if (pNodeAnim->mNumRotationKeys == 1) - { - 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; - - if (pNodeAnim->mNumScalingKeys == 1) - { - 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); - - NodeTransformation = matTranslation * matRotation * matScale; - } - - aiMatrix4x4 GlobalTransformation = ParentTransform * NodeTransformation; - - if (boneMapping.find(NodeName) != boneMapping.end()) - { - uint32_t BoneIndex = boneMapping[NodeName]; - boneInfo[BoneIndex].finalTransformation = globalInverseTransform * GlobalTransformation * boneInfo[BoneIndex].offset; - } - - for (uint32_t i = 0; i < pNode->mNumChildren; i++) - { - readNodeHierarchy(AnimationTime, pNode->mChildren[i], GlobalTransformation); - } - } -}; - -class VulkanExample : public VulkanExampleBase -{ -public: - struct { - vks::Texture2D colorMap; - vks::Texture2D floor; - } textures; - - SkinnedMesh *skinnedMesh = nullptr; - - struct { - vks::Buffer mesh; - vks::Buffer floor; - } uniformBuffers; - - struct { - glm::mat4 projection; - glm::mat4 view; - glm::mat4 model; - glm::mat4 bones[MAX_BONES]; - glm::vec4 lightPos = glm::vec4(0.0f, -250.0f, 250.0f, 1.0); - glm::vec4 viewPos; - } uboVS; - - struct { - glm::mat4 projection; - glm::mat4 view; - glm::mat4 model; - 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 { - vks::Model floor; - } models; - - VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; - VkDescriptorSetLayout descriptorSetLayout; - - struct { - VkDescriptorSet skinning; - VkDescriptorSet floor; - } descriptorSets; - - float runningTime = 0.0f; - - VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) - { - title = "Skeletal animation (GPU skinning)"; - settings.overlay = true; - camera.type = Camera::CameraType::lookat; - camera.setPerspective(60.0f, (float)width / (float)height, 1.0f, 512.0f); - camera.setRotation(glm::vec3(-182.5f, -38.5f, 180.0f)); - camera.setRotation(glm::vec3(0.0f, 135.0f, 0.0f)); - camera.setPosition(glm::vec3(0.0f, 0.0f, -20.0f)); - } - - ~VulkanExample() - { - // Clean up used Vulkan resources - // Note : Inherited destructor cleans up resources stored in base class - vkDestroyPipeline(device, pipelines.skinning, nullptr); - vkDestroyPipeline(device, pipelines.texture, nullptr); - - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - - textures.colorMap.destroy(); - textures.floor.destroy(); - - uniformBuffers.mesh.destroy(); - uniformBuffers.floor.destroy(); - - models.floor.destroy(); - delete(skinnedMesh); - } - - // Enable physical device features required for this example - virtual void getEnabledFeatures() - { - // Enable anisotropic filtering if supported - if (deviceFeatures.samplerAnisotropy) { - enabledFeatures.samplerAnisotropy = VK_TRUE; - } - // Enable texture compression - if (deviceFeatures.textureCompressionBC) { - enabledFeatures.textureCompressionBC = VK_TRUE; - } - else if (deviceFeatures.textureCompressionASTC_LDR) { - enabledFeatures.textureCompressionASTC_LDR = VK_TRUE; - } - else if (deviceFeatures.textureCompressionETC2) { - enabledFeatures.textureCompressionETC2 = VK_TRUE; - } - } - - void buildCommandBuffers() - { - VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); - - VkClearValue clearValues[2]; - clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 0.0f} }; - clearValues[1].depthStencil = { 1.0f, 0 }; - - VkRenderPassBeginInfo renderPassBeginInfo = vks::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) - { - renderPassBeginInfo.framebuffer = frameBuffers[i]; - - VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); - - vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - - VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); - vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); - - VkRect2D scissor = vks::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); - - 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); - - // 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); - - 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); - - drawUI(drawCmdBuffers[i]); - - vkCmdEndRenderPass(drawCmdBuffers[i]); - - VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); - } - } - - // Load a mesh based on data read via assimp - void loadMesh() - { - skinnedMesh = new SkinnedMesh(); - - std::string filename = getAssetPath() + "models/goblin.dae"; - -#if defined(__ANDROID__) - // 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); -#endif - skinnedMesh->setAnimation(0); - - // Setup bones - // One vertex bone info structure per vertex - uint32_t vertexCount(0); - for (uint32_t m = 0; m < skinnedMesh->scene->mNumMeshes; m++) { - vertexCount += skinnedMesh->scene->mMeshes[m]->mNumVertices; - }; - skinnedMesh->bones.resize(vertexCount); - // Store global inverse transform matrix of root node - skinnedMesh->globalInverseTransform = skinnedMesh->scene->mRootNode->mTransformation; - skinnedMesh->globalInverseTransform.Inverse(); - // Load bones (weights and IDs) - 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); - } - vertexBase += skinnedMesh->scene->mMeshes[m]->mNumVertices; - } - - // Generate vertex buffer - std::vector vertexBuffer; - // 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++) { - Vertex vertex; - - 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); - - // Fetch bone weights and IDs - 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]; - } - - vertexBuffer.push_back(vertex); - } - vertexBase += skinnedMesh->scene->mMeshes[m]->mNumVertices; - } - VkDeviceSize vertexBufferSize = vertexBuffer.size() * sizeof(Vertex); - - // Generate index buffer from loaded mesh file - std::vector indexBuffer; - for (uint32_t m = 0; m < skinnedMesh->scene->mNumMeshes; m++) { - uint32_t indexBase = static_cast(indexBuffer.size()); - 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); - } - } - } - VkDeviceSize indexBufferSize = indexBuffer.size() * sizeof(uint32_t); - skinnedMesh->vertexBuffer.indexCount = static_cast(indexBuffer.size()); - - 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, - &skinnedMesh->vertexBuffer.vertices, - vertexBufferSize)); - // 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, - &skinnedMesh->vertexBuffer.indices, - indexBufferSize)); - - // Copy from staging buffers - VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - - VkBufferCopy copyRegion = {}; - - copyRegion.size = vertexBufferSize; - vkCmdCopyBuffer( - copyCmd, - vertexStaging.buffer, - skinnedMesh->vertexBuffer.vertices.buffer, - 1, - ©Region); - - copyRegion.size = indexBufferSize; - vkCmdCopyBuffer( - copyCmd, - indexStaging.buffer, - skinnedMesh->vertexBuffer.indices.buffer, - 1, - ©Region); - - vulkanDevice->flushCommandBuffer(copyCmd, queue, true); - - vkDestroyBuffer(device, vertexStaging.buffer, nullptr); - vkFreeMemory(device, vertexStaging.memory, nullptr); - vkDestroyBuffer(device, indexStaging.buffer, nullptr); - vkFreeMemory(device, indexStaging.memory, nullptr); - } - - void loadAssets() - { - models.floor.loadFromFile(getAssetPath() + "models/plane_z.obj", vertexLayout, 512.0f, vulkanDevice, queue); - - // Textures - std::string texFormatSuffix; - VkFormat texFormat; - // Get supported compressed texture format - if (vulkanDevice->features.textureCompressionBC) { - texFormatSuffix = "_bc3_unorm"; - texFormat = VK_FORMAT_BC3_UNORM_BLOCK; - } - else if (vulkanDevice->features.textureCompressionASTC_LDR) { - texFormatSuffix = "_astc_8x8_unorm"; - texFormat = VK_FORMAT_ASTC_8x8_UNORM_BLOCK; - } - else if (vulkanDevice->features.textureCompressionETC2) { - texFormatSuffix = "_etc2_unorm"; - texFormat = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; - } - else { - vks::tools::exitFatal("Device does not support any compressed texture format!", VK_ERROR_FEATURE_NOT_PRESENT); - } - - textures.colorMap.loadFromFile(getAssetPath() + "textures/goblin" + texFormatSuffix + ".ktx", texFormat, vulkanDevice, queue); - textures.floor.loadFromFile(getAssetPath() + "textures/trail" + texFormatSuffix + ".ktx", texFormat, vulkanDevice, queue); - } - - void setupDescriptorPool() - { - // Example uses one ubo and one combined image sampler - std::vector poolSizes = - { - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2), - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2), - }; - - VkDescriptorPoolCreateInfo descriptorPoolInfo = - vks::initializers::descriptorPoolCreateInfo( - poolSizes.size(), - poolSizes.data(), - 2); - - VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } - - void setupDescriptorSetLayout() - { - std::vector setLayoutBindings = - { - // Binding 0 : Vertex shader uniform buffer - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - VK_SHADER_STAGE_VERTEX_BIT, - 0), - // Binding 1 : Fragment shader combined sampler - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - VK_SHADER_STAGE_FRAGMENT_BIT, - 1), - }; - - VkDescriptorSetLayoutCreateInfo descriptorLayout = - vks::initializers::descriptorSetLayoutCreateInfo( - setLayoutBindings.data(), - setLayoutBindings.size()); - - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); - - VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo( - &descriptorSetLayout, - 1); - - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - } - - void setupDescriptorSet() - { - VkDescriptorSetAllocateInfo allocInfo = - vks::initializers::descriptorSetAllocateInfo( - descriptorPool, - &descriptorSetLayout, - 1); - - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); - - VkDescriptorImageInfo texDescriptor = - vks::initializers::descriptorImageInfo( - textures.colorMap.sampler, - textures.colorMap.view, - VK_IMAGE_LAYOUT_GENERAL); - - std::vector writeDescriptorSets = - { - // Binding 0 : Vertex shader uniform buffer - vks::initializers::writeDescriptorSet( - descriptorSet, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 0, - &uniformBuffers.mesh.descriptor), - // Binding 1 : Color map - vks::initializers::writeDescriptorSet( - descriptorSet, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - 1, - &texDescriptor) - }; - - vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); - - // Floor - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.floor)); - - texDescriptor.imageView = textures.floor.view; - texDescriptor.sampler = textures.floor.sampler; - - writeDescriptorSets.clear(); - - // Binding 0 : Vertex shader uniform buffer - writeDescriptorSets.push_back( - vks::initializers::writeDescriptorSet( - descriptorSets.floor, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 0, - &uniformBuffers.floor.descriptor)); - // Binding 1 : Color map - writeDescriptorSets.push_back( - vks::initializers::writeDescriptorSet( - descriptorSets.floor, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - 1, - &texDescriptor)); - - vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); - } - - void preparePipelines() - { - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = - vks::initializers::pipelineInputAssemblyStateCreateInfo( - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - 0, - VK_FALSE); - - VkPipelineRasterizationStateCreateInfo rasterizationState = - vks::initializers::pipelineRasterizationStateCreateInfo( - VK_POLYGON_MODE_FILL, - VK_CULL_MODE_BACK_BIT, - VK_FRONT_FACE_CLOCKWISE, - 0); - - VkPipelineColorBlendAttachmentState blendAttachmentState = - vks::initializers::pipelineColorBlendAttachmentState( - 0xf, - VK_FALSE); - - VkPipelineColorBlendStateCreateInfo colorBlendState = - vks::initializers::pipelineColorBlendStateCreateInfo( - 1, - &blendAttachmentState); - - VkPipelineDepthStencilStateCreateInfo depthStencilState = - vks::initializers::pipelineDepthStencilStateCreateInfo( - VK_TRUE, - VK_TRUE, - VK_COMPARE_OP_LESS_OR_EQUAL); - - VkPipelineViewportStateCreateInfo viewportState = - vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); - - VkPipelineMultisampleStateCreateInfo multisampleState = - vks::initializers::pipelineMultisampleStateCreateInfo( - VK_SAMPLE_COUNT_1_BIT, - 0); - - std::vector dynamicStateEnables = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR - }; - VkPipelineDynamicStateCreateInfo dynamicState = - vks::initializers::pipelineDynamicStateCreateInfo( - dynamicStateEnables.data(), - dynamicStateEnables.size(), - 0); - - // Skinned rendering pipeline - std::array shaderStages; - - VkGraphicsPipelineCreateInfo pipelineCreateInfo = - vks::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; - pipelineCreateInfo.stageCount = static_cast(shaderStages.size()); - pipelineCreateInfo.pStages = shaderStages.data(); - - // Shared vertex inputs - - // Binding description - VkVertexInputBindingDescription vertexInputBinding = - vks::initializers::vertexInputBindingDescription(VERTEX_BUFFER_BIND_ID, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX); - - // Attribute descriptions - // Describes memory layout and shader positions - std::vector vertexInputAttributes = { - vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Location 0: Position - vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), // Location 1: Normal - vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 2, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 6), // Location 2: Texture coordinates - vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 3, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 8), // Location 3: Color - vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 4, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 11), // Location 4: Bone weights - vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 5, VK_FORMAT_R32G32B32A32_SINT, sizeof(float) * 15), // Location 5: Bone IDs - }; - - VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); - vertexInputState.vertexBindingDescriptionCount = 1; - vertexInputState.pVertexBindingDescriptions = &vertexInputBinding; - vertexInputState.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); - vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data(); - - pipelineCreateInfo.pVertexInputState = &vertexInputState; - - // Skinned mesh rendering pipeline - shaderStages[0] = loadShader(getShadersPath() + "skeletalanimation/mesh.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getShadersPath() + "skeletalanimation/mesh.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.skinning)); - - // Environment rendering pipeline - shaderStages[0] = loadShader(getShadersPath() + "skeletalanimation/texture.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getShadersPath() + "skeletalanimation/texture.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.texture)); - } - - // Prepare and initialize uniform buffer containing shader uniforms - void prepareUniformBuffers() - { - // Mesh uniform buffer block - vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBuffers.mesh, - sizeof(uboVS)); - // Map persistant - VK_CHECK_RESULT(uniformBuffers.mesh.map()); - - // Floor uniform buffer block - vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBuffers.floor, - sizeof(uboFloor)); - // Map persistant - VK_CHECK_RESULT(uniformBuffers.floor.map()); - - updateUniformBuffers(true); - } - - void updateUniformBuffers(bool viewChanged) - { - if (viewChanged) - { - const glm::vec3 scale = glm::vec3(0.0025f); - - uboVS.projection = camera.matrices.perspective; - uboVS.view = camera.matrices.view; - uboVS.viewPos = glm::vec4(camera.position, 0.0f) * glm::vec4(-1.0f); - uboVS.model = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)); - uboVS.model = glm::scale(uboVS.model, scale); - - uboFloor.projection = camera.matrices.perspective; - uboFloor.view = camera.matrices.view; - uboFloor.model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 4.5f, 0.0f)); - uboFloor.model = glm::rotate(uboFloor.model, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)); - uboFloor.model = glm::scale(uboFloor.model, scale); - uboFloor.viewPos = glm::vec4(camera.position, 0.0f) * glm::vec4(-1.0f); - } - - // Update bones - skinnedMesh->update(runningTime); - for (uint32_t i = 0; i < skinnedMesh->boneTransforms.size(); i++) - { - uboVS.bones[i] = glm::transpose(glm::make_mat4(&skinnedMesh->boneTransforms[i].a1)); - } - - uniformBuffers.mesh.copyTo(&uboVS, sizeof(uboVS)); - - // Update floor animation - uboFloor.uvOffset.t -= 0.25f * skinnedMesh->animationSpeed * frameTimer; - uniformBuffers.floor.copyTo(&uboFloor, sizeof(uboFloor)); - } - - void draw() - { - VulkanExampleBase::prepareFrame(); - - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - - VulkanExampleBase::submitFrame(); - } - - void prepare() - { - VulkanExampleBase::prepare(); - loadAssets(); - loadMesh(); - prepareUniformBuffers(); - setupDescriptorSetLayout(); - preparePipelines(); - setupDescriptorPool(); - setupDescriptorSet(); - buildCommandBuffers(); - prepared = true; - } - - virtual void render() - { - if (!prepared) - return; - draw(); - if (!paused) - { - runningTime += frameTimer * skinnedMesh->animationSpeed; - updateUniformBuffers(false); - } - } - - virtual void viewChanged() - { - updateUniformBuffers(true); - } - - void changeAnimationSpeed(float delta) - { - skinnedMesh->animationSpeed += delta; - } - - virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) - { - if (overlay->header("Settings")) { - overlay->sliderFloat("Animation speed", &skinnedMesh->animationSpeed, 0.0f, 10.0f); - } - } -}; - -VULKAN_EXAMPLE_MAIN() \ No newline at end of file