diff options
| author | Cosmic Linden <cosmic@lindenlab.com> | 2023-10-13 10:42:29 -0700 | 
|---|---|---|
| committer | Cosmic Linden <cosmic@lindenlab.com> | 2023-10-13 10:42:29 -0700 | 
| commit | 1d885181d850388feb89c92a018cb591b5cc7f18 (patch) | |
| tree | d34e8da1ae85b51e985c7e53d9a0f708915279c8 | |
| parent | 6e949e5d63c56a899b6a7745fcca04e0cd2f9639 (diff) | |
DRTVWR-592: (WIP) (has debug) Apply triplanar optimization technique to PBR material sampling. Use slightly different alpha ramp to hide unused materials
| -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);  }  | 
