From 82ab5f9765ad76c73d1d7ddd5716b22d6b92bf62 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Thu, 15 Sep 2022 17:23:34 -0500
Subject: [PATCH] SL-18156 WIP -- Add NormalizedScale/NormalizedTranslation to
 mesh assets to recover mesh's original coordinate frame when generating
 tangents post download.

---
 indra/llmath/llvolume.cpp        | 78 ++++++++++++++++++++++----------
 indra/llmath/llvolume.h          |  6 +++
 indra/llprimitive/llmodel.cpp    | 13 +++++-
 indra/newview/llmodelpreview.cpp |  9 ++++
 4 files changed, 81 insertions(+), 25 deletions(-)

diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 563a325f03b..ae753fc0f37 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2483,6 +2483,24 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 			min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]);
 			max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]);
 
+            //unpack normalized scale/translation
+            if (mdl[i].has("NormalizedScale"))
+            {
+                face.mNormalizedScale.setValue(mdl[i]["NormalizedScale"]);
+            }
+            else
+            {
+                face.mNormalizedScale.set(1, 1, 1);
+            }
+            if (mdl[i].has("NormalizedTranslation"))
+            {
+                face.mNormalizedTranslation.setValue(mdl[i]["NormalizedTranslation"]);
+            }
+            else
+            {
+                face.mNormalizedTranslation.set(1, 1, 1);
+            }
+
 			LLVector4a pos_range;
 			pos_range.setSub(max_pos, min_pos);
 			LLVector2 tc_range2 = max_tc - min_tc;
@@ -2533,6 +2551,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 				}
 			}
 
+#if 0
             {
                 if (!tangent.empty())
                 {
@@ -2559,6 +2578,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
                     }
                 }
             }
+#endif
 
 			{
 				if (!tc.empty())
@@ -4888,7 +4908,9 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
     }
 
 	mOptimized = src.mOptimized;
-
+    mNormalizedScale = src.mNormalizedScale;
+    mNormalizedTranslation = src.mNormalizedTranslation;
+    
 	//delete 
 	return *this;
 }
@@ -5432,12 +5454,19 @@ struct MikktData
             w.resize(count);
         }
 
+
+        LLVector3 inv_scale(1.f / face->mNormalizedScale.mV[0], 1.f / face->mNormalizedScale.mV[1], 1.f / face->mNormalizedScale.mV[2]);
+        
+
         for (int i = 0; i < face->mNumIndices; ++i)
         {
             U32 idx = face->mIndices[i];
 
             p[i].set(face->mPositions[idx].getF32ptr());
+            p[i].scaleVec(face->mNormalizedScale); //put mesh in original coordinate frame when reconstructing tangents
             n[i].set(face->mNormals[idx].getF32ptr());
+            n[i].scaleVec(inv_scale);
+            n[i].normalize();
             tc[i].set(face->mTexCoords[idx]);
 
             if (face->mWeights)
@@ -5481,10 +5510,7 @@ bool LLVolumeFace::cacheOptimize()
         ms.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert)
         {
             MikktData* data = (MikktData*)pContext->m_pUserData;
-            LLVolumeFace* face = data->face;
-            S32 idx = face->mIndices[iFace * 3 + iVert];
-            auto& vert = face->mPositions[idx];
-            F32* v = vert.getF32ptr();
+            F32* v = data->p[iFace * 3 + iVert].mV;
             fvPosOut[0] = v[0];
             fvPosOut[1] = v[1];
             fvPosOut[2] = v[2];
@@ -5493,10 +5519,7 @@ bool LLVolumeFace::cacheOptimize()
         ms.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert)
         {
             MikktData* data = (MikktData*)pContext->m_pUserData;
-            LLVolumeFace* face = data->face;
-            S32 idx = face->mIndices[iFace * 3 + iVert];
-            auto& norm = face->mNormals[idx];
-            F32* n = norm.getF32ptr();
+            F32* n = data->n[iFace * 3 + iVert].mV;
             fvNormOut[0] = n[0];
             fvNormOut[1] = n[1];
             fvNormOut[2] = n[2];
@@ -5505,27 +5528,16 @@ bool LLVolumeFace::cacheOptimize()
         ms.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert)
         {
             MikktData* data = (MikktData*)pContext->m_pUserData;
-            LLVolumeFace* face = data->face;
-            S32 idx = face->mIndices[iFace * 3 + iVert];
-            auto& tc = face->mTexCoords[idx];
-            fvTexcOut[0] = tc.mV[0];
-            fvTexcOut[1] = tc.mV[1];
+            F32* tc = data->tc[iFace * 3 + iVert].mV;
+            fvTexcOut[0] = tc[0];
+            fvTexcOut[1] = tc[1];
         };
 
         ms.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert)
         {
             MikktData* data = (MikktData*)pContext->m_pUserData;
-            LLVolumeFace* face = data->face;
             S32 i = iFace * 3 + iVert;
-            S32 idx = face->mIndices[i];
-
-            LLVector3 p(face->mPositions[idx].getF32ptr());
-            LLVector3 n(face->mNormals[idx].getF32ptr());
-            LLVector3 t(fvTangent);
-
-            // assert that this tangent hasn't already been set
-            llassert(data->t[i].magVec() < 0.1f);
-
+            
             data->t[i].set(fvTangent);
             data->t[i].mV[3] = fSign;
         };
@@ -5585,6 +5597,24 @@ bool LLVolumeFace::cacheOptimize()
                 mWeights[dst_idx].loadua(data.w[src_idx].mV);
             }
         }
+
+
+        // put back in normalized coordinate frame
+        LLVector4a inv_scale(1.f/mNormalizedScale.mV[0], 1.f / mNormalizedScale.mV[1], 1.f / mNormalizedScale.mV[2]);
+        LLVector4a scale;
+        scale.load3(mNormalizedScale.mV);
+        scale.getF32ptr()[3] = 1.f;
+
+        for (int i = 0; i < mNumVertices; ++i)
+        {
+            mPositions[i].mul(inv_scale);
+            mNormals[i].mul(scale);
+            mNormals[i].normalize3();
+            F32 w = mMikktSpaceTangents[i].getF32ptr()[3];
+            mMikktSpaceTangents[i].mul(scale);
+            mMikktSpaceTangents[i].normalize3();
+            mMikktSpaceTangents[i].getF32ptr()[3] = w;
+        }
     }
 
     // cache optimize index buffer
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index f1feaade58f..e373d0175d3 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -984,6 +984,12 @@ class LLVolumeFace
 	//whether or not face has been cache optimized
 	BOOL mOptimized;
 
+    // if this is a mesh asset, scale and translation that were applied
+    // when encoding the source mesh into a unit cube
+    // used for regenerating tangents
+    LLVector3 mNormalizedScale = LLVector3(1,1,1);
+    LLVector3 mNormalizedTranslation;
+
 private:
 	BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE);
 	BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE);
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 1ce287d7737..ab507edc402 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -337,6 +337,12 @@ void LLModel::normalizeVolumeFaces()
 		mNormalizedScale.set(normalized_scale.getF32ptr());
 		mNormalizedTranslation.set(trans.getF32ptr());
 		mNormalizedTranslation *= -1.f; 
+
+        for (auto& face : mVolumeFaces)
+        {
+            face.mNormalizedScale = mNormalizedScale;
+            face.mNormalizedTranslation = mNormalizedTranslation;
+        }
 	}
 }
 
@@ -749,7 +755,7 @@ LLSD LLModel::writeModel(
 
 				U32 vert_idx = 0;
 				U32 norm_idx = 0;
-                U32 tan_idx = 0;
+                //U32 tan_idx = 0;
 				U32 tc_idx = 0;
 			
 				LLVector2* ftc = (LLVector2*) face.mTexCoords;
@@ -803,6 +809,7 @@ LLSD LLModel::writeModel(
 						}
 					}
 
+#if 0
                     if (face.mMikktSpaceTangents)
                     { //normals
                         F32* tangent = face.mMikktSpaceTangents[j].getF32ptr();
@@ -818,6 +825,7 @@ LLSD LLModel::writeModel(
                             tangents[tan_idx++] = buff[1];
                         }
                     }
+#endif
 					
 					//texcoord
 					if (face.mTexCoords)
@@ -848,6 +856,9 @@ LLSD LLModel::writeModel(
 				//write out face data
 				mdl[model_names[idx]][i]["PositionDomain"]["Min"] = min_pos.getValue();
 				mdl[model_names[idx]][i]["PositionDomain"]["Max"] = max_pos.getValue();
+                mdl[model_names[idx]][i]["NormalizedScale"] = face.mNormalizedScale.getValue();
+                mdl[model_names[idx]][i]["NormalizedTranslation"] = face.mNormalizedTranslation.getValue();
+
 				mdl[model_names[idx]][i]["Position"] = verts;
 				
 				if (face.mNormals)
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 2c0f0ae4432..4a85d459c5c 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1843,6 +1843,15 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
 
             LLModel* target_model = mModel[lod][mdl_idx];
 
+            // carry over normalized transform into simplified model
+            for (int i = 0; i < base->getNumVolumeFaces(); ++i)
+            {
+                LLVolumeFace& src = base->getVolumeFace(i);
+                LLVolumeFace& dst = target_model->getVolumeFace(i);
+                dst.mNormalizedScale = src.mNormalizedScale;
+                dst.mNormalizedTranslation = src.mNormalizedTranslation;
+            }
+
             S32 model_meshopt_mode = meshopt_mode;
 
             // Ideally this should run not per model,
-- 
GitLab