summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llprimitive/llgltfmaterial.cpp90
-rw-r--r--indra/llprimitive/llgltfmaterial.h8
-rw-r--r--indra/newview/llface.cpp85
-rw-r--r--indra/newview/llface.h2
-rw-r--r--indra/newview/llpanelface.cpp21
5 files changed, 192 insertions, 14 deletions
diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp
index b2cd1dc597..1c47001272 100644
--- a/indra/llprimitive/llgltfmaterial.cpp
+++ b/indra/llprimitive/llgltfmaterial.cpp
@@ -924,6 +924,25 @@ void LLGLTFMaterial::updateTextureTracking()
// for material overrides editor will set it
}
+// Test cases:
+// Case 1.
+// Input: scale 1.0,1.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation 0.349066;
+// Expected output: scale 1.0,1.0; Offset horizontal 0.201, Offset vertical -0.141 Rotation -0.349066;
+// Case 2.
+// Input: scale 1.0,1.0; Offset horizontal 0.5, Offset vertical 0.1 Rotation 0;
+// Expected output: scale 1.0,1.0; Offset horizontal 0.5, Offset vertical -0.1 Rotation -0;
+// Case 3.
+// Input: scale 1.0,1.0; Offset horizontal 0.1, Offset vertical 0.2 Rotation 0.349066;
+// Expected output: scale 1.0,1.0; Offset horizontal 0.295, Offset vertical -0.345 Rotation -0.349066;
+// Case 4.
+// Input: scale 1.0,1.0; Offset horizontal 0.5, Offset vertical 0.0 Rotation 0.349066;
+// Expected output: scale 1.0,1.0; Offset horizontal 0.701, Offset vertical -0.141 Rotation -0.349066;
+//
+// Legacy offsets are right to left and top to bottom.
+// PBR offsets are right to left and bottom to top.
+//
+// Legacy rotation is relative to face's center counter clockwise,
+// PBR rotation is relative to top-left corner, clockwise
void LLGLTFMaterial::convertTextureTransformToPBR(
F32 tex_scale_s,
F32 tex_scale_t,
@@ -935,22 +954,65 @@ void LLGLTFMaterial::convertTextureTransformToPBR(
F32& pbr_rotation)
{
pbr_scale.set(tex_scale_s, tex_scale_t);
- pbr_rotation = -(tex_rotation) / 2.f;
- const F32 adjusted_offset_s = tex_offset_s;
- const F32 adjusted_offset_t = -tex_offset_t;
+ pbr_rotation = -tex_rotation;
+
+ // Center of the tile
+ const F32 center_s = 0.5f;
+ const F32 center_t = 0.5f;
+
+ // Center adjustment for scale
F32 center_adjust_s = 0.5f * (1.0f - tex_scale_s);
F32 center_adjust_t = 0.5f * (1.0f - tex_scale_t);
- if (pbr_rotation != 0.0f)
- {
- const F32 c = cosf(pbr_rotation);
- const F32 s = sinf(pbr_rotation);
- const F32 tmp_s = center_adjust_s * c - center_adjust_t * s;
- const F32 tmp_t = center_adjust_s * s + center_adjust_t * c;
- center_adjust_s = tmp_s;
- center_adjust_t = tmp_t;
- }
+ // 2. Offset from center
+ F32 pos_s = center_adjust_s - center_s;
+ F32 pos_t = center_adjust_t - center_t;
+
+ // 3. Rotate around center (clockwise, as per GLTF spec)
+ F32 c = cosf(pbr_rotation);
+ F32 s = sinf(pbr_rotation);
+ F32 rot_s = pos_s * c + pos_t * s;
+ F32 rot_t = -pos_s * s + pos_t * c;
+
+ // 4. Move back to top-left and apply offset
+ pbr_offset.set(rot_s + center_s + tex_offset_s, rot_t + center_t - tex_offset_t);
+}
+
+// Convert PBR transform values back to legacy TE transform values.
+// This is the reverse of convertTextureTransformToPBR.
+void LLGLTFMaterial::convertPBRTransformToTexture(
+ const LLVector2& pbr_scale,
+ const LLVector2& pbr_offset,
+ F32 pbr_rotation,
+ F32& tex_scale_s,
+ F32& tex_scale_t,
+ F32& tex_offset_s,
+ F32& tex_offset_t,
+ F32& tex_rotation)
+{
+ tex_scale_s = pbr_scale.mV[0];
+ tex_scale_t = pbr_scale.mV[1];
+ tex_rotation = -pbr_rotation;
+
+ // Center of the tile
+ const F32 center_s = 0.5f;
+ const F32 center_t = 0.5f;
+
+ // Center adjustment for scale
+ F32 center_adjust_s = 0.5f * (1.0f - tex_scale_s);
+ F32 center_adjust_t = 0.5f * (1.0f - tex_scale_t);
+
+ // 2. Offset from center
+ F32 pos_s = center_adjust_s - center_s;
+ F32 pos_t = center_adjust_t - center_t;
+
+ // 3. Rotate around center (clockwise, as per GLTF spec)
+ F32 c = cosf(pbr_rotation);
+ F32 s = sinf(pbr_rotation);
+ F32 rot_s = pos_s * c + pos_t * s;
+ F32 rot_t = -pos_s * s + pos_t * c;
- pbr_offset.set(adjusted_offset_s + center_adjust_s,
- adjusted_offset_t + center_adjust_t);
+ // 3. Recover legacy offset
+ tex_offset_s = pbr_offset.mV[0] - rot_s - center_s;
+ tex_offset_t = -(pbr_offset.mV[1] - rot_t - center_t);
}
diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h
index 8d45cb6185..c37062e7d3 100644
--- a/indra/llprimitive/llgltfmaterial.h
+++ b/indra/llprimitive/llgltfmaterial.h
@@ -222,6 +222,14 @@ public:
LLVector2& pbr_scale,
LLVector2& pbr_offset,
F32& pbr_rotation);
+
+ // Convert PBR transform values to legacy TE transform values.
+ static void convertPBRTransformToTexture(const LLVector2& pbr_scale,
+ const LLVector2& pbr_offset,
+ F32 pbr_rotation,
+ F32& tex_scale_s, F32& tex_scale_t,
+ F32& tex_offset_s, F32& tex_offset_t,
+ F32& tex_rotation);
protected:
static LLVector2 vec2FromJson(const std::map<std::string, tinygltf::Value>& object, const char* key, const LLVector2& default_value);
static F32 floatFromJson(const std::map<std::string, tinygltf::Value>& object, const char* key, const F32 default_value);
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)
{