Skip to content

Instantly share code, notes, and snippets.

@JuanDiegoMontoya
Last active March 3, 2021 01:55
Show Gist options
  • Save JuanDiegoMontoya/668b5e0b590a1a478c1dcdf576441e72 to your computer and use it in GitHub Desktop.
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!
#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);
}
#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