forked from aya/aya
Initial commit
This commit is contained in:
181
client/common/shaders/bgfx_source/water.sc
Normal file
181
client/common/shaders/bgfx_source/water.sc
Normal file
@@ -0,0 +1,181 @@
|
||||
$input a_position, a_normal
|
||||
$output v_pos, v_texcoord0, v_worldPos, v_normal, v_lightpos_fog, v_color0
|
||||
|
||||
#include "common.sh"
|
||||
#include "globals.sh"
|
||||
|
||||
//
|
||||
// Water shader.
|
||||
// Big, fat and ugly.
|
||||
//
|
||||
// All (most) things considered, I have converged to this particular way of rendering water:
|
||||
//
|
||||
// Vertex waves
|
||||
// No transparency. Solid color for deep water.
|
||||
// Fresnel law, reflects environment.
|
||||
// Phong speculars.
|
||||
// Ripples via animated normal map. Adjustable intensity, speed and scale. Affect reflection and speculars.
|
||||
|
||||
uniform vec4 u_nmAnimLerp; // ratio between normal map frames
|
||||
uniform vec4 u_waveParams; // .x = frequency .y = phase .z = height
|
||||
uniform vec4 u_waterColor; // deep water color
|
||||
|
||||
SAMPLER2D(s_normalMap1, 0);
|
||||
SAMPLER2D(s_normalMap2, 1);
|
||||
SAMPLERCUBE(s_envMap, 2);
|
||||
SAMPLER2D(s_lightMap, 3);
|
||||
SAMPLER2D(s_lightMapLookup, 4);
|
||||
|
||||
#ifdef PIN_HQ
|
||||
# define WATER_LOD 1
|
||||
#else
|
||||
# define WATER_LOD 2
|
||||
#endif
|
||||
|
||||
#define LODBIAS (-1.0)
|
||||
|
||||
float fadeFactor(vec3 wspos)
|
||||
{
|
||||
return saturate0(-0.4 + 1.4 * length(u_cameraPosition - wspos.xyz) * u_fadeDistance_GlowFactor.y);
|
||||
}
|
||||
|
||||
float wave(vec4 wspos)
|
||||
{
|
||||
float x = sin((wspos.z - wspos.x - u_waveParams.y) * u_waveParams.x);
|
||||
float z = sin((wspos.z + wspos.x + u_waveParams.y) * u_waveParams.x);
|
||||
float p = (x + z) * u_waveParams.z;
|
||||
return p - p * fadeFactor(wspos.xyz);
|
||||
}
|
||||
|
||||
// perturbs the water mesh and vertex normals
|
||||
void makeWaves(inout vec4 wspos, inout vec3 wsnrm)
|
||||
{
|
||||
#if WATER_LOD == 0
|
||||
float gridSize = 4.0;
|
||||
|
||||
vec4 wspos1 = wspos;
|
||||
vec4 wspos2 = wspos;
|
||||
|
||||
wspos1.x += gridSize;
|
||||
wspos2.z += gridSize;
|
||||
|
||||
wspos.y += wave(wspos);
|
||||
wspos1.y += wave(wspos1);
|
||||
wspos2.y += wave(wspos2);
|
||||
|
||||
wsnrm = normalize(cross(wspos2.xyz - wspos.xyz, wspos1.xyz - wspos.xyz));
|
||||
#elif WATER_LOD == 1
|
||||
wspos.y += wave(wspos);
|
||||
#else /* do nothing */
|
||||
#endif
|
||||
}
|
||||
|
||||
void water_vs()
|
||||
{
|
||||
// Decode vertex data
|
||||
vec3 normal = (a_normal.xyz - 127.0) / 127.0;
|
||||
normal = normalize(normal);
|
||||
|
||||
vec4 wspos = mul(u_worldMatrix, vec4(a_position.xyz, 1.0));
|
||||
vec3 wsnrm = normal;
|
||||
|
||||
wspos.y -= 2.0 * u_waveParams.z;
|
||||
|
||||
makeWaves(wspos, wsnrm);
|
||||
|
||||
v_worldPos = wspos;
|
||||
v_normal = wsnrm;
|
||||
|
||||
if (normal.y < 0.01) v_normal = normal;
|
||||
|
||||
// box mapping
|
||||
vec2 tcselect;
|
||||
vec3 wspostc = vec3(wspos.x, -wspos.y, wspos.z);
|
||||
|
||||
tcselect.x = dot(abs(normal.yxz), wspostc.xzx);
|
||||
tcselect.y = dot(abs(normal.yxz), wspostc.zyy);
|
||||
|
||||
v_pos = mul(u_viewProjection, wspos);
|
||||
v_texcoord0.xy = tcselect * 0.05;
|
||||
v_texcoord0.z = saturate0((u_fogParams.z - v_pos.w) * u_fogParams.w);
|
||||
v_texcoord0.w = LODBIAS;
|
||||
|
||||
v_lightpos_fog.xyz = lgridPrepareSample(lgridOffset(wspos.xyz, wsnrm.xyz));
|
||||
|
||||
v_color0.x = fadeFactor(wspos.xyz);
|
||||
v_color0.y = (1.0 - v_color0.x) * saturate0(dot(wsnrm, -u_lamp0Dir)) * 100.0;
|
||||
v_color0.z = 1.0 - 0.9 * saturate1(exp(-0.005 * length(u_cameraPosition - wspos.xyz)));
|
||||
|
||||
gl_Position = v_pos;
|
||||
}
|
||||
|
||||
vec3 pixelNormal(vec4 tc0)
|
||||
{
|
||||
vec4 nm1 = texture2DLod(s_normalMap1, tc0.xy, tc0.w);
|
||||
#if WATER_LOD <= 1
|
||||
vec4 nm2 = texture2DLod(s_normalMap2, tc0.xy, tc0.w);
|
||||
vec4 nm3 = mix(nm1, nm2, u_nmAnimLerp.xxxx);
|
||||
#else
|
||||
vec4 nm3 = nm1;
|
||||
#endif
|
||||
return nmapUnpack(nm3);
|
||||
}
|
||||
|
||||
// Fresnel approximation. N1 and N2 are refractive indices.
|
||||
// for above water, use n1 = 1, n2 = 1.3, for underwater use n1 = 1.3, n2 = 1
|
||||
float fresnel(vec3 N, vec3 V, float n1, float n2, float p, float fade)
|
||||
{
|
||||
#if WATER_LOD == 0
|
||||
float r0 = (n1 - n2) / (n1 + n2);
|
||||
r0 *= r0;
|
||||
return r0 + (1.0 - r0) * pow(1.0 - abs(dot(normalize(N), V)), p);
|
||||
#else
|
||||
return 0.1 + saturate0(-1.9 * abs(dot(N, V)) + 0.8); // HAXX!
|
||||
#endif
|
||||
}
|
||||
|
||||
vec4 envColor(vec3 N, vec3 V, float fade)
|
||||
{
|
||||
vec3 dir = reflect(V, N);
|
||||
return textureCube(s_envMap, dir) * 0.91;
|
||||
}
|
||||
|
||||
vec4 deepWaterColor(vec4 light)
|
||||
{
|
||||
vec4 tint = 0.8 * vec4(118.0, 143.0, 153.0, 255.0) / 255.0;
|
||||
return (light + textureCubeLod(s_envMap, vec3(0.0, 1.0, 0.0), 10.0)) * tint;
|
||||
}
|
||||
|
||||
void water_ps()
|
||||
{
|
||||
vec3 N2 = v_normal;
|
||||
vec3 N1 = pixelNormal(v_texcoord0).xzy;
|
||||
vec3 N3 = 0.5 * (N2 + N1);
|
||||
|
||||
N3 = mix(N3, N2, v_color0.z);
|
||||
|
||||
vec3 L = -u_lamp0Dir.xyz;
|
||||
vec3 E = normalize(u_cameraPosition - v_worldPos.xyz);
|
||||
|
||||
vec4 light = lgridSample(s_lightMap, s_lightMapLookup, v_lightpos_fog.xyz);
|
||||
|
||||
float fre = fresnel(N3, E, 1.0, 1.3, 5.0, v_color0.x);
|
||||
vec3 diffuse = deepWaterColor(light).rgb;
|
||||
vec3 env = envColor(N3, -E, v_color0.x).rgb;
|
||||
|
||||
vec3 R = reflect(-L, N1);
|
||||
|
||||
#if WATER_LOD <= 1
|
||||
float specular = pow(saturate0(dot(R, E)), 1600.0) * L.y * 100.0; // baseline
|
||||
# ifndef GLSLES
|
||||
specular = 0.65 * saturate1(specular * saturate0(light.a - 0.4));
|
||||
# endif
|
||||
#else
|
||||
float specular = 0.0;
|
||||
#endif
|
||||
|
||||
vec3 result = mix(diffuse, env, fre) + vec3(specular, specular, specular);
|
||||
result = mix(u_fogColor.rgb, result, v_texcoord0.z);
|
||||
|
||||
gl_FragColor = vec4(result, 1.0);
|
||||
}
|
||||
Reference in New Issue
Block a user