summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl61
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl288
2 files changed, 301 insertions, 48 deletions
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl
index 7febbe280e..7b5eba14b7 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl
@@ -82,6 +82,19 @@ vec4 sample_and_mix_color4(float alpha1, float alpha2, float alphaFinal, Terrain
vec3 sample_and_mix_vector3(float alpha1, float alpha2, float alphaFinal, TerrainCoord texcoord, vec3[4] factors, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3);
vec3 sample_and_mix_normal(float alpha1, float alpha2, float alphaFinal, TerrainCoord texcoord, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3);
+#if 1 // TODO: Remove
+#define TERRAIN_DEBUG 1 // TODO: Remove debug
+struct TerrainMix
+{
+ vec4 weight;
+ int type;
+#if TERRAIN_DEBUG
+ ivec4 usage;
+#endif
+};
+TerrainMix _t_mix(float alpha1, float alpha2, float alphaFinal);
+#endif
+
void main()
{
@@ -125,16 +138,60 @@ void main()
// from mikktspace.com
vec3 vNt = sample_and_mix_normal(alpha1, alpha2, alphaFinal, terrain_texcoord, detail_0_normal, detail_1_normal, detail_2_normal, detail_3_normal);
- float sign = vary_sign;
vec3 vN = vary_normal;
vec3 vT = vary_tangent.xyz;
- vec3 vB = sign * cross(vN, vT);
+ 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;
+#if 0 // TODO: Remove (terrain weights visualization)
+ TerrainMix tm = _t_mix(alpha1, alpha2, alphaFinal);
+#if 1
+ // Show full usage and weights
+ float uw = 0.3;
+#if 1
+#if 0
+ vec4 mix_usage = vec4(tm.usage);
+#else
+ vec4 mix_usage = vec4(tm.weight);
+#endif
+#else
+ // Version with easier-to-see boundaries of weights vs usage
+ vec4 mix_usage = mix(vec4(tm.usage),
+ mix(max(vec4(0.0), sign(tm.weight - 0.01)),
+ max(vec4(0.0), sign(tm.weight - 0.005)),
+ 0.5),
+ uw);
+#endif
+ col.xyz = mix_usage.xyz;
+ col.x = max(col.x, mix_usage.w);
+ //col.y = 0.0;
+ //col.z = 0.0;
+#else
+ // Show places where weight > usage + tolerance
+ float tolerance = 0.005;
+ vec4 weight_gt_usage = sign(
+ max(
+ vec4(0.0),
+ (tm.weight - (vec4(tm.usage) + vec4(tolerance)))
+ )
+ );
+ col.xyz = weight_gt_usage.xyz;
+ col.x = max(col.x, weight_gt_usage.w);
+#endif
+#endif
+#if 0 // TODO: Remove (material channel discriminator)
+ //col.rgb = vec3(0.0, 1.0, 0.0);
+ //col.rgb = spec.rgb;
+ //col.rgb = (vNt + 1.0) / 2.0;
+ col.rgb = (tnorm + 1.0) / 2.0;
+ spec.rgb = vec3(1.0, 1.0, 0.0);
+ tnorm = vary_normal;
+ emissive = vec3(0);
+#endif
frag_data[0] = max(vec4(col.xyz, 0.0), vec4(0)); // Diffuse
frag_data[1] = max(vec4(spec.rgb, base_color_factor_alpha), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal.
frag_data[2] = max(vec4(encode_normal(tnorm), base_color_factor_alpha, GBUFFER_FLAG_HAS_PBR), vec4(0)); // normal, environment intensity, flags
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl
index e2d6cdb2d6..59b273afc3 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl
@@ -49,11 +49,62 @@ in vec3 vary_vertex_normal;
vec3 srgb_to_linear(vec3 c);
+// A relatively agressive threshold ensures that only one or two materials are used in most places
+#define TERRAIN_RAMP_MIX_THRESHOLD 0.1
+
+#define MIX_X 1 << 3
+#define MIX_Y 1 << 2
+#define MIX_Z 1 << 1
+#define MIX_W 1 << 0
+
+#define TERRAIN_DEBUG 1 // TODO: Remove debug
+struct TerrainMix
+{
+ vec4 weight;
+ int type;
+#if TERRAIN_DEBUG
+ ivec4 usage;
+#endif
+};
+
+#define TerrainMixSample vec4[4]
+#define TerrainMixSample3 vec3[4]
+
+TerrainMix _t_mix(float alpha1, float alpha2, float alphaFinal)
+{
+ TerrainMix tm;
+ vec4 sample_x = vec4(1,0,0,0);
+ vec4 sample_y = vec4(0,1,0,0);
+ vec4 sample_z = vec4(0,0,1,0);
+ vec4 sample_w = vec4(0,0,0,1);
+
+ tm.weight = mix( mix(sample_w, sample_z, alpha2), mix(sample_y, sample_x, alpha1), alphaFinal );
+ tm.weight -= TERRAIN_RAMP_MIX_THRESHOLD;
+ ivec4 usage = max(ivec4(0), ivec4(ceil(tm.weight)));
+ // Prevent negative weights and keep weights balanced
+ tm.weight = normalize(tm.weight*vec4(usage));
+
+ tm.type = (usage.x * MIX_X) |
+ (usage.y * MIX_Y) |
+ (usage.z * MIX_Z) |
+ (usage.w * MIX_W);
+#if TERRAIN_DEBUG // TODO: Remove debug
+ tm.usage = usage;
+#endif
+ return tm;
+}
+
float terrain_mix(vec4 samples, float alpha1, float alpha2, float alphaFinal)
{
- return mix( mix(samples.w, samples.z, alpha2), mix(samples.y, samples.x, alpha1), alphaFinal );
+ TerrainMix tm = _t_mix(alpha1, alpha2, alphaFinal);
+ // Assume weights are normalized
+ return tm.weight.x * samples.x +
+ tm.weight.y * samples.y +
+ tm.weight.z * samples.z +
+ tm.weight.w * samples.w;
}
+#if 0 // TODO: Decide if still needed, and if so, use _t_mix internally for weights
vec3 terrain_mix(vec3[4] samples, float alpha1, float alpha2, float alphaFinal)
{
return mix( mix(samples[3], samples[2], alpha2), mix(samples[1], samples[0], alpha1), alphaFinal );
@@ -63,6 +114,25 @@ vec4 terrain_mix(vec4[4] samples, float alpha1, float alpha2, float alphaFinal)
{
return mix( mix(samples[3], samples[2], alpha2), mix(samples[1], samples[0], alpha1), alphaFinal );
}
+#endif
+
+vec4 terrain_mix(TerrainMix tm, TerrainMixSample tms)
+{
+ // Assume weights are normalized
+ return tm.weight.x * tms[0] +
+ tm.weight.y * tms[1] +
+ tm.weight.z * tms[2] +
+ tm.weight.w * tms[3];
+}
+
+vec3 terrain_mix(TerrainMix tm, TerrainMixSample3 tms3)
+{
+ // Assume weights are normalized
+ return tm.weight.x * tms3[0] +
+ tm.weight.y * tms3[1] +
+ tm.weight.z * tms3[2] +
+ tm.weight.w * tms3[3];
+}
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
// Triplanar mapping
@@ -98,15 +168,12 @@ TerrainWeight _t_weight(TerrainCoord terrain_coord)
vec3 weight_signed = normalize(pow(abs(vary_vertex_normal), vec3(sharpness)));
weight_signed -= vec3(threshold);
TerrainWeight tw;
- tw.weight = max(vec3(0), weight_signed);
+ // *NOTE: Make sure the threshold doesn't affect the materials
+ tw.weight = normalize(max(vec3(0), weight_signed));
ivec3 usage = ivec3(round(max(vec3(0), sign(weight_signed))));
tw.type = ((usage.x) * SAMPLE_X) |
((usage.y) * SAMPLE_Y) |
((usage.z) * SAMPLE_Z);
-#if TERRAIN_DEBUG
- tw.weight_signed = weight_signed;
- tw.usage = usage;
-#endif
return tw;
}
@@ -256,59 +323,188 @@ vec4 terrain_texture_color(sampler2D tex, TerrainCoord terrain_coord)
}
#endif
+// The goal of _tmix_sample and related functions is to only sample textures when necessary, ignoring if the weights are low.
+// *TODO: Currently, there is much more switch..case branching than needed. This could be simplified by branching per-material rather than per-texture.
+
+TerrainMixSample _tmix_sample(TerrainMix tm, TerrainCoord texcoord, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3)
+{
+ TerrainMixSample tms;
+
+ switch (tm.type & MIX_X)
+ {
+ case MIX_X:
+ tms[0] = terrain_texture(tex0, texcoord);
+ break;
+ default:
+ tms[0] = vec4(1.0, 0.0, 1.0, 1.0);
+ break;
+ }
+ switch (tm.type & MIX_Y)
+ {
+ case MIX_Y:
+ tms[1] = terrain_texture(tex1, texcoord);
+ break;
+ default:
+ tms[1] = vec4(1.0, 0.0, 1.0, 1.0);
+ break;
+ }
+ switch (tm.type & MIX_Z)
+ {
+ case MIX_Z:
+ tms[2] = terrain_texture(tex2, texcoord);
+ break;
+ default:
+ tms[2] = vec4(1.0, 0.0, 1.0, 1.0);
+ break;
+ }
+ switch (tm.type & MIX_W)
+ {
+ case MIX_W:
+ tms[3] = terrain_texture(tex3, texcoord);
+ break;
+ default:
+ tms[3] = vec4(1.0, 0.0, 1.0, 1.0);
+ break;
+ }
+
+ return tms;
+}
+
+TerrainMixSample _tmix_sample_color(TerrainMix tm, TerrainCoord texcoord, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3)
+{
+ TerrainMixSample tmix;
+
+ switch (tm.type & MIX_X)
+ {
+ case MIX_X:
+ tmix[0] = terrain_texture_color(tex0, texcoord);
+ break;
+ default:
+ tmix[0] = vec4(1.0, 0.0, 1.0, 1.0);
+ break;
+ }
+ switch (tm.type & MIX_Y)
+ {
+ case MIX_Y:
+ tmix[1] = terrain_texture_color(tex1, texcoord);
+ break;
+ default:
+ tmix[1] = vec4(1.0, 0.0, 1.0, 1.0);
+ break;
+ }
+ switch (tm.type & MIX_Z)
+ {
+ case MIX_Z:
+ tmix[2] = terrain_texture_color(tex2, texcoord);
+ break;
+ default:
+ tmix[2] = vec4(1.0, 0.0, 1.0, 1.0);
+ break;
+ }
+ switch (tm.type & MIX_W)
+ {
+ case MIX_W:
+ tmix[3] = terrain_texture_color(tex3, texcoord);
+ break;
+ default:
+ tmix[3] = vec4(1.0, 0.0, 1.0, 1.0);
+ break;
+ }
+
+ return tmix;
+}
+
+TerrainMixSample3 _tmix_sample_normal(TerrainMix tm, TerrainCoord texcoord, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3)
+{
+ TerrainMixSample3 tmix3;
+
+ switch (tm.type & MIX_X)
+ {
+ case MIX_X:
+ tmix3[0] = terrain_texture_normal(tex0, texcoord);
+ break;
+ default:
+ tmix3[0] = vec3(1.0, 0.0, 1.0);
+ break;
+ }
+ switch (tm.type & MIX_Y)
+ {
+ case MIX_Y:
+ tmix3[1] = terrain_texture_normal(tex1, texcoord);
+ break;
+ default:
+ tmix3[1] = vec3(1.0, 0.0, 1.0);
+ break;
+ }
+ switch (tm.type & MIX_Z)
+ {
+ case MIX_Z:
+ tmix3[2] = terrain_texture_normal(tex2, texcoord);
+ break;
+ default:
+ tmix3[2] = vec3(1.0, 0.0, 1.0);
+ break;
+ }
+ switch (tm.type & MIX_W)
+ {
+ case MIX_W:
+ tmix3[3] = terrain_texture_normal(tex3, texcoord);
+ break;
+ default:
+ tmix3[3] = vec3(1.0, 0.0, 1.0);
+ break;
+ }
+
+ return tmix3;
+}
+
vec3 sample_and_mix_color3(float alpha1, float alpha2, float alphaFinal, TerrainCoord texcoord, vec3[4] factors, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3)
{
- vec3[4] samples;
- samples[0] = terrain_texture(tex0, texcoord).xyz;
- samples[1] = terrain_texture(tex1, texcoord).xyz;
- samples[2] = terrain_texture(tex2, texcoord).xyz;
- samples[3] = terrain_texture(tex3, texcoord).xyz;
- samples[0] = srgb_to_linear(samples[0]);
- samples[1] = srgb_to_linear(samples[1]);
- samples[2] = srgb_to_linear(samples[2]);
- samples[3] = srgb_to_linear(samples[3]);
- samples[0] *= factors[0];
- samples[1] *= factors[1];
- samples[2] *= factors[2];
- samples[3] *= factors[3];
- return terrain_mix(samples, alpha1, alpha2, alphaFinal);
+ TerrainMix tm = _t_mix(alpha1, alpha2, alphaFinal);
+ TerrainMixSample tms = _tmix_sample_color(tm, texcoord, tex0, tex1, tex2, tex3);
+ vec3[4] tms3;
+ tms3[0] = tms[0].xyz;
+ tms3[1] = tms[1].xyz;
+ tms3[2] = tms[2].xyz;
+ tms3[3] = tms[3].xyz;
+ tms3[0] *= factors[0];
+ tms3[1] *= factors[1];
+ tms3[2] *= factors[2];
+ tms3[3] *= factors[3];
+ return terrain_mix(tm, tms3);
}
vec4 sample_and_mix_color4(float alpha1, float alpha2, float alphaFinal, TerrainCoord texcoord, vec4[4] factors, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3)
{
- vec4[4] samples;
- samples[0] = terrain_texture_color(tex0, texcoord);
- samples[1] = terrain_texture_color(tex1, texcoord);
- samples[2] = terrain_texture_color(tex2, texcoord);
- samples[3] = terrain_texture_color(tex3, texcoord);
- samples[0] *= factors[0];
- samples[1] *= factors[1];
- samples[2] *= factors[2];
- samples[3] *= factors[3];
- return terrain_mix(samples, alpha1, alpha2, alphaFinal);
+ TerrainMix tm = _t_mix(alpha1, alpha2, alphaFinal);
+ TerrainMixSample tms = _tmix_sample_color(tm, texcoord, tex0, tex1, tex2, tex3);
+ tms[0] *= factors[0];
+ tms[1] *= factors[1];
+ tms[2] *= factors[2];
+ tms[3] *= factors[3];
+ return terrain_mix(tm, tms);
}
vec3 sample_and_mix_vector3(float alpha1, float alpha2, float alphaFinal, TerrainCoord texcoord, vec3[4] factors, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3)
{
- vec3[4] samples;
- samples[0] = terrain_texture(tex0, texcoord).xyz;
- samples[1] = terrain_texture(tex1, texcoord).xyz;
- samples[2] = terrain_texture(tex2, texcoord).xyz;
- samples[3] = terrain_texture(tex3, texcoord).xyz;
- samples[0] *= factors[0];
- samples[1] *= factors[1];
- samples[2] *= factors[2];
- samples[3] *= factors[3];
- return terrain_mix(samples, alpha1, alpha2, alphaFinal);
+ TerrainMix tm = _t_mix(alpha1, alpha2, alphaFinal);
+ TerrainMixSample tms = _tmix_sample(tm, texcoord, tex0, tex1, tex2, tex3);
+ vec3[4] tms3;
+ tms3[0] = tms[0].xyz;
+ tms3[1] = tms[1].xyz;
+ tms3[2] = tms[2].xyz;
+ tms3[3] = tms[3].xyz;
+ tms3[0] *= factors[0];
+ tms3[1] *= factors[1];
+ tms3[2] *= factors[2];
+ tms3[3] *= factors[3];
+ return terrain_mix(tm, tms3);
}
// Returns the unpacked normal texture in range [-1, 1]
vec3 sample_and_mix_normal(float alpha1, float alpha2, float alphaFinal, TerrainCoord texcoord, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3)
{
- vec3[4] samples;
- samples[0] = terrain_texture_normal(tex0, texcoord).xyz;
- samples[1] = terrain_texture_normal(tex1, texcoord).xyz;
- samples[2] = terrain_texture_normal(tex2, texcoord).xyz;
- samples[3] = terrain_texture_normal(tex3, texcoord).xyz;
- return terrain_mix(samples, alpha1, alpha2, alphaFinal);
+ TerrainMix tm = _t_mix(alpha1, alpha2, alphaFinal);
+ TerrainMixSample3 tms3 = _tmix_sample_normal(tm, texcoord, tex0, tex1, tex2, tex3);
+ return terrain_mix(tm, tms3);
}