mirror of
https://github.com/FirestormViewer/phoenix-firestorm.git
synced 2026-08-14 08:53:53 +00:00
#2975 PBR support for planar aligment
Since checkbox is shared between pbr and normal textures, I'm making it affect both for now.
This commit is contained in:
@@ -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;
|
||||
|
||||
pbr_offset.set(adjusted_offset_s + center_adjust_s,
|
||||
adjusted_offset_t + center_adjust_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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user