From c793ec532ebb4df6857daaa94ae12e12d5999b4c Mon Sep 17 00:00:00 2001 From: Eunki Hong Date: Sat, 21 Jan 2023 01:28:32 +0900 Subject: [PATCH] Generate tangent as Vector4 for gltf Since gltf use aTangent as Vector4 type, we seperate the tangent load logic and shaders. But dali auto generated aTangent used only for Vector3. It mean Vector4's w value was ignored. This patch branch whether we use Vector3 tangent or not. Change-Id: I95a8d33c01fa84f06a60f843ec0a84681ccbd003 Signed-off-by: Eunki Hong --- dali-scene3d/public-api/loader/mesh-definition.cpp | 146 ++++++++++++--------- 1 file changed, 85 insertions(+), 61 deletions(-) diff --git a/dali-scene3d/public-api/loader/mesh-definition.cpp b/dali-scene3d/public-api/loader/mesh-definition.cpp index 3beaf83..6c4c104 100644 --- a/dali-scene3d/public-api/loader/mesh-definition.cpp +++ b/dali-scene3d/public-api/loader/mesh-definition.cpp @@ -20,10 +20,12 @@ // EXTERNAL INCLUDES #include +#include #include +#include #include #include -#include "dali/devel-api/adaptor-framework/pixel-buffer.h" +#include namespace Dali { @@ -247,83 +249,90 @@ void GenerateNormals(MeshDefinition::RawData& raw) attribs.push_back({"aNormal", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer)}); } -void GenerateTangentsWithUvs(MeshDefinition::RawData& raw) +template, typename = std::enable_if_t<(std::is_same::value || std::is_same::value)>> +bool GenerateTangents(MeshDefinition::RawData& raw) { auto& attribs = raw.mAttribs; - DALI_ASSERT_DEBUG(attribs.size() > 2); // positions, normals, uvs - IndexProvider getIndex(raw.mIndices.data()); - - const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : static_cast(raw.mIndices.size()); - - auto* positions = reinterpret_cast(attribs[0].mData.data()); - auto* uvs = reinterpret_cast(attribs[2].mData.data()); - - std::vector buffer(attribs[0].mNumElements * sizeof(Vector3)); - auto tangents = reinterpret_cast(buffer.data()); - - for(uint32_t i = 0; i < numIndices; i += 3) + // Required positions, normals, uvs (if we have). If not, skip generation + if(attribs.size() < (2 + static_cast(hasUvs))) { - uint16_t indices[]{getIndex(), getIndex(), getIndex()}; - Vector3 pos[]{positions[indices[0]], positions[indices[1]], positions[indices[2]]}; - Vector2 uv[]{uvs[indices[0]], uvs[indices[1]], uvs[indices[2]]}; - - float x0 = pos[1].x - pos[0].x; - float y0 = pos[1].y - pos[0].y; - float z0 = pos[1].z - pos[0].z; + return false; + } - float x1 = pos[2].x - pos[0].x; - float y1 = pos[2].y - pos[0].y; - float z1 = pos[2].z - pos[0].z; + std::vector buffer(attribs[0].mNumElements * sizeof(T)); + auto tangents = reinterpret_cast(buffer.data()); - float s0 = uv[1].x - uv[0].x; - float t0 = uv[1].y - uv[0].y; + if constexpr(hasUvs) + { + IndexProvider getIndex(raw.mIndices.data()); + const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : static_cast(raw.mIndices.size()); - float s1 = uv[2].x - uv[0].x; - float t1 = uv[2].y - uv[0].y; + auto* positions = reinterpret_cast(attribs[0].mData.data()); + auto* uvs = reinterpret_cast(attribs[2].mData.data()); - float r = 1.f / (s0 * t1 - t0 * s1); - Vector3 tangent((x0 * t1 - t0 * x1) * r, (y0 * t1 - t0 * y1) * r, (z0 * t1 - t0 * z1) * r); - tangents[indices[0]] += tangent; - tangents[indices[1]] += tangent; - tangents[indices[2]] += tangent; + for(uint32_t i = 0; i < numIndices; i += 3) + { + uint16_t indices[]{getIndex(), getIndex(), getIndex()}; + Vector3 pos[]{positions[indices[0]], positions[indices[1]], positions[indices[2]]}; + Vector2 uv[]{uvs[indices[0]], uvs[indices[1]], uvs[indices[2]]}; + + float x0 = pos[1].x - pos[0].x; + float y0 = pos[1].y - pos[0].y; + float z0 = pos[1].z - pos[0].z; + + float x1 = pos[2].x - pos[0].x; + float y1 = pos[2].y - pos[0].y; + float z1 = pos[2].z - pos[0].z; + + float s0 = uv[1].x - uv[0].x; + float t0 = uv[1].y - uv[0].y; + + float s1 = uv[2].x - uv[0].x; + float t1 = uv[2].y - uv[0].y; + + float det = (s0 * t1 - t0 * s1); + float r = 1.f / ((std::abs(det) < Dali::Epsilon<1000>::value) ? (Dali::Epsilon<1000>::value * (det > 0.0f ? 1.f : -1.f)) : det); + Vector3 tangent((x0 * t1 - t0 * x1) * r, (y0 * t1 - t0 * y1) * r, (z0 * t1 - t0 * z1) * r); + tangents[indices[0]] += T(tangent); + tangents[indices[1]] += T(tangent); + tangents[indices[2]] += T(tangent); + } } auto* normals = reinterpret_cast(attribs[1].mData.data()); auto iEnd = normals + attribs[1].mNumElements; while(normals != iEnd) { - *tangents -= *normals * normals->Dot(*tangents); - tangents->Normalize(); - - ++tangents; - ++normals; - } - attribs.push_back({"aTangent", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer)}); -} - -void GenerateTangents(MeshDefinition::RawData& raw) -{ - auto& attribs = raw.mAttribs; - DALI_ASSERT_DEBUG(attribs.size() > 1); // positions, normals - - auto* normals = reinterpret_cast(attribs[1].mData.data()); - - std::vector buffer(attribs[0].mNumElements * sizeof(Vector3)); - auto tangents = reinterpret_cast(buffer.data()); - - auto iEnd = normals + attribs[1].mNumElements; - while(normals != iEnd) - { - Vector3 t[]{normals->Cross(Vector3::XAXIS), normals->Cross(Vector3::YAXIS)}; + Vector3 tangentVec3; + if constexpr(hasUvs) + { + // Calculated by indexs + tangentVec3 = Vector3((*tangents).x, (*tangents).y, (*tangents).z); + } + else + { + // Only choiced by normal vector. by indexs + Vector3 t[]{normals->Cross(Vector3::XAXIS), normals->Cross(Vector3::YAXIS)}; + tangentVec3 = t[t[1].LengthSquared() > t[0].LengthSquared()]; + } - *tangents = t[t[1].LengthSquared() > t[0].LengthSquared()]; - *tangents -= *normals * normals->Dot(*tangents); - tangents->Normalize(); + tangentVec3 -= *normals * normals->Dot(tangentVec3); + tangentVec3.Normalize(); + if constexpr(useVec3) + { + *tangents = tangentVec3; + } + else + { + *tangents = Vector4(tangentVec3.x, tangentVec3.y, tangentVec3.z, 1.0f); + } ++tangents; ++normals; } - attribs.push_back({"aTangent", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer)}); + attribs.push_back({"aTangent", useVec3 ? Property::VECTOR3 : Property::VECTOR4, attribs[0].mNumElements, std::move(buffer)}); + + return true; } void CalculateTextureSize(uint32_t totalTextureSize, uint32_t& textureWidth, uint32_t& textureHeight) @@ -833,7 +842,22 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& else if(mTangents.mBlob.mLength != 0 && hasNormals && isTriangles) { DALI_ASSERT_DEBUG(mTangents.mBlob.mLength == mNormals.mBlob.GetBufferSize()); - hasUvs ? GenerateTangentsWithUvs(raw) : GenerateTangents(raw); + static const std::function GenerateTangentsFunction[2][2] = + { + { + GenerateTangents, + GenerateTangents, + }, + { + GenerateTangents, + GenerateTangents, + }, + }; + const bool generateSuccessed = GenerateTangentsFunction[mTangentType == Property::VECTOR3][hasUvs](raw); + if(!generateSuccessed) + { + DALI_LOG_ERROR("Failed to generate tangents\n"); + } } if(mColors.IsDefined()) -- 2.7.4