diff --git a/modules/geometry/include/vkcv/geometry/Geometry.hpp b/modules/geometry/include/vkcv/geometry/Geometry.hpp index 7924dfa570c510bddab6e0003a17ed7602290d0d..cf2b6eb5132e46883a81dc6d45eae18f51f48bea 100644 --- a/modules/geometry/include/vkcv/geometry/Geometry.hpp +++ b/modules/geometry/include/vkcv/geometry/Geometry.hpp @@ -24,6 +24,19 @@ namespace vkcv::geometry { */ glm::vec3 m_position; + protected: + /** + * Generate tangent from positions and uv-coordinates + * for a given triangle. + * + * @param[in] positions Array of positions + * @param[in] uvs Array of uv-coordinates + * @return Calculated tangent + */ + [[nodiscard]] + glm::vec3 generateTangent(const std::array<glm::vec3, 3>& positions, + const std::array<glm::vec2, 3>& uvs) const; + public: /** * Constructor creating geometry by a given position diff --git a/modules/geometry/src/vkcv/geometry/Cuboid.cpp b/modules/geometry/src/vkcv/geometry/Cuboid.cpp index 0256261e4bc2c4dc73bc51721718e4e986905d15..f8be3f90caf07414bea053c0a063efb40da5016e 100644 --- a/modules/geometry/src/vkcv/geometry/Cuboid.cpp +++ b/modules/geometry/src/vkcv/geometry/Cuboid.cpp @@ -134,6 +134,69 @@ namespace vkcv::geometry { 20, 23, 21 }; + std::vector<glm::vec3> cuboidTangents; + cuboidTangents.resize(24, glm::vec3(0.0f)); + + std::vector<size_t> cuboidTangentWeights; + cuboidTangentWeights.resize(cuboidTangents.size(), 0); + + for (size_t i = 0; i < cuboidIndices.size(); i += 3) { + const auto index0 = cuboidIndices[i + 0]; + const auto index1 = cuboidIndices[i + 1]; + const auto index2 = cuboidIndices[i + 2]; + + const std::array<glm::vec3, 3> positions = { + glm::vec3( + cuboidPositions[index0 * 3 + 0], + cuboidPositions[index0 * 3 + 1], + cuboidPositions[index0 * 3 + 2] + ), + glm::vec3( + cuboidPositions[index1 * 3 + 0], + cuboidPositions[index1 * 3 + 1], + cuboidPositions[index1 * 3 + 2] + ), + glm::vec3( + cuboidPositions[index2 * 3 + 0], + cuboidPositions[index2 * 3 + 1], + cuboidPositions[index2 * 3 + 2] + ) + }; + + const std::array<glm::vec2, 3> uvs = { + glm::vec2( + cuboidUVCoords[index0 * 3 + 0], + cuboidUVCoords[index0 * 3 + 1] + ), + glm::vec2( + cuboidUVCoords[index1 * 3 + 0], + cuboidUVCoords[index1 * 3 + 1] + ), + glm::vec2( + cuboidUVCoords[index2 * 3 + 0], + cuboidUVCoords[index2 * 3 + 1] + ) + }; + + const glm::vec3 tangent = generateTangent(positions, uvs); + + cuboidTangents[index0] += tangent; + cuboidTangents[index1] += tangent; + cuboidTangents[index2] += tangent; + + cuboidTangentWeights[index0]++; + cuboidTangentWeights[index1]++; + cuboidTangentWeights[index2]++; + } + + for (size_t i = 0; i < cuboidTangents.size(); i++) { + if (cuboidTangentWeights[i] <= 0) { + continue; + } + + cuboidTangents[i] /= cuboidTangentWeights[i]; + } + const auto& position = getPosition(); const auto& size = getSize(); @@ -152,10 +215,14 @@ namespace vkcv::geometry { auto uvBuffer = buffer<float>(core, BufferType::VERTEX, cuboidUVCoords.size()); uvBuffer.fill(cuboidUVCoords); + auto tangentBuffer = buffer<glm::vec3>(core, BufferType::VERTEX, cuboidTangents.size()); + tangentBuffer.fill(cuboidTangents); + VertexData data ({ vkcv::vertexBufferBinding(positionBuffer.getHandle()), vkcv::vertexBufferBinding(normalBuffer.getHandle()), - vkcv::vertexBufferBinding(uvBuffer.getHandle()) + vkcv::vertexBufferBinding(uvBuffer.getHandle()), + vkcv::vertexBufferBinding(tangentBuffer.getHandle()) }); const auto& featureManager = core.getContext().getFeatureManager(); @@ -174,7 +241,8 @@ namespace vkcv::geometry { data.setIndexBuffer(indexBuffer.getHandle(), IndexBitCount::Bit8); data.setCount(indexBuffer.getCount()); } else { - std::array<uint16_t, cuboidIndices.size()> cuboidIndices16; + std::vector<uint16_t> cuboidIndices16; + cuboidIndices16.resize(cuboidIndices.size()); for (size_t i = 0; i < cuboidIndices16.size(); i++) { cuboidIndices16[i] = static_cast<uint16_t>(cuboidIndices[i]); diff --git a/modules/geometry/src/vkcv/geometry/Cylinder.cpp b/modules/geometry/src/vkcv/geometry/Cylinder.cpp index cffdaf47fb44c916032dda8f62651c7c3d6962c6..79e31496b559f049fb0a9931b7e5e061fd310cb2 100644 --- a/modules/geometry/src/vkcv/geometry/Cylinder.cpp +++ b/modules/geometry/src/vkcv/geometry/Cylinder.cpp @@ -107,6 +107,48 @@ namespace vkcv::geometry { offset += 4; } + std::vector<glm::vec3> cylinderTangents; + cylinderTangents.resize(cylinderVertices.size(), glm::vec3(0.0f)); + + std::vector<size_t> cylinderTangentWeights; + cylinderTangentWeights.resize(cylinderTangents.size(), 0); + + for (i = 0; i < cylinderIndices.size(); i += 3) { + const auto index0 = cylinderIndices[i + 0]; + const auto index1 = cylinderIndices[i + 1]; + const auto index2 = cylinderIndices[i + 2]; + + const std::array<glm::vec3, 3> positions = { + cylinderVertices[index0], + cylinderVertices[index1], + cylinderVertices[index2] + }; + + const std::array<glm::vec2, 3> uvs = { + cylinderUVCoords[index0], + cylinderUVCoords[index1], + cylinderUVCoords[index2] + }; + + const glm::vec3 tangent = generateTangent(positions, uvs); + + cylinderTangents[index0] += tangent; + cylinderTangents[index1] += tangent; + cylinderTangents[index2] += tangent; + + cylinderTangentWeights[index0]++; + cylinderTangentWeights[index1]++; + cylinderTangentWeights[index2]++; + } + + for (i = 0; i < cylinderTangents.size(); i++) { + if (cylinderTangentWeights[i] <= 0) { + continue; + } + + cylinderTangents[i] /= cylinderTangentWeights[i]; + } + auto positionBuffer = buffer<glm::vec3>(core, BufferType::VERTEX, cylinderVertices.size()); positionBuffer.fill(cylinderVertices); @@ -116,13 +158,17 @@ namespace vkcv::geometry { auto uvBuffer = buffer<glm::vec2>(core, BufferType::VERTEX, cylinderUVCoords.size()); uvBuffer.fill(cylinderUVCoords); + auto tangentBuffer = buffer<glm::vec3>(core, BufferType::VERTEX, cylinderTangents.size()); + tangentBuffer.fill(cylinderTangents); + auto indexBuffer = buffer<uint32_t>(core, BufferType::INDEX, cylinderIndices.size()); indexBuffer.fill(cylinderIndices); VertexData data ({ vkcv::vertexBufferBinding(positionBuffer.getHandle()), vkcv::vertexBufferBinding(normalBuffer.getHandle()), - vkcv::vertexBufferBinding(uvBuffer.getHandle()) + vkcv::vertexBufferBinding(uvBuffer.getHandle()), + vkcv::vertexBufferBinding(tangentBuffer.getHandle()) }); data.setIndexBuffer(indexBuffer.getHandle(), IndexBitCount::Bit32); diff --git a/modules/geometry/src/vkcv/geometry/Geometry.cpp b/modules/geometry/src/vkcv/geometry/Geometry.cpp index ccdc45fc1be7301691f1ec14e705a0f68d83fe88..feaa84a04f2e180b08fd92977d6494ac997af6b2 100644 --- a/modules/geometry/src/vkcv/geometry/Geometry.cpp +++ b/modules/geometry/src/vkcv/geometry/Geometry.cpp @@ -14,4 +14,18 @@ namespace vkcv::geometry { m_position = position; } + glm::vec3 Geometry::generateTangent(const std::array<glm::vec3, 3>& positions, + const std::array<glm::vec2, 3>& uvs) const { + auto delta1 = positions[1] - positions[0]; + auto delta2 = positions[2] - positions[0]; + + auto deltaUV1 = uvs[1] - uvs[0]; + auto deltaUV2 = uvs[2] - uvs[0]; + + return glm::normalize(glm::vec3( + delta1 * deltaUV2.y - + delta2 * deltaUV1.y + )); + } + } diff --git a/modules/geometry/src/vkcv/geometry/Sphere.cpp b/modules/geometry/src/vkcv/geometry/Sphere.cpp index e7ed47dc13265dd83d186ad88834950b8c08b693..d516a1dad4e11651e4ad6d6c056dcf9442d29f18 100644 --- a/modules/geometry/src/vkcv/geometry/Sphere.cpp +++ b/modules/geometry/src/vkcv/geometry/Sphere.cpp @@ -79,6 +79,48 @@ namespace vkcv::geometry { offset += (resolution + 1); } + std::vector<glm::vec3> sphereTangents; + sphereTangents.resize(sphereVertices.size(), glm::vec3(0.0f)); + + std::vector<size_t> sphereTangentWeights; + sphereTangentWeights.resize(sphereTangents.size(), 0); + + for (i = 0; i < sphereIndices.size(); i += 3) { + const auto index0 = sphereIndices[i + 0]; + const auto index1 = sphereIndices[i + 1]; + const auto index2 = sphereIndices[i + 2]; + + const std::array<glm::vec3, 3> positions = { + sphereVertices[index0], + sphereVertices[index1], + sphereVertices[index2] + }; + + const std::array<glm::vec2, 3> uvs = { + sphereUVCoords[index0], + sphereUVCoords[index1], + sphereUVCoords[index2] + }; + + const glm::vec3 tangent = generateTangent(positions, uvs); + + sphereTangents[index0] += tangent; + sphereTangents[index1] += tangent; + sphereTangents[index2] += tangent; + + sphereTangentWeights[index0]++; + sphereTangentWeights[index1]++; + sphereTangentWeights[index2]++; + } + + for (i = 0; i < sphereTangents.size(); i++) { + if (sphereTangentWeights[i] <= 0) { + continue; + } + + sphereTangents[i] /= sphereTangentWeights[i]; + } + auto positionBuffer = buffer<glm::vec3>(core, BufferType::VERTEX, sphereVertices.size()); positionBuffer.fill(sphereVertices); @@ -88,13 +130,17 @@ namespace vkcv::geometry { auto uvBuffer = buffer<glm::vec2>(core, BufferType::VERTEX, sphereUVCoords.size()); uvBuffer.fill(sphereUVCoords); + auto tangentBuffer = buffer<glm::vec3>(core, BufferType::VERTEX, sphereTangents.size()); + tangentBuffer.fill(sphereTangents); + auto indexBuffer = buffer<uint32_t>(core, BufferType::INDEX, sphereIndices.size()); indexBuffer.fill(sphereIndices); VertexData data ({ vkcv::vertexBufferBinding(positionBuffer.getHandle()), vkcv::vertexBufferBinding(normalBuffer.getHandle()), - vkcv::vertexBufferBinding(uvBuffer.getHandle()) + vkcv::vertexBufferBinding(uvBuffer.getHandle()), + vkcv::vertexBufferBinding(tangentBuffer.getHandle()) }); data.setIndexBuffer(indexBuffer.getHandle(), IndexBitCount::Bit32); diff --git a/modules/geometry/src/vkcv/geometry/Teapot.cpp b/modules/geometry/src/vkcv/geometry/Teapot.cpp index d1c7465ab646ba4ffcce0f356e5d4935b4e610e1..7becdef5941769c79da0b0b17a45ec3e5d0a1cb6 100644 --- a/modules/geometry/src/vkcv/geometry/Teapot.cpp +++ b/modules/geometry/src/vkcv/geometry/Teapot.cpp @@ -14846,6 +14846,69 @@ namespace vkcv::geometry { 3859, 3860, 3870, 3870, 3860, 3871 }; + std::vector<glm::vec3> teapotTangents; + teapotTangents.resize(teapotVertices.size() / 3, glm::vec3(0.0f)); + + std::vector<size_t> teapotTangentWeights; + teapotTangentWeights.resize(teapotTangents.size(), 0); + + for (size_t i = 0; i < teapotIndices.size(); i += 3) { + const auto index0 = teapotIndices[i + 0]; + const auto index1 = teapotIndices[i + 1]; + const auto index2 = teapotIndices[i + 2]; + + const std::array<glm::vec3, 3> positions = { + glm::vec3( + teapotVertices[index0 * 3 + 0], + teapotVertices[index0 * 3 + 1], + teapotVertices[index0 * 3 + 2] + ), + glm::vec3( + teapotVertices[index1 * 3 + 0], + teapotVertices[index1 * 3 + 1], + teapotVertices[index1 * 3 + 2] + ), + glm::vec3( + teapotVertices[index2 * 3 + 0], + teapotVertices[index2 * 3 + 1], + teapotVertices[index2 * 3 + 2] + ) + }; + + const std::array<glm::vec2, 3> uvs = { + glm::vec2( + teapotUVCoords[index0 * 3 + 0], + teapotUVCoords[index0 * 3 + 1] + ), + glm::vec2( + teapotUVCoords[index1 * 3 + 0], + teapotUVCoords[index1 * 3 + 1] + ), + glm::vec2( + teapotUVCoords[index2 * 3 + 0], + teapotUVCoords[index2 * 3 + 1] + ) + }; + + const glm::vec3 tangent = generateTangent(positions, uvs); + + teapotTangents[index0] += tangent; + teapotTangents[index1] += tangent; + teapotTangents[index2] += tangent; + + teapotTangentWeights[index0]++; + teapotTangentWeights[index1]++; + teapotTangentWeights[index2]++; + } + + for (size_t i = 0; i < teapotTangents.size(); i++) { + if (teapotTangentWeights[i] <= 0) { + continue; + } + + teapotTangents[i] /= teapotTangentWeights[i]; + } + const auto& position = getPosition(); const auto scale = getScale(); @@ -14864,13 +14927,17 @@ namespace vkcv::geometry { auto uvBuffer = buffer<float>(core, BufferType::VERTEX, teapotUVCoords.size()); uvBuffer.fill(teapotUVCoords); + auto tangentBuffer = buffer<glm::vec3>(core, BufferType::VERTEX, teapotTangents.size()); + tangentBuffer.fill(teapotTangents); + auto indexBuffer = buffer<uint16_t>(core, BufferType::INDEX, teapotIndices.size()); indexBuffer.fill(teapotIndices); VertexData data ({ vkcv::vertexBufferBinding(positionBuffer.getHandle()), vkcv::vertexBufferBinding(normalBuffer.getHandle()), - vkcv::vertexBufferBinding(uvBuffer.getHandle()) + vkcv::vertexBufferBinding(uvBuffer.getHandle()), + vkcv::vertexBufferBinding(tangentBuffer.getHandle()) }); data.setIndexBuffer(indexBuffer.getHandle());