diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp index 0ba51b2d7..444d60540 100644 --- a/Source/Engine/Graphics/Models/Mesh.cpp +++ b/Source/Engine/Graphics/Models/Mesh.cpp @@ -10,6 +10,127 @@ #include "Engine/Serialization/MemoryReadStream.h" #include +namespace +{ + template + bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, Vector3* vertices, IndexType* triangles, Vector3* normals, Vector3* tangents, Vector2* uvs, Color32* colors) + { + auto model = mesh->GetModel(); + CHECK_RETURN(model && model->IsVirtual(), true); + CHECK_RETURN(triangles && vertices, true); + + // Pack mesh data into vertex buffers + Array vb1; + Array vb2; + vb1.Resize(vertexCount); + if (normals) + { + if (tangents) + { + for (uint32 i = 0; i < vertexCount; i++) + { + const Vector3 normal = normals[i]; + const Vector3 tangent = tangents[i]; + + // Calculate bitangent sign + Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent)); + byte sign = static_cast(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0); + + // Set tangent frame + vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign); + vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0); + } + } + else + { + for (uint32 i = 0; i < vertexCount; i++) + { + const Vector3 normal = normals[i]; + + // Calculate tangent + Vector3 c1 = Vector3::Cross(normal, Vector3::UnitZ); + Vector3 c2 = Vector3::Cross(normal, Vector3::UnitY); + Vector3 tangent; + if (c1.LengthSquared() > c2.LengthSquared()) + tangent = c1; + else + tangent = c2; + + // Calculate bitangent sign + Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent)); + byte sign = static_cast(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0); + + // Set tangent frame + vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign); + vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0); + } + } + } + else + { + // Set default tangent frame + const auto n = Float1010102(Vector3::UnitZ); + const auto t = Float1010102(Vector3::UnitX); + for (uint32 i = 0; i < vertexCount; i++) + { + vb1[i].Normal = n; + vb1[i].Tangent = t; + } + } + if (uvs) + { + for (uint32 i = 0; i < vertexCount; i++) + vb1[i].TexCoord = Half2(uvs[i]); + } + else + { + auto v = Half2(0, 0); + for (uint32 i = 0; i < vertexCount; i++) + vb1[i].TexCoord = v; + } + { + auto v = Half2(0, 0); + for (uint32 i = 0; i < vertexCount; i++) + vb1[i].LightmapUVs = v; + } + if (colors) + { + vb2.Resize(vertexCount); + for (uint32 i = 0; i < vertexCount; i++) + vb2[i].Color = colors[i]; + } + + return mesh->UpdateMesh(vertexCount, triangleCount, (VB0ElementType*)vertices, vb1.Get(), vb2.HasItems() ? vb2.Get() : nullptr, triangles); + } + + template + bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj) + { + ASSERT((uint32)mono_array_length(verticesObj) >= vertexCount); + ASSERT((uint32)mono_array_length(trianglesObj) / 3 >= triangleCount); + auto vertices = (Vector3*)(void*)mono_array_addr_with_size(verticesObj, sizeof(Vector3), 0); + auto triangles = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0); + const auto normals = normalsObj ? (Vector3*)(void*)mono_array_addr_with_size(normalsObj, sizeof(Vector3), 0) : nullptr; + const auto tangents = tangentsObj ? (Vector3*)(void*)mono_array_addr_with_size(tangentsObj, sizeof(Vector3), 0) : nullptr; + const auto uvs = uvObj ? (Vector2*)(void*)mono_array_addr_with_size(uvObj, sizeof(Vector2), 0) : nullptr; + const auto colors = colorsObj ? (Color32*)(void*)mono_array_addr_with_size(colorsObj, sizeof(Color32), 0) : nullptr; + return UpdateMesh(mesh, vertexCount, triangleCount, vertices, triangles, normals, tangents, uvs, colors); + } + + template + bool UpdateTriangles(Mesh* mesh, int32 triangleCount, MonoArray* trianglesObj) + { + const auto model = mesh->GetModel(); + ASSERT(model && model->IsVirtual() && trianglesObj); + + // Get buffer data + ASSERT((int32)mono_array_length(trianglesObj) / 3 >= triangleCount); + auto ib = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0); + + return mesh->UpdateTriangles(triangleCount, ib); + } +} + bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, void* ib, bool use16BitIndices) { Unload(); @@ -31,6 +152,16 @@ bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* return failed; } +bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint16* triangles, Vector3* normals, Vector3* tangents, Vector2* uvs, Color32* colors) +{ + return ::UpdateMesh(this, vertexCount, triangleCount, vertices, triangles, normals, tangents, uvs, colors); +} + +bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint32* triangles, Vector3* normals, Vector3* tangents, Vector2* uvs, Color32* colors) +{ + return ::UpdateMesh(this, vertexCount, triangleCount, vertices, triangles, normals, tangents, uvs, colors); +} + bool Mesh::UpdateTriangles(uint32 triangleCount, void* ib, bool use16BitIndices) { // Cache data @@ -384,108 +515,9 @@ ScriptingObject* Mesh::GetParentModel() return _model; } -template -bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj) -{ - auto model = mesh->GetModel(); - ASSERT(model && model->IsVirtual() && verticesObj && trianglesObj); - - // Get buffers data - ASSERT((uint32)mono_array_length(verticesObj) >= vertexCount); - ASSERT((uint32)mono_array_length(trianglesObj) / 3 >= triangleCount); - auto vb0 = (Vector3*)(void*)mono_array_addr_with_size(verticesObj, sizeof(Vector3), 0); - auto ib = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0); - Array vb1; - Array vb2; - vb1.Resize(vertexCount); - if (normalsObj) - { - const auto normals = (Vector3*)(void*)mono_array_addr_with_size(normalsObj, sizeof(Vector3), 0); - if (tangentsObj) - { - const auto tangents = (Vector3*)(void*)mono_array_addr_with_size(tangentsObj, sizeof(Vector3), 0); - for (uint32 i = 0; i < vertexCount; i++) - { - // Peek normal and tangent - const Vector3 normal = normals[i]; - const Vector3 tangent = tangents[i]; - - // Calculate bitangent sign - Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent)); - byte sign = static_cast(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0); - - // Set tangent frame - vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign); - vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0); - } - } - else - { - for (uint32 i = 0; i < vertexCount; i++) - { - // Peek normal - const Vector3 normal = normals[i]; - - // Calculate tangent - Vector3 c1 = Vector3::Cross(normal, Vector3::UnitZ); - Vector3 c2 = Vector3::Cross(normal, Vector3::UnitY); - Vector3 tangent; - if (c1.LengthSquared() > c2.LengthSquared()) - tangent = c1; - else - tangent = c2; - - // Calculate bitangent sign - Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent)); - byte sign = static_cast(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0); - - // Set tangent frame - vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign); - vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0); - } - } - } - else - { - const auto n = Float1010102(Vector3::UnitZ); - const auto t = Float1010102(Vector3::UnitX); - for (uint32 i = 0; i < vertexCount; i++) - { - vb1[i].Normal = n; - vb1[i].Tangent = t; - } - } - if (uvObj) - { - const auto uvs = (Vector2*)(void*)mono_array_addr_with_size(uvObj, sizeof(Vector2), 0); - for (uint32 i = 0; i < vertexCount; i++) - vb1[i].TexCoord = Half2(uvs[i]); - } - else - { - auto v = Half2(0, 0); - for (uint32 i = 0; i < vertexCount; i++) - vb1[i].TexCoord = v; - } - { - auto v = Half2(0, 0); - for (uint32 i = 0; i < vertexCount; i++) - vb1[i].LightmapUVs = v; - } - if (colorsObj) - { - vb2.Resize(vertexCount); - const auto colors = (Color32*)(void*)mono_array_addr_with_size(colorsObj, sizeof(Color32), 0); - for (uint32 i = 0; i < vertexCount; i++) - vb2[i].Color = colors[i]; - } - - return mesh->UpdateMesh(vertexCount, triangleCount, (VB0ElementType*)vb0, vb1.Get(), vb2.HasItems() ? vb2.Get() : nullptr, ib); -} - bool Mesh::UpdateMeshInt(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj) { - return ::UpdateMesh(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj); + return ::UpdateMesh(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj); } bool Mesh::UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj) @@ -493,22 +525,9 @@ bool Mesh::UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* v return ::UpdateMesh(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj); } -template -bool UpdateTriangles(Mesh* mesh, int32 triangleCount, MonoArray* trianglesObj) -{ - auto model = mesh->GetModel(); - ASSERT(model && model->IsVirtual() && trianglesObj); - - // Get buffer data - ASSERT((int32)mono_array_length(trianglesObj) / 3 >= triangleCount); - auto ib = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0); - - return mesh->UpdateTriangles(triangleCount, ib); -} - bool Mesh::UpdateTrianglesInt(int32 triangleCount, MonoArray* trianglesObj) { - return ::UpdateTriangles(this, triangleCount, trianglesObj); + return ::UpdateTriangles(this, triangleCount, trianglesObj); } bool Mesh::UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj) diff --git a/Source/Engine/Graphics/Models/Mesh.h b/Source/Engine/Graphics/Models/Mesh.h index 33e21aa5f..80d566fa3 100644 --- a/Source/Engine/Graphics/Models/Mesh.h +++ b/Source/Engine/Graphics/Models/Mesh.h @@ -218,7 +218,7 @@ public: /// The third vertex buffer data. /// The index buffer in clockwise order. /// True if failed, otherwise false. - FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, int32* ib) + FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, uint32* ib) { return UpdateMesh(vertexCount, triangleCount, vb0, vb1, vb2, ib, false); } @@ -240,6 +240,8 @@ public: /// /// Updates the model mesh (used by the virtual models created with Init rather than Load). + /// Can be used only for virtual assets (see and ). + /// Mesh data will be cached and uploaded to the GPU with a delay. /// /// The amount of vertices in the vertex buffer. /// The amount of triangles in the index buffer. @@ -251,6 +253,38 @@ public: /// True if failed, otherwise false. bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, void* ib, bool use16BitIndices); + /// + /// Updates the model mesh (used by the virtual models created with Init rather than Load). + /// Can be used only for virtual assets (see and ). + /// Mesh data will be cached and uploaded to the GPU with a delay. + /// + /// The amount of vertices in the vertex buffer. + /// The amount of triangles in the index buffer. + /// The mesh vertices positions. Cannot be null. + /// The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null. + /// The normal vectors (per vertex). + /// The normal vectors (per vertex). Use null to compute them from normal vectors. + /// The texture coordinates (per vertex). + /// The vertex colors (per vertex). + /// True if failed, otherwise false. + bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint16* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr); + + /// + /// Updates the model mesh (used by the virtual models created with Init rather than Load). + /// Can be used only for virtual assets (see and ). + /// Mesh data will be cached and uploaded to the GPU with a delay. + /// + /// The amount of vertices in the vertex buffer. + /// The amount of triangles in the index buffer. + /// The mesh vertices positions. Cannot be null. + /// The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null. + /// The normal vectors (per vertex). + /// The normal vectors (per vertex). Use null to compute them from normal vectors. + /// The texture coordinates (per vertex). + /// The vertex colors (per vertex). + /// True if failed, otherwise false. + bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint32* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr); + public: /// @@ -259,7 +293,7 @@ public: /// The amount of triangles in the index buffer. /// The index buffer. /// True if failed, otherwise false. - FORCE_INLINE bool UpdateTriangles(uint32 triangleCount, int32* ib) + FORCE_INLINE bool UpdateTriangles(uint32 triangleCount, uint32* ib) { return UpdateTriangles(triangleCount, ib, false); }