summaryrefslogtreecommitdiff
path: root/indra/llprimitive/llgltfmaterial.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llprimitive/llgltfmaterial.cpp')
-rw-r--r--indra/llprimitive/llgltfmaterial.cpp145
1 files changed, 129 insertions, 16 deletions
diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp
index 930222e3db..764ab222ad 100644
--- a/indra/llprimitive/llgltfmaterial.cpp
+++ b/indra/llprimitive/llgltfmaterial.cpp
@@ -214,7 +214,7 @@ std::string LLGLTFMaterial::asJSON(bool prettyprint) const
// to WriteGltfSceneToStream in the viewer.
gltf.WriteGltfSceneToStream(&model_out, str, prettyprint, false);
- return str.str();
+ return std::move(str).str();
}
void LLGLTFMaterial::setFromModel(const tinygltf::Model& model, S32 mat_index)
@@ -924,6 +924,34 @@ 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;
+// Case 5.
+// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation -1.57079637
+// Expected output: scale 15.0,10.0; Offset horizontal 7.5, Offset vertical -4.0 Rotation 1.57079637;
+// Case 6.
+// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation 0
+// Expected output: scale 10.0,15.0; Offset horizontal 0.5, Offset vertical .0 Rotation 0;
+// Case 7.
+// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation -0.785398163
+// Expected output: scale 12.74,12.74; Offset horizontal 0.5, Offset vertical .0 Rotation 0.785398163;
+//
+// 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,
@@ -934,23 +962,108 @@ void LLGLTFMaterial::convertTextureTransformToPBR(
LLVector2& pbr_offset,
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;
- F32 center_adjust_s = 0.5f * (1.0f - tex_scale_s);
- F32 center_adjust_t = 0.5f * (1.0f - tex_scale_t);
+ // Legacy is counter-clockwise, PBR is clockwise
+ pbr_rotation = -tex_rotation;
- if (pbr_rotation != 0.0f)
+ // Center of the tile
+ const F32 center_s = 0.5f;
+ const F32 center_t = 0.5f;
+
+ // Calculate the rotated scale
+ F32 cos_rot = cosf(tex_rotation);
+ F32 sin_rot = sinf(tex_rotation);
+ F32 cos_sq = cos_rot * cos_rot;
+ F32 sin_sq = sin_rot * sin_rot;
+
+ // GLTF scale doesn't match legacy scaling when rotation is applied.
+ // Legacy applies scale then rotation, which allows for planar aligment
+ // withoutn deformations, but gltf rotates first, so when scale gets
+ // aplied image gets deformed by rotation.
+ // It appears to be imposible to properly match legacy scale, so this
+ // is an approximation that at least matches at 0, 90, 180, 270 degree
+ // rotations, and is close enough at angles like 45.
+ pbr_scale.mV[VX] = tex_scale_s * cos_sq + tex_scale_t * sin_sq;
+ pbr_scale.mV[VY] = tex_scale_s * sin_sq + tex_scale_t * cos_sq;
+
+ // Center adjustment for scale
+ F32 center_adjust_s = 0.5f * (1.0f - pbr_scale.mV[VX]);
+ F32 center_adjust_t = 0.5f * (1.0f - pbr_scale.mV[VY]);
+
+ // 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_rotation = -pbr_rotation;
+
+ // Reverse the scale transformation
+ // From: pbr_s = tex_s * cos² + tex_t * sin²
+ // pbr_t = tex_s * sin² + tex_t * cos²
+ // Solve for tex_s and tex_t
+ F32 cos_rot = cosf(tex_rotation);
+ F32 sin_rot = sinf(tex_rotation);
+ F32 cos_sq = cos_rot * cos_rot;
+ F32 sin_sq = sin_rot * sin_rot;
+
+ F32 denom = cos_sq * cos_sq - sin_sq * sin_sq;
+
+ if (fabsf(denom) < 0.0001f) // Near 45 degrees (cos²≈sin²≈0.5)
+ {
+ // At 45°: both scales contribute equally
+ // pbr_s = pbr_t = (tex_s + tex_t) / 2
+ // So: tex_s + tex_t = 2 * pbr_avg
+ // Use the average and assume symmetric scaling
+ tex_scale_s = tex_scale_t = (pbr_scale.mV[VX] + pbr_scale.mV[VY]) / 2.f;
+ }
+ else
{
- 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;
+ // Solve the 2x2 system:
+ // pbr_s * cos² - pbr_t * sin² = tex_s * (cos⁴ - sin⁴)
+ // pbr_t * cos² - pbr_s * sin² = tex_t * (cos⁴ - sin⁴)
+ tex_scale_s = (pbr_scale.mV[VX] * cos_sq - pbr_scale.mV[VY] * sin_sq) / denom;
+ tex_scale_t = (pbr_scale.mV[VY] * cos_sq - pbr_scale.mV[VX] * sin_sq) / denom;
}
- pbr_offset.set(adjusted_offset_s + center_adjust_s,
- adjusted_offset_t + center_adjust_t);
+ // 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 - pbr_scale.mV[VX]);
+ F32 center_adjust_t = 0.5f * (1.0f - pbr_scale.mV[VY]);
+
+ // 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;
+
+ // 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);
}