diff --git a/data/shaders/mesh/mesh.frag b/data/shaders/mesh/mesh.frag index 17d4a95b..fb415cef 100644 --- a/data/shaders/mesh/mesh.frag +++ b/data/shaders/mesh/mesh.frag @@ -18,7 +18,7 @@ void main() vec3 L = normalize(inLightVec); vec3 V = normalize(inViewVec); vec3 R = reflect(-L, N); - vec3 diffuse = max(dot(N, L), 0.0) * inColor; + vec3 diffuse = max(dot(N, L), 0.15) * inColor; vec3 specular = pow(max(dot(R, V), 0.0), 16.0) * vec3(0.75); outFragColor = vec4(diffuse * color.rgb + specular, 1.0); } \ No newline at end of file diff --git a/data/shaders/mesh/mesh.frag.spv b/data/shaders/mesh/mesh.frag.spv index 3c870fe5..5cd56265 100644 Binary files a/data/shaders/mesh/mesh.frag.spv and b/data/shaders/mesh/mesh.frag.spv differ diff --git a/data/shaders/mesh/mesh.vert b/data/shaders/mesh/mesh.vert index 22b6aeb9..2760684e 100644 --- a/data/shaders/mesh/mesh.vert +++ b/data/shaders/mesh/mesh.vert @@ -5,12 +5,16 @@ layout (location = 1) in vec3 inNormal; layout (location = 2) in vec2 inUV; layout (location = 3) in vec3 inColor; -layout (set = 0, binding = 0) uniform UBO +layout (set = 0, binding = 0) uniform UBOScene { mat4 projection; - mat4 model; + mat4 view; vec4 lightPos; -} ubo; +} uboScene; + +layout(push_constant) uniform PushConsts { + mat4 model; +} primitive; layout (location = 0) out vec3 outNormal; layout (location = 1) out vec3 outColor; @@ -18,21 +22,16 @@ 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() { outNormal = inNormal; outColor = inColor; outUV = inUV; - gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0); + gl_Position = uboScene.projection * uboScene.view * primitive.model * vec4(inPos.xyz, 1.0); - vec4 pos = ubo.model * vec4(inPos, 1.0); - outNormal = mat3(ubo.model) * inNormal; - vec3 lPos = mat3(ubo.model) * ubo.lightPos.xyz; + vec4 pos = uboScene.view * vec4(inPos, 1.0); + outNormal = mat3(uboScene.view) * inNormal; + vec3 lPos = mat3(uboScene.view) * uboScene.lightPos.xyz; outLightVec = lPos - pos.xyz; outViewVec = -pos.xyz; } \ No newline at end of file diff --git a/data/shaders/mesh/mesh.vert.spv b/data/shaders/mesh/mesh.vert.spv index 2d0a79fc..cf6fc4ac 100644 Binary files a/data/shaders/mesh/mesh.vert.spv and b/data/shaders/mesh/mesh.vert.spv differ diff --git a/examples/mesh/mesh.cpp b/examples/mesh/mesh.cpp index c4d44791..fb35da1f 100644 --- a/examples/mesh/mesh.cpp +++ b/examples/mesh/mesh.cpp @@ -9,7 +9,7 @@ /* * Shows how to load and display a simple mesh from a glTF file * Note that this isn't a complete glTF loader and only basic functions are shown here - * This means only linear nodes (no parent<->child tree), no animations, no skins, etc. + * This means no complex materials, no animations, no skins, etc. * For details on how glTF 2.0 works, see the official spec at https://github.com/KhronosGroup/glTF/tree/master/specification/2.0 * * Other samples will load models using a dedicated model loader with more features (see base/VulkanglTFModel.hpp) @@ -203,7 +203,7 @@ public: node.matrix *= glm::mat4(q); } if (inputNode.scale.size() == 3) { - node.matrix = glm::scale(node.matrix, glm::vec3(glm::make_vec3(inputNode.translation.data()))); + node.matrix = glm::scale(node.matrix, glm::vec3(glm::make_vec3(inputNode.scale.data()))); } if (inputNode.matrix.size() == 16) { node.matrix = glm::make_mat4x4(inputNode.matrix.data()); @@ -261,8 +261,6 @@ public: vert.normal = glm::normalize(glm::vec3(normalsBuffer ? glm::make_vec3(&normalsBuffer[v * 3]) : glm::vec3(0.0f))); vert.uv = texCoordsBuffer ? glm::make_vec2(&texCoordsBuffer[v * 2]) : glm::vec3(0.0f); vert.color = glm::vec3(1.0f); - // Flip Y-Axis - vert.pos.y *= -1.0f; vertexBuffer.push_back(vert); } } @@ -329,10 +327,21 @@ public: void drawglTFNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node node) { if (node.mesh.primitives.size() > 0) { + // Pass the node's matrix via push constanst + // Traverse the node hierarchy to the top-most parent to get the final matrix of the current node + glm::mat4 nodeMatrix = node.matrix; + VulkanglTFModel::Node* currentParent = node.parent; + while (currentParent) { + nodeMatrix = currentParent->matrix * nodeMatrix; + currentParent = currentParent->parent; + } + // Pass the final matrix to the vertex shader using push constants + vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &nodeMatrix); for (VulkanglTFModel::Primitive& primitive : node.mesh.primitives) { if (primitive.indexCount > 0) { // Get the texture index for this primitive VulkanglTFModel::Texture texture = textures[materials[primitive.materialIndex].baseColorTextureIndex]; + // Bind the descriptor for the current primitive's texture vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &images[texture.imageIndex].descriptorSet, 0, nullptr); vkCmdDrawIndexed(commandBuffer, primitive.indexCount, 1, primitive.firstIndex, 0, 0); } @@ -392,6 +401,7 @@ public: { title = "glTF model rendering"; camera.type = Camera::CameraType::lookat; + camera.flipY = true; camera.movementSpeed = 2.5f; camera.rotationSpeed = 0.5f; camera.setPosition(glm::vec3(0.1f, 1.1f, -20.0f)); @@ -507,7 +517,6 @@ public: } } else { - // TODO: throw std::cerr << "Could not load gltf file: " << error << std::endl; return; } @@ -616,6 +625,11 @@ public: // Pipeline layout using both descriptor sets (set 0 = matrices, set 1 = material) std::array setLayouts = { descriptorSetLayouts.matrices, descriptorSetLayouts.textures }; VkPipelineLayoutCreateInfo pipelineLayoutCI= vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast(setLayouts.size())); + // We will use push constants to push the local matrices of a primitive to the vertex shader + VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::mat4), 0); + // Push constant ranges are part of the pipeline layout + pipelineLayoutCI.pushConstantRangeCount = 1; + pipelineLayoutCI.pPushConstantRanges = &pushConstantRange; VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); // Descriptor set for scene matrices