DRTVWR-592: (WIP) PBR Terrain: Improve orientation of textures and normal maps for triplanar mapping, minor cleanup
parent
23ca385f3d
commit
db4bc52829
|
|
@ -35,7 +35,7 @@ out vec4 frag_data[4];
|
|||
|
||||
uniform sampler2D alpha_ramp;
|
||||
|
||||
// *TODO: Configurable quality level which disables PBR features on machines
|
||||
// *TODO: More configurable quality level which disables PBR features on machines
|
||||
// with limited texture availability
|
||||
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#additional-textures
|
||||
uniform sampler2D detail_0_base_color;
|
||||
|
|
@ -57,7 +57,6 @@ uniform sampler2D detail_2_emissive;
|
|||
uniform sampler2D detail_3_emissive;
|
||||
#endif
|
||||
|
||||
// *TODO: More efficient packing?
|
||||
uniform vec4[4] baseColorFactors; // See also vertex_color in pbropaqueV.glsl
|
||||
uniform vec4 metallicFactors;
|
||||
uniform vec4 roughnessFactors;
|
||||
|
|
@ -66,7 +65,9 @@ uniform vec3[4] emissiveColors;
|
|||
#endif
|
||||
uniform vec4 minimum_alphas; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff()
|
||||
|
||||
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
||||
in vec4[2] vary_coords;
|
||||
#endif
|
||||
in vec3 vary_normal;
|
||||
in vec3 vary_tangent;
|
||||
flat in float vary_sign;
|
||||
|
|
@ -79,7 +80,7 @@ float terrain_mix(vec4 samples, float alpha1, float alpha2, float alphaFinal);
|
|||
vec3 sample_and_mix_color3(float alpha1, float alpha2, float alphaFinal, TerrainCoord texcoord, vec3[4] factors, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3);
|
||||
vec4 sample_and_mix_color4(float alpha1, float alpha2, float alphaFinal, TerrainCoord texcoord, vec4[4] factors, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3);
|
||||
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_vector3_no_scale(float alpha1, float alpha2, float alphaFinal, TerrainCoord texcoord, 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);
|
||||
|
||||
void main()
|
||||
{
|
||||
|
|
@ -101,7 +102,6 @@ void main()
|
|||
discard;
|
||||
}
|
||||
|
||||
vec3 normal_texture = sample_and_mix_vector3_no_scale(alpha1, alpha2, alphaFinal, terrain_texcoord, detail_0_normal, detail_1_normal, detail_2_normal, detail_3_normal);
|
||||
|
||||
vec3[4] orm_factors;
|
||||
orm_factors[0] = vec3(1.0, roughnessFactors.x, metallicFactors.x);
|
||||
|
|
@ -124,7 +124,7 @@ void main()
|
|||
float base_color_factor_alpha = terrain_mix(vec4(baseColorFactors[0].z, baseColorFactors[1].z, baseColorFactors[2].z, baseColorFactors[3].z), alpha1, alpha2, alphaFinal);
|
||||
|
||||
// from mikktspace.com
|
||||
vec3 vNt = normal_texture.xyz*2.0-1.0;
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -65,14 +65,56 @@ vec4 terrain_mix(vec4[4] samples, float alpha1, float alpha2, float alphaFinal)
|
|||
}
|
||||
|
||||
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
||||
// Pre-transformed texture coordinates for each axial uv slice (Packing: xy, yz, zx, unused)
|
||||
#define TerrainCoord vec4[2]
|
||||
// Triplanar mapping
|
||||
|
||||
// Pre-transformed texture coordinates for each axial uv slice (Packing: xy, yz, (-x)z, unused)
|
||||
#define TerrainCoord vec4[2]
|
||||
|
||||
vec4 _t_texture(sampler2D tex, vec2 uv_unflipped, float sign)
|
||||
{
|
||||
// If the vertex normal is negative, flip the texture back
|
||||
// right-side up.
|
||||
vec2 uv = uv_unflipped * vec2(sign, 1);
|
||||
return texture(tex, uv);
|
||||
}
|
||||
|
||||
vec3 _t_texture_n(sampler2D tex, vec2 uv_unflipped, float sign)
|
||||
{
|
||||
// Unpack normal from pixel to vector
|
||||
vec3 n = _t_texture(tex, uv_unflipped, sign).xyz*2.0-1.0;
|
||||
// If the sign is negative, rotate normal by 180 degrees
|
||||
n.xy = (min(0, sign) * n.xy) + (min(0, -sign) * -n.xy);
|
||||
return n;
|
||||
}
|
||||
|
||||
vec4 terrain_texture(sampler2D tex, TerrainCoord terrain_coord)
|
||||
{
|
||||
vec4 x = texture(tex, terrain_coord[0].zw);
|
||||
vec4 y = texture(tex, terrain_coord[1].xy);
|
||||
vec4 z = texture(tex, terrain_coord[0].xy);
|
||||
// Multiplying the UVs by the sign of the normal flips the texture upright.
|
||||
vec4 x = _t_texture(tex, terrain_coord[0].zw, sign(vary_vertex_normal.x));
|
||||
vec4 y = _t_texture(tex, terrain_coord[1].xy, sign(vary_vertex_normal.y));
|
||||
vec4 z = _t_texture(tex, terrain_coord[0].xy, sign(vary_vertex_normal.z));
|
||||
float sharpness = TERRAIN_TRIPLANAR_BLEND_FACTOR;
|
||||
vec3 weight = pow(abs(vary_vertex_normal), vec3(sharpness));
|
||||
return ((x * weight.x) + (y * weight.y) + (z * weight.z)) / (weight.x + weight.y + weight.z);
|
||||
}
|
||||
|
||||
// Specialized triplanar normal texture sampling implementation, taking into
|
||||
// account how the rotation of the texture affects the lighting and trying to
|
||||
// negate that.
|
||||
// *TODO: Decide if we want this. It may be better to just calculate the
|
||||
// tangents on-the-fly here rather than messing with the normals, due to the
|
||||
// subtleties of the effects of triplanar mapping on UVs. These sampled normals
|
||||
// are only valid on the faces of a cube, and the pregenerated tangents are
|
||||
// only valid for uv = xy.
|
||||
// *NOTE: Bottom face has not been tested
|
||||
vec3 terrain_texture_normal(sampler2D tex, TerrainCoord terrain_coord)
|
||||
{
|
||||
vec3 x = _t_texture_n(tex, terrain_coord[0].zw, sign(vary_vertex_normal.x));
|
||||
x.xy = vec2(-x.y, x.x);
|
||||
vec3 y = _t_texture_n(tex, terrain_coord[1].xy, sign(vary_vertex_normal.y));
|
||||
y.xy = -y.xy;
|
||||
vec3 z = _t_texture_n(tex, terrain_coord[0].xy, sign(vary_vertex_normal.z));
|
||||
|
||||
float sharpness = TERRAIN_TRIPLANAR_BLEND_FACTOR;
|
||||
vec3 weight = pow(abs(vary_vertex_normal), vec3(sharpness));
|
||||
return ((x * weight.x) + (y * weight.y) + (z * weight.z)) / (weight.x + weight.y + weight.z);
|
||||
|
|
@ -83,6 +125,11 @@ vec4 terrain_texture(sampler2D tex, TerrainCoord terrain_coord)
|
|||
{
|
||||
return texture(tex, terrain_coord);
|
||||
}
|
||||
|
||||
vec3 terrain_texture_normal(sampler2D tex, TerrainCoord terrain_coord)
|
||||
{
|
||||
return texture(tex, terrain_coord).xyz;
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 sample_and_mix_color3(float alpha1, float alpha2, float alphaFinal, TerrainCoord texcoord, vec3[4] factors, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3)
|
||||
|
|
@ -135,12 +182,13 @@ vec3 sample_and_mix_vector3(float alpha1, float alpha2, float alphaFinal, Terrai
|
|||
return terrain_mix(samples, alpha1, alpha2, alphaFinal);
|
||||
}
|
||||
|
||||
vec3 sample_and_mix_vector3_no_scale(float alpha1, float alpha2, float alphaFinal, TerrainCoord texcoord, sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3)
|
||||
// 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(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] = 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@ in vec4 diffuse_color;
|
|||
in vec2 texcoord0;
|
||||
in vec2 texcoord1;
|
||||
|
||||
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
||||
out vec4[2] vary_coords;
|
||||
#endif
|
||||
out vec3 vary_vertex_normal; // Used by pbrterrainUtilF.glsl
|
||||
out vec3 vary_normal;
|
||||
out vec3 vary_tangent;
|
||||
|
|
@ -42,22 +44,13 @@ flat out float vary_sign;
|
|||
out vec4 vary_texcoord0;
|
||||
out vec4 vary_texcoord1;
|
||||
|
||||
uniform vec4 object_plane_s;
|
||||
uniform vec4 object_plane_t;
|
||||
// *HACK: tangent_space_transform should use texture_normal_transform, or maybe
|
||||
// we shouldn't use tangent_space_transform at all. See the call to
|
||||
// tangent_space_transform below.
|
||||
uniform vec4[2] texture_base_color_transform;
|
||||
|
||||
vec4 texgen_object_pbr(vec4 tc, mat4 mat, vec4 tp0, vec4 tp1)
|
||||
{
|
||||
vec4 tcoord;
|
||||
|
||||
tcoord.x = dot(tc, tp0);
|
||||
tcoord.y = dot(tc, tp1);
|
||||
tcoord.z = tcoord.z;
|
||||
tcoord.w = tcoord.w;
|
||||
|
||||
tcoord = mat * tcoord;
|
||||
|
||||
return tcoord;
|
||||
}
|
||||
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);
|
||||
|
||||
void main()
|
||||
{
|
||||
|
|
@ -65,23 +58,36 @@ void main()
|
|||
gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
|
||||
|
||||
vec3 n = normal_matrix * normal;
|
||||
// *TODO: Looks like terrain normals are per-vertex when they should be per-triangle instead, causing incorrect values on triangles touching steep edges of terrain
|
||||
vary_vertex_normal = normal;
|
||||
vec3 t = normal_matrix * tangent.xyz;
|
||||
|
||||
vary_tangent = normalize(t);
|
||||
// *TODO: Decide if we want this. It may be better to just calculate the
|
||||
// tangents on-the-fly in the fragment shader, due to the subtleties of the
|
||||
// effect of triplanar mapping on UVs.
|
||||
// *HACK: Should be using texture_normal_transform here. The KHR texture
|
||||
// transform spec requires handling texture transforms separately for each
|
||||
// individual texture.
|
||||
vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_base_color_transform, texture_matrix0));
|
||||
vary_sign = tangent.w;
|
||||
vary_normal = normalize(n);
|
||||
|
||||
// Transform and pass tex coords
|
||||
// *NOTE: KHR texture transform is ignored for now
|
||||
vary_texcoord0.xy = texgen_object_pbr(vec4(texcoord0, 0, 1), texture_matrix0, object_plane_s, object_plane_t).xy;
|
||||
|
||||
vec4 tc = vec4(texcoord1,0,1); // TODO: This is redundant. Better to just use position and ignore texcoord? (We still need to decide how to handle alpha ramp, though...)
|
||||
vary_coords[0].xy = texgen_object_pbr(vec4(position.xy, 0, 1), texture_matrix0, object_plane_s, object_plane_t).xy;
|
||||
vary_coords[0].zw = texgen_object_pbr(vec4(position.yz, 0, 1), texture_matrix0, object_plane_s, object_plane_t).xy;
|
||||
vary_coords[1].xy = texgen_object_pbr(vec4(position.zx, 0, 1), texture_matrix0, object_plane_s, object_plane_t).xy;
|
||||
// *HACK: texture_base_color_transform is used for all of these here, but
|
||||
// the KHR texture transform spec requires handling texture transforms
|
||||
// separately for each individual texture.
|
||||
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
||||
// xy
|
||||
vary_coords[0].xy = texture_transform(position.xy, texture_base_color_transform, texture_matrix0);
|
||||
// yz
|
||||
vary_coords[0].zw = texture_transform(position.yz, texture_base_color_transform, texture_matrix0);
|
||||
// (-x)z
|
||||
vary_coords[1].xy = texture_transform(position.xz * vec2(-1, 1), texture_base_color_transform, texture_matrix0);
|
||||
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
|
||||
vary_texcoord0.xy = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0);
|
||||
#endif
|
||||
|
||||
vec4 tc = vec4(texcoord1,0,1);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl
|
|||
// Apply texture animation first to avoid shearing and other artifacts
|
||||
texcoord = (sl_animation_transform * vec4(texcoord, 0, 1)).xy;
|
||||
// Convert to left-handed coordinate system. The offset of 1 is necessary
|
||||
// for rotations to be applied correctly.
|
||||
// for rotation and scale to be applied correctly.
|
||||
texcoord.y = 1.0 - texcoord.y;
|
||||
texcoord = khr_texture_transform(texcoord, khr_gltf_transform[0].xy, khr_gltf_transform[0].z, khr_gltf_transform[1].xy);
|
||||
// Convert back to right-handed coordinate system
|
||||
|
|
|
|||
|
|
@ -383,16 +383,6 @@ void LLDrawPoolTerrain::renderFullShaderPBR(BOOL local_materials)
|
|||
materials = &gLocalTerrainMaterials.mDetailMaterials;
|
||||
}
|
||||
|
||||
// *TODO: Figure out why this offset is *sometimes* producing seams at the region edge, and repeat jumps when crossing regions, when RenderTerrainPBRScale is not a factor of the region scale.
|
||||
LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal();
|
||||
F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sPBRDetailScale)*sPBRDetailScale;
|
||||
F32 offset_y = (F32)fmod(region_origin_global.mdV[VY], 1.0/(F64)sPBRDetailScale)*sPBRDetailScale;
|
||||
|
||||
LLVector4 tp0, tp1;
|
||||
|
||||
tp0.setVec(sPBRDetailScale, 0.0f, 0.0f, offset_x);
|
||||
tp1.setVec(0.0f, sPBRDetailScale, 0.0f, offset_y);
|
||||
|
||||
constexpr U32 terrain_material_count = 1 + LLViewerShaderMgr::TERRAIN_DETAIL3_BASE_COLOR - LLViewerShaderMgr::TERRAIN_DETAIL0_BASE_COLOR;
|
||||
S32 detail_basecolor[terrain_material_count];
|
||||
S32 detail_normal[terrain_material_count];
|
||||
|
|
@ -463,8 +453,22 @@ void LLDrawPoolTerrain::renderFullShaderPBR(BOOL local_materials)
|
|||
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
|
||||
llassert(shader);
|
||||
|
||||
shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV);
|
||||
shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV);
|
||||
|
||||
// *TODO: Figure out why this offset is *sometimes* producing seams at the
|
||||
// region edge, and repeat jumps when crossing regions, when
|
||||
// RenderTerrainPBRScale is not a factor of the region scale.
|
||||
LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal();
|
||||
F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sPBRDetailScale)*sPBRDetailScale;
|
||||
F32 offset_y = (F32)fmod(region_origin_global.mdV[VY], 1.0/(F64)sPBRDetailScale)*sPBRDetailScale;
|
||||
|
||||
LLGLTFMaterial::TextureTransform base_color_transform;
|
||||
base_color_transform.mScale = LLVector2(sPBRDetailScale, sPBRDetailScale);
|
||||
base_color_transform.mOffset = LLVector2(offset_x, offset_y);
|
||||
F32 base_color_packed[8];
|
||||
base_color_transform.getPacked(base_color_packed);
|
||||
// *HACK: Use the same texture repeats for all PBR terrain textures for now
|
||||
// (not compliant with KHR texture transform spec)
|
||||
shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed);
|
||||
|
||||
LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue