DRTVWR-592: (WIP) (has debug) Apply triplanar optimization technique to PBR material sampling. Use slightly different alpha ramp to hide unused materials
parent
6e949e5d63
commit
1d885181d8
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -49,11 +49,62 @@ in vec3 vary_vertex_normal;
|
|||
|
||||
vec3 srgb_to_linear(vec3 c);
|
||||
|
||||
float terrain_mix(vec4 samples, float alpha1, float alpha2, float alphaFinal)
|
||||
// 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
|
||||
{
|
||||
return mix( mix(samples.w, samples.z, alpha2), mix(samples.y, samples.x, alpha1), alphaFinal );
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue