diff options
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl | 61 | ||||
-rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl | 288 |
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); } |