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 /indra/newview | |
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
Diffstat (limited to 'indra/newview')
-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 |
9 files changed, 606 insertions, 97 deletions
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; |