From d0c97077d07da3a4f07d92473155db11c2e5a6c3 Mon Sep 17 00:00:00 2001 From: Gary Hsu Date: Fri, 28 Jun 2024 10:33:16 -0700 Subject: [PATCH] Add apply skeleton function to native optimizations plugin (#1399) This is the counterpart to https://github.com/BabylonJS/Babylon.js/pull/15234. Putting these two together will improve the performance of `refreshBoundingInfo` function dramatically. --- .../Source/NativeOptimizations.cpp | 99 +++++++++++++++++-- 1 file changed, 90 insertions(+), 9 deletions(-) diff --git a/Plugins/NativeOptimizations/Source/NativeOptimizations.cpp b/Plugins/NativeOptimizations/Source/NativeOptimizations.cpp index 81bbe5cf0..63ccadf8f 100644 --- a/Plugins/NativeOptimizations/Source/NativeOptimizations.cpp +++ b/Plugins/NativeOptimizations/Source/NativeOptimizations.cpp @@ -1,13 +1,45 @@ #include #include +#include namespace { + void MatrixScaleAdd(const float inputMatrix[16], float scale, float outputMatrix[16]) + { + for (size_t i = 0; i < 16; ++i) + { + outputMatrix[i] += inputMatrix[i] * scale; + } + } + + void MatrixTransformNormal(const float matrix[16], float &x, float &y, float &z) + { + float rx = x * matrix[0] + y * matrix[4] + z * matrix[8]; + float ry = x * matrix[1] + y * matrix[5] + z * matrix[9]; + float rz = x * matrix[2] + y * matrix[6] + z * matrix[10]; + + x = rx; + y = ry; + z = rz; + } + + void MatrixTransformCoordinates(const float matrix[16], float& x, float& y, float& z) + { + float rx = x * matrix[0] + y * matrix[4] + z * matrix[8] + matrix[12]; + float ry = x * matrix[1] + y * matrix[5] + z * matrix[9] + matrix[13]; + float rz = x * matrix[2] + y * matrix[6] + z * matrix[10] + matrix[14]; + float rw = 1.0f / (x * matrix[3] + y * matrix[7] + z * matrix[11] + matrix[15]); + + x = rx * rw; + y = ry * rw; + z = rz * rw; + } + void TransformVector3Coordinates(const Napi::CallbackInfo& info) { - auto coordinates{info[0].As>()}; + auto coordinates{info[0].As()}; const auto transform{info[1].As()}; - const auto m{transform.Get("_m").As>()}; + const auto m{transform.Get("_m").As()}; const auto offset{info[2].As().Uint32Value()}; const auto length{info[3].As().Uint32Value()}; @@ -27,9 +59,9 @@ namespace void TransformVector3Normals(const Napi::CallbackInfo& info) { - auto normals{info[0].As>()}; + auto normals{info[0].As()}; const auto transform{info[1].As()}; - const auto m{transform.Get("_m").As>()}; + const auto m{transform.Get("_m").As()}; const auto offset{info[2].As().Uint32Value()}; const auto length{info[3].As().Uint32Value()}; @@ -45,9 +77,9 @@ namespace void TransformVector4Normals(const Napi::CallbackInfo& info) { - auto normals{info[0].As>()}; + auto normals{info[0].As()}; const auto transform{info[1].As()}; - const auto m{transform.Get("_m").As>()}; + const auto m{transform.Get("_m").As()}; const auto offset{info[2].As().Uint32Value()}; const auto length{info[3].As().Uint32Value()}; @@ -97,7 +129,7 @@ namespace } template - void ExtractMinAndMaxIndexedT(const Napi::TypedArrayOf positions, const Napi::TypedArrayOf indices, uint32_t indexStart, uint32_t indexCount, Napi::Object minVector, Napi::Object maxVector) + void ExtractMinAndMaxIndexedT(const Napi::Float32Array positions, const Napi::TypedArrayOf indices, uint32_t indexStart, uint32_t indexCount, Napi::Object minVector, Napi::Object maxVector) { auto minX{minVector.Get("_x").As().FloatValue()}; auto minY{minVector.Get("_y").As().FloatValue()}; @@ -131,7 +163,7 @@ namespace void ExtractMinAndMaxIndexed(const Napi::CallbackInfo& info) { - const auto positions{info[0].As>()}; + const auto positions{info[0].As()}; const auto indices{info[1].As()}; const auto indexStart{info[2].As().Uint32Value()}; const auto indexCount{info[3].As().Uint32Value()}; @@ -158,7 +190,7 @@ namespace void ExtractMinAndMax(const Napi::CallbackInfo& info) { - const auto positions{info[0].As>()}; + const auto positions{info[0].As()}; const auto start{info[1].As().Uint32Value()}; const auto count{info[2].As().Uint32Value()}; const auto stride{info[3].As().Uint32Value()}; @@ -193,6 +225,54 @@ namespace maxVector.Set("_y", maxY); maxVector.Set("_z", maxZ); } + + // Ported from `applySkeleton` function in abstractMesh.ts + void ApplySkeleton(const Napi::CallbackInfo& info) + { + auto data = info[0].As(); + const auto kind = info[1].As().Utf8Value(); + const auto skeletonMatrices = info[2].As(); + const auto matricesIndicesData = info[3].As(); + const auto matricesWeightsData = info[4].As(); + + std::optional matricesIndicesExtraData; + if (!info[5].IsNull()) + { + matricesIndicesExtraData = info[5].As(); + }; + + std::optional matricesWeightsExtraData; + if (!info[6].IsNull()) + { + matricesWeightsExtraData = info[6].As(); + } + + auto matrixTransform = kind == "normal" ? MatrixTransformNormal : MatrixTransformCoordinates; + + for (size_t index = 0, matWeightIdx = 0; index < data.ElementLength(); index += 3, matWeightIdx += 4) + { + float finalMatrix[16]{}; + + for (size_t inf = 0; inf < 4; ++inf) { + float weight = matricesWeightsData[matWeightIdx + inf]; + if (weight > 0.0f) { + MatrixScaleAdd(&skeletonMatrices[static_cast(matricesIndicesData[matWeightIdx + inf] * 16.0f)], weight, finalMatrix); + } + } + if (matricesIndicesExtraData.has_value() && matricesWeightsExtraData.has_value()) { + const auto& indices = matricesIndicesExtraData.value(); + const auto& weights = matricesWeightsExtraData.value(); + for (size_t inf = 0; inf < 4; ++inf) { + float weight = weights[matWeightIdx + inf]; + if (weight > 0.0f) { + MatrixScaleAdd(&skeletonMatrices[static_cast(indices[matWeightIdx + inf] * 16.0f)], weight, finalMatrix); + } + } + } + + matrixTransform(finalMatrix, data[index], data[index + 1], data[index + 2]); + } + } } namespace Babylon::Plugins::NativeOptimizations @@ -200,6 +280,7 @@ namespace Babylon::Plugins::NativeOptimizations void BABYLON_API Initialize(Napi::Env env) { auto nativeObject{JsRuntime::NativeObject::GetFromJavaScript(env)}; + nativeObject.Set("_ApplySkeleton", Napi::Function::New(env, ApplySkeleton, "_ApplySkeleton")); nativeObject.Set("_TransformVector3Coordinates", Napi::Function::New(env, TransformVector3Coordinates, "_TransformVector3Coordinates")); nativeObject.Set("_TransformVector3Normals", Napi::Function::New(env, TransformVector3Normals, "_TransformVector3Normals")); nativeObject.Set("_TransformVector4Normals", Napi::Function::New(env, TransformVector4Normals, "_TransformVector4Normals"));