diff --git a/README.md b/README.md index 713c948..1ada749 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ # Presence Colour-enhancing shaders for Minetest + +This is my attempt at subtly improving Minetest graphics without modifying core engine code. If you have any suggestions for future improvement, feel free to contact me, as I know little about the Minetest graphics code. + +## Installation +Rename the `/client/shaders` directory to something else (or delete it entirely). Then copy the `shaders` folder to the `client` folder. The shaders will take effect after leaving and rejoining the game. + +## Credits +All shaders are identical to or are derivative works of the original shaders for Minetest, found [here](https://github.com/minetest/minetest/tree/master/client/shaders). All due credit goes to the original author(s) of this code. \ No newline at end of file diff --git a/screenshots/screenshot1.png b/screenshots/screenshot1.png new file mode 100644 index 0000000..567f57b Binary files /dev/null and b/screenshots/screenshot1.png differ diff --git a/screenshots/screenshot2.png b/screenshots/screenshot2.png new file mode 100644 index 0000000..f0547ed Binary files /dev/null and b/screenshots/screenshot2.png differ diff --git a/screenshots/screenshot3.png b/screenshots/screenshot3.png new file mode 100644 index 0000000..cdeeacc Binary files /dev/null and b/screenshots/screenshot3.png differ diff --git a/shaders/default_shader/opengl_fragment.glsl b/shaders/default_shader/opengl_fragment.glsl new file mode 100644 index 0000000..925ab6e --- /dev/null +++ b/shaders/default_shader/opengl_fragment.glsl @@ -0,0 +1,4 @@ +void main(void) +{ + gl_FragColor = gl_Color; +} diff --git a/shaders/default_shader/opengl_vertex.glsl b/shaders/default_shader/opengl_vertex.glsl new file mode 100644 index 0000000..d0b16c8 --- /dev/null +++ b/shaders/default_shader/opengl_vertex.glsl @@ -0,0 +1,9 @@ +uniform mat4 mWorldViewProj; + +void main(void) +{ + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = mWorldViewProj * gl_Vertex; + + gl_FrontColor = gl_BackColor = gl_Color; +} diff --git a/shaders/minimap_shader/opengl_fragment.glsl b/shaders/minimap_shader/opengl_fragment.glsl new file mode 100644 index 0000000..fa4f9cb --- /dev/null +++ b/shaders/minimap_shader/opengl_fragment.glsl @@ -0,0 +1,32 @@ +uniform sampler2D baseTexture; +uniform sampler2D normalTexture; +uniform vec3 yawVec; + +void main (void) +{ + vec2 uv = gl_TexCoord[0].st; + + //texture sampling rate + const float step = 1.0 / 256.0; + float tl = texture2D(normalTexture, vec2(uv.x - step, uv.y + step)).r; + float t = texture2D(normalTexture, vec2(uv.x - step, uv.y - step)).r; + float tr = texture2D(normalTexture, vec2(uv.x + step, uv.y + step)).r; + float r = texture2D(normalTexture, vec2(uv.x + step, uv.y)).r; + float br = texture2D(normalTexture, vec2(uv.x + step, uv.y - step)).r; + float b = texture2D(normalTexture, vec2(uv.x, uv.y - step)).r; + float bl = texture2D(normalTexture, vec2(uv.x - step, uv.y - step)).r; + float l = texture2D(normalTexture, vec2(uv.x - step, uv.y)).r; + float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl); + float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr); + vec4 bump = vec4 (normalize(vec3 (dX, dY, 0.1)),1.0); + float height = 2.0 * texture2D(normalTexture, vec2(uv.x, uv.y)).r - 1.0; + vec4 base = texture2D(baseTexture, uv).rgba; + vec3 L = normalize(vec3(0.0, 0.75, 1.0)); + float specular = pow(clamp(dot(reflect(L, bump.xyz), yawVec), 0.0, 1.0), 1.0); + float diffuse = dot(yawVec, bump.xyz); + + vec3 color = (1.1 * diffuse + 0.05 * height + 0.5 * specular) * base.rgb; + vec4 col = vec4(color.rgb, base.a); + col *= gl_Color; + gl_FragColor = vec4(col.rgb, base.a); +} diff --git a/shaders/minimap_shader/opengl_vertex.glsl b/shaders/minimap_shader/opengl_vertex.glsl new file mode 100644 index 0000000..88f9356 --- /dev/null +++ b/shaders/minimap_shader/opengl_vertex.glsl @@ -0,0 +1,9 @@ +uniform mat4 mWorldViewProj; +uniform mat4 mWorld; + +void main(void) +{ + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = mWorldViewProj * gl_Vertex; + gl_FrontColor = gl_BackColor = gl_Color; +} diff --git a/shaders/nodes_shader/opengl_fragment.glsl b/shaders/nodes_shader/opengl_fragment.glsl new file mode 100644 index 0000000..ec11619 --- /dev/null +++ b/shaders/nodes_shader/opengl_fragment.glsl @@ -0,0 +1,220 @@ +uniform sampler2D baseTexture; +uniform sampler2D normalTexture; +uniform sampler2D textureFlags; + +uniform vec4 skyBgColor; +uniform float fogDistance; +uniform vec3 eyePosition; + +varying vec3 vPosition; +varying vec3 worldPosition; +varying float area_enable_parallax; + +varying vec3 eyeVec; +varying vec3 tsEyeVec; +varying vec3 lightVec; +varying vec3 tsLightVec; + +bool normalTexturePresent = false; + +const float e = 2.718281828459; +const float BS = 10.0; +const float fogStart = FOG_START; +const float fogShadingParameter = 1 / ( 1 - fogStart); + +#ifdef ENABLE_TONE_MAPPING + +/* Hable's UC2 Tone mapping parameters + A = 0.22; + B = 0.30; + C = 0.10; + D = 0.20; + E = 0.01; + F = 0.30; + W = 11.2; + equation used: ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F +*/ + +vec3 uncharted2Tonemap(vec3 x) +{ + return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03333; +} + +vec4 applyToneMapping(vec4 color) +{ + color = vec4(pow(color.rgb, vec3(2.2)), color.a); + const float gamma = 1.6; + const float exposureBias = 5.5; + color.rgb = uncharted2Tonemap(exposureBias * color.rgb); + // Precalculated white_scale from + //vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W)); + vec3 whiteScale = vec3(1.036015346); + color.rgb *= whiteScale; + return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a); +} + +#endif + +void get_texture_flags() +{ + vec4 flags = texture2D(textureFlags, vec2(0.0, 0.0)); + if (flags.r > 0.5) { + normalTexturePresent = true; + } +} + +float intensity(vec3 color) +{ + return (color.r + color.g + color.b) / 3.0; +} + +float get_rgb_height(vec2 uv) +{ + return intensity(texture2D(baseTexture, uv).rgb); +} + +vec4 get_normal_map(vec2 uv) +{ + vec4 bump = texture2D(normalTexture, uv).rgba; + bump.xyz = normalize(bump.xyz * 2.0 - 1.0); + return bump; +} + +float find_intersection(vec2 dp, vec2 ds) +{ + float depth = 1.0; + float best_depth = 0.0; + float size = 0.0625; + for (int i = 0; i < 15; i++) { + depth -= size; + float h = texture2D(normalTexture, dp + ds * depth).a; + if (depth <= h) { + best_depth = depth; + break; + } + } + depth = best_depth; + for (int i = 0; i < 4; i++) { + size *= 0.5; + float h = texture2D(normalTexture,dp + ds * depth).a; + if (depth <= h) { + best_depth = depth; + depth += size; + } else { + depth -= size; + } + } + return best_depth; +} + +float find_intersectionRGB(vec2 dp, vec2 ds) +{ + const float depth_step = 1.0 / 24.0; + float depth = 1.0; + for (int i = 0 ; i < 24 ; i++) { + float h = get_rgb_height(dp + ds * depth); + if (h >= depth) + break; + depth -= depth_step; + } + return depth; +} + +void main(void) +{ + vec3 color; + vec4 bump; + vec2 uv = gl_TexCoord[0].st; + bool use_normalmap = false; + get_texture_flags(); + +#ifdef ENABLE_PARALLAX_OCCLUSION + vec2 eyeRay = vec2 (tsEyeVec.x, -tsEyeVec.y); + const float scale = PARALLAX_OCCLUSION_SCALE / PARALLAX_OCCLUSION_ITERATIONS; + const float bias = PARALLAX_OCCLUSION_BIAS / PARALLAX_OCCLUSION_ITERATIONS; + +#if PARALLAX_OCCLUSION_MODE == 0 + // Parallax occlusion with slope information + if (normalTexturePresent && area_enable_parallax > 0.0) { + for (int i = 0; i < PARALLAX_OCCLUSION_ITERATIONS; i++) { + vec4 normal = texture2D(normalTexture, uv.xy); + float h = normal.a * scale - bias; + uv += h * normal.z * eyeRay; + } +#endif + +#if PARALLAX_OCCLUSION_MODE == 1 + // Relief mapping + if (normalTexturePresent && area_enable_parallax > 0.0) { + vec2 ds = eyeRay * PARALLAX_OCCLUSION_SCALE; + float dist = find_intersection(uv, ds); + uv += dist * ds; +#endif + } else if (GENERATE_NORMALMAPS == 1 && area_enable_parallax > 0.0) { + vec2 ds = eyeRay * PARALLAX_OCCLUSION_SCALE; + float dist = find_intersectionRGB(uv, ds); + uv += dist * ds; + } +#endif + +#if USE_NORMALMAPS == 1 + if (normalTexturePresent) { + bump = get_normal_map(uv); + use_normalmap = true; + } +#endif + +#if GENERATE_NORMALMAPS == 1 + if (normalTexturePresent == false) { + float tl = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y + SAMPLE_STEP)); + float t = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y - SAMPLE_STEP)); + float tr = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y + SAMPLE_STEP)); + float r = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y)); + float br = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y - SAMPLE_STEP)); + float b = get_rgb_height(vec2(uv.x, uv.y - SAMPLE_STEP)); + float bl = get_rgb_height(vec2(uv.x -SAMPLE_STEP, uv.y - SAMPLE_STEP)); + float l = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y)); + float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl); + float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr); + bump = vec4(normalize(vec3 (dX, dY, NORMALMAPS_STRENGTH)), 1.0); + use_normalmap = true; + } +#endif + vec4 base = texture2D(baseTexture, uv).rgba; + +#ifdef ENABLE_BUMPMAPPING + if (use_normalmap) { + vec3 L = normalize(lightVec); + vec3 E = normalize(eyeVec); + float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0), 1.0); + float diffuse = dot(-E,bump.xyz); + color = (diffuse + 0.1 * specular) * base.rgb; + } else { + color = base.rgb; + } +#else + color = base.rgb; +#endif + + vec4 col = vec4(color.rgb * gl_Color.rgb, 1.0); + +#ifdef ENABLE_TONE_MAPPING + col = applyToneMapping(col); +#endif + + // Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?), + // the fog will only be rendered correctly if the last operation before the + // clamp() is an addition. Else, the clamp() seems to be ignored. + // E.g. the following won't work: + // float clarity = clamp(fogShadingParameter + // * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0); + // As additions usually come for free following a multiplication, the new formula + // should be more efficient as well. + // Note: clarity = (1 - fogginess) + float clarity = clamp(fogShadingParameter + - fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0); + col = mix(skyBgColor, col, clarity); + col = vec4(col.rgb, base.a); + + gl_FragColor = col; +} diff --git a/shaders/nodes_shader/opengl_vertex.glsl b/shaders/nodes_shader/opengl_vertex.glsl new file mode 100644 index 0000000..ce53e7e --- /dev/null +++ b/shaders/nodes_shader/opengl_vertex.glsl @@ -0,0 +1,157 @@ +uniform mat4 mWorldViewProj; +uniform mat4 mWorld; + +// Color of the light emitted by the sun. +uniform vec3 dayLight; +uniform vec3 eyePosition; +uniform float animationTimer; + +varying vec3 vPosition; +varying vec3 worldPosition; + +varying vec3 eyeVec; +varying vec3 lightVec; +varying vec3 tsEyeVec; +varying vec3 tsLightVec; +varying float area_enable_parallax; + +// Color of the light emitted by the light sources. +const vec3 artificialLight = vec3(1.04, 1.04, 1.04); + +// random-geek's colour definitions, for use with colour tinting. +const vec3 sunEffect = vec3(1.0, 0.8, 0.4); +const vec3 orange = vec3(1.0, 0.89, 0.75); +const vec3 cyan = vec3(0.75, 0.89, 1.0); + +const float e = 2.718281828459; +const float BS = 10.0; + +// random-geek's custom daylight. Colour temperature is based on amount of light, with intermediate values (dusk and dawn) being the most orange. +vec3 globalSun = dayLight.rgb * mix(vec3(1.0), sunEffect, -2.25 * abs(dayLight.r - 0.5) + 1); + +float smoothCurve(float x) +{ + return x * x * (3.0 - 2.0 * x); +} + + +float triangleWave(float x) +{ + return abs(fract(x + 0.5) * 2.0 - 1.0); +} + + +float smoothTriangleWave(float x) +{ + return smoothCurve(triangleWave(x)) * 2.0 - 1.0; +} + + +void main(void) +{ + gl_TexCoord[0] = gl_MultiTexCoord0; + //TODO: make offset depending on view angle and parallax uv displacement + //thats for textures that doesnt align vertically, like dirt with grass + //gl_TexCoord[0].y += 0.008; + + //Allow parallax/relief mapping only for certain kind of nodes + //Variable is also used to control area of the effect +#if (DRAW_TYPE == NDT_NORMAL || DRAW_TYPE == NDT_LIQUID || DRAW_TYPE == NDT_FLOWINGLIQUID) + area_enable_parallax = 1.0; +#else + area_enable_parallax = 0.0; +#endif + + +float disp_x; +float disp_z; +#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES && ENABLE_WAVING_LEAVES) || (MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS && ENABLE_WAVING_PLANTS) + vec4 pos2 = mWorld * gl_Vertex; + float tOffset = (pos2.x + pos2.y) * 0.001 + pos2.z * 0.002; + disp_x = (smoothTriangleWave(animationTimer * 23.0 + tOffset) + + smoothTriangleWave(animationTimer * 11.0 + tOffset)) * 0.4; + disp_z = (smoothTriangleWave(animationTimer * 31.0 + tOffset) + + smoothTriangleWave(animationTimer * 29.0 + tOffset) + + smoothTriangleWave(animationTimer * 13.0 + tOffset)) * 0.5; +#endif + + +#if (MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE) && ENABLE_WAVING_WATER + vec4 pos = gl_Vertex; + pos.y -= 2.0; + float posYbuf = (pos.z / WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH); + pos.y -= sin(posYbuf) * WATER_WAVE_HEIGHT + sin(posYbuf / 7.0) * WATER_WAVE_HEIGHT; + gl_Position = mWorldViewProj * pos; +#elif MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES && ENABLE_WAVING_LEAVES + vec4 pos = gl_Vertex; + pos.x += disp_x; + pos.y += disp_z * 0.1; + pos.z += disp_z; + gl_Position = mWorldViewProj * pos; +#elif MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS && ENABLE_WAVING_PLANTS + vec4 pos = gl_Vertex; + if (gl_TexCoord[0].y < 0.05) { + pos.x += disp_x; + pos.z += disp_z; + } + gl_Position = mWorldViewProj * pos; +#else + gl_Position = mWorldViewProj * gl_Vertex; +#endif + + + vPosition = gl_Position.xyz; + worldPosition = (mWorld * gl_Vertex).xyz; + + // Don't generate heightmaps when too far from the eye + float dist = distance (vec3(0.0, 0.0, 0.0), vPosition); + if (dist > 150.0) { + area_enable_parallax = 0.0; + } + + vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0); + + vec3 normal, tangent, binormal; + normal = normalize(gl_NormalMatrix * gl_Normal); + tangent = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz); + binormal = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz); + + vec3 v; + + lightVec = sunPosition - worldPosition; + v.x = dot(lightVec, tangent); + v.y = dot(lightVec, binormal); + v.z = dot(lightVec, normal); + tsLightVec = normalize (v); + + eyeVec = -(gl_ModelViewMatrix * gl_Vertex).xyz; + v.x = dot(eyeVec, tangent); + v.y = dot(eyeVec, binormal); + v.z = dot(eyeVec, normal); + tsEyeVec = normalize (v); + // Calculate color. + // Red, green and blue components are pre-multiplied with + // the brightness, so now we have to multiply these + // colors with the color of the incoming light. + // The pre-baked colors are halved to prevent overflow. + vec4 color; + // The alpha gives the ratio of sunlight in the incoming light. + float nightRatio = 1 - gl_Color.a; + + vec3 localSun = globalSun * mix(cyan, orange, pow(gl_Color.a * globalSun.r, 3)); + + color.rgb = gl_Color.rgb * (gl_Color.a * globalSun + + nightRatio * artificialLight.rgb) * 2; + + // random-geek's contrast; makes lights lighter and darks darker for better clarity. + float light = max(color.r, max(color.g, color.b)); + float lightNew = 0.75*(light-0.5)/(abs(light-0.5) + 0.25) + 0.5; + color.rgb *= lightNew/light; + + // random-geek's colour grading; adds blue to darker areas and orange to lighter areas. + color.rgb *= mix(cyan, orange, pow(lightNew, 2)); + + color.a = 1; + + gl_FrontColor = gl_BackColor = clamp(color, 0.0, 1.0); +} \ No newline at end of file diff --git a/shaders/nodes_shader/opengl_vertex_bak.glsl b/shaders/nodes_shader/opengl_vertex_bak.glsl new file mode 100644 index 0000000..3ac79c2 --- /dev/null +++ b/shaders/nodes_shader/opengl_vertex_bak.glsl @@ -0,0 +1,144 @@ +uniform mat4 mWorldViewProj; +uniform mat4 mWorld; + +// Color of the light emitted by the sun. +uniform vec3 dayLight; +uniform vec3 eyePosition; +uniform float animationTimer; + +varying vec3 vPosition; +varying vec3 worldPosition; + +varying vec3 eyeVec; +varying vec3 lightVec; +varying vec3 tsEyeVec; +varying vec3 tsLightVec; +varying float area_enable_parallax; + +// Color of the light emitted by the light sources. +const vec3 artificialLight = vec3(1.04, 1.04, 1.04); +const float e = 2.718281828459; +const float BS = 10.0; + + +float smoothCurve(float x) +{ + return x * x * (3.0 - 2.0 * x); +} + + +float triangleWave(float x) +{ + return abs(fract(x + 0.5) * 2.0 - 1.0); +} + + +float smoothTriangleWave(float x) +{ + return smoothCurve(triangleWave(x)) * 2.0 - 1.0; +} + + +void main(void) +{ + gl_TexCoord[0] = gl_MultiTexCoord0; + //TODO: make offset depending on view angle and parallax uv displacement + //thats for textures that doesnt align vertically, like dirt with grass + //gl_TexCoord[0].y += 0.008; + + //Allow parallax/relief mapping only for certain kind of nodes + //Variable is also used to control area of the effect +#if (DRAW_TYPE == NDT_NORMAL || DRAW_TYPE == NDT_LIQUID || DRAW_TYPE == NDT_FLOWINGLIQUID) + area_enable_parallax = 1.0; +#else + area_enable_parallax = 0.0; +#endif + + +float disp_x; +float disp_z; +#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES && ENABLE_WAVING_LEAVES) || (MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS && ENABLE_WAVING_PLANTS) + vec4 pos2 = mWorld * gl_Vertex; + float tOffset = (pos2.x + pos2.y) * 0.001 + pos2.z * 0.002; + disp_x = (smoothTriangleWave(animationTimer * 23.0 + tOffset) + + smoothTriangleWave(animationTimer * 11.0 + tOffset)) * 0.4; + disp_z = (smoothTriangleWave(animationTimer * 31.0 + tOffset) + + smoothTriangleWave(animationTimer * 29.0 + tOffset) + + smoothTriangleWave(animationTimer * 13.0 + tOffset)) * 0.5; +#endif + + +#if (MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE) && ENABLE_WAVING_WATER + vec4 pos = gl_Vertex; + pos.y -= 2.0; + float posYbuf = (pos.z / WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH); + pos.y -= sin(posYbuf) * WATER_WAVE_HEIGHT + sin(posYbuf / 7.0) * WATER_WAVE_HEIGHT; + gl_Position = mWorldViewProj * pos; +#elif MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES && ENABLE_WAVING_LEAVES + vec4 pos = gl_Vertex; + pos.x += disp_x; + pos.y += disp_z * 0.1; + pos.z += disp_z; + gl_Position = mWorldViewProj * pos; +#elif MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS && ENABLE_WAVING_PLANTS + vec4 pos = gl_Vertex; + if (gl_TexCoord[0].y < 0.05) { + pos.x += disp_x; + pos.z += disp_z; + } + gl_Position = mWorldViewProj * pos; +#else + gl_Position = mWorldViewProj * gl_Vertex; +#endif + + + vPosition = gl_Position.xyz; + worldPosition = (mWorld * gl_Vertex).xyz; + + // Don't generate heightmaps when too far from the eye + float dist = distance (vec3(0.0, 0.0, 0.0), vPosition); + if (dist > 150.0) { + area_enable_parallax = 0.0; + } + + vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0); + + vec3 normal, tangent, binormal; + normal = normalize(gl_NormalMatrix * gl_Normal); + tangent = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz); + binormal = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz); + + vec3 v; + + lightVec = sunPosition - worldPosition; + v.x = dot(lightVec, tangent); + v.y = dot(lightVec, binormal); + v.z = dot(lightVec, normal); + tsLightVec = normalize (v); + + eyeVec = -(gl_ModelViewMatrix * gl_Vertex).xyz; + v.x = dot(eyeVec, tangent); + v.y = dot(eyeVec, binormal); + v.z = dot(eyeVec, normal); + tsEyeVec = normalize (v); + + // Calculate color. + // Red, green and blue components are pre-multiplied with + // the brightness, so now we have to multiply these + // colors with the color of the incoming light. + // The pre-baked colors are halved to prevent overflow. + vec4 color; + // The alpha gives the ratio of sunlight in the incoming light. + float nightRatio = 1 - gl_Color.a; + color.rgb = gl_Color.rgb * (gl_Color.a * dayLight.rgb + + nightRatio * artificialLight.rgb) * 2; + color.a = 1; + + // Emphase blue a bit in darker places + // See C++ implementation in mapblock_mesh.cpp finalColorBlend() + float brightness = (color.r + color.g + color.b) / 3; + color.b += max(0.0, 0.021 - abs(0.2 * brightness - 0.021) + + 0.07 * brightness); + + gl_FrontColor = gl_BackColor = clamp(color, 0.0, 1.0); +} diff --git a/shaders/selection_shader/opengl_fragment.glsl b/shaders/selection_shader/opengl_fragment.glsl new file mode 100644 index 0000000..c679d0e --- /dev/null +++ b/shaders/selection_shader/opengl_fragment.glsl @@ -0,0 +1,9 @@ +uniform sampler2D baseTexture; + +void main(void) +{ + vec2 uv = gl_TexCoord[0].st; + vec4 color = texture2D(baseTexture, uv); + color.rgb *= gl_Color.rgb; + gl_FragColor = color; +} diff --git a/shaders/selection_shader/opengl_vertex.glsl b/shaders/selection_shader/opengl_vertex.glsl new file mode 100644 index 0000000..d0b16c8 --- /dev/null +++ b/shaders/selection_shader/opengl_vertex.glsl @@ -0,0 +1,9 @@ +uniform mat4 mWorldViewProj; + +void main(void) +{ + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = mWorldViewProj * gl_Vertex; + + gl_FrontColor = gl_BackColor = gl_Color; +} diff --git a/shaders/wielded_shader/opengl_fragment.glsl b/shaders/wielded_shader/opengl_fragment.glsl new file mode 100644 index 0000000..546aef7 --- /dev/null +++ b/shaders/wielded_shader/opengl_fragment.glsl @@ -0,0 +1,127 @@ +uniform sampler2D baseTexture; +uniform sampler2D normalTexture; +uniform sampler2D textureFlags; + +uniform vec4 skyBgColor; +uniform float fogDistance; +uniform vec3 eyePosition; + +varying vec3 vPosition; +varying vec3 worldPosition; + +varying vec3 eyeVec; +varying vec3 lightVec; + +bool normalTexturePresent = false; +bool texTileableHorizontal = false; +bool texTileableVertical = false; +bool texSeamless = false; + +const float e = 2.718281828459; +const float BS = 10.0; +const float fogStart = FOG_START; +const float fogShadingParameter = 1 / ( 1 - fogStart); + +void get_texture_flags() +{ + vec4 flags = texture2D(textureFlags, vec2(0.0, 0.0)); + if (flags.r > 0.5) { + normalTexturePresent = true; + } + if (flags.g > 0.5) { + texTileableHorizontal = true; + } + if (flags.b > 0.5) { + texTileableVertical = true; + } + if (texTileableHorizontal && texTileableVertical) { + texSeamless = true; + } +} + +float intensity(vec3 color) +{ + return (color.r + color.g + color.b) / 3.0; +} + +float get_rgb_height(vec2 uv) +{ + if (texSeamless) { + return intensity(texture2D(baseTexture, uv).rgb); + } else { + return intensity(texture2D(baseTexture, clamp(uv, 0.0, 0.999)).rgb); + } +} + +vec4 get_normal_map(vec2 uv) +{ + vec4 bump = texture2D(normalTexture, uv).rgba; + bump.xyz = normalize(bump.xyz * 2.0 - 1.0); + return bump; +} + +void main(void) +{ + vec3 color; + vec4 bump; + vec2 uv = gl_TexCoord[0].st; + bool use_normalmap = false; + get_texture_flags(); + +#if USE_NORMALMAPS == 1 + if (normalTexturePresent) { + bump = get_normal_map(uv); + use_normalmap = true; + } +#endif + +#if GENERATE_NORMALMAPS == 1 + if (normalTexturePresent == false) { + float tl = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y + SAMPLE_STEP)); + float t = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y - SAMPLE_STEP)); + float tr = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y + SAMPLE_STEP)); + float r = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y)); + float br = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y - SAMPLE_STEP)); + float b = get_rgb_height(vec2(uv.x, uv.y - SAMPLE_STEP)); + float bl = get_rgb_height(vec2(uv.x -SAMPLE_STEP, uv.y - SAMPLE_STEP)); + float l = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y)); + float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl); + float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr); + bump = vec4(normalize(vec3 (dX, dY, NORMALMAPS_STRENGTH)), 1.0); + use_normalmap = true; + } +#endif + + vec4 base = texture2D(baseTexture, uv).rgba; + +#ifdef ENABLE_BUMPMAPPING + if (use_normalmap) { + vec3 L = normalize(lightVec); + vec3 E = normalize(eyeVec); + float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0), 1.0); + float diffuse = dot(-E,bump.xyz); + color = (diffuse + 0.1 * specular) * base.rgb; + } else { + color = base.rgb; + } +#else + color = base.rgb; +#endif + + vec4 col = vec4(color.rgb, base.a); + col *= gl_Color; + // Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?), + // the fog will only be rendered correctly if the last operation before the + // clamp() is an addition. Else, the clamp() seems to be ignored. + // E.g. the following won't work: + // float clarity = clamp(fogShadingParameter + // * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0); + // As additions usually come for free following a multiplication, the new formula + // should be more efficient as well. + // Note: clarity = (1 - fogginess) + float clarity = clamp(fogShadingParameter + - fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0); + col = mix(skyBgColor, col, clarity); + + gl_FragColor = vec4(col.rgb, base.a); +} diff --git a/shaders/wielded_shader/opengl_vertex.glsl b/shaders/wielded_shader/opengl_vertex.glsl new file mode 100644 index 0000000..9f05b83 --- /dev/null +++ b/shaders/wielded_shader/opengl_vertex.glsl @@ -0,0 +1,32 @@ +uniform mat4 mWorldViewProj; +uniform mat4 mWorld; + +uniform vec3 eyePosition; +uniform float animationTimer; + +varying vec3 vPosition; +varying vec3 worldPosition; + +varying vec3 eyeVec; +varying vec3 lightVec; +varying vec3 tsEyeVec; +varying vec3 tsLightVec; + +const float e = 2.718281828459; +const float BS = 10.0; + +void main(void) +{ + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = mWorldViewProj * gl_Vertex; + + vPosition = gl_Position.xyz; + worldPosition = (mWorld * gl_Vertex).xyz; + + vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0); + + lightVec = sunPosition - worldPosition; + eyeVec = -(gl_ModelViewMatrix * gl_Vertex).xyz; + + gl_FrontColor = gl_BackColor = gl_Color; +}