diff options
Diffstat (limited to 'indra/newview/app_settings/shaders')
10 files changed, 352 insertions, 71 deletions
diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl index 5193a46ac2..8588a93648 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl @@ -99,10 +99,13 @@ void calcHalfVectors(vec3 lv, vec3 n, vec3 v, { l = normalize(lv); h = normalize(l + v); - nh = clamp(dot(n, h), 0.0, 1.0); - nl = clamp(dot(n, l), 0.0, 1.0); - nv = clamp(dot(n, v), 0.0, 1.0); - vh = clamp(dot(v, h), 0.0, 1.0); + + // lower bound to avoid divide by zero + float eps = 0.000001; + nh = clamp(dot(n, h), eps, 1.0); + nl = clamp(dot(n, l), eps, 1.0); + nv = clamp(dot(n, v), eps, 1.0); + vh = clamp(dot(v, h), eps, 1.0); lightDist = length(lv); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl index 902746366d..607a8c6ef6 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl @@ -25,24 +25,53 @@ /*[EXTRA_CODE_HERE]*/ + + +// generate a normal map using an approximation of the old emboss bump map "brightness/darkness" technique +// srcMap is a source color image, output should be a normal + out vec4 frag_color; -uniform sampler2D alphaMap; +uniform sampler2D srcMap; in vec2 vary_texcoord0; uniform float stepX; uniform float stepY; uniform float norm_scale; +uniform int bump_code; + +#define BE_BRIGHTNESS 1 +#define BE_DARKNESS 2 + +// get luminance or inverse luminance depending on bump_code +float getBumpValue(vec2 texcoord) +{ + vec3 c = texture(srcMap, texcoord).rgb; + + vec3 WEIGHT = vec3(0.2995, 0.5875, 0.1145); + + float l = dot(c, WEIGHT); + + if (bump_code == BE_DARKNESS) + { + l = 1.0 - l; + } + + return l; +} + void main() { - float c = texture(alphaMap, vary_texcoord0).r; + float c = getBumpValue(vary_texcoord0); + + float scaler = 512.0; - vec3 right = vec3(norm_scale, 0, (texture(alphaMap, vary_texcoord0+vec2(stepX, 0)).r-c)*255); - vec3 left = vec3(-norm_scale, 0, (texture(alphaMap, vary_texcoord0-vec2(stepX, 0)).r-c)*255); - vec3 up = vec3(0, -norm_scale, (texture(alphaMap, vary_texcoord0-vec2(0, stepY)).r-c)*255); - vec3 down = vec3(0, norm_scale, (texture(alphaMap, vary_texcoord0+vec2(0, stepY)).r-c)*255); + vec3 right = vec3(norm_scale, 0, (getBumpValue(vary_texcoord0+vec2(stepX, 0))-c)*scaler); + vec3 left = vec3(-norm_scale, 0, (getBumpValue(vary_texcoord0-vec2(stepX, 0))-c)*scaler); + vec3 up = vec3(0, -norm_scale, (getBumpValue(vary_texcoord0-vec2(0, stepY))-c)*scaler); + vec3 down = vec3(0, norm_scale, (getBumpValue(vary_texcoord0+vec2(0, stepY))-c)*scaler); vec3 norm = cross(right, down) + cross(down, left) + cross(left,up) + cross(up, right); diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl index ae179d3f37..66adf50fa9 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl @@ -69,7 +69,7 @@ flat out float vary_sign; out vec3 vary_normal; 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); +vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); void main() @@ -103,8 +103,9 @@ void main() n = normalize(n); - vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0)); - vary_sign = tangent.w; + vec4 transformed_tangent = tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0); + vary_tangent = normalize(transformed_tangent.xyz); + vary_sign = transformed_tangent.w; vary_normal = n; vertex_color = diffuse_color; diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl index fd020afd57..0ad9bf5e4b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl @@ -63,7 +63,7 @@ out vec3 vary_normal; out vec3 vary_position; 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); +vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); void main() { @@ -97,8 +97,9 @@ void main() n = normalize(n); - vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0)); - vary_sign = tangent.w; + vec4 transformed_tangent = tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0); + vary_tangent = normalize(transformed_tangent.xyz); + vary_sign = transformed_tangent.w; vary_normal = n; vertex_color = diffuse_color; diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl index 2cb7ff196b..410c447c64 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl @@ -30,6 +30,9 @@ #define TERRAIN_PBR_DETAIL_NORMAL -2 #define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3 +#define TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE 0 +#define TERRAIN_PAINT_TYPE_PBR_PAINTMAP 1 + #if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 #define TerrainCoord vec4[3] #elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 @@ -48,6 +51,7 @@ struct TerrainMix }; TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal); +TerrainMix get_terrain_usage_from_weight3(vec3 weight3); struct PBRMix { @@ -75,6 +79,9 @@ PBRMix terrain_sample_and_multiply_pbr( #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , sampler2D tex_vNt +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , float transform_sign +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , sampler2D tex_emissive @@ -94,7 +101,11 @@ PBRMix mix_pbr(PBRMix mix1, PBRMix mix2, float mix2_weight); out vec4 frag_data[4]; +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE uniform sampler2D alpha_ramp; +#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP +uniform sampler2D paint_map; +#endif // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#additional-textures uniform sampler2D detail_0_base_color; @@ -130,19 +141,25 @@ uniform vec3[4] emissiveColors; #endif 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; #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) in vec3 vary_tangents[4]; -flat in float vary_sign; +flat in float vary_signs[4]; #endif + +// vary_texcoord* are used for terrain composition, vary_coords are used for terrain UVs +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE in vec4 vary_texcoord0; in vec4 vary_texcoord1; +#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP +in vec2 vary_texcoord; +#endif +#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 void mirrorClip(vec3 position); @@ -150,11 +167,11 @@ 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 mikktspace(vec3 vNt, vec3 vT, float sign) { vec3 vN = vary_normal; - vec3 vB = vary_sign * cross(vN, vT); + vec3 vB = sign * cross(vN, vT); vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); tnorm *= gl_FrontFacing ? 1.0 : -1.0; @@ -168,11 +185,16 @@ void main() // Make sure we clip the terrain if we're in a mirror. mirrorClip(vary_position); + TerrainMix tm; +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE 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; - TerrainMix tm = get_terrain_mix_weights(alpha1, alpha2, alphaFinal); + tm = get_terrain_mix_weights(alpha1, alpha2, alphaFinal); +#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP + tm = get_terrain_usage_from_weight3(texture(paint_map, vary_texcoord).xyz); +#endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) // RGB = Occlusion, Roughness, Metal @@ -216,6 +238,9 @@ void main() #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , detail_0_normal +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , vary_signs[0] +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , detail_0_emissive @@ -231,7 +256,7 @@ void main() #endif ); #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) - mix2.vNt = mikktspace(mix2.vNt, vary_tangents[0]); + mix2.vNt = mikktspace(mix2.vNt, vary_tangents[0], vary_signs[0]); #endif pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.x); break; @@ -258,6 +283,9 @@ void main() #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , detail_1_normal +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , vary_signs[1] +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , detail_1_emissive @@ -273,7 +301,7 @@ void main() #endif ); #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) - mix2.vNt = mikktspace(mix2.vNt, vary_tangents[1]); + mix2.vNt = mikktspace(mix2.vNt, vary_tangents[1], vary_signs[1]); #endif pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.y); break; @@ -300,6 +328,9 @@ void main() #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , detail_2_normal +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , vary_signs[2] +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , detail_2_emissive @@ -315,7 +346,7 @@ void main() #endif ); #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) - mix2.vNt = mikktspace(mix2.vNt, vary_tangents[2]); + mix2.vNt = mikktspace(mix2.vNt, vary_tangents[2], vary_signs[2]); #endif pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.z); break; @@ -342,6 +373,9 @@ void main() #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , detail_3_normal +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , vary_signs[3] +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , detail_3_emissive @@ -357,7 +391,7 @@ void main() #endif ); #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) - mix2.vNt = mikktspace(mix2.vNt, vary_tangents[3]); + mix2.vNt = mikktspace(mix2.vNt, vary_tangents[3], vary_signs[3]); #endif pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.w); break; diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl index d1a380bf94..fb4b139662 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl @@ -51,7 +51,12 @@ #define TERRAIN_PBR_DETAIL_NORMAL -2 #define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3 +#define TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE 0 +#define TERRAIN_PAINT_TYPE_PBR_PAINTMAP 1 + +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 in vec3 vary_vertex_normal; +#endif vec3 srgb_to_linear(vec3 c); @@ -202,6 +207,45 @@ TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal) return tm; } +// A paintmap weight applier for 4 swatches. The input saves a channel by not +// storing swatch 1, and assuming the weights of the 4 swatches add to 1. +// The components of weight3 should be between 0 and 1 +// The sum of the components of weight3 should be between 0 and 1 +TerrainMix get_terrain_usage_from_weight3(vec3 weight3) +{ + // These steps ensure the output weights add to between 0 and 1 + weight3.xyz = max(vec3(0.0), weight3.xyz); + weight3.xyz /= max(1.0, weight3.x + weight3.y + weight3.z); + + TerrainMix tm; + + // Extract the first weight from the other weights + tm.weight.x = 1.0 - (weight3.x + weight3.y + weight3.z); + tm.weight.yzw = weight3.xyz; + ivec4 usage = max(ivec4(0), ivec4(ceil(tm.weight))); + + tm.type = (usage.x * MIX_X) | + (usage.y * MIX_Y) | + (usage.z * MIX_Z) | + (usage.w * MIX_W); + return tm; +} + +// Inverse of get_terrain_usage_from_weight3, excluding usage flags +// The components of weight should be between 0 and 1 +// The sum of the components of weight should be 1 +vec3 get_weight3_from_terrain_weight(vec4 weight) +{ + // These steps ensure the input weights add to 1 + weight = max(vec4(0.0), weight); + weight.x += 1.0 - sign(weight.x + weight.y + weight.z + weight.w); + weight /= weight.x + weight.y + weight.z + weight.w; + + // Then return the input weights with the first weight truncated + return weight.yzw; +} + +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 TerrainTriplanar _t_triplanar() { float sharpness = TERRAIN_TRIPLANAR_BLEND_FACTOR; @@ -219,6 +263,8 @@ TerrainTriplanar _t_triplanar() ((usage.z) * SAMPLE_Z); return tw; } +#endif + // Assume weights add to 1 float terrain_mix(TerrainMix tm, vec4 tms4) @@ -256,11 +302,12 @@ vec3 _t_normal_post_1(vec3 vNt0, float sign_or_zero) } // Triplanar-specific normal texture fixes -vec3 _t_normal_post_x(vec3 vNt0) +vec3 _t_normal_post_x(vec3 vNt0, float tangent_sign) { vec3 vNt_x = _t_normal_post_1(vNt0, sign(vary_vertex_normal.x)); // *HACK: Transform normals according to orientation of the UVs vNt_x.xy = vec2(-vNt_x.y, vNt_x.x); + vNt_x.xy *= tangent_sign; return vNt_x; } vec3 _t_normal_post_y(vec3 vNt0) @@ -285,6 +332,7 @@ PBRMix terrain_sample_pbr( #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , sampler2D tex_vNt + , float tangent_sign #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , sampler2D tex_emissive @@ -314,7 +362,7 @@ PBRMix terrain_sample_pbr( ); #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) // Triplanar-specific normal texture fix - mix_x.vNt = _t_normal_post_x(mix_x.vNt); + mix_x.vNt = _t_normal_post_x(mix_x.vNt, tangent_sign); #endif mix = mix_pbr(mix, mix_x, tw.weight.x); break; @@ -420,6 +468,9 @@ PBRMix terrain_sample_and_multiply_pbr( #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , sampler2D tex_vNt +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , float tangent_sign +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , sampler2D tex_emissive @@ -446,6 +497,9 @@ PBRMix terrain_sample_and_multiply_pbr( #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , tex_vNt +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , tangent_sign +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , tex_emissive diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl index f8e826bbdb..6791a22a76 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl @@ -28,31 +28,47 @@ #define TERRAIN_PBR_DETAIL_NORMAL -2 #define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3 +#define TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE 0 +#define TERRAIN_PAINT_TYPE_PBR_PAINTMAP 1 + uniform mat3 normal_matrix; uniform mat4 texture_matrix0; uniform mat4 modelview_matrix; uniform mat4 modelview_projection_matrix; +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP +uniform float region_scale; +#endif in vec3 position; in vec3 normal; in vec4 tangent; in vec4 diffuse_color; +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE in vec2 texcoord1; +#endif -out vec3 vary_vertex_normal; // Used by pbrterrainUtilF.glsl +out vec3 vary_position; out vec3 vary_normal; +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +out vec3 vary_vertex_normal; // Used by pbrterrainUtilF.glsl +#endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) out vec3 vary_tangents[4]; -flat out float vary_sign; +flat out float vary_signs[4]; #endif + +// vary_texcoord* are used for terrain composition, vary_coords are used for terrain UVs +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE out vec4 vary_texcoord0; out vec4 vary_texcoord1; +#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP +out vec2 vary_texcoord; +#endif #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: Each material uses only one texture transform, but the KHR texture // transform spec allows handling texture transforms separately for each @@ -60,7 +76,7 @@ out vec3 vary_position; uniform vec4[5] terrain_texture_transforms; 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); +vec4 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform); void main() { @@ -69,43 +85,52 @@ void main() vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; vec3 n = normal_matrix * normal; +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 vary_vertex_normal = normal; +#endif vec3 t = normal_matrix * tangent.xyz; #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) { vec4[2] ttt; + vec4 transformed_tangent; // 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)); + transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt); + vary_tangents[0] = normalize(transformed_tangent.xyz); + vary_signs[0] = transformed_tangent.w; // 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)); + transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt); + vary_tangents[1] = normalize(transformed_tangent.xyz); + vary_signs[1] = transformed_tangent.w; // 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)); + transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt); + vary_tangents[2] = normalize(transformed_tangent.xyz); + vary_signs[2] = transformed_tangent.w; // 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)); + transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt); + vary_tangents[3] = normalize(transformed_tangent.xyz); + vary_signs[3] = transformed_tangent.w; } - - vary_sign = tangent.w; #endif vary_normal = normalize(n); // Transform and pass tex coords { vec4[2] ttt; +#define transform_xy() terrain_texture_transform(position.xy, ttt) #if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 // 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) @@ -150,26 +175,30 @@ void main() 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); + vary_coords[0].xy = transform_xy(); // 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); + vary_coords[0].zw = transform_xy(); // 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); + vary_coords[1].xy = transform_xy(); // 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); + vary_coords[1].zw = transform_xy(); #endif } - vec4 tc = vec4(texcoord1,0,1); +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE + vec2 tc = texcoord1.xy; vary_texcoord0.zw = tc.xy; vary_texcoord1.xy = tc.xy-vec2(2.0, 0.0); vary_texcoord1.zw = tc.xy-vec2(1.0, 0.0); +#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP + vary_texcoord = position.xy / region_scale; +#endif } diff --git a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl index 767416d564..c75a0e0d5d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl @@ -94,36 +94,48 @@ vec2 terrain_texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform) // 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. +// In practice, this applies the inverse of the texture transform to the tangent. +// It is effectively an inverse of the rotation // *HACK: Assume the imported GLTF model did not have both normal texture // transforms and tangent vertices. The use of this function is inconsistent // with the GLTF sample viewer when that is the case. See getNormalInfo in // https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Viewer/47a191931461a6f2e14de48d6da0f0eb6ec2d147/source/Renderer/shaders/material_info.glsl // We may want to account for this case during GLTF model import. // -Cosmic,2023-06-06 -vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform) +vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform) { - vec2 weights = vec2(0, 1); - - // Apply texture animation first to avoid shearing and other artifacts (rotation only) - mat2 sl_rot_scale; - sl_rot_scale[0][0] = sl_animation_transform[0][0]; - sl_rot_scale[0][1] = sl_animation_transform[0][1]; - sl_rot_scale[1][0] = sl_animation_transform[1][0]; - sl_rot_scale[1][1] = sl_animation_transform[1][1]; - weights = sl_rot_scale * weights; - // Remove scale - weights = normalize(weights); - - // Convert to left-handed coordinate system - weights.y = -weights.y; + // Immediately convert to left-handed coordinate system, but it has no + // effect here because y is 0 ((1,0) -> (1,0)) + vec2 weights = vec2(1, 0); - // Apply KHR_texture_transform (rotation only) - float khr_rotation = khr_gltf_transform[0].z; + // Apply inverse KHR_texture_transform (rotation and scale sign 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; + vec2 khr_scale_sign = sign(khr_gltf_transform[0].xy); + weights *= khr_scale_sign.xy; + + // *NOTE: Delay conversion to right-handed coordinate system here, to + // remove the need for computing the inverse of the SL texture animation + // matrix. + + // Apply texture animation last to avoid shearing and other artifacts (rotation only) + mat2 inv_sl_rot_scale; + inv_sl_rot_scale[0][0] = sl_animation_transform[0][0]; + inv_sl_rot_scale[0][1] = sl_animation_transform[0][1]; + inv_sl_rot_scale[1][0] = sl_animation_transform[1][0]; + inv_sl_rot_scale[1][1] = sl_animation_transform[1][1]; + weights = inv_sl_rot_scale * weights; + // *NOTE: Scale to be removed later + + // Set weights to default if 0 for some reason + weights.x += 1.0 - abs(sign(sign(weights.x) + (0.5 * sign(weights.y)))); + + // Remove scale from SL texture animation transform + weights = normalize(weights); // Convert back to right-handed coordinate system weights.y = -weights.y; @@ -132,27 +144,41 @@ vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] kh // from the normal and tangent, as seen in the fragment shader vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz); - return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz); + // An additional sign flip prevents the binormal from being flipped as a + // result of a propagation of the tangent sign during the cross product. + float sign_flip = khr_scale_sign.x * khr_scale_sign.y; + return vec4((weights.x * vertex_tangent.xyz) + (weights.y * vertex_binormal.xyz), vertex_tangent.w * sign_flip); } // Similar to tangent_space_transform but no texture animation support. -vec3 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform) +vec4 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); + // Immediately convert to left-handed coordinate system, but it has no + // effect here because y is 0 ((1,0) -> (1,0)) + vec2 weights = vec2(1, 0); - // Apply KHR_texture_transform (rotation only) - float khr_rotation = khr_gltf_transform[0].z; + // Apply inverse KHR_texture_transform (rotation and scale sign 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; + vec2 khr_scale_sign = sign(khr_gltf_transform[0].xy); + weights *= khr_scale_sign.xy; + + // Set weights to default if 0 for some reason + weights.x += 1.0 - abs(sign(sign(weights.x) + (0.5 * sign(weights.y)))); // Convert back to right-handed coordinate system weights.y = -weights.y; + // Similar to the MikkTSpace-compatible method of extracting the binormal + // from the normal and tangent, as seen in the fragment shader vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz); - return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz); + // An additional sign flip prevents the binormal from being flipped as a + // result of a propagation of the tangent sign during the cross product. + float sign_flip = khr_scale_sign.x * khr_scale_sign.y; + return vec4((weights.x * vertex_tangent.xyz) + (weights.y * vertex_binormal.xyz), vertex_tangent.w * sign_flip); } diff --git a/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl new file mode 100644 index 0000000000..cf20653a0f --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl @@ -0,0 +1,62 @@ +/** + * @file terrainBakeF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +/*[EXTRA_CODE_HERE]*/ + +out vec4 frag_color; + +struct TerrainMix +{ + vec4 weight; + int type; +}; + +TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal); + +uniform sampler2D alpha_ramp; + +// vary_texcoord* are used for terrain composition +in vec4 vary_texcoord0; +in vec4 vary_texcoord1; + +void main() +{ + TerrainMix tm; + 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; + + tm = get_terrain_mix_weights(alpha1, alpha2, alphaFinal); + + // tm.weight.x can be ignored. The paintmap saves a channel by not storing + // swatch 1, and assuming the weights of the 4 swatches add to 1. + // TERRAIN_PAINT_PRECISION emulates loss of precision at lower bit depth + // when a corresponding low-bit image format is not available. Because + // integral values at one depth cannot be precisely represented at another + // bit depth, rounding is required. To maximize numerical stability for + // future conversions, bit depth conversions should round to the nearest + // integer, not floor or ceil. + frag_color = max(vec4(round(tm.weight.yzw * TERRAIN_PAINT_PRECISION) / TERRAIN_PAINT_PRECISION, 1.0), vec4(0)); +} diff --git a/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeV.glsl b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeV.glsl new file mode 100644 index 0000000000..fd150b54ad --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeV.glsl @@ -0,0 +1,42 @@ +/** + * @file pbrTerrainBakeV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat4 modelview_projection_matrix; + +in vec3 position; +in vec2 texcoord1; + +out vec4 vary_texcoord0; +out vec4 vary_texcoord1; + +void main() +{ + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + vec2 tc = texcoord1.xy; + vary_texcoord0.zw = tc.xy; + vary_texcoord1.xy = tc.xy-vec2(2.0, 0.0); + vary_texcoord1.zw = tc.xy-vec2(1.0, 0.0); +} + |