diff --git a/armoury/src/gearview.cpp b/armoury/src/gearview.cpp index d898f4f..7c9a471 100644 --- a/armoury/src/gearview.cpp +++ b/armoury/src/gearview.cpp @@ -339,6 +339,7 @@ void GearView::updatePart() gearAddition.bodyId = physis_get_race_code(fallbackRace, fallbackSubrace, currentGender); mdlPart->addModel(mdl, + true, glm::vec3(), sanitizeMdlPath(mdlPath), materials, @@ -390,7 +391,7 @@ void GearView::updatePart() } } - mdlPart->addModel(mdl, glm::vec3(), sanitizeMdlPath(mdlPath), materials, currentLod); + mdlPart->addModel(mdl, true, glm::vec3(), sanitizeMdlPath(mdlPath), materials, currentLod); } } @@ -413,7 +414,7 @@ void GearView::updatePart() } } - mdlPart->addModel(mdl, glm::vec3(), sanitizeMdlPath(mdlPath), materials, currentLod); + mdlPart->addModel(mdl, true, glm::vec3(), sanitizeMdlPath(mdlPath), materials, currentLod); } } @@ -436,7 +437,7 @@ void GearView::updatePart() } } - mdlPart->addModel(mdl, glm::vec3(), sanitizeMdlPath(mdlPath), materials, currentLod); + mdlPart->addModel(mdl, true, glm::vec3(), sanitizeMdlPath(mdlPath), materials, currentLod); } } @@ -453,7 +454,7 @@ void GearView::updatePart() if (cache.fileExists(QLatin1String(skinmtrl_path.c_str()))) { auto mat = physis_material_parse(cache.lookupFile(QLatin1String(skinmtrl_path.c_str()))); - mdlPart->addModel(mdl, glm::vec3(), sanitizeMdlPath(mdlPath), {mat}, currentLod); + mdlPart->addModel(mdl, true, glm::vec3(), sanitizeMdlPath(mdlPath), {mat}, currentLod); } } } diff --git a/mapeditor/src/mapview.cpp b/mapeditor/src/mapview.cpp index 0eed3bf..352b818 100644 --- a/mapeditor/src/mapview.cpp +++ b/mapeditor/src/mapview.cpp @@ -38,7 +38,12 @@ void MapView::addTerrain(QString basePath, physis_Terrain terrain) auto plateMdlFile = physis_gamedata_extract_file(data, mdlPathStd.c_str()); auto plateMdl = physis_mdl_parse(plateMdlFile); - mdlPart->addModel(plateMdl, glm::vec3(terrain.plates[i].position[0], 0.0f, terrain.plates[i].position[1]), QStringLiteral("terapart%1").arg(i), {}, 0); + mdlPart->addModel(plateMdl, + false, + glm::vec3(terrain.plates[i].position[0], 0.0f, terrain.plates[i].position[1]), + QStringLiteral("terapart%1").arg(i), + {}, + 0); } } diff --git a/mdlviewer/src/mainwindow.cpp b/mdlviewer/src/mainwindow.cpp index e297cf7..866a396 100644 --- a/mdlviewer/src/mainwindow.cpp +++ b/mdlviewer/src/mainwindow.cpp @@ -58,7 +58,7 @@ void MainWindow::setupFileMenu(QMenu *menu) auto buffer = physis_read_file(fileName.toStdString().c_str()); - part->addModel(physis_mdl_parse(buffer), glm::vec3(), QStringLiteral("mdl"), {}, 0); + part->addModel(physis_mdl_parse(buffer), false, glm::vec3(), QStringLiteral("mdl"), {}, 0); }); } diff --git a/parts/mdl/mdlpart.cpp b/parts/mdl/mdlpart.cpp index 92953f8..c31dd33 100644 --- a/parts/mdl/mdlpart.cpp +++ b/parts/mdl/mdlpart.cpp @@ -72,6 +72,7 @@ void MDLPart::clear() } void MDLPart::addModel(physis_MDL mdl, + bool skinned, glm::vec3 position, const QString &name, std::vector materials, @@ -86,6 +87,7 @@ void MDLPart::addModel(physis_MDL mdl, model.from_body_id = fromBodyId; model.to_body_id = toBodyId; model.position = position; + model.skinned = skinned; std::transform(materials.begin(), materials.end(), std::back_inserter(model.materials), [this](const physis_Material &mat) { return createMaterial(mat); diff --git a/parts/mdl/mdlpart.h b/parts/mdl/mdlpart.h index 2ba6f4a..81a4245 100644 --- a/parts/mdl/mdlpart.h +++ b/parts/mdl/mdlpart.h @@ -53,6 +53,7 @@ public Q_SLOTS: /// Adds a new MDL with a list of materials used. void addModel(physis_MDL mdl, + bool skinned, glm::vec3 position, const QString &name, std::vector materials, diff --git a/renderer/CMakeLists.txt b/renderer/CMakeLists.txt index d835b0d..8831e92 100644 --- a/renderer/CMakeLists.txt +++ b/renderer/CMakeLists.txt @@ -16,7 +16,8 @@ qt_add_resources(renderer shaders/imgui.frag.spv shaders/imgui.vert.spv shaders/mesh.frag.spv - shaders/mesh.vert.spv) + shaders/mesh.vert.spv + shaders/skinned.vert.spv) target_include_directories(renderer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_link_libraries(renderer PUBLIC diff --git a/renderer/include/renderer.hpp b/renderer/include/renderer.hpp index 17694fb..d905dae 100644 --- a/renderer/include/renderer.hpp +++ b/renderer/include/renderer.hpp @@ -47,6 +47,7 @@ struct RenderModel { std::array boneData; std::vector materials; glm::vec3 position; + bool skinned = false; uint16_t from_body_id = 101; uint16_t to_body_id = 101; @@ -109,6 +110,7 @@ public: std::map cachedDescriptors; VkPipeline pipeline; + VkPipeline skinnedPipeline; VkPipelineLayout pipelineLayout; std::tuple createBuffer(size_t size, VkBufferUsageFlags usageFlags); diff --git a/renderer/shaders/compile_shaders.sh b/renderer/shaders/compile_shaders.sh index 95271ea..702826f 100755 --- a/renderer/shaders/compile_shaders.sh +++ b/renderer/shaders/compile_shaders.sh @@ -3,6 +3,7 @@ # SPDX-License-Identifier: CC0-1.0 glslc mesh.vert -o mesh.vert.spv && +glslc skinned.vert -o skinned.vert.spv && glslc mesh.frag -o mesh.frag.spv && glslc imgui.vert -o imgui.vert.spv && glslc imgui.frag -o imgui.frag.spv \ No newline at end of file diff --git a/renderer/shaders/mesh.frag b/renderer/shaders/mesh.frag index 0ea859d..ea01613 100644 --- a/renderer/shaders/mesh.frag +++ b/renderer/shaders/mesh.frag @@ -23,7 +23,12 @@ layout(std430, push_constant) uniform PushConstant { void main() { const vec3 lightPos = vec3(3); - vec3 diffuse = texture(diffuseTexture, inUV).rgb; + vec3 diffuse; + if (textureSize(diffuseTexture, 0).x == 1) { + diffuse = vec3(1); + } else { + 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); diff --git a/renderer/shaders/mesh.frag.spv b/renderer/shaders/mesh.frag.spv index 0d0b971..050b402 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 d81e5e2..06f0032 100644 --- a/renderer/shaders/mesh.vert +++ b/renderer/shaders/mesh.vert @@ -32,15 +32,8 @@ layout(std430, binding = 2) buffer readonly BoneInformation { }; void main() { - mat4 BoneTransform = bones[boneOffset + inBoneIds[0]] * inBoneWeights[0]; - BoneTransform += bones[boneOffset + inBoneIds[1]] * inBoneWeights[1]; - BoneTransform += bones[boneOffset + inBoneIds[2]] * inBoneWeights[2]; - BoneTransform += bones[boneOffset + inBoneIds[3]] * inBoneWeights[3]; - - BoneTransform = model * BoneTransform; - - vec4 bPos = BoneTransform * vec4(inPosition, 1.0); - vec4 bNor = BoneTransform * vec4(inNormal, 0.0); + vec4 bPos = model * vec4(inPosition, 1.0); + vec4 bNor = vec4(inNormal, 0.0); gl_Position = vp * bPos; outNormal = bNor.xyz; diff --git a/renderer/shaders/mesh.vert.spv b/renderer/shaders/mesh.vert.spv index 3f02e37..1b15571 100644 Binary files a/renderer/shaders/mesh.vert.spv and b/renderer/shaders/mesh.vert.spv differ diff --git a/renderer/shaders/skinned.vert b/renderer/shaders/skinned.vert new file mode 100644 index 0000000..d81e5e2 --- /dev/null +++ b/renderer/shaders/skinned.vert @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: CC0-1.0 + +#version 450 + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec2 inUV0; +layout(location = 2) in vec2 inUV1; +layout(location = 3) in vec3 inNormal; +layout(location = 4) in vec4 inBiTangent; +layout(location = 5) in vec4 inColor; +layout(location = 6) in vec4 inBoneWeights; +layout(location = 7) in uvec4 inBoneIds; + +layout(location = 0) out vec3 outNormal; +layout(location = 1) out vec3 outFragPos; +layout(location = 2) out vec2 outUV; + +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 { + mat4 bones[128]; +}; + +void main() { + mat4 BoneTransform = bones[boneOffset + inBoneIds[0]] * inBoneWeights[0]; + BoneTransform += bones[boneOffset + inBoneIds[1]] * inBoneWeights[1]; + BoneTransform += bones[boneOffset + inBoneIds[2]] * inBoneWeights[2]; + BoneTransform += bones[boneOffset + inBoneIds[3]] * inBoneWeights[3]; + + BoneTransform = model * BoneTransform; + + vec4 bPos = BoneTransform * vec4(inPosition, 1.0); + vec4 bNor = BoneTransform * vec4(inNormal, 0.0); + + gl_Position = vp * bPos; + outNormal = bNor.xyz; + outFragPos = vec3(model * vec4(inPosition, 1.0)); + outUV = inUV0; +} diff --git a/renderer/shaders/skinned.vert.spv b/renderer/shaders/skinned.vert.spv new file mode 100644 index 0000000..3f02e37 Binary files /dev/null and b/renderer/shaders/skinned.vert.spv differ diff --git a/renderer/src/renderer.cpp b/renderer/src/renderer.cpp index 5337895..f603e48 100644 --- a/renderer/src/renderer.cpp +++ b/renderer/src/renderer.cpp @@ -472,9 +472,13 @@ void Renderer::render(const std::vector &models) vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - for (auto model : models) { + if (model.skinned) { + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, skinnedPipeline); + } else { + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + } + // copy bone data { const size_t bufferSize = sizeof(glm::mat4) * 128; @@ -731,6 +735,12 @@ void Renderer::initPipeline() vertexShaderStageInfo.module = loadShaderFromDisk(":/shaders/mesh.vert.spv"); vertexShaderStageInfo.pName = "main"; + VkPipelineShaderStageCreateInfo skinnedVertexShaderStageInfo = {}; + skinnedVertexShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + skinnedVertexShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + skinnedVertexShaderStageInfo.module = loadShaderFromDisk(":/shaders/skinned.vert.spv"); + skinnedVertexShaderStageInfo.pName = "main"; + VkPipelineShaderStageCreateInfo fragmentShaderStageInfo = {}; fragmentShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; fragmentShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; @@ -867,6 +877,10 @@ void Renderer::initPipeline() createInfo.renderPass = renderPass; vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipeline); + + shaderStages[0] = skinnedVertexShaderStageInfo; + + vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &skinnedPipeline); } VkShaderModule Renderer::createShaderModule(const uint32_t *code, const int length) diff --git a/sagasu/src/mainwindow.cpp b/sagasu/src/mainwindow.cpp index 613d48b..e3e4852 100644 --- a/sagasu/src/mainwindow.cpp +++ b/sagasu/src/mainwindow.cpp @@ -89,7 +89,7 @@ void MainWindow::refreshParts(const QString &path) partHolder->addTab(exdWidget, QStringLiteral("Note")); } else if (info.completeSuffix() == QStringLiteral("mdl")) { auto mdlWidget = new MDLPart(data, fileCache); - mdlWidget->addModel(physis_mdl_parse(file), glm::vec3(), QStringLiteral("mdl"), {}, 0); + mdlWidget->addModel(physis_mdl_parse(file), false, glm::vec3(), QStringLiteral("mdl"), {}, 0); partHolder->addTab(mdlWidget, QStringLiteral("Model")); } else if (info.completeSuffix() == QStringLiteral("tex") || info.completeSuffix() == QStringLiteral("atex")) { auto texWidget = new TexPart(data);