Last active
March 3, 2021 01:55
-
-
Save JuanDiegoMontoya/668b5e0b590a1a478c1dcdf576441e72 to your computer and use it in GitHub Desktop.
Simple vertex+fragment shader for giving a mesh a water-like material. NOTE: this relies on the mesh being a vertically displaced planar mesh to work! This will not apply ripples, etc. itself!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 450 | |
out vec4 FragColor; | |
in vec3 vPos; | |
in vec3 vNormal; | |
in vec2 vTexCoord; | |
uniform vec3 u_viewpos; | |
uniform float u_waterRefract; // water | |
uniform float u_airRefract; // air | |
uniform sampler2D heightTex; | |
uniform samplerCube envTex; | |
#define FRESNEL_POWER 5.0 | |
float FresnelSchlick(vec3 i, vec3 n, float Eta, float Power) | |
{ | |
float F = ((1.0-Eta) * (1.0-Eta)) / ((1.0+Eta) * (1.0+Eta)); | |
return F + (1.0 - F) * pow((1.0 - dot(-i, n)), Power); | |
} | |
vec3 CalcEnvColor(vec3 normal, vec3 viewDir) | |
{ | |
float inDex = u_waterRefract; | |
float exDex = u_airRefract; | |
// viewing from under water | |
if (dot(normal, -viewDir) > 0) | |
{ | |
float tmp = inDex; | |
inDex = exDex; | |
exDex = tmp; | |
normal *= -1; | |
} | |
float eta = exDex / inDex; | |
float Ratio = FresnelSchlick(-viewDir, normal, eta, FRESNEL_POWER); | |
vec3 reflectColor = texture(envTex, reflect(-viewDir, normal)).rgb; | |
vec3 refractColor = texture(envTex, refract(-viewDir, normal, eta)).rgb; | |
// snell's window | |
if (all(lessThan(abs(refract(-viewDir, normal, eta)), vec3(0.1)))) | |
refractColor = reflectColor; | |
return mix(refractColor, reflectColor, Ratio); | |
} | |
void main() | |
{ | |
vec3 viewDir = normalize(u_viewpos - vPos); | |
vec3 normal = normalize(vNormal); | |
vec3 envColor = CalcEnvColor(normal, viewDir); | |
FragColor = vec4(envColor, 1.0); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 450 | |
layout (location = 0) in vec2 aPosXZ; // no Y- that is provided by the height texture! Normally Y would be included and the height texture would just add or subtract from it. | |
layout (location = 1) in vec2 aTexCoord; // mirror repeat recommended | |
uniform mat4 u_proj; | |
uniform mat4 u_view; | |
uniform mat4 u_model; | |
out vec3 vPos; | |
out vec3 vNormal; | |
out vec2 vTexCoord; | |
uniform sampler2D heightTex; // height field texture | |
void main() | |
{ | |
vTexCoord = aTexCoord; | |
vec2 dim = textureSize(heightTex, 0); | |
// get the height at the current, above, and right cell (any two other adjacent cells would work) | |
float height = texture(heightTex, aTexCoord).r; | |
float uHeight = texture(heightTex, vec2(aTexCoord.x, aTexCoord.y + 1.0 / dim.y)).r; | |
float rHeight = texture(heightTex, vec2(aTexCoord.x + 1.0 / dim.x, aTexCoord.y)).r; | |
// vertex position (model/local space) simply has the height of this cell | |
vec3 aPos = vec3(aPosXZ.x, height, aPosXZ.y); | |
// make a triangle that goes between current, above, and right cell, then use cross product to get the normal of that triangle | |
vec3 aPosU = vec3(aPosXZ.x, uHeight, aPosXZ.y + 1); | |
vec3 aPosR = vec3(aPosXZ.x + 1, rHeight, aPosXZ.y); | |
vec3 aNormal = cross(aPosU - aPos, aPosR - aPos); | |
// world space transform for vertex position and normal | |
vPos = vec3(u_model * vec4(aPos, 1.0)); | |
vNormal = mat3(transpose(inverse(u_model))) * aNormal; // model->world space (normally this would just be `vNormal = aNormal`, but we want don't want scaling to screw up the normals, just in case) | |
// clip space transform | |
gl_Position = u_proj * u_view * vec4(vPos, 1.0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment