From 693a47cf4e9a479aaa47cc1dab0d8712ef0e95ed Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sun, 17 Dec 2023 19:00:43 -0500 Subject: [PATCH] Fix tangent reading/writing Updates to latest physis changes, and fixing tangent reading/writing. --- extern/libphysis | 2 +- parts/mdl/mdlexport.cpp | 39 +++++++++++++++++------------- parts/mdl/mdlimport.cpp | 42 ++++++++++++++++++++++++++------- renderer/shaders/mesh.vert | 9 ++++--- renderer/shaders/mesh.vert.spv | Bin 5312 -> 5256 bytes renderer/src/renderer.cpp | 30 +++++++---------------- 6 files changed, 70 insertions(+), 52 deletions(-) diff --git a/extern/libphysis b/extern/libphysis index b439934..be79c3c 160000 --- a/extern/libphysis +++ b/extern/libphysis @@ -1 +1 @@ -Subproject commit b439934f816fef2f07a62cf04cf892d46e1c4080 +Subproject commit be79c3c9e7dedcdf7494f2ed849ce257d5421230 diff --git a/parts/mdl/mdlexport.cpp b/parts/mdl/mdlexport.cpp index fcb0bfd..8835721 100644 --- a/parts/mdl/mdlexport.cpp +++ b/parts/mdl/mdlexport.cpp @@ -175,9 +175,10 @@ void exportModel(const QString &name, const physis_MDL &model, const physis_Skel gltfPrimitive.attributes["TEXCOORD_0"] = gltfModel.accessors.size() + 1; gltfPrimitive.attributes["TEXCOORD_1"] = gltfModel.accessors.size() + 2; gltfPrimitive.attributes["NORMAL"] = gltfModel.accessors.size() + 3; - gltfPrimitive.attributes["COLOR_0"] = gltfModel.accessors.size() + 6; - gltfPrimitive.attributes["WEIGHTS_0"] = gltfModel.accessors.size() + 7; - gltfPrimitive.attributes["JOINTS_0"] = gltfModel.accessors.size() + 8; + gltfPrimitive.attributes["TANGENT"] = gltfModel.accessors.size() + 4; + gltfPrimitive.attributes["COLOR_0"] = gltfModel.accessors.size() + 5; + gltfPrimitive.attributes["WEIGHTS_0"] = gltfModel.accessors.size() + 6; + gltfPrimitive.attributes["JOINTS_0"] = gltfModel.accessors.size() + 7; } mesh_offset += part.num_submeshes; @@ -211,19 +212,13 @@ void exportModel(const QString &name, const physis_MDL &model, const physis_Skel normalAccessor.type = TINYGLTF_TYPE_VEC3; normalAccessor.byteOffset = offsetof(Vertex, normal); - auto &tangent1Accessor = gltfModel.accessors.emplace_back(); - tangent1Accessor.bufferView = gltfModel.bufferViews.size(); - tangent1Accessor.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; - tangent1Accessor.count = lod.parts[i].num_vertices; - tangent1Accessor.type = TINYGLTF_TYPE_VEC4; - tangent1Accessor.byteOffset = offsetof(Vertex, tangent1); - - auto &tangent2Accessor = gltfModel.accessors.emplace_back(); - tangent2Accessor.bufferView = gltfModel.bufferViews.size(); - tangent2Accessor.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; - tangent2Accessor.count = lod.parts[i].num_vertices; - tangent2Accessor.type = TINYGLTF_TYPE_VEC4; - tangent2Accessor.byteOffset = offsetof(Vertex, tangent2); + // We're reusing this spot for tangents (see later post-processing step) + auto &tangentAccessor = gltfModel.accessors.emplace_back(); + tangentAccessor.bufferView = gltfModel.bufferViews.size(); + tangentAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT; + tangentAccessor.count = lod.parts[i].num_vertices; + tangentAccessor.type = TINYGLTF_TYPE_VEC4; + tangentAccessor.byteOffset = offsetof(Vertex, bitangent); auto &colorAccessor = gltfModel.accessors.emplace_back(); colorAccessor.bufferView = gltfModel.bufferViews.size(); @@ -261,6 +256,18 @@ void exportModel(const QString &name, const physis_MDL &model, const physis_Skel vertex.bone_id[2]++; vertex.bone_id[3]++; + // Do the reverse of what we do in importing, because we need to get the tangent from the binormal. + const glm::vec3 normal = glm::vec3(vertex.normal[0], vertex.normal[1], vertex.normal[2]); + const glm::vec4 tangent = glm::vec4(vertex.bitangent[0], vertex.bitangent[1], vertex.bitangent[2], vertex.bitangent[3]); + const glm::vec3 bitangent = glm::cross(glm::vec3(tangent), normal) * tangent.w; + + const float handedness = glm::dot(glm::cross(bitangent, glm::vec3(tangent)), normal) > 0 ? 1 : -1; + + vertex.bitangent[0] = bitangent.x; + vertex.bitangent[1] = bitangent.y; + vertex.bitangent[2] = bitangent.z; + vertex.bitangent[3] = handedness; + newVertices.push_back(vertex); } diff --git a/parts/mdl/mdlimport.cpp b/parts/mdl/mdlimport.cpp index f143e11..f8b41dd 100644 --- a/parts/mdl/mdlimport.cpp +++ b/parts/mdl/mdlimport.cpp @@ -84,20 +84,18 @@ void importModel(physis_MDL &existingModel, const QString &filename) auto &mesh = model.meshes[node.mesh]; auto &primitive = mesh.primitives[0]; - const auto getAccessor = [&model, &primitive](const std::string &name, const int index) -> unsigned char const * { + const auto getAccessor = [&model, &primitive](const std::string &name, const size_t index) -> unsigned char const * { const auto &positionAccessor = model.accessors[primitive.attributes[name]]; const auto &positionView = model.bufferViews[positionAccessor.bufferView]; const auto &positionBuffer = model.buffers[positionView.buffer]; - int elementCount = tinygltf::GetNumComponentsInType(positionAccessor.type); - int elementSize = tinygltf::GetComponentSizeInBytes(positionAccessor.componentType); - - return (positionBuffer.data.data() + (std::max(positionView.byteStride, (size_t)elementCount * elementSize) * index) + positionView.byteOffset + return (positionBuffer.data.data() + (positionAccessor.ByteStride(positionView) * index) + positionView.byteOffset + positionAccessor.byteOffset); }; - // All of the accessors are mapped to the same buffer vertex view + // All the accessors are mapped to the same buffer vertex view const auto &positionAccessor = model.accessors[primitive.attributes["POSITION"]]; + const auto &colorAccessor = model.accessors[primitive.attributes["COLOR_0"]]; const auto &indexAccessor = model.accessors[primitive.indices]; const auto &indexView = model.bufferViews[indexAccessor.bufferView]; @@ -119,12 +117,10 @@ void importModel(physis_MDL &existingModel, const QString &filename) glm::vec2 const *uv1Data = reinterpret_cast(getAccessor("TEXCOORD_1", i)); glm::vec4 const *weightsData = reinterpret_cast(getAccessor("WEIGHTS_0", i)); uint8_t const *jointsData = reinterpret_cast(getAccessor("JOINTS_0", i)); + glm::vec4 const *tangent1Data = reinterpret_cast(getAccessor("TANGENT", i)); // Replace position data Vertex vertex{}; - if (i < existingModel.lods[lodNumber].parts[partNumber].num_vertices) { - vertex = existingModel.lods[lodNumber].parts[partNumber].vertices[i]; - } vertex.position[0] = positionData->x; vertex.position[1] = positionData->y; @@ -145,6 +141,34 @@ void importModel(physis_MDL &existingModel, const QString &filename) vertex.bone_weight[2] = weightsData->z; vertex.bone_weight[3] = weightsData->w; + // calculate binormal, because glTF won't give us those!! + const glm::vec3 normal = glm::vec3(vertex.normal[0], vertex.normal[1], vertex.normal[2]); + const glm::vec4 tangent = *tangent1Data; + const glm::vec3 bitangent = glm::cross(normal, glm::vec3(tangent)) * tangent.w; + + const float handedness = glm::dot(glm::cross(glm::vec3(tangent), bitangent), normal) > 0 ? 1 : -1; + + // In a cruel twist of fate, Tangent1 is actually the **BINORMAL** and not the tangent data. Square Enix is AMAZING. + vertex.bitangent[0] = bitangent.x; + vertex.bitangent[1] = bitangent.y; + vertex.bitangent[2] = bitangent.z; + vertex.bitangent[3] = handedness; + + if (colorAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) { + unsigned short const *colorData = reinterpret_cast(getAccessor("COLOR_0", i)); + + vertex.color[0] = static_cast(*colorData) / std::numeric_limits::max(); + vertex.color[1] = static_cast(*(colorData + 1)) / std::numeric_limits::max(); + vertex.color[2] = static_cast(*(colorData + 2)) / std::numeric_limits::max(); + vertex.color[3] = static_cast(*(colorData + 3)) / std::numeric_limits::max(); + } else { + glm::vec4 const *colorData = reinterpret_cast(getAccessor("COLOR_0", i)); + vertex.color[0] = colorData->x; + vertex.color[1] = colorData->y; + vertex.color[2] = colorData->z; + vertex.color[3] = colorData->w; + } + // We need to ensure the bones are mapped correctly // When exporting from modeling software, it's possible it sorted the nodes (Blender does this) for (int i = 0; i < 4; i++) { diff --git a/renderer/shaders/mesh.vert b/renderer/shaders/mesh.vert index 391db9e..d81e5e2 100644 --- a/renderer/shaders/mesh.vert +++ b/renderer/shaders/mesh.vert @@ -7,11 +7,10 @@ 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 uvec4 inTangent1; -layout(location = 5) in uvec4 inTangent2; -layout(location = 6) in vec4 inColor; -layout(location = 7) in vec4 inBoneWeights; -layout(location = 8) in uvec4 inBoneIds; +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; diff --git a/renderer/shaders/mesh.vert.spv b/renderer/shaders/mesh.vert.spv index d1f17c52abba21fc34e770c9e21cae9f4e07afc3..3f02e37564408625281797c213622a9e293f99ab 100644 GIT binary patch delta 315 zcmX@0*`dkH%%sfDz`)4B&A`iWXdSQT3TswYDj8DNoi3k16X|j&$*_C!Pfq2)JwV=WAXWgX*bAgV03-&| a0pf!!0Rb3)KZFbCA3)l5%mo1ZSUOn% delta 345 zcmeCsJfO+T%%sfDz`)4B&A`iWcp|SUqtHZWN5fg<&^X%sD?NzX-@@W7t30kXc;v08lh9zbH2`CnU9^q_ij%$Op+DoSeuk z&Uk2ZC9^xDAO}#;9cY9)kd^~t_Q@AnK68Q$1o7A=-({6&WS;yNNU}_pWs{d=1&V^y z9|F=!Knwz4{$^9QY-U3lAa^GaGXk+SP#K61axsjr24sT_2k|8tI2ra#KFFyYxEILV n1H=kI9s7VZ2!O;uCV=?+K>|Pk;~xO?5d4E^{6m{fxq`U>DUdtF diff --git a/renderer/src/renderer.cpp b/renderer/src/renderer.cpp index 5646b89..d8bb0f4 100644 --- a/renderer/src/renderer.cpp +++ b/renderer/src/renderer.cpp @@ -759,40 +759,28 @@ void Renderer::initPipeline() normalAttribute.location = 3; normalAttribute.offset = offsetof(Vertex, normal); - VkVertexInputAttributeDescription tangent1Attribute = {}; - tangent1Attribute.format = VK_FORMAT_R8G8B8A8_UINT; - tangent1Attribute.location = 4; - tangent1Attribute.offset = offsetof(Vertex, tangent1); - - VkVertexInputAttributeDescription tangent2Attribute = {}; - tangent2Attribute.format = VK_FORMAT_R8G8B8A8_UINT; - tangent2Attribute.location = 5; - tangent2Attribute.offset = offsetof(Vertex, tangent2); + VkVertexInputAttributeDescription bitangentAttribute = {}; + bitangentAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT; + bitangentAttribute.location = 4; + bitangentAttribute.offset = offsetof(Vertex, bitangent); VkVertexInputAttributeDescription colorAttribute = {}; colorAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT; - colorAttribute.location = 6; + colorAttribute.location = 5; colorAttribute.offset = offsetof(Vertex, color); VkVertexInputAttributeDescription boneWeightAttribute = {}; boneWeightAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT; - boneWeightAttribute.location = 7; + boneWeightAttribute.location = 6; boneWeightAttribute.offset = offsetof(Vertex, bone_weight); VkVertexInputAttributeDescription boneIdAttribute = {}; boneIdAttribute.format = VK_FORMAT_R8G8B8A8_UINT; - boneIdAttribute.location = 8; + boneIdAttribute.location = 7; boneIdAttribute.offset = offsetof(Vertex, bone_id); - const std::array attributes = {positionAttribute, - uv0Attribute, - uv1Attribute, - normalAttribute, - tangent1Attribute, - tangent2Attribute, - colorAttribute, - boneWeightAttribute, - boneIdAttribute}; + const std::array attributes = + {positionAttribute, uv0Attribute, uv1Attribute, normalAttribute, bitangentAttribute, colorAttribute, boneWeightAttribute, boneIdAttribute}; VkPipelineVertexInputStateCreateInfo vertexInputState = {}; vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;