上一篇: 纯GLSL分步实现电影般画面的湖光山色<Step1>: 艳阳蓝天(WebGL实现)_含影的博客-CSDN博客
这一篇加了水,模拟了水面的反射和折射。
Demo1(水面只有反射和自发光):Rendering & Art
precision highp float;
// u_param.xy: (stageWidth,stageHeight), u_param.z>1.0: mouse_down,u_param.z<1.0: mouse_up
uniform vec4 u_param;
// u_mouse.x: mouse x offset from mouseDown position x,
// u_mouse.y: mouse y offset from mouseDown position y,
// u_mouse.z: mouse x accumulation from mouseDown position x,
// u_mouse.w: mouse y accumulation from mouseDown position y
uniform vec4 u_mouse;
//
mat2 rotY(const in float a) {
return mat2(cos(a),sin(a),-sin(a),cos(a));
}
// light direction
vec3 lightDirection = normalize(vec3( 0.3,0.7, 0.6));
// create the sky and a sun
vec3 createSkyAndSun( const in vec3 ray ) {
float sunDensity = clamp( dot(lightDirection, ray), 0.0, 1.0 );
// sky color
vec3 color = vec3(0.2,0.4,0.6) - ray.y*0.3*vec3(0.1,0.5,1.0) + 0.13;
// sun and sun's halo
color += vec3(0.8,.7,0.2)*pow( sunDensity, 8.0 ) * 0.4 + vec3(1.0,.7,0.2)*pow( sunDensity, 16.0 ) * 0.6;
color *= 0.95;
return color;
}
// Intersection of the ray and the lake plane
bool intersectLakePlane(const in vec3 ro, const in vec3 ray, const in float height, inout float dis)
{
if (ray.y < 0.0) {
float d = -(ro.y - height)/ray.y;
d = min(10000.0, d);
if( d > 0. && d < dis ) {
dis = d;
return true;
}
}
return false;
}
// create a matrix33 of camera space to world space
mat3 viewMatrix3(vec3 eye, vec3 center, vec3 up) {
vec3 f = normalize(center - eye);
vec3 s = normalize(cross(f, up));
vec3 u = cross(s, f);
return mat3(s, u, -f);
}
// return gradient noise (in x) and its derivatives (in yz)
vec3 random3(vec3 c) {
float j = 4096.0*sin(dot(c,vec3(0.1,0.2,0.3)));
vec3 r;
r.z = fract(512.0*j);
j *= .125;
r.x = fract(512.0*j);
j *= .125;
r.y = fract(512.0*j);
return r-0.5;
}
/* skew constants for 3d simplex functions */
const float F3 = 0.3333333;
const float G3 = 0.1666667;
// thanks: https://www.shadertoy.com/view/XsX3zB
/* 3d simplex noise */
float simplex3d(vec3 p) {
/* 1. find current tetrahedron T and it's four vertices */
/* s, s+i1, s+i2, s+1.0 - absolute skewed (integer) coordinates of T vertices */
/* x, x1, x2, x3 - unskewed coordinates of p relative to each of T vertices*/
/* calculate s and x */
vec3 s = floor( p + dot(p, vec3(F3)) );
vec3 x = p - s + dot(s, vec3(G3));
/* calculate i1 and i2 */
vec3 e = step(vec3(0.0), (x - x.yzx));
vec3 i1 = e*(1.0 - e.zxy);
vec3 i2 = 1.0 - e.zxy*(1.0 - e);
/* x1, x2, x3 */
vec3 x1 = x - i1 + G3;
vec3 x2 = x - i2 + 2.0*G3;
vec3 x3 = x - 1.0 + 3.0*G3;
/* 2. find four surflets and store them in d */
vec4 w, d;
/* calculate surflet weights */
w.x = dot(x, x);
w.y = dot(x1, x1);
w.z = dot(x2, x2);
w.w = dot(x3, x3);
/* w fades from 0.6 at the center of the surflet to 0.0 at the margin */
w = max(0.6 - w, 0.0);
//
/* calculate surflet components */
d.x = dot(random3(s), x);
d.y = dot(random3(s + i1), x1);
d.z = dot(random3(s + i2), x2);
d.w = dot(random3(s + 1.0), x3);
/* multiply d by w^4 */
w *= w;
w *= w;
d *= w;
/* 3. return the sum of the four surflets */
return dot(d * 0.5, vec4(56.0));
}
void main()
{
vec2 coord = gl_FragCoord.xy / u_param.xy;
vec2 q = coord;
q = -1.0 + 2.0*q;
q.x *= u_param.x/ u_param.y;
//
float inTime = u_param.z * 2.0;
vec3 lookAtCenter = vec3(0.0, 0.3, 0.0);
//
vec3 eye = vec3(0.0, 0.3, 3.0);
inTime += 0.1 * u_mouse.z;
eye.xz *= rotY( mod(inTime * 0.03, 6.2831852) );
//
vec3 ray = normalize(vec3(q.x,q.y,1.5));
ray = viewMatrix3(eye, lookAtCenter, vec3(0.0,1.0,0.0)) * ray;
// color1 is sky color
vec3 color2,color1 = createSkyAndSun( ray );
//
float fresnelFactor = 0.0;
float reflectDis = 550.0;
vec3 normal = vec3(0.0,1.0,0.0);
if( intersectLakePlane( eye, ray, 0.0, reflectDis ))
{
vec3 pv = eye + reflectDis*ray;
float t = u_param.z * 0.1;
vec3 irv = vec3(pv.xz * 0.5,t);
normal.x = simplex3d(30.0 * irv) * 0.13;
normal.z = simplex3d(40.0 * irv) * 0.12;
normal = normalize(normal);
float nDotR = dot(normal,ray);
// Simulating the change of reflected light and refraction
fresnelFactor = clamp(pow(1.0 - abs(nDotR), 3.0),0.0,1.0);
// calculate sun linght on the lake surface
ray = reflect( ray, normal);
vec3 reflectSkyColor = createSkyAndSun( ray );
//
float k = (clamp(abs(reflectDis), 8.0, 30.0) - 8.0) / 22.0;
//k *= k;
// create the lake water surface color
vec3 waterReflectColor = vec3(0.4,0.4,0.5);
vec3 waterEmitColor = vec3(0.05,0.1,0.0);
color2 = (reflectSkyColor * 2.0 + waterReflectColor) * 0.2 * fresnelFactor + (1.0 - fresnelFactor) * waterEmitColor;
// calculate water color and sky color weights
color1 = color2 * (1.0 - k) + k * color1;
}
//
gl_FragColor = vec4( color1 * vec3(1.0,1.0,1.4), 1.0 );
}
Demo2(水面增加了湖底纹理和折射):Rendering & Art
precision highp float;
// texture is cobble.jpg
uniform sampler2D u_sampler0;
// u_param.xy: (stageWidth,stageHeight), u_param.z>1.0: mouse_down,u_param.z<1.0: mouse_up
uniform vec4 u_param;
// u_mouse.x: mouse x offset from mouseDown position x,
// u_mouse.y: mouse y offset from mouseDown position y,
// u_mouse.z: mouse x accumulation from mouseDown position x,
// u_mouse.w: mouse y accumulation from mouseDown position y
uniform vec4 u_mouse;
//
mat2 rotY(const in float a) {
return mat2(cos(a),sin(a),-sin(a),cos(a));
}
// light direction
vec3 lightDirection = normalize(vec3( 0.3,0.7, 0.6));
// create the sky and a sun
vec3 createSkyAndSun( const in vec3 ray ) {
float sunDensity = clamp( dot(lightDirection, ray), 0.0, 1.0 );
// sky color
vec3 color = vec3(0.2,0.4,0.6) - ray.y*0.3*vec3(0.1,0.5,1.0) + 0.13;
// sun and sun's halo
color += vec3(0.8,.7,0.2)*pow( sunDensity, 8.0 ) * 0.4 + vec3(1.0,.7,0.2)*pow( sunDensity, 16.0 ) * 0.6;
color *= 0.95;
return color;
}
// Intersection of the ray and the lake plane
bool intersectLakePlane(const in vec3 ro, const in vec3 ray, const in float height, inout float dis)
{
if (ray.y < 0.0) {
float d = -(ro.y - height)/ray.y;
d = min(10000.0, d);
if( d > 0. && d < dis ) {
dis = d;
return true;
}
}
return false;
}
// create a matrix33 of camera space to world space
mat3 viewMatrix3(vec3 eye, vec3 center, vec3 up) {
vec3 f = normalize(center - eye);
vec3 s = normalize(cross(f, up));
vec3 u = cross(s, f);
return mat3(s, u, -f);
}
// return gradient noise (in x) and its derivatives (in yz)
vec3 random3(vec3 c) {
float j = 4096.0*sin(dot(c,vec3(0.1,0.2,0.3)));
vec3 r;
r.z = fract(512.0*j);
j *= .125;
r.x = fract(512.0*j);
j *= .125;
r.y = fract(512.0*j);
return r-0.5;
}
/* skew constants for 3d simplex functions */
const float F3 = 0.3333333;
const float G3 = 0.1666667;
// thanks: https://www.shadertoy.com/view/XsX3zB
/* 3d simplex noise */
float simplex3d(vec3 p) {
/* 1. find current tetrahedron T and it's four vertices */
/* s, s+i1, s+i2, s+1.0 - absolute skewed (integer) coordinates of T vertices */
/* x, x1, x2, x3 - unskewed coordinates of p relative to each of T vertices*/
/* calculate s and x */
vec3 s = floor( p + dot(p, vec3(F3)) );
vec3 x = p - s + dot(s, vec3(G3));
/* calculate i1 and i2 */
vec3 e = step(vec3(0.0), (x - x.yzx));
vec3 i1 = e*(1.0 - e.zxy);
vec3 i2 = 1.0 - e.zxy*(1.0 - e);
/* x1, x2, x3 */
vec3 x1 = x - i1 + G3;
vec3 x2 = x - i2 + 2.0*G3;
vec3 x3 = x - 1.0 + 3.0*G3;
/* 2. find four surflets and store them in d */
vec4 w, d;
/* calculate surflet weights */
w.x = dot(x, x);
w.y = dot(x1, x1);
w.z = dot(x2, x2);
w.w = dot(x3, x3);
/* w fades from 0.6 at the center of the surflet to 0.0 at the margin */
w = max(0.6 - w, 0.0);
//
/* calculate surflet components */
d.x = dot(random3(s), x);
d.y = dot(random3(s + i1), x1);
d.z = dot(random3(s + i2), x2);
d.w = dot(random3(s + 1.0), x3);
/* multiply d by w^4 */
w *= w;
w *= w;
d *= w;
/* 3. return the sum of the four surflets */
return dot(d * 0.5, vec4(56.0));
}
void main()
{
vec2 coord = gl_FragCoord.xy / u_param.xy;
vec2 q = coord;
q = -1.0 + 2.0*q;
q.x *= u_param.x/ u_param.y;
//
float inTime = u_param.z * 2.0;
vec3 lookAtCenter = vec3(0.0, 0.3, 0.0);
//
vec3 eye = vec3(0.0, 0.3, 3.0);
inTime += 0.1 * u_mouse.z;
eye.xz *= rotY( mod(inTime * 0.03, 6.2831852) );
//
vec3 ray = normalize(vec3(q.x,q.y,1.5));
ray = viewMatrix3(eye, lookAtCenter, vec3(0.0,1.0,0.0)) * ray;
// color1 is sky color
vec3 color2,color1 = createSkyAndSun( ray );
//
float fresnelFactor = 0.0;
float reflectDis = 550.0;
vec3 normal = vec3(0.0,1.0,0.0);
if( intersectLakePlane( eye, ray, 0.0, reflectDis ))
{
vec3 pv = eye + reflectDis*ray;
float t = u_param.z * 0.1;
vec3 irv = vec3(pv.xz * 0.5,t);
normal.x = simplex3d(30.0 * irv) * 0.13;
normal.z = simplex3d(40.0 * irv) * 0.12;
normal = normalize(normal);
float nDotR = dot(normal,ray);
// Simulating the change of reflected light and refraction
fresnelFactor = clamp(pow(1.0 - abs(nDotR), 3.0),0.0,1.0);
// calculate sun linght on the lake surface
vec3 tempRay = reflect( ray, normal);
vec3 reflectSkyColor = createSkyAndSun( tempRay );
// Smooth the boundary between the sky and the water surface
float k = (clamp(abs(reflectDis), 5.0, 30.0) - 5.0) / 25.0;
//k *= k;
// create the lake water surface color
vec3 waterReflectColor = vec3(0.4,0.4,0.5);
vec3 waterEmitColor = vec3(0.05,0.1,0.0);
color2 = (reflectSkyColor * 2.0 + waterReflectColor) * 0.2 * fresnelFactor + (1.0 - fresnelFactor) * waterEmitColor;
// calculate water color and sky color weights
color1 = color2 * (1.0 - k) + k * color1;
// Simulating refraction of the lake bottom
vec3 refr = refract( ray, normal, 1./1.3330 );
intersectLakePlane( pv, refr, -2., reflectDis );
color1 += mix( texture2D( u_sampler0, (eye+reflectDis*refr).xz*1.3 ).xyz *
vec3(1.,.9,0.6), vec3(1.,.9,0.8)*0.5, clamp( reflectDis / 3., 0., 1.) )
* (1.-fresnelFactor)*0.125;
}
//
gl_FragColor = vec4( color1 * vec3(1.0,1.0,1.4), 1.0 );
}
//下面这一对标识是我这里识别资源数据的标识
//##config
texUrls = [
"static/voxgl/engine2/sdftest/column/res/cobble.jpg"
]
//##end
相关的知识点:
1).3D空间射线和平面相交求交点,请参考:
https://www.cnblogs.com/vilyLei/articles/2195156.html
2).反射reflection,请参考:
立方体贴图 - LearnOpenGL CN
3).菲涅尔(fresnel)折射refraction,请参考
立方体贴图 - LearnOpenGL CN
4).图像噪声noise(非常重要的东西,博大精深), 请参考
【图形学】谈谈噪声_worley噪声_妈妈说女孩子要自立自强的博客-CSDN博客
The Book of Shaders: Noise