diff options
| author | cosmic-linden <111533034+cosmic-linden@users.noreply.github.com> | 2024-05-14 10:11:52 -0700 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-14 10:11:52 -0700 | 
| commit | 193d9d5f767c2bfad1dc5ced4fa630d05ae798ae (patch) | |
| tree | cab4485b64288b3c52e26da8436c26a78c17e297 | |
| parent | 942ff2cd8b0fe2787a9c0b85a4c61d853cd7d7dc (diff) | |
| parent | 87c889b370dc08a5a6b183621346e30b729ec51c (diff) | |
Merge pull request #1453 from secondlife/v-907
secondlife/viewer#907: Local PBR terrain texture transform in advanced settings
| -rw-r--r-- | indra/llprimitive/llgltfmaterial.cpp | 11 | ||||
| -rw-r--r-- | indra/llprimitive/llgltfmaterial.h | 13 | ||||
| -rw-r--r-- | indra/llprimitive/tests/llgltfmaterial_test.cpp | 78 | ||||
| -rw-r--r-- | indra/llrender/llshadermgr.cpp | 4 | ||||
| -rw-r--r-- | indra/llrender/llshadermgr.h | 2 | ||||
| -rw-r--r-- | indra/newview/app_settings/settings.xml | 220 | ||||
| -rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl | 93 | ||||
| -rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl | 19 | ||||
| -rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl | 135 | ||||
| -rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl | 39 | ||||
| -rw-r--r-- | indra/newview/lldrawpoolterrain.cpp | 64 | ||||
| -rw-r--r-- | indra/newview/llviewercontrol.cpp | 45 | ||||
| -rw-r--r-- | indra/newview/llvlcomposition.cpp | 77 | ||||
| -rw-r--r-- | indra/newview/llvlcomposition.h | 11 | 
14 files changed, 702 insertions, 109 deletions
| diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index 12af568b7e..94bc5ef74c 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -81,7 +81,7 @@ LLGLTFMaterial::LLGLTFMaterial()  #endif  } -void LLGLTFMaterial::TextureTransform::getPacked(F32 (&packed)[8]) const +void LLGLTFMaterial::TextureTransform::getPacked(Pack& packed) const  {      packed[0] = mScale.mV[VX];      packed[1] = mScale.mV[VY]; @@ -92,6 +92,15 @@ void LLGLTFMaterial::TextureTransform::getPacked(F32 (&packed)[8]) const      packed[3] = packed[6] = packed[7] = 0.f;  } +void LLGLTFMaterial::TextureTransform::getPackedTight(PackTight& packed) const +{ +    packed[0] = mScale.mV[VX]; +    packed[1] = mScale.mV[VY]; +    packed[2] = mRotation; +    packed[3] = mOffset.mV[VX]; +    packed[4] = mOffset.mV[VY]; +} +  bool LLGLTFMaterial::TextureTransform::operator==(const TextureTransform& other) const  {      return mOffset == other.mOffset && mScale == other.mScale && mRotation == other.mRotation; diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index 90f1ecfa8f..1b0ab19f71 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -68,7 +68,12 @@ public:          LLVector2 mScale = { 1.f, 1.f };          F32 mRotation = 0.f; -        void getPacked(F32 (&packed)[8]) const; +        static const size_t PACK_SIZE = 8; +        static const size_t PACK_TIGHT_SIZE = 5; +        using Pack = F32[PACK_SIZE]; +        using PackTight = F32[PACK_TIGHT_SIZE]; +        void getPacked(Pack& packed) const; +        void getPackedTight(PackTight& packed) const;          bool operator==(const TextureTransform& other) const;          bool operator!=(const TextureTransform& other) const { return !(*this == other); } @@ -120,12 +125,6 @@ public:      //       heightmaps cannot currently be described as finite enclosed      //       volumes.      // See also LLPanelRegionTerrainInfo::validateMaterials -    bool mDoubleSided = false; - - -    // These fields are local to viewer and are a part of local bitmap support -    typedef std::map<LLUUID, LLUUID> local_tex_map_t; -    local_tex_map_t                  mTrackingIdToLocalTexture;  public: diff --git a/indra/llprimitive/tests/llgltfmaterial_test.cpp b/indra/llprimitive/tests/llgltfmaterial_test.cpp index b56c9ab4f5..585b9da3ad 100644 --- a/indra/llprimitive/tests/llgltfmaterial_test.cpp +++ b/indra/llprimitive/tests/llgltfmaterial_test.cpp @@ -26,6 +26,8 @@  #include "linden_common.h"  #include "lltut.h" +#include <set> +  #include "../llgltfmaterial.h"  #include "lluuid.cpp" @@ -108,9 +110,9 @@ namespace tut          material.setAlphaCutoff(test_fraction);          // Because this is the default value, it should append to the extras field to mark it as an override -        material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_OPAQUE); +        material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_OPAQUE, true);          // Because this is the default value, it should append to the extras field to mark it as an override -        material.setDoubleSided(false); +        material.setDoubleSided(false, true);          return material;      } @@ -143,7 +145,7 @@ namespace tut  #if LL_WINDOWS          // If any fields are added/changed, these tests should be updated (consider also updating ASSET_VERSION in LLGLTFMaterial)          // This test result will vary between compilers, so only test a single platform -        ensure_equals("fields supported for GLTF (sizeof check)", sizeof(LLGLTFMaterial), 224); +        ensure_equals("fields supported for GLTF (sizeof check)", sizeof(LLGLTFMaterial), 232);  #endif  #endif          ensure_equals("LLGLTFMaterial texture info count", (U32)LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT, 4); @@ -366,4 +368,74 @@ namespace tut              ensure_equals("LLGLTFMaterial: double sided override flag unset", material.mOverrideDoubleSided, false);          }      } + +    template<typename T> +    void ensure_material_hash_pre(LLGLTFMaterial& material, T& material_field, const T new_value, const std::string& field_name) +    { +        ensure("LLGLTFMaterial: Hash: Test field " + field_name + " is part of the test material object", ( +                    size_t(&material_field) >= size_t(&material) && +                    (size_t(&material_field) + sizeof(material_field)) <= (size_t(&material) + sizeof(material)) +                    )); +        ensure("LLGLTFMaterial: Hash: " + field_name + " differs and will cause a perturbation worth hashing", material_field != new_value); +    } + +    template<typename T> +    void ensure_material_hash_not_changed(LLGLTFMaterial& material, T& material_field, const T new_value, const std::string& field_name) +    { +        ensure_material_hash_pre(material, material_field, new_value, field_name); + +        const LLGLTFMaterial old_material = material; +        material_field = new_value; +        // If this test fails, consult LLGLTFMaterial::getHash, and optionally consult http://www.catb.org/esr/structure-packing/ for guidance on optimal memory packing (effectiveness is platform-dependent) +        ensure_equals(("LLGLTFMaterial: Hash: Perturbing " + field_name + " to new value does NOT change the hash").c_str(), material.getHash(), old_material.getHash()); +    } + +    template<typename T> +    void ensure_material_hash_changed(LLGLTFMaterial& material, T& material_field, const T new_value, const std::string& field_name) +    { +        ensure_material_hash_pre(material, material_field, new_value, field_name); + +        const LLGLTFMaterial old_material = material; +        material_field = new_value; +        // If this test fails, consult LLGLTFMaterial::getHash, and optionally consult http://www.catb.org/esr/structure-packing/ for guidance on optimal memory packing (effectiveness is platform-dependent) +        ensure_not_equals(("LLGLTFMaterial: Hash: Perturbing " + field_name + " to new value changes the hash").c_str(), material.getHash(), old_material.getHash()); +    } + +#define ENSURE_HASH_NOT_CHANGED(HASH_MAT, SOURCE_MAT, FIELD) ensure_material_hash_not_changed(HASH_MAT, HASH_MAT.FIELD, SOURCE_MAT.FIELD, #FIELD) +#define ENSURE_HASH_CHANGED(HASH_MAT, SOURCE_MAT, FIELD) ensure_material_hash_changed(HASH_MAT, HASH_MAT.FIELD, SOURCE_MAT.FIELD, #FIELD) + +    // Test LLGLTFMaterial::getHash, which is very sensitive to the ordering of fields +    template<> template<> +    void llgltfmaterial_object_t::test<12>() +    { +        // *NOTE: Due to direct manipulation of the fields of materials +        // throughout this test, the resulting modified materials may not be +        // compliant or properly serializable. + +        // Ensure all fields of source_mat are set to values that differ from +        // LLGLTFMaterial::sDefault, even if that would result in an invalid +        // material object. +        LLGLTFMaterial source_mat = create_test_material(); +        source_mat.mTrackingIdToLocalTexture[LLUUID::generateNewID()] = LLUUID::generateNewID(); +        source_mat.mLocalTexDataDigest = 1; +        source_mat.mAlphaMode = LLGLTFMaterial::ALPHA_MODE_MASK; +        source_mat.mDoubleSided = true; + +        LLGLTFMaterial hash_mat; + +        ENSURE_HASH_NOT_CHANGED(hash_mat, source_mat, mTrackingIdToLocalTexture); +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mLocalTexDataDigest); + +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mTextureId); +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mTextureTransform); +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mBaseColor); +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mEmissiveColor); +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mMetallicFactor); +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mRoughnessFactor); +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mAlphaCutoff); +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mAlphaMode); +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mDoubleSided); +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mOverrideDoubleSided); +        ENSURE_HASH_CHANGED(hash_mat, source_mat, mOverrideAlphaMode); +    }  } diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 4e03882b7a..21541c8bc8 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1179,7 +1179,9 @@ void LLShaderMgr::initAttribsAndUniforms()      mReservedUniforms.push_back("texture_metallic_roughness_transform"); // (GLTF)      mReservedUniforms.push_back("texture_emissive_transform"); // (GLTF) -    llassert(mReservedUniforms.size() == LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM+1); +    mReservedUniforms.push_back("terrain_texture_transforms"); // (GLTF) + +    llassert(mReservedUniforms.size() == LLShaderMgr::TERRAIN_TEXTURE_TRANSFORMS +1);  	mReservedUniforms.push_back("viewport"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 2f344c8105..3dfac3cf0a 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -58,6 +58,8 @@ public:          TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, //  "texture_metallic_roughness_transform" (GLTF)          TEXTURE_EMISSIVE_TRANSFORM,           //  "texture_emissive_transform" (GLTF) +        TERRAIN_TEXTURE_TRANSFORMS,           //  "terrain_texture_transforms" (GLTF) +          VIEWPORT,                           //  "viewport"          LIGHT_POSITION,                     //  "light_position"          LIGHT_DIRECTION,                    //  "light_direction" diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index af63d6ff87..c3f9a64fd6 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -16829,6 +16829,226 @@        <key>Value</key>        <string>00000000-0000-0000-0000-000000000000</string>      </map> +    <key>LocalTerrainTransform1ScaleU</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset1 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>1.0</real> +    </map> +    <key>LocalTerrainTransform1ScaleV</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset1 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>1.0</real> +    </map> +    <key>LocalTerrainTransform1Rotation</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset1 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map> +    <key>LocalTerrainTransform1OffsetU</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset1 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map> +    <key>LocalTerrainTransform1OffsetV</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset1 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map> +    <key>LocalTerrainTransform2ScaleU</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset2 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>1.0</real> +    </map> +    <key>LocalTerrainTransform2ScaleV</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset2 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>1.0</real> +    </map> +    <key>LocalTerrainTransform2Rotation</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset2 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map> +    <key>LocalTerrainTransform2OffsetU</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset2 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map> +    <key>LocalTerrainTransform2OffsetV</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset2 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map> +    <key>LocalTerrainTransform3ScaleU</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset3 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>1.0</real> +    </map> +    <key>LocalTerrainTransform3ScaleV</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset3 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>1.0</real> +    </map> +    <key>LocalTerrainTransform3Rotation</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset3 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map> +    <key>LocalTerrainTransform3OffsetU</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset3 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map> +    <key>LocalTerrainTransform3OffsetV</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset3 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map> +    <key>LocalTerrainTransform4ScaleU</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset4 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>1.0</real> +    </map> +    <key>LocalTerrainTransform4ScaleV</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset4 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>1.0</real> +    </map> +    <key>LocalTerrainTransform4Rotation</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset4 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map> +    <key>LocalTerrainTransform4OffsetU</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset4 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map> +    <key>LocalTerrainTransform4OffsetV</key> +    <map> +      <key>Comment</key> +      <string>KHR texture transform component if LocalTerrainAsset4 is set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.0</real> +    </map>  	<key>PathfindingRetrieveNeighboringRegion</key>      <map>        <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl index de4745c1c4..65a6b8613d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl @@ -31,7 +31,7 @@  #define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3  #if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 -#define TerrainCoord vec4[2] +#define TerrainCoord vec4[3]  #elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1  #define TerrainCoord vec2  #endif @@ -131,12 +131,16 @@ uniform vec3[4] emissiveColors;  uniform vec4 minimum_alphas; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff()  #if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +in vec4[10] vary_coords; +#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1  in vec4[2] vary_coords;  #endif  in vec3 vary_position;  in vec3 vary_normal; -in vec3 vary_tangent; +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) +in vec3 vary_tangents[4];  flat in float vary_sign; +#endif  in vec4 vary_texcoord0;  in vec4 vary_texcoord1; @@ -144,17 +148,26 @@ void mirrorClip(vec3 position);  float terrain_mix(TerrainMix tm, vec4 tms4); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) +// from mikktspace.com +vec3 mikktspace(vec3 vNt, vec3 vT) +{ +    vec3 vN = vary_normal; +     +    vec3 vB = vary_sign * cross(vN, vT); +    vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); + +    tnorm *= gl_FrontFacing ? 1.0 : -1.0; + +    return tnorm; +} +#endif +  void main()  {      // Make sure we clip the terrain if we're in a mirror.      mirrorClip(vary_position); -#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 -    TerrainCoord terrain_texcoord = vary_coords; -#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 -    TerrainCoord terrain_texcoord = vary_texcoord0.xy; -#endif -      float alpha1 = texture(alpha_ramp, vary_texcoord0.zw).a;      float alpha2 = texture(alpha_ramp,vary_texcoord1.xy).a;      float alphaFinal = texture(alpha_ramp, vary_texcoord1.zw).a; @@ -185,6 +198,16 @@ void main()      switch (tm.type & MIX_X)      {      case MIX_X: +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +        TerrainCoord terrain_texcoord; +        terrain_texcoord[0].xy = vary_coords[0].xy; +        terrain_texcoord[0].zw = vary_coords[0].zw; +        terrain_texcoord[1].xy = vary_coords[1].xy; +        terrain_texcoord[1].zw = vary_coords[1].zw; +        terrain_texcoord[2].xy = vary_coords[2].xy; +#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 +        TerrainCoord terrain_texcoord = vary_coords[0].xy; +#endif          mix2 = terrain_sample_and_multiply_pbr(              terrain_texcoord              , detail_0_base_color @@ -207,6 +230,9 @@ void main()              , emissiveColors[0]  #endif          ); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) +        mix2.vNt = mikktspace(mix2.vNt, vary_tangents[0]); +#endif          mix = mix_pbr(mix, mix2, tm.weight.x);          break;      default: @@ -215,6 +241,16 @@ void main()      switch (tm.type & MIX_Y)      {      case MIX_Y: +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +        TerrainCoord terrain_texcoord; +        terrain_texcoord[0].xy = vary_coords[2].zw; +        terrain_texcoord[0].zw = vary_coords[3].xy; +        terrain_texcoord[1].xy = vary_coords[3].zw; +        terrain_texcoord[1].zw = vary_coords[4].xy; +        terrain_texcoord[2].xy = vary_coords[4].zw; +#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 +        TerrainCoord terrain_texcoord = vary_coords[0].zw; +#endif          mix2 = terrain_sample_and_multiply_pbr(              terrain_texcoord              , detail_1_base_color @@ -237,6 +273,9 @@ void main()              , emissiveColors[1]  #endif          ); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) +        mix2.vNt = mikktspace(mix2.vNt, vary_tangents[1]); +#endif          mix = mix_pbr(mix, mix2, tm.weight.y);          break;      default: @@ -245,6 +284,16 @@ void main()      switch (tm.type & MIX_Z)      {      case MIX_Z: +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +        TerrainCoord terrain_texcoord; +        terrain_texcoord[0].xy = vary_coords[5].xy; +        terrain_texcoord[0].zw = vary_coords[5].zw; +        terrain_texcoord[1].xy = vary_coords[6].xy; +        terrain_texcoord[1].zw = vary_coords[6].zw; +        terrain_texcoord[2].xy = vary_coords[7].xy; +#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 +        TerrainCoord terrain_texcoord = vary_coords[1].xy; +#endif          mix2 = terrain_sample_and_multiply_pbr(              terrain_texcoord              , detail_2_base_color @@ -267,6 +316,9 @@ void main()              , emissiveColors[2]  #endif          ); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) +        mix2.vNt = mikktspace(mix2.vNt, vary_tangents[2]); +#endif          mix = mix_pbr(mix, mix2, tm.weight.z);          break;      default: @@ -275,6 +327,16 @@ void main()      switch (tm.type & MIX_W)      {      case MIX_W: +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +        TerrainCoord terrain_texcoord; +        terrain_texcoord[0].xy = vary_coords[7].zw; +        terrain_texcoord[0].zw = vary_coords[8].xy; +        terrain_texcoord[1].xy = vary_coords[8].zw; +        terrain_texcoord[1].zw = vary_coords[9].xy; +        terrain_texcoord[2].xy = vary_coords[9].zw; +#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 +        TerrainCoord terrain_texcoord = vary_coords[1].zw; +#endif          mix2 = terrain_sample_and_multiply_pbr(              terrain_texcoord              , detail_3_base_color @@ -297,6 +359,9 @@ void main()              , emissiveColors[3]  #endif          ); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) +        mix2.vNt = mikktspace(mix2.vNt, vary_tangents[3]); +#endif          mix = mix_pbr(mix, mix2, tm.weight.w);          break;      default: @@ -311,19 +376,11 @@ void main()      float base_color_factor_alpha = terrain_mix(tm, vec4(baseColorFactors[0].z, baseColorFactors[1].z, baseColorFactors[2].z, baseColorFactors[3].z));  #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) -    // from mikktspace.com -    vec3 vNt = mix.vNt; -    vec3 vN = vary_normal; -    vec3 vT = vary_tangent.xyz; -     -    vec3 vB = vary_sign * cross(vN, vT); -    vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); - -    tnorm *= gl_FrontFacing ? 1.0 : -1.0; +    vec3 tnorm = normalize(mix.vNt);  #else      vec3 tnorm = vary_normal; -    tnorm *= gl_FrontFacing ? 1.0 : -1.0;  #endif +    tnorm *= gl_FrontFacing ? 1.0 : -1.0;  #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl index 935c3f9301..7a7fd783ec 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl @@ -233,17 +233,12 @@ float terrain_mix(TerrainMix tm, vec4 tms4)  // Triplanar mapping  // Pre-transformed texture coordinates for each axial uv slice (Packing: xy, yz, (-x)z, unused) -#define TerrainCoord vec4[2] +#define TerrainCoord vec4[3] -vec2 _t_uv(vec2 uv_unflipped, float sign_or_zero) +// If sign_or_zero is positive, use uv_unflippped, otherwise use uv_flipped +vec2 _t_uv(vec2 uv_unflipped, vec2 uv_flipped, float sign_or_zero)  { -    // Handle case where sign is 0 -    float sign = (2.0*sign_or_zero) + 1.0; -    sign /= abs(sign); -    // If the vertex normal is negative, flip the texture back -    // right-side up. -    vec2 uv = uv_unflipped * vec2(sign, 1); -    return uv; +    return mix(uv_flipped, uv_unflipped, max(0.0, sign_or_zero));  }  vec3 _t_normal_post_1(vec3 vNt0, float sign_or_zero) @@ -298,9 +293,9 @@ PBRMix terrain_sample_pbr(  {      PBRMix mix = init_pbr_mix(); -#define get_uv_x() _t_uv(terrain_coord[0].zw, sign(vary_vertex_normal.x)) -#define get_uv_y() _t_uv(terrain_coord[1].xy, sign(vary_vertex_normal.y)) -#define get_uv_z() _t_uv(terrain_coord[0].xy, sign(vary_vertex_normal.z)) +#define get_uv_x() _t_uv(terrain_coord[0].zw, terrain_coord[1].zw, sign(vary_vertex_normal.x)) +#define get_uv_y() _t_uv(terrain_coord[1].xy, terrain_coord[2].xy, sign(vary_vertex_normal.y)) +#define get_uv_z() _t_uv(terrain_coord[0].xy, vec2(0),             sign(vary_vertex_normal.z))      switch (tw.type & SAMPLE_X)      {      case SAMPLE_X: diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl index 489fc26e3f..167d980eb8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl @@ -23,6 +23,11 @@   * $/LicenseInfo$   */ +#define TERRAIN_PBR_DETAIL_EMISSIVE 0 +#define TERRAIN_PBR_DETAIL_OCCLUSION -1 +#define TERRAIN_PBR_DETAIL_NORMAL -2 +#define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3 +  uniform mat3 normal_matrix;  uniform mat4 texture_matrix0;  uniform mat4 modelview_matrix; @@ -34,24 +39,28 @@ in vec4 tangent;  in vec4 diffuse_color;  in vec2 texcoord1; -#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 -out vec4[2] vary_coords; -#endif  out vec3 vary_vertex_normal; // Used by pbrterrainUtilF.glsl  out vec3 vary_normal; -out vec3 vary_tangent; +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) +out vec3 vary_tangents[4];  flat out float vary_sign; +#endif  out vec4 vary_texcoord0;  out vec4 vary_texcoord1; +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +out vec4[10] vary_coords; +#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 +out vec4[2] vary_coords; +#endif  out vec3 vary_position; -// *HACK: tangent_space_transform should use texture_normal_transform, or maybe -// we shouldn't use tangent_space_transform at all. See the call to -// tangent_space_transform below. -uniform vec4[2] texture_base_color_transform; +// *HACK: Each material uses only one texture transform, but the KHR texture +// transform spec allows handling texture transforms separately for each +// individual texture info. +uniform vec4[5] terrain_texture_transforms; -vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); -vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); +vec2 terrain_texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform); +vec3 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform);  void main()  { @@ -63,31 +72,101 @@ void main()      vary_vertex_normal = normal;  	vec3 t = normal_matrix * tangent.xyz; -    vary_tangent = normalize(t); -    // *TODO: Decide if we want this. It may be better to just calculate the -    // tangents on-the-fly in the fragment shader, due to the subtleties of the -    // effect of triplanar mapping on UVs. -    // *HACK: Should be using texture_normal_transform here. The KHR texture -    // transform spec requires handling texture transforms separately for each -    // individual texture. -    vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_base_color_transform, texture_matrix0)); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) +    { +        vec4[2] ttt; +        // material 1 +        ttt[0].xyz = terrain_texture_transforms[0].xyz; +        ttt[1].x = terrain_texture_transforms[0].w; +        ttt[1].y = terrain_texture_transforms[1].x; +        vary_tangents[0] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt)); +        // material 2 +        ttt[0].xyz = terrain_texture_transforms[1].yzw; +        ttt[1].xy = terrain_texture_transforms[2].xy; +        vary_tangents[1] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt)); +        // material 3 +        ttt[0].xy = terrain_texture_transforms[2].zw; +        ttt[0].z = terrain_texture_transforms[3].x; +        ttt[1].xy = terrain_texture_transforms[3].yz; +        vary_tangents[2] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt)); +        // material 4 +        ttt[0].x = terrain_texture_transforms[3].w; +        ttt[0].yz = terrain_texture_transforms[4].xy; +        ttt[1].xy = terrain_texture_transforms[4].zw; +        vary_tangents[3] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt)); +    } +      vary_sign = tangent.w; +#endif      vary_normal = normalize(n);      // Transform and pass tex coords -    // *HACK: texture_base_color_transform is used for all of these here, but -    // the KHR texture transform spec requires handling texture transforms -    // separately for each individual texture. +    { +        vec4[2] ttt;  #if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 -    // xy -    vary_coords[0].xy = texture_transform(position.xy, texture_base_color_transform, texture_matrix0); -    // yz -    vary_coords[0].zw = texture_transform(position.yz, texture_base_color_transform, texture_matrix0); -    // (-x)z -    vary_coords[1].xy = texture_transform(position.xz * vec2(-1, 1), texture_base_color_transform, texture_matrix0); +// Don't care about upside-down (transform_xy_flipped()) +#define transform_xy()             terrain_texture_transform(position.xy,               ttt) +#define transform_yz()             terrain_texture_transform(position.yz,               ttt) +#define transform_negx_z()         terrain_texture_transform(position.xz * vec2(-1, 1), ttt) +#define transform_yz_flipped()     terrain_texture_transform(position.yz * vec2(-1, 1), ttt) +#define transform_negx_z_flipped() terrain_texture_transform(position.xz,               ttt) +        // material 1 +        ttt[0].xyz = terrain_texture_transforms[0].xyz; +        ttt[1].x = terrain_texture_transforms[0].w; +        ttt[1].y = terrain_texture_transforms[1].x; +        vary_coords[0].xy = transform_xy(); +        vary_coords[0].zw = transform_yz(); +        vary_coords[1].xy = transform_negx_z(); +        vary_coords[1].zw = transform_yz_flipped(); +        vary_coords[2].xy = transform_negx_z_flipped(); +        // material 2 +        ttt[0].xyz = terrain_texture_transforms[1].yzw; +        ttt[1].xy = terrain_texture_transforms[2].xy; +        vary_coords[2].zw = transform_xy(); +        vary_coords[3].xy = transform_yz(); +        vary_coords[3].zw = transform_negx_z(); +        vary_coords[4].xy = transform_yz_flipped(); +        vary_coords[4].zw = transform_negx_z_flipped(); +        // material 3 +        ttt[0].xy = terrain_texture_transforms[2].zw; +        ttt[0].z = terrain_texture_transforms[3].x; +        ttt[1].xy = terrain_texture_transforms[3].yz; +        vary_coords[5].xy = transform_xy(); +        vary_coords[5].zw = transform_yz(); +        vary_coords[6].xy = transform_negx_z(); +        vary_coords[6].zw = transform_yz_flipped(); +        vary_coords[7].xy = transform_negx_z_flipped(); +        // material 4 +        ttt[0].x = terrain_texture_transforms[3].w; +        ttt[0].yz = terrain_texture_transforms[4].xy; +        ttt[1].xy = terrain_texture_transforms[4].zw; +        vary_coords[7].zw = transform_xy(); +        vary_coords[8].xy = transform_yz(); +        vary_coords[8].zw = transform_negx_z(); +        vary_coords[9].xy = transform_yz_flipped(); +        vary_coords[9].zw = transform_negx_z_flipped();  #elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 -    vary_texcoord0.xy = texture_transform(position.xy, texture_base_color_transform, texture_matrix0); +        // material 1 +        ttt[0].xyz = terrain_texture_transforms[0].xyz; +        ttt[1].x = terrain_texture_transforms[0].w; +        ttt[1].y = terrain_texture_transforms[1].x; +        vary_coords[0].xy = terrain_texture_transform(position.xy, ttt); +        // material 2 +        ttt[0].xyz = terrain_texture_transforms[1].yzw; +        ttt[1].xy = terrain_texture_transforms[2].xy; +        vary_coords[0].zw = terrain_texture_transform(position.xy, ttt); +        // material 3 +        ttt[0].xy = terrain_texture_transforms[2].zw; +        ttt[0].z = terrain_texture_transforms[3].x; +        ttt[1].xy = terrain_texture_transforms[3].yz; +        vary_coords[1].xy = terrain_texture_transform(position.xy, ttt); +        // material 4 +        ttt[0].x = terrain_texture_transforms[3].w; +        ttt[0].yz = terrain_texture_transforms[4].xy; +        ttt[1].xy = terrain_texture_transforms[4].zw; +        vary_coords[1].zw = terrain_texture_transform(position.xy, ttt);  #endif +    }      vec4 tc = vec4(texcoord1,0,1);      vary_texcoord0.zw = tc.xy; diff --git a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl index 732333311c..baf4010fa7 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl @@ -48,6 +48,7 @@ vec2 khr_texture_transform(vec2 texcoord, vec2 scale, float rotation, vec2 offse      return (transform * vec3(texcoord, 1)).xy;  } +// A texture transform function for PBR materials applied to shape prims/Collada model prims  // vertex_texcoord - The UV texture coordinates sampled from the vertex at  //     runtime. Per SL convention, this is in a right-handed UV coordinate  //     system. Collada models also have right-handed UVs. @@ -77,6 +78,21 @@ vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl      return texcoord;  } +// Similar to texture_transform but no offset during coordinate system +// conversion, and no texture animation support. +vec2 terrain_texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform) +{ +    vec2 texcoord = vertex_texcoord; + +    texcoord.y = 1.0 - texcoord.y; +    //texcoord.y = -texcoord.y; +    texcoord = khr_texture_transform(texcoord, khr_gltf_transform[0].xy, khr_gltf_transform[0].z, khr_gltf_transform[1].xy); +    texcoord.y = 1.0 - texcoord.y; +    //texcoord.y = -texcoord.y; + +    return texcoord; +} +  // Take the rotation only from both transforms and apply to the tangent. This  // accounts for the change of the topology of the normal texture when a texture  // rotation is applied to it. @@ -120,3 +136,26 @@ vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] kh      return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz);  } + +// Similar to tangent_space_transform but no offset during coordinate system +// conversion, and no texture animation support. +vec3 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform) +{ +    // Immediately convert to left-handed coordinate system ((0,1) -> (0, -1)) +    vec2 weights = vec2(0, -1); + +    // Apply KHR_texture_transform (rotation only) +    float khr_rotation = khr_gltf_transform[0].z; +    mat2 khr_rotation_mat = mat2( +        cos(khr_rotation),-sin(khr_rotation), +        sin(khr_rotation), cos(khr_rotation) +    ); +    weights = khr_rotation_mat * weights; + +    // Convert back to right-handed coordinate system +    weights.y = -weights.y; + +    vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz); + +    return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz); +} diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index c5932a6ad9..de48d315e6 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -330,7 +330,7 @@ void LLDrawPoolTerrain::renderFullShaderPBR(BOOL local_materials)  	// Hack! Get the region that this draw pool is rendering from!  	LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion();  	LLVLComposition *compp = regionp->getComposition(); -	LLPointer<LLFetchedGLTFMaterial> (*fetched_materials)[LLVLComposition::ASSET_COUNT] = &compp->mDetailMaterials; +	LLPointer<LLFetchedGLTFMaterial> (*fetched_materials)[LLVLComposition::ASSET_COUNT] = &compp->mDetailRenderMaterials;  	constexpr U32 terrain_material_count = LLVLComposition::ASSET_COUNT;  #ifdef SHOW_ASSERT @@ -341,7 +341,7 @@ void LLDrawPoolTerrain::renderFullShaderPBR(BOOL local_materials)      if (local_materials)      {          // Override region terrain with the global local override terrain -		fetched_materials = &gLocalTerrainMaterials.mDetailMaterials; +		fetched_materials = &gLocalTerrainMaterials.mDetailRenderMaterials;      }  	const LLGLTFMaterial* materials[terrain_material_count];  	for (U32 i = 0; i < terrain_material_count; ++i) @@ -433,21 +433,51 @@ void LLDrawPoolTerrain::renderFullShaderPBR(BOOL local_materials)  	llassert(shader); -    // *TODO: Figure out why this offset is *sometimes* producing seams at the -    // region edge, and repeat jumps when crossing regions, when -    // RenderTerrainPBRScale is not a factor of the region scale. -	LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal(); -	F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sPBRDetailScale)*sPBRDetailScale; -	F32 offset_y = (F32)fmod(region_origin_global.mdV[VY], 1.0/(F64)sPBRDetailScale)*sPBRDetailScale; - -    LLGLTFMaterial::TextureTransform base_color_transform; -    base_color_transform.mScale = LLVector2(sPBRDetailScale, sPBRDetailScale); -    base_color_transform.mOffset = LLVector2(offset_x, offset_y); -    F32 base_color_packed[8]; -    base_color_transform.getPacked(base_color_packed); -    // *HACK: Use the same texture repeats for all PBR terrain textures for now -    // (not compliant with KHR texture transform spec) -    shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed); +    // Like for PBR materials, PBR terrain texture transforms are defined by +    // the KHR_texture_transform spec, but with the following notable +    // differences: +    //   1) The PBR UV origin is defined as the Southwest corner of the region, +    //      with positive U facing East and positive V facing South. +    //   2) There is an additional scaling factor RenderTerrainPBRScale. If +    //      we've done our math right, RenderTerrainPBRScale should not affect the +    //      overall behavior of KHR_texture_transform +    //   3) There is only one texture transform per material, whereas +    //      KHR_texture_transform supports one texture transform per texture info. +    //      i.e. this isn't fully compliant with KHR_texture_transform, but is +    //      compliant when all texture infos used by a material have the same +    //      texture transform. + +    LLGLTFMaterial::TextureTransform::PackTight transforms_packed[terrain_material_count]; +    for (U32 i = 0; i < terrain_material_count; ++i) +	{ +		const LLFetchedGLTFMaterial* fetched_material = (*fetched_materials)[i].get(); +        LLGLTFMaterial::TextureTransform transform; +        if (fetched_material) +        { +            transform = fetched_material->mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]; +#ifdef SHOW_ASSERT +            // Assert condition where the contents of the texture transforms +            // differ per texture info - we currently don't support this case. +            for (U32 ti = 1; ti < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++ti) +            { +                llassert(fetched_material->mTextureTransform[0] == fetched_material->mTextureTransform[ti]); +            } +#endif +        } +        // *NOTE: Notice here we are combining the scale from +        // RenderTerrainPBRScale into the KHR_texture_transform. This only +        // works if the scale is uniform and no other transforms are +        // applied to the terrain UVs. +        transform.mScale.mV[VX] *= sPBRDetailScale; +        transform.mScale.mV[VY] *= sPBRDetailScale; + +        transform.getPackedTight(transforms_packed[i]); +    } +    const U32 transform_param_count = LLGLTFMaterial::TextureTransform::PACK_TIGHT_SIZE * terrain_material_count; +    constexpr U32 vec4_size = 4; +    const U32 transform_vec4_count = (transform_param_count + (vec4_size - 1)) / vec4_size; +    llassert(transform_vec4_count == 5); // If false, need to update shader +    shader->uniform4fv(LLShaderMgr::TERRAIN_TEXTURE_TRANSFORMS, transform_vec4_count, (F32*)transforms_packed);      LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater(); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 4aadc822ab..410d6a9d55 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -691,6 +691,28 @@ void handleLocalTerrainChanged(const LLSD& newValue)          const auto setting = gSavedSettings.getString(std::string("LocalTerrainAsset") + std::to_string(i + 1));          const LLUUID materialID(setting);          gLocalTerrainMaterials.setDetailAssetID(i, materialID); + +        // *NOTE: The GLTF spec allows for different texture infos to have their texture transforms set independently, but as a simplification, this debug setting only updates all the transforms in-sync (i.e. only one texture transform per terrain material). +        LLGLTFMaterial::TextureTransform transform; +        const std::string prefix = std::string("LocalTerrainTransform") + std::to_string(i + 1); +        transform.mScale.mV[VX] = gSavedSettings.getF32(prefix + "ScaleU"); +        transform.mScale.mV[VY] = gSavedSettings.getF32(prefix + "ScaleV"); +        transform.mRotation = gSavedSettings.getF32(prefix + "Rotation") * DEG_TO_RAD; +        transform.mOffset.mV[VX] = gSavedSettings.getF32(prefix + "OffsetU"); +        transform.mOffset.mV[VY] = gSavedSettings.getF32(prefix + "OffsetV"); +        LLPointer<LLGLTFMaterial> mat_override = new LLGLTFMaterial(); +        for (U32 info = 0; info < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++info) +        { +            mat_override->mTextureTransform[info] = transform; +        } +        if (*mat_override == LLGLTFMaterial::sDefault) +        { +            gLocalTerrainMaterials.setMaterialOverride(i, nullptr); +        } +        else +        { +            gLocalTerrainMaterials.setMaterialOverride(i, mat_override); +		}      }  }  //////////////////////////////////////////////////////////////////////////// @@ -879,10 +901,25 @@ void settings_setup_listeners()      setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorFarAwayDistance", handleUserImpostorDistanceChanged);      setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorByDistEnabled", handleUserImpostorByDistEnabledChanged);      setting_setup_signal_listener(gSavedSettings, "TuningFPSStrategy", handleFPSTuningStrategyChanged); -    setting_setup_signal_listener(gSavedSettings, "LocalTerrainAsset1", handleLocalTerrainChanged); -    setting_setup_signal_listener(gSavedSettings, "LocalTerrainAsset2", handleLocalTerrainChanged); -    setting_setup_signal_listener(gSavedSettings, "LocalTerrainAsset3", handleLocalTerrainChanged); -    setting_setup_signal_listener(gSavedSettings, "LocalTerrainAsset4", handleLocalTerrainChanged); +    { +        const char* transform_suffixes[] = { +            "ScaleU", +            "ScaleV", +            "Rotation", +            "OffsetU", +            "OffsetV" +        }; +        for (U32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) +        { +            const auto asset_setting_name = std::string("LocalTerrainAsset") + std::to_string(i + 1); +            setting_setup_signal_listener(gSavedSettings, asset_setting_name, handleLocalTerrainChanged); +            for (const char* ts : transform_suffixes) +            { +                const auto transform_setting_name = std::string("LocalTerrainTransform") + std::to_string(i + 1) + ts; +                setting_setup_signal_listener(gSavedSettings, transform_setting_name, handleLocalTerrainChanged); +            } +        } +    }      setting_setup_signal_listener(gSavedPerAccountSettings, "AvatarHoverOffsetZ", handleAvatarHoverOffsetChanged);  } diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index dc97beac93..c161c42256 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -188,9 +188,24 @@ void LLTerrainMaterials::setDetailAssetID(S32 asset, const LLUUID& id)  	mDetailTextures[asset] = fetch_terrain_texture(id);      LLPointer<LLFetchedGLTFMaterial>& mat = mDetailMaterials[asset];      mat = id.isNull() ? nullptr : gGLTFMaterialList.getMaterial(id); +    mDetailRenderMaterials[asset] = nullptr;      mMaterialTexturesSet[asset] = false;  } +const LLGLTFMaterial* LLTerrainMaterials::getMaterialOverride(S32 asset) +{ +    return mDetailMaterialOverrides[asset]; +} + +void LLTerrainMaterials::setMaterialOverride(S32 asset, LLGLTFMaterial* mat_override) +{ +    // Non-null overrides must be nontrivial. Otherwise, please set the override to null instead. +    llassert(!mat_override || *mat_override != LLGLTFMaterial::sDefault); + +    mDetailMaterialOverrides[asset] = mat_override; +    mDetailRenderMaterials[asset] = nullptr; +} +  LLTerrainMaterials::Type LLTerrainMaterials::getMaterialType()  {  	LL_PROFILE_ZONE_SCOPED; @@ -221,13 +236,36 @@ bool LLTerrainMaterials::texturesReady(bool boost, bool strict)      return one_ready;  } +namespace +{ +    bool material_asset_ready(LLFetchedGLTFMaterial* mat) { return mat && mat->isLoaded(); } +}; +  bool LLTerrainMaterials::materialsReady(bool boost, bool strict)  {      bool ready[ASSET_COUNT]; -    // *NOTE: Calls to materialReady may boost materials/textures. Do not early-return. +    // *NOTE: This section may boost materials/textures. Do not early-return if ready[i] is false.      for (S32 i = 0; i < ASSET_COUNT; i++)      { -        ready[i] = materialReady(mDetailMaterials[i], mMaterialTexturesSet[i], boost, strict); +        ready[i] = false; +        LLPointer<LLFetchedGLTFMaterial>& mat = mDetailMaterials[i]; +        if (!material_asset_ready(mat)) { continue; } + +        LLPointer<LLFetchedGLTFMaterial>& render_mat = mDetailRenderMaterials[i]; +        if (!render_mat) +        { +            render_mat = new LLFetchedGLTFMaterial(); +            *render_mat = *mat; +            // This render_mat is effectively already loaded, because it gets its data from mat. + +            LLPointer<LLGLTFMaterial>& override_mat = mDetailMaterialOverrides[i]; +            if (override_mat) +            { +                render_mat->applyOverride(*override_mat); +            } +        } + +        ready[i] = materialTexturesReady(render_mat, mMaterialTexturesSet[i], boost, strict);      }  #if 1 @@ -308,15 +346,13 @@ bool LLTerrainMaterials::textureReady(LLPointer<LLViewerFetchedTexture>& tex, bo      return true;  } -// Boost the loading priority of every known texture in the material -// Return true when ready to use +// Make sure to call material_asset_ready first +// strict = true -> all materials must be sufficiently loaded +// strict = false -> at least one material must be loaded  // static -bool LLTerrainMaterials::materialReady(LLPointer<LLFetchedGLTFMaterial> &mat, bool &textures_set, bool boost, bool strict) +bool LLTerrainMaterials::materialTexturesReady(LLPointer<LLFetchedGLTFMaterial>& mat, bool& textures_set, bool boost, bool strict)  { -    if (!mat || !mat->isLoaded()) -    { -        return false; -    } +    llassert(mat);      // Material is loaded, but textures may not be      if (!textures_set) @@ -357,6 +393,16 @@ bool LLTerrainMaterials::materialReady(LLPointer<LLFetchedGLTFMaterial> &mat, bo      return true;  } +// Boost the loading priority of every known texture in the material +// Return true when ready to use +// static +bool LLTerrainMaterials::materialReady(LLPointer<LLFetchedGLTFMaterial> &mat, bool &textures_set, bool boost, bool strict) +{ +    if (!material_asset_ready(mat)) { return false; } + +    return materialTexturesReady(mat, textures_set, boost, strict); +} +  // static  const LLUUID (&LLVLComposition::getDefaultTextures())[ASSET_COUNT]  { @@ -669,19 +715,20 @@ bool LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y,              }              else              { -                tex = mDetailMaterials[i]->mBaseColorTexture; -                tex_emissive = mDetailMaterials[i]->mEmissiveTexture; -                base_color_factor = LLColor3(mDetailMaterials[i]->mBaseColor); +                LLPointer<LLFetchedGLTFMaterial>& mat = mDetailRenderMaterials[i]; +                tex = mat->mBaseColorTexture; +                tex_emissive = mat->mEmissiveTexture; +                base_color_factor = LLColor3(mat->mBaseColor);                  // *HACK: Treat alpha as black -                base_color_factor *= (mDetailMaterials[i]->mBaseColor.mV[VW]); -                emissive_factor = mDetailMaterials[i]->mEmissiveColor; +                base_color_factor *= (mat->mBaseColor.mV[VW]); +                emissive_factor = mat->mEmissiveColor;                  has_base_color_factor = (base_color_factor.mV[VX] != 1.f ||                                           base_color_factor.mV[VY] != 1.f ||                                           base_color_factor.mV[VZ] != 1.f);                  has_emissive_factor = (emissive_factor.mV[VX] != 1.f ||                                         emissive_factor.mV[VY] != 1.f ||                                         emissive_factor.mV[VZ] != 1.f); -                has_alpha = mDetailMaterials[i]->mAlphaMode != LLGLTFMaterial::ALPHA_MODE_OPAQUE; +                has_alpha = mat->mAlphaMode != LLGLTFMaterial::ALPHA_MODE_OPAQUE;              }              if (!tex) { tex = LLViewerFetchedTexture::sWhiteImagep; } diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index cde0e216c3..568786973d 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -35,6 +35,7 @@  class LLSurface;  class LLViewerFetchedTexture; +class LLGLTFMaterial;  class LLFetchedGLTFMaterial;  class LLTerrainMaterials @@ -62,6 +63,8 @@ public:  	virtual LLUUID getDetailAssetID(S32 asset);  	virtual void setDetailAssetID(S32 asset, const LLUUID& id); +	virtual const LLGLTFMaterial* getMaterialOverride(S32 asset); +	virtual void setMaterialOverride(S32 asset, LLGLTFMaterial* mat_override);      Type getMaterialType();      bool texturesReady(bool boost, bool strict);      // strict = true -> all materials must be sufficiently loaded @@ -74,8 +77,13 @@ protected:      // strict = true -> all materials must be sufficiently loaded      // strict = false -> at least one material must be loaded      static bool materialReady(LLPointer<LLFetchedGLTFMaterial>& mat, bool& textures_set, bool boost, bool strict); +    // *NOTE: Prefer calling materialReady if mat is known to be LLFetchedGLTFMaterial +    static bool materialTexturesReady(LLPointer<LLFetchedGLTFMaterial>& mat, bool& textures_set, bool boost, bool strict); +  	LLPointer<LLViewerFetchedTexture> mDetailTextures[ASSET_COUNT];  	LLPointer<LLFetchedGLTFMaterial> mDetailMaterials[ASSET_COUNT]; +    LLPointer<LLGLTFMaterial> mDetailMaterialOverrides[ASSET_COUNT]; +    LLPointer<LLFetchedGLTFMaterial> mDetailRenderMaterials[ASSET_COUNT];      bool mMaterialTexturesSet[ASSET_COUNT];  }; @@ -125,9 +133,6 @@ public:  	bool getParamsReady() const	{ return mParamsReady; }  protected: -    static bool textureReady(LLPointer<LLViewerFetchedTexture>& tex, bool boost = false); -    static bool materialReady(LLPointer<LLFetchedGLTFMaterial>& mat, bool& textures_set, bool boost = false); -  	bool mParamsReady = false;  	LLSurface *mSurfacep; | 
