1. 程式人生 > >純GLSL分步實現電影般畫面的湖光山色: 豔陽藍天和碧水(WebGL實現)

純GLSL分步實現電影般畫面的湖光山色: 豔陽藍天和碧水(WebGL實現)

這一篇加了水,模擬了水面的反射和折射。

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 );
}

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

相關的知識點: