diff --git a/renderer/include/renderer.hpp b/renderer/include/renderer.hpp index 4219f11..98aa554 100644 --- a/renderer/include/renderer.hpp +++ b/renderer/include/renderer.hpp @@ -13,6 +13,8 @@ struct RenderPart { VkBuffer vertexBuffer, indexBuffer; VkDeviceMemory vertexMemory, indexMemory; + + int materialIndex = 0; }; struct RenderTexture { @@ -22,12 +24,28 @@ struct RenderTexture { VkSampler sampler = VK_NULL_HANDLE; }; +enum class MaterialType { + Object, + Skin +}; + +struct RenderMaterial { + MaterialType type = MaterialType::Object; + + RenderTexture* diffuseTexture = nullptr; + RenderTexture* normalTexture = nullptr; + RenderTexture* specularTexture = nullptr; + RenderTexture* multiTexture = nullptr; +}; + struct RenderModel { physis_MDL model; std::vector parts; std::array boneData; + std::vector materials; - RenderTexture* texture = nullptr; + VkBuffer boneInfoBuffer = VK_NULL_HANDLE; + VkDeviceMemory boneInfoMemory = VK_NULL_HANDLE; }; class Renderer { @@ -67,11 +85,9 @@ public: VkDescriptorPool descriptorPool = VK_NULL_HANDLE; - VkBuffer boneInfoBuffer = VK_NULL_HANDLE; - VkDeviceMemory boneInfoMemory = VK_NULL_HANDLE; VkDescriptorSetLayout setLayout = VK_NULL_HANDLE; - std::map cachedDescriptors; + std::map cachedDescriptors; VkPipeline pipeline; VkPipelineLayout pipelineLayout; @@ -94,5 +110,7 @@ public: VkPipelineStageFlags src_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); - VkDescriptorSet createDescriptorFor(RenderTexture& texture); + VkDescriptorSet createDescriptorFor(const RenderModel& model, const RenderMaterial& material); + + int hash(const RenderModel& model, const RenderMaterial& material); }; \ No newline at end of file diff --git a/renderer/shaders/mesh.frag b/renderer/shaders/mesh.frag index 08a7978..65bab20 100644 --- a/renderer/shaders/mesh.frag +++ b/renderer/shaders/mesh.frag @@ -6,15 +6,32 @@ layout(location = 2) in vec2 inUV; layout(location = 0) out vec4 outColor; -layout(binding = 3) uniform sampler2D tex; +layout(binding = 3) uniform sampler2D diffuseTexture; +layout(binding = 4) uniform sampler2D normalTexture; +layout(binding = 5) uniform sampler2D specularTexture; +layout(binding = 6) uniform sampler2D multiTexture; + +layout(std430, push_constant) uniform PushConstant { + mat4 vp, model; + int boneOffset; + int type; +}; void main() { const vec3 lightPos = vec3(3); + vec3 diffuse = texture(diffuseTexture, inUV).rgb; + if(type == 1) { + const float skinInfluence = texture(specularTexture, inUV).r; + vec3 skinColor = vec3(250 / 255.0, 199 / 255.0, 166 / 255.0); + + diffuse = mix(texture(diffuseTexture, inUV).rgb, skinColor, 1.0); + } + vec3 norm = normalize(inNormal); vec3 lightDir = normalize(lightPos - inFragPos); float diff = max(dot(norm, lightDir), 0.0); - outColor = texture(tex, inUV) * diff; + outColor = vec4(diffuse * diff, 1.0); } diff --git a/renderer/shaders/mesh.frag.spv b/renderer/shaders/mesh.frag.spv index 79cf7db..0d0b971 100644 Binary files a/renderer/shaders/mesh.frag.spv and b/renderer/shaders/mesh.frag.spv differ diff --git a/renderer/shaders/mesh.vert b/renderer/shaders/mesh.vert index 28a5ab3..7638d84 100644 --- a/renderer/shaders/mesh.vert +++ b/renderer/shaders/mesh.vert @@ -10,9 +10,15 @@ layout(location = 0) out vec3 outNormal; layout(location = 1) out vec3 outFragPos; layout(location = 2) out vec2 outUV; -layout(push_constant) uniform PushConstant { +layout(binding = 3) uniform sampler2D diffuseTexture; +layout(binding = 4) uniform sampler2D normalTexture; +layout(binding = 5) uniform sampler2D specularTexture; +layout(binding = 6) uniform sampler2D multiTexture; + +layout(std430, push_constant) uniform PushConstant { mat4 vp, model; int boneOffset; + int type; }; layout(std430, binding = 2) buffer readonly BoneInformation { diff --git a/renderer/shaders/mesh.vert.spv b/renderer/shaders/mesh.vert.spv index e1b82a6..4904d14 100644 Binary files a/renderer/shaders/mesh.vert.spv and b/renderer/shaders/mesh.vert.spv differ diff --git a/renderer/src/renderer.cpp b/renderer/src/renderer.cpp index c328aab..d48da08 100644 --- a/renderer/src/renderer.cpp +++ b/renderer/src/renderer.cpp @@ -469,45 +469,54 @@ void Renderer::render(std::vector models) { { const size_t bufferSize = sizeof(glm::mat4) * 128; void *mapped_data = nullptr; - vkMapMemory(device, boneInfoMemory, 0, bufferSize, 0, &mapped_data); + vkMapMemory(device, model.boneInfoMemory, 0, bufferSize, 0, &mapped_data); memcpy(mapped_data, model.boneData.data(), bufferSize); VkMappedMemoryRange range = {}; range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range.memory = boneInfoMemory; + range.memory = model.boneInfoMemory; range.size = bufferSize; vkFlushMappedMemoryRanges(device, 1, &range); - vkUnmapMemory(device, boneInfoMemory); + vkUnmapMemory(device, model.boneInfoMemory); } - if(model.texture == nullptr) + if(model.materials.empty()) continue; - if(!cachedDescriptors.count(model.texture->handle)) - cachedDescriptors[model.texture->handle] = createDescriptorFor(*model.texture); - - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &cachedDescriptors[model.texture->handle], 0, nullptr); - for(const auto& part : model.parts) { + RenderMaterial& material = model.materials[part.materialIndex]; + + int h = hash(model, material); + if(!cachedDescriptors.count(h)) { + fmt::print("Caching descriptor for hash {}\n", h); + cachedDescriptors[h] = createDescriptorFor(model, material); + } + + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &cachedDescriptors[h], 0, nullptr); + + VkDeviceSize offsets[] = {0}; vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer, offsets); vkCmdBindIndexBuffer(commandBuffer, part.indexBuffer, 0, VK_INDEX_TYPE_UINT16); glm::mat4 p = glm::perspective(glm::radians(45.0f), swapchainExtent.width / (float) swapchainExtent.height, 0.1f, 100.0f); - glm::mat4 v = glm::lookAt(glm::vec3(0, 1, 3), glm::vec3(0, 1, 0), glm::vec3(0, -1, 0)); + glm::mat4 v = glm::lookAt(glm::vec3(0, 1, 1), glm::vec3(0, 1, 0), glm::vec3(0, -1, 0)); glm::mat4 vp = p * v; - vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &vp); + vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(glm::mat4), &vp); glm::mat4 m = glm::mat4(1.0f); - vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::mat4), sizeof(glm::mat4), &m); + vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(glm::mat4), sizeof(glm::mat4), &m); int test = 0; - vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::mat4) * 2, sizeof(int), &test); + vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(glm::mat4) * 2, sizeof(int), &test); + + int type = (int)material.type; + vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(glm::mat4) * 2 + sizeof(int), sizeof(int), &type); vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0); } @@ -609,10 +618,12 @@ RenderModel Renderer::addModel(const physis_MDL& model, int lod) { if(lod < 0 || lod > model.num_lod) return {}; - for(int i = 0; i < model.lods[0].num_parts; i++) { + for(int i = 0; i < model.lods[lod].num_parts; i++) { RenderPart renderPart; - const physis_Part part = model.lods[0].parts[i]; + const physis_Part part = model.lods[lod].parts[i]; + + renderPart.materialIndex = part.material_index; size_t vertexSize = part.num_vertices * sizeof(Vertex); auto[vertexBuffer, vertexMemory] = createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); @@ -663,6 +674,12 @@ RenderModel Renderer::addModel(const physis_MDL& model, int lod) { renderModel.parts.push_back(renderPart); } + const size_t bufferSize = sizeof(glm::mat4) * 128; + auto [buffer, memory] = createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + + renderModel.boneInfoBuffer = buffer; + renderModel.boneInfoMemory = memory; + return renderModel; } @@ -759,8 +776,8 @@ void Renderer::initPipeline() { dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; VkPushConstantRange pushConstantRange = {}; - pushConstantRange.size = (sizeof(glm::mat4) * 2) + sizeof(int); - pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + pushConstantRange.size = (sizeof(glm::mat4) * 2) + sizeof(int) * 2; + pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; @@ -852,10 +869,28 @@ void Renderer::initDescriptors() { VkDescriptorSetLayoutBinding textureBinding = {}; textureBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; textureBinding.descriptorCount = 1; - textureBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + textureBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; textureBinding.binding = 3; - const std::array bindings = {boneInfoBufferBinding, textureBinding}; + VkDescriptorSetLayoutBinding normalBinding = {}; + normalBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + normalBinding.descriptorCount = 1; + normalBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + normalBinding.binding = 4; + + VkDescriptorSetLayoutBinding specularBinding = {}; + specularBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + specularBinding.descriptorCount = 1; + specularBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + specularBinding.binding = 5; + + VkDescriptorSetLayoutBinding multiBinding = {}; + multiBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + multiBinding.descriptorCount = 1; + multiBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + multiBinding.binding = 6; + + const std::array bindings = {boneInfoBufferBinding, textureBinding, normalBinding, specularBinding, multiBinding}; VkDescriptorSetLayoutCreateInfo layoutInfo = {}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; @@ -863,12 +898,6 @@ void Renderer::initDescriptors() { layoutInfo.pBindings = bindings.data(); vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &setLayout); - - const size_t bufferSize = sizeof(glm::mat4) * 128; - auto [buffer, memory] = createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); - - boneInfoBuffer = buffer; - boneInfoMemory = memory; } void Renderer::initDepth(int width, int height) { @@ -1122,7 +1151,21 @@ void Renderer::inlineTransitionImageLayout(VkCommandBuffer commandBuffer, VkImag nullptr, 0, nullptr, 1, &barrier); } -VkDescriptorSet Renderer::createDescriptorFor(RenderTexture &texture) { +int Renderer::hash(const RenderModel& model, const RenderMaterial& material) { + int hash = 0; + hash += reinterpret_cast((void*)&model); + if (material.diffuseTexture) + hash += reinterpret_cast((void*)material.diffuseTexture); + if (material.normalTexture) + hash += reinterpret_cast((void*)material.normalTexture); + if (material.specularTexture) + hash += reinterpret_cast((void*)material.specularTexture); + if (material.multiTexture) + hash += reinterpret_cast((void*)material.multiTexture); + return hash; +} + +VkDescriptorSet Renderer::createDescriptorFor(const RenderModel& model, const RenderMaterial& material) { VkDescriptorSet set; VkDescriptorSetAllocateInfo allocateInfo = {}; @@ -1135,8 +1178,10 @@ VkDescriptorSet Renderer::createDescriptorFor(RenderTexture &texture) { const size_t bufferSize = sizeof(glm::mat4) * 128; + std::vector writes; + VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = boneInfoBuffer; + bufferInfo.buffer = model.boneInfoBuffer; bufferInfo.range = bufferSize; VkWriteDescriptorSet descriptorWrite = {}; @@ -1147,20 +1192,79 @@ VkDescriptorSet Renderer::createDescriptorFor(RenderTexture &texture) { descriptorWrite.pBufferInfo = &bufferInfo; descriptorWrite.dstBinding = 2; + writes.push_back(descriptorWrite); + VkDescriptorImageInfo imageInfo = {}; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo.imageView = texture.view; - imageInfo.sampler = texture.sampler; - VkWriteDescriptorSet descriptorWrite2 = {}; - descriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite2.dstSet = set; - descriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorWrite2.descriptorCount = 1; - descriptorWrite2.pImageInfo = &imageInfo; - descriptorWrite2.dstBinding = 3; + if(material.diffuseTexture) { + imageInfo.imageView = material.diffuseTexture->view; + imageInfo.sampler = material.diffuseTexture->sampler; - const std::array writes = {descriptorWrite, descriptorWrite2}; + VkWriteDescriptorSet descriptorWrite2 = {}; + descriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite2.dstSet = set; + descriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrite2.descriptorCount = 1; + descriptorWrite2.pImageInfo = &imageInfo; + descriptorWrite2.dstBinding = 3; + + writes.push_back(descriptorWrite2); + } + + VkDescriptorImageInfo normalImageInfo = {}; + normalImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + if(material.normalTexture) { + normalImageInfo.imageView = material.normalTexture->view; + normalImageInfo.sampler = material.normalTexture->sampler; + + VkWriteDescriptorSet normalDescriptorWrite2 = {}; + normalDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + normalDescriptorWrite2.dstSet = set; + normalDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + normalDescriptorWrite2.descriptorCount = 1; + normalDescriptorWrite2.pImageInfo = &normalImageInfo; + normalDescriptorWrite2.dstBinding = 4; + + writes.push_back(normalDescriptorWrite2); + } + + VkDescriptorImageInfo specularImageInfo = {}; + specularImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + if(material.specularTexture) { + specularImageInfo.imageView = material.specularTexture->view; + specularImageInfo.sampler = material.specularTexture->sampler; + + VkWriteDescriptorSet specularDescriptorWrite2 = {}; + specularDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + specularDescriptorWrite2.dstSet = set; + specularDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + specularDescriptorWrite2.descriptorCount = 1; + specularDescriptorWrite2.pImageInfo = &specularImageInfo; + specularDescriptorWrite2.dstBinding = 5; + + writes.push_back(specularDescriptorWrite2); + } + + VkDescriptorImageInfo multiImageInfo = {}; + multiImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + if (material.multiTexture) { + multiImageInfo.imageView = material.multiTexture->view; + multiImageInfo.sampler = material.multiTexture->sampler; + + VkWriteDescriptorSet multiDescriptorWrite2 = {}; + multiDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + multiDescriptorWrite2.dstSet = set; + multiDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + multiDescriptorWrite2.descriptorCount = 1; + multiDescriptorWrite2.pImageInfo = &multiImageInfo; + multiDescriptorWrite2.dstBinding = 6; + + writes.push_back(multiDescriptorWrite2); + } vkUpdateDescriptorSets(device, writes.size(), writes.data(), 0, nullptr);