summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2026-01-28 03:43:43 +0200
committerAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2026-01-30 01:07:21 +0200
commit98d7f697ce5d7509a4dabde877de2856e27892dd (patch)
tree3ce17a419652d89e41985face72bd1f867f90bd2 /indra/newview
parent493455a7caf8449ccc4112612a192cd0dfea29df (diff)
#2975 PBR support for planar aligment
Since checkbox is shared between pbr and normal textures, I'm making it affect both for now.
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/llface.cpp85
-rw-r--r--indra/newview/llface.h2
-rw-r--r--indra/newview/llpanelface.cpp21
3 files changed, 108 insertions, 0 deletions
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 7c631a7280..2b318dcf5f 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1067,6 +1067,91 @@ bool LLFace::calcAlignedPlanarTE(const LLFace* align_to, LLVector2* res_st_offs
return true;
}
+F32 dot_product(const LLVector3& a, const LLVector3& b)
+{
+ return a.mV[VX] * b.mV[VX] + a.mV[VY] * b.mV[VY] + a.mV[VZ] * b.mV[VZ];
+}
+
+bool LLFace::calcAlignedPlanarGLTF(
+ const LLFace* align_to,
+ LLVector2* res_st_offset,
+ LLVector2* res_st_scale,
+ F32* res_st_rot,
+ S32 gltf_info_index) const
+{
+ if (!align_to)
+ {
+ return false;
+ }
+
+ const LLTextureEntry* orig_tep = align_to->getTextureEntry();
+ const LLTextureEntry* tep = getTextureEntry();
+ if (!orig_tep || !tep)
+ {
+ return false;
+ }
+
+ // Only support planar mapping for now
+ if (orig_tep->getTexGen() != LLTextureEntry::TEX_GEN_PLANAR ||
+ tep->getTexGen() != LLTextureEntry::TEX_GEN_PLANAR)
+ {
+ return false;
+ }
+
+ LLGLTFMaterial* orig_mat = orig_tep->getGLTFRenderMaterial();
+ LLGLTFMaterial* this_mat = tep->getGLTFRenderMaterial();
+ if (!orig_mat || !this_mat)
+ {
+ return false;
+ }
+
+ // Get the original GLTF transform for the specified channel
+ const auto& orig_tt = orig_mat->mTextureTransform[gltf_info_index];
+
+ // Convert GLTF transform to legacy TE transform
+ F32 map_scaleS, map_scaleT, map_offsS, map_offsT, map_rot;
+ LLGLTFMaterial::convertPBRTransformToTexture(
+ orig_tt.mScale,
+ orig_tt.mOffset,
+ orig_tt.mRotation,
+ map_scaleS, map_scaleT, map_offsS, map_offsT, map_rot);
+
+ // Calculate aligments
+ LLVector3 orig_pos, this_pos;
+ LLQuaternion orig_face_rot, this_face_rot;
+ F32 orig_proj_scale, this_proj_scale;
+ align_to->getPlanarProjectedParams(&orig_face_rot, &orig_pos, &orig_proj_scale);
+ getPlanarProjectedParams(&this_face_rot, &this_pos, &this_proj_scale);
+
+ // The rotation of "this face's" texture:
+ LLQuaternion orig_st_rot = LLQuaternion(map_rot, LLVector3::z_axis) * orig_face_rot;
+ LLQuaternion this_st_rot = orig_st_rot * ~this_face_rot;
+ F32 x_ang, y_ang, z_ang;
+ this_st_rot.getEulerAngles(&x_ang, &y_ang, &z_ang);
+
+ // Offset and scale of "this face's" texture:
+ LLVector3 centers_dist = (this_pos - orig_pos) * ~orig_st_rot;
+ LLVector3 st_scale(map_scaleS, map_scaleT, 1.f);
+ st_scale *= orig_proj_scale;
+ centers_dist.scaleVec(st_scale);
+ LLVector2 orig_st_offset(map_offsS, map_offsT);
+
+ LLVector2 tex_res_st_offset = orig_st_offset + (LLVector2)centers_dist;
+ tex_res_st_offset.mV[VX] -= (S32)tex_res_st_offset.mV[VX];
+ tex_res_st_offset.mV[VY] -= (S32)tex_res_st_offset.mV[VY];
+
+ st_scale /= this_proj_scale;
+
+ // Convert aligned legacy TE transform back to GLTF transform
+ LLGLTFMaterial::convertTextureTransformToPBR(
+ st_scale.mV[0], st_scale.mV[1],
+ tex_res_st_offset.mV[0], tex_res_st_offset.mV[1],
+ z_ang,
+ *res_st_scale, *res_st_offset, *res_st_rot);
+
+ return true;
+}
+
void LLFace::updateRebuildFlags()
{
if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index df31e9ea90..6e9d23c3a2 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -103,6 +103,8 @@ public:
LLVector3 getPositionAgent() const;
LLVector2 surfaceToTexture(LLVector2 surface_coord, const LLVector4a& position, const LLVector4a& normal);
void getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_pos, F32* scale) const;
+ bool calcAlignedPlanarGLTF(const LLFace* align_to, LLVector2* res_st_offset,
+ LLVector2* res_st_scale, F32* res_st_rot, S32 gltf_info_index = 0) const;
bool calcAlignedPlanarTE(const LLFace* align_to, LLVector2* st_offset,
LLVector2* st_scale, F32* st_rot, LLRender::eTexIndex map = LLRender::DIFFUSE_MAP) const;
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index bcb51b22ca..128ba42efd 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -852,6 +852,27 @@ struct LLPanelFaceSetAlignedTEFunctor : public LLSelectedTEFunctor
LLPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, uv_scale.mV[VX], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, uv_scale.mV[VY], te, object->getID());
}
+
+ // Also align GLTF material if any
+ S32 gltf_info_index = 0; // base texture
+ LLVector2 gltf_offset, gltf_scale;
+ F32 gltf_rot;
+ if (facep->calcAlignedPlanarGLTF(mCenterFace, &gltf_offset, &gltf_scale, &gltf_rot, gltf_info_index))
+ {
+ LLGLTFMaterial new_override;
+ const LLTextureEntry* tep = object->getTE(te);
+ if (tep && tep->getGLTFMaterialOverride())
+ {
+ new_override = *tep->getGLTFMaterialOverride();
+ }
+
+ LLGLTFMaterial::TextureTransform& transform = new_override.mTextureTransform[gltf_info_index];
+ transform.mOffset.set(gltf_offset.mV[0], gltf_offset.mV[1]);
+ transform.mScale.set(gltf_scale.mV[0], gltf_scale.mV[1]);
+ transform.mRotation = gltf_rot;
+
+ LLGLTFMaterialList::queueModify(object, te, &new_override);
+ }
}
if (!set_aligned)
{