diff options
Diffstat (limited to 'indra/llprimitive/llgltfmaterial.cpp')
| -rw-r--r-- | indra/llprimitive/llgltfmaterial.cpp | 145 |
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); } |
