mirror of
https://github.com/redstrate/Novus.git
synced 2025-04-25 13:17:46 +00:00
Expand Renderer's capabilities for materials and skeletons
The renderer can now store diffuse, normal, specular, and multi textures. Skin textures now color with a hardcoded skin tone (to be changed) and bone info buffers are now per-model instead of set globally Level of detail above 0 is now loaded properly, although break for other reasons.
This commit is contained in:
parent
8003571d13
commit
792da6da6a
6 changed files with 190 additions and 45 deletions
|
@ -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<RenderPart> parts;
|
||||
std::array<glm::mat4, 128> boneData;
|
||||
std::vector<RenderMaterial> 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<VkImage, VkDescriptorSet> cachedDescriptors;
|
||||
std::map<int, VkDescriptorSet> 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);
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -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 {
|
||||
|
|
Binary file not shown.
|
@ -469,45 +469,54 @@ void Renderer::render(std::vector<RenderModel> 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<intptr_t>((void*)&model);
|
||||
if (material.diffuseTexture)
|
||||
hash += reinterpret_cast<intptr_t>((void*)material.diffuseTexture);
|
||||
if (material.normalTexture)
|
||||
hash += reinterpret_cast<intptr_t>((void*)material.normalTexture);
|
||||
if (material.specularTexture)
|
||||
hash += reinterpret_cast<intptr_t>((void*)material.specularTexture);
|
||||
if (material.multiTexture)
|
||||
hash += reinterpret_cast<intptr_t>((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<VkWriteDescriptorSet> writes;
|
||||
|
||||
VkDescriptorBufferInfo bufferInfo = {};
|
||||
bufferInfo.buffer = boneInfoBuffer;
|
||||
bufferInfo.buffer = model.boneInfoBuffer;
|
||||
bufferInfo.range = bufferSize;
|
||||
|
||||
VkWriteDescriptorSet descriptorWrite = {};
|
||||
|
@ -1147,10 +1192,14 @@ 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;
|
||||
|
||||
if(material.diffuseTexture) {
|
||||
imageInfo.imageView = material.diffuseTexture->view;
|
||||
imageInfo.sampler = material.diffuseTexture->sampler;
|
||||
|
||||
VkWriteDescriptorSet descriptorWrite2 = {};
|
||||
descriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
|
@ -1160,7 +1209,62 @@ VkDescriptorSet Renderer::createDescriptorFor(RenderTexture &texture) {
|
|||
descriptorWrite2.pImageInfo = &imageInfo;
|
||||
descriptorWrite2.dstBinding = 3;
|
||||
|
||||
const std::array writes = {descriptorWrite, descriptorWrite2};
|
||||
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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue