From 580c375d4bef77e49d9bda53697e68eea74e955c Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Tue, 26 Jan 2021 20:17:17 +0000 Subject: [PATCH] WS30: Use perlin texture to reduce tiling Use a perlin noise texture to rotate some of the landclass textures to reduce tiling. Also add a quality=1 technique which uses it. --- Effects/ws30.eff | 166 ++++++++++++++++++++++++++++++++++++++++++- Shaders/ws30-q1.frag | 65 +++++++++++++++++ Shaders/ws30.frag | 1 + Textures/perlin.png | Bin 0 -> 14539 bytes 4 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 Shaders/ws30-q1.frag create mode 100644 Textures/perlin.png diff --git a/Effects/ws30.eff b/Effects/ws30.eff index 17e478ca8..69a5c5247 100644 --- a/Effects/ws30.eff +++ b/Effects/ws30.eff @@ -19,6 +19,15 @@ 1.2 + + Textures/perlin.png + 2d + nearest + repeat + repeat + normalized + + Textures/Terrain/snow3.png 2d @@ -182,7 +191,7 @@ - /sim/rendering/shaders/quality-level + /sim/rendering/shaders/skydome 2.0 @@ -269,6 +278,15 @@ texture[4]/internal-format + + 6 + texture[6]/image + texture[6]/filter + texture[6]/wrap-s + texture[6]/wrap-t + texture[6]/internal-format + + Shaders/ws30-ALS.vert Shaders/shadows-include.vert @@ -414,6 +432,12 @@ sampler-1d 4 + + perlin + sampler-2d + 6 + + colorMode int @@ -444,6 +468,145 @@ + + + + + /sim/rendering/shaders/quality-level + + + 2.0 + + + + GL_ARB_shader_objects + GL_ARB_shading_language_100 + GL_ARB_vertex_shader + GL_ARB_fragment_shader + + + + + + + true + + material/ambient + material/diffuse + material/specular + material/emissive + material/shininess + ambient-and-diffuse + + transparent + transparent + smooth + back + + render-bin/bin-number + render-bin/bin-name + + + + 0 + texture[0]/image + nearest + nearest + texture[0]/wrap-s + texture[0]/wrap-t + texture[0]/internal-format + + max + max + max + + + + + 1 + texture[1]/image + nearest-mipmap-nearest + nearest-mipmap-nearest + texture[0]/wrap-s + texture[0]/wrap-t + texture[0]/internal-format + + + + 2 + texture[2]/image + texture[2]/filter + texture[2]/wrap-s + texture[2]/wrap-t + texture[2]/internal-format + + + + 3 + texture[3]/image + texture[3]/filter + texture[3]/wrap-s + texture[3]/wrap-t + texture[3]/internal-format + + + + 4 + texture[4]/image + texture[4]/filter + texture[4]/wrap-s + texture[4]/wrap-t + texture[4]/internal-format + + + + 6 + texture[6]/image + texture[6]/filter + texture[6]/wrap-s + texture[6]/wrap-t + texture[6]/internal-format + + + + Shaders/ws30.vert + Shaders/include_fog.frag + Shaders/ws30-q1.frag + + + + landclass + sampler-2d + 0 + + + atlas + sampler-2d + 1 + + + dimensionsArray + sampler-1d + 2 + + + diffuseArray + sampler-1d + 3 + + + specularArray + sampler-1d + 4 + + + perlin + sampler-2d + 6 + + + + @@ -548,7 +711,6 @@ sampler-1d 4 - diff --git a/Shaders/ws30-q1.frag b/Shaders/ws30-q1.frag new file mode 100644 index 000000000..8263f0d69 --- /dev/null +++ b/Shaders/ws30-q1.frag @@ -0,0 +1,65 @@ +// WS30 FRAGMENT SHADER + +// -*-C++-*- +#version 130 +#extension GL_EXT_texture_array : enable + +varying vec3 normal; + +uniform sampler2D landclass; +uniform sampler2DArray atlas; +uniform sampler1D dimensionsArray; +uniform sampler1D diffuseArray; +uniform sampler1D specularArray; +uniform sampler2D perlin; + +// Passed from VPBTechnique, not the Effect +uniform float tile_width; +uniform float tile_height; + +// See include_fog.frag +uniform int fogType; +vec3 fog_Func(vec3 color, int type); + +void main() +{ + vec3 lightDir = gl_LightSource[0].position.xyz; + vec3 halfVector = gl_LightSource[0].halfVector.xyz; + vec4 texel; + vec4 fragColor; + + // The Landclass for this particular fragment. This can be used to + // index into the atlas textures. + int lc = int(texture2D(landclass, gl_TexCoord[0].st).g * 255.0 + 0.5); + + // If gl_Color.a == 0, this is a back-facing polygon and the + // normal should be reversed. + vec3 n = (2.0 * gl_Color.a - 1.0) * normal; + n = normalize(n); + float NdotL = dot(n, lightDir); + float NdotHV = max(dot(n, halfVector), 0.0); + + // Different textures have different have different dimensions. + // Dimensions array is scaled to fit in [0...1.0] in the texture1D, so has to be scaled back up here. + vec4 color = texture(diffuseArray, float(lc)/512.0) * NdotL; + vec4 specular = texture(specularArray, float(lc)/512.0); + vec2 atlas_dimensions = 10000.0 * texture(dimensionsArray, float(lc)/512.0).st; + vec2 atlas_scale = vec2(tile_width / atlas_dimensions.s, tile_height / atlas_dimensions.t ); + vec2 st = atlas_scale * gl_TexCoord[0].st; + + // Rotate texture using the perlin texture as a mask to reduce tiling + if (step(0.5, texture(perlin, atlas_scale * gl_TexCoord[0].st / 8.0).r) == 1.0) { + st = vec2(atlas_scale.s * gl_TexCoord[0].t, atlas_scale.t * gl_TexCoord[0].s); + } + + if (step(0.5, texture(perlin, - atlas_scale * gl_TexCoord[0].st / 16.0).r) == 1.0) { + st = -st; + } + + texel = texture(atlas, vec3(st, lc)); + + fragColor = texel + pow(NdotHV, gl_FrontMaterial.shininess) * gl_LightSource[0].specular * specular; + + fragColor.rgb = fog_Func(fragColor.rgb, fogType); + gl_FragColor = fragColor; +} diff --git a/Shaders/ws30.frag b/Shaders/ws30.frag index 64cd58c59..77b9238cc 100644 --- a/Shaders/ws30.frag +++ b/Shaders/ws30.frag @@ -44,6 +44,7 @@ void main() vec4 specular = texture(specularArray, float(lc)/512.0); vec2 atlas_dimensions = 10000.0 * texture(dimensionsArray, float(lc)/512.0).st; vec2 atlas_scale = vec2(tile_width / atlas_dimensions.s, tile_height / atlas_dimensions.t ); + texel = texture(atlas, vec3(atlas_scale * gl_TexCoord[0].st, lc)); fragColor = texel + pow(NdotHV, gl_FrontMaterial.shininess) * gl_LightSource[0].specular * specular; diff --git a/Textures/perlin.png b/Textures/perlin.png new file mode 100644 index 0000000000000000000000000000000000000000..26c21e9610269f72c308a3b37d4aa531ab3c4d19 GIT binary patch literal 14539 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 literal 0 HcmV?d00001