diff --git a/README.md b/README.md index 06fcfd4..f9ec215 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,46 @@ +Fully Featured Globe: + +![Globe fully featured](resources/globe_best_water.png) + +Animated Butterfly Function: + +![Butterfly](resources/butterfly0.png) + +------------------------------------------------------------------------------- +CIS565: Project 5: WebGL +------------------------------------------------------------------------------- + +Part1: +Implemented: +* Sine and Simplex waves +* Animated butterfly function. + * A description of the butterfly function can be found here: http://mathworld.wolfram.com/ButterflyFunction.html + * Video can be found here: http://youtu.be/lUHQKqqMGtc + +Part2: +Implemented: +* Bump mapped terrain +* Rim lighting to simulate atmosphere +* Night-time lights on the dark side of the globe +* Specular mapping +* Moving clouds +Additionally: +* Procedural water rendering and animation using noise + * This was a pretty good attempt but it could definitely be more physically motivated. + It leads to some interesting artifacts but also some great looking bits. + +Video of my globe can be found here: http://youtu.be/C0MUYax2qEw + +Images showing water effect: + +![water0](resources/water0.png) +![water1](resources/water1.png) +![water2](resources/water2.png) + + + + + ------------------------------------------------------------------------------- CIS565: Project 5: WebGL ------------------------------------------------------------------------------- diff --git a/part1/butterfly.html b/part1/butterfly.html new file mode 100644 index 0000000..d98a2f3 --- /dev/null +++ b/part1/butterfly.html @@ -0,0 +1,65 @@ + + + +Butterfly + + + + + +
+ + + + + + + + + + + + diff --git a/part1/simplex.html b/part1/simplex.html new file mode 100644 index 0000000..80cd63b --- /dev/null +++ b/part1/simplex.html @@ -0,0 +1,100 @@ + + + +Simplex + + + + + +
+ + + + + + + + + + + + diff --git a/part1/vert_wave.html b/part1/vert_wave.html index 57107ca..4337eee 100644 --- a/part1/vert_wave.html +++ b/part1/vert_wave.html @@ -12,22 +12,39 @@ diff --git a/part1/vert_wave.js b/part1/vert_wave.js index b90b9cf..b0ec324 100644 --- a/part1/vert_wave.js +++ b/part1/vert_wave.js @@ -3,8 +3,8 @@ /*global window,document,Float32Array,Uint16Array,mat4,vec3,snoise*/ /*global getShaderSource,createWebGLContext,createProgram*/ - var NUM_WIDTH_PTS = 32; - var NUM_HEIGHT_PTS = 32; + var NUM_WIDTH_PTS = 200; + var NUM_HEIGHT_PTS = 200; var message = document.getElementById("message"); var canvas = document.getElementById("canvas"); @@ -31,6 +31,9 @@ var positionLocation = 0; var heightLocation = 1; var u_modelViewPerspectiveLocation; + var u_timeLocation; + //var u_color = vec3(0.0, 0.0, 0.0); + var u_time = 0.0; (function initializeShader() { var program; @@ -40,6 +43,8 @@ var program = createProgram(context, vs, fs, message); context.bindAttribLocation(program, positionLocation, "position"); u_modelViewPerspectiveLocation = context.getUniformLocation(program,"u_modelViewPerspective"); + u_timeLocation = context.getUniformLocation(program, "u_time"); + //u_color = context.getUniformLocation(program, "u_color"); context.useProgram(program); })(); @@ -138,11 +143,14 @@ var mvp = mat4.create(); mat4.multiply(persp, mv, mvp); + u_time += 0.01; + /////////////////////////////////////////////////////////////////////////// // Render context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT); - + context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); + context.uniform1f( u_timeLocation, u_time ); context.drawElements(context.LINES, numberOfIndices, context.UNSIGNED_SHORT,0); window.requestAnimFrame(animate); diff --git a/part2/frag_globe.html b/part2/frag_globe.html index 6aa5609..5b47381 100644 --- a/part2/frag_globe.html +++ b/part2/frag_globe.html @@ -69,6 +69,8 @@ varying vec3 v_Position; // position in camera coordinates varying vec3 v_positionMC; // position in model coordinates + float genwave( vec2 pos, float time ); + float simplexNoise(vec2 v); mat3 eastNorthUpToEyeCoordinates(vec3 positionMC, vec3 normalEC); void main(void) @@ -77,21 +79,85 @@ vec3 normal = normalize(v_Normal); // normalized eye-to-position vector in camera coordinates vec3 eyeToPosition = normalize(v_Position); - - float diffuse = clamp(dot(u_CameraSpaceDirLight, normal), 0.0, 1.0); + + float diff = dot(u_CameraSpaceDirLight, normal); vec3 toReflectedLight = reflect(-u_CameraSpaceDirLight, normal); float specular = max(dot(toReflectedLight, -eyeToPosition), 0.0); - specular = pow(specular, 20.0); - + specular = pow(specular, 40.0); + + // isOcean mask + float isOcean = texture2D( u_EarthSpec, v_Texcoord ).r; + // Remove specular if we are on land because its not shiny + vec3 bnormal; + if ( isOcean < 1.0 ) { + specular = 0.0; + + // Bump mapping + float center = texture2D( u_Bump, v_Texcoord ).r; + float right = texture2D( u_Bump, vec2(v_Texcoord.x+1.0/1024.0, v_Texcoord.y)).r; + float top = texture2D( u_Bump, vec2(v_Texcoord.x, v_Texcoord.y+1.0/512.0) ).r; + bnormal = normalize(vec3(center - right, center - top, 0.1)); + bnormal = normalize(eastNorthUpToEyeCoordinates( v_positionMC, -eyeToPosition)*bnormal); + } else { + + // Ocean waves and such + float xfreq =200.0; + float yfreq = 400.0; + float wave_scl = 0.4; + float scl = 0.5; + + float pnoise = 100.0*simplexNoise( vec2( 0.05*u_time, v_Texcoord.y*v_Texcoord.x) ); + + float cnoise = scl*simplexNoise( vec2(u_time + v_Texcoord.x*xfreq, v_Texcoord.y*yfreq) ); + float rnoise = scl*simplexNoise( vec2(u_time + (v_Texcoord.x+1.0/1024.0)*xfreq, v_Texcoord.y*yfreq) ); + float tnoise = scl*simplexNoise( vec2(u_time + v_Texcoord.x*xfreq, (v_Texcoord.y+1.0/512.0)*yfreq) ); + // Primary waves + /* + float center = sin( min(xfreq*v_Texcoord.x + 50.0*u_time + cnoise ); + float right = sin( xfreq*(v_Texcoord.x + 1.0/1024.0) + 50.0*u_time + rnoise); + float top = sin( xfreq*v_Texcoord.x + 50.0*u_time + tnoise); + */ + float tscl = 10.0; + float center = cnoise + wave_scl*sin( xfreq*v_Texcoord.y + tscl*(u_time+pnoise) + cnoise ); + float right = rnoise + wave_scl*sin( xfreq*(v_Texcoord.y + 1.0/1024.0) + tscl*(u_time+pnoise) + rnoise); + float top = tnoise + wave_scl*sin( xfreq*v_Texcoord.y + tscl*(u_time+pnoise) + tnoise); + + // Secondary waves + + + bnormal = normalize(vec3(center - right, center - top, 2.0)); + bnormal = normalize(eastNorthUpToEyeCoordinates( v_positionMC, -eyeToPosition)*bnormal); + } + + float cloudDiffuse = clamp( diff, 0.0, 1.0 ); + float diffuse = clamp( cloudDiffuse - dot(u_CameraSpaceDirLight, bnormal), 0.0, 1.0); + + vec3 dayColor = texture2D( u_DayDiffuse, v_Texcoord ).rgb; + vec3 nightColor = texture2D( u_Night, v_Texcoord ).rgb; + + // Read in cloud data + vec2 cloudCoord = vec2(v_Texcoord.x + 25.0*u_time/1024.0, v_Texcoord.y); + vec3 cloudColor = texture2D( u_Cloud, cloudCoord ).rgb; + vec3 cloudTrans = texture2D( u_CloudTrans, cloudCoord ).rgb; + float gammaCorrect = 1.0/1.2; //gamma correct by 1/1.2 - - vec3 dayColor = texture2D(u_DayDiffuse, v_Texcoord).rgb; - vec3 nightColor = texture2D(u_Night, v_Texcoord).rgb; //apply gamma correction to nighttime texture nightColor = pow(nightColor,vec3(gammaCorrect)); - vec3 color = ((0.6 * diffuse) + (0.4 * specular)) * dayColor; + // Mix blending factor + float range = 0.6; + float alpha = clamp(0.5*(diff + 1.0)/range, 0.0, 1.0); + vec3 color = mix( nightColor, ((0.6 * diffuse) + (0.4 * specular)) * dayColor, alpha ); + // Mix in cloud colors + color = mix( cloudDiffuse*cloudColor, color, cloudTrans ); + + // Apply Rim Lighting to create an atmosphere effect + float rim_factor = dot( v_Normal, v_Position ) + 1.0; + // If rim_factor is greater than zero then add some atmospheric blue + if ( rim_factor > 0.0 ) + color += vec3( rim_factor/4.0, rim_factor/2.0, rim_factor/1.0 ); + gl_FragColor = vec4(color, 1.0); } @@ -109,6 +175,46 @@ bitangentEC.x, bitangentEC.y, bitangentEC.z, normalEC.x, normalEC.y, normalEC.z); } + + vec3 permute(vec3 x) { + x = ((x*34.0)+1.0)*x; + return x - floor(x * (1.0 / 289.0)) * 289.0; + } + // Simple Simplex noise implementation + float simplexNoise(vec2 v) + { + const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439); + + vec2 i = floor(v + dot(v, C.yy) ); + vec2 x0 = v - i + dot(i, C.xx); + + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + + i = i - floor(i * (1.0 / 289.0)) * 289.0; + + vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + + i.x + vec3(0.0, i1.x, 1.0 )); + + vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); + m = m*m ; + m = m*m ; + + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + + m *= inversesqrt( a0*a0 + h*h ); + + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); + } diff --git a/part2/frag_globe.js b/part2/frag_globe.js index 1d8a877..110cc64 100644 --- a/part2/frag_globe.js +++ b/part2/frag_globe.js @@ -17,6 +17,7 @@ var message = document.getElementById("message"); var canvas = document.getElementById("canvas"); var gl = createWebGLContext(canvas, message); + //var gl = canvas.getContext("webgl", {antialias: true}); if (!gl) { return; } @@ -55,6 +56,7 @@ var u_EarthSpecLocation; var u_BumpLocation; var u_timeLocation; + var u_time; (function initializeShader() { var vs = getShaderSource(document.getElementById("vs")); @@ -108,7 +110,8 @@ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(positionLocation); - + + // Normals var normalsName = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, normalsName); @@ -250,12 +253,16 @@ mat4.inverse(mv, invTrans); mat4.transpose(invTrans); - var lightdir = vec3.create([1.0, 0.0, 1.0]); + var lightdir = vec3.create([0.0, 0.0, 1.0]); var lightdest = vec4.create(); vec3.normalize(lightdir); mat4.multiplyVec4(view, [lightdir[0], lightdir[1], lightdir[2], 0.0], lightdest); lightdir = vec3.createFrom(lightdest[0],lightdest[1],lightdest[2]); vec3.normalize(lightdir); + + + // Time + gl.uniform1f( u_timeLocation, time ); /////////////////////////////////////////////////////////////////////////// // Render @@ -288,6 +295,7 @@ gl.uniform1i(u_EarthSpecLocation, 5); gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); + // Update time time += 0.001; window.requestAnimFrame(animate); } diff --git a/part2/index.html b/part2/index.html new file mode 100644 index 0000000..2aea6fc --- /dev/null +++ b/part2/index.html @@ -0,0 +1,245 @@ + + + +Fragment Globe + + + + + +
+ + + + + + + + + + + + diff --git a/part2/noise3D.js b/part2/noise3D.js new file mode 100644 index 0000000..d519f47 --- /dev/null +++ b/part2/noise3D.js @@ -0,0 +1,316 @@ +(function(exports) { + "use strict"; + /*global window,vec3*/ + + exports = exports || window; + + function step(edge, x) { + return [ + (x[0] < edge[0]) ? 0.0 : 1.0, + (x[1] < edge[1]) ? 0.0 : 1.0, + (x[2] < edge[2]) ? 0.0 : 1.0 + ]; + } + + function step_vec4(edge, x) { + return [ + (x[0] < edge[0]) ? 0.0 : 1.0, + (x[1] < edge[1]) ? 0.0 : 1.0, + (x[2] < edge[2]) ? 0.0 : 1.0, + (x[3] < edge[3]) ? 0.0 : 1.0 + ]; + } + + function min(x, y) { + return [ + y[0] < x[0] ? y[0] : x[0], + y[1] < x[1] ? y[1] : x[1], + y[2] < x[2] ? y[2] : x[2] + ]; + } + + function max(x, y) { + return [ + y[0] > x[0] ? y[0] : x[0], + y[1] > x[1] ? y[1] : x[1], + y[2] > x[2] ? y[2] : x[2] + ]; + } + + function max_vec4(x, y) { + return [ + y[0] > x[0] ? y[0] : x[0], + y[1] > x[1] ? y[1] : x[1], + y[2] > x[2] ? y[2] : x[2], + y[3] > x[3] ? y[3] : x[3] + ]; + } + + function vec4_dot(left, right) { + return left[0] * right[0] + + left[1] * right[1] + + left[2] * right[2] + + left[3] * right[3]; + } + + // + // Description : Array and textureless GLSL 2D/3D/4D simplex + // noise functions. + // Author : Ian McEwan, Ashima Arts. + // Maintainer : ijm + // Lastmod : 20110822 (ijm) + // License : Copyright (C) 2011 Ashima Arts. All rights reserved. + // Distributed under the MIT License. See LICENSE file. + // https://github.com/ashima/webgl-noise + // + function mod289_vec3(x) { + var temp = (1.0 / 289.0); + return [ + x[0] - Math.floor(x[0] * temp) * 289.0, + x[1] - Math.floor(x[1] * temp) * 289.0, + x[2] - Math.floor(x[2] * temp) * 289.0 + ]; + } + + function mod289_vec4(x) { + var temp = (1.0 / 289.0); + return [ + x[0] - Math.floor(x[0] * temp) * 289.0, + x[1] - Math.floor(x[1] * temp) * 289.0, + x[2] - Math.floor(x[2] * temp) * 289.0, + x[3] - Math.floor(x[3] * temp) * 289.0 + ]; + } + + function permute_vec4(x) { + return mod289_vec4([ + ((x[0]*34.0)+1.0)*x[0], + ((x[1]*34.0)+1.0)*x[1], + ((x[2]*34.0)+1.0)*x[2], + ((x[3]*34.0)+1.0)*x[3] + ]); + } + + function taylorInvSqrt_vec4(r) { + return [ + 1.79284291400159 - 0.85373472095314 * r[0], + 1.79284291400159 - 0.85373472095314 * r[1], + 1.79284291400159 - 0.85373472095314 * r[2], + 1.79284291400159 - 0.85373472095314 * r[3] + ]; + } + + exports.snoise = function(v) { + // const vec2 C = vec2(1.0f/6.0f, 1.0f/3.0f) ; + // const vec4 D = vec4(0.0f, 0.5f, 1.0f, 2.0f); + var C = [1.0/6.0, 1.0/3.0]; + var D = [0.0, 0.5, 1.0, 2.0]; + + // vec3 i = floor(v + dot(v, vec3(C.y, C.y, C.y)) ); + // vec3 x0 = v - i + dot(i, vec3(C.x, C.x, C.x) ); + var temp0 = vec3.create(); + var temp3 = vec3.dot(v, [C[1], C[1], C[1]]); + vec3.add(v, [temp3, temp3, temp3], temp0); + var i = [Math.floor(temp0[0]), Math.floor(temp0[1]), Math.floor(temp0[2])]; + var temp1 = vec3.create(); + vec3.subtract(v, i, temp1); + var temp2 = vec3.dot(i, [C[0], C[0], C[0]]); + var x0 = vec3.create(); + vec3.add(temp1, [temp2, temp2, temp2], x0); + + // vec3 g = step(vec3(x0.y, x0.z, x0.x), vec3(x0.x, x0.y, x0.z)); + // vec3 l = 1.0f - g; + // vec3 i1 = min( vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y) ); + // vec3 i2 = max( vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y) ); + var g = step([x0[1], x0[2], x0[0]], [x0[0], x0[1], x0[2]]); + var l = [1.0 - g[0], 1.0 - g[1], 1.0 - g[2]]; + var i1 = min([g[0], g[1], g[2]], [l[2], l[0], l[1]]); + var i2 = max([g[0], g[1], g[2]], [l[2], l[0], l[1]]); + + // vec3 x1 = x0 - i1 + vec3(C.x, C.x, C.x); + // vec3 x2 = x0 - i2 + vec3(C.y, C.y, C.y); // 2.0*C.x = 1/3 = C.y + // vec3 x3 = x0 - vec3(D.y, D.y, D.y); // -1.0+3.0*C.x = -0.5 = -D.y + var temp4 = vec3.create(); + vec3.subtract(x0, i1, temp4); + var x1 = vec3.create(); + vec3.add(temp4, [C[0], C[0], C[0]], x1); + var temp5 = vec3.create(); + vec3.subtract(x0, i2, temp5); + var x2 = vec3.create(); + vec3.add(temp5, [C[1], C[1], C[1]], x2); + var x3 = vec3.create(); + vec3.subtract(x0, [D[1], D[1], D[1]], x3); + + // i = mod289(i); + // vec4 p = permute( permute( permute( + // i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + // + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + // + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); + i = mod289_vec3(i); + var p = permute_vec4([i[2] + 0.0, i[2] + i1[2], i[2] + i2[2], i[2] + 1.0]); + p[0] += i[1] + 0.0; + p[1] += i[1] + i1[1]; + p[2] += i[1] + i2[1]; + p[3] += i[1] + 1.0; + p = permute_vec4(p); + p[0] += i[0] + 0.0; + p[1] += i[0] + i1[0]; + p[2] += i[0] + i2[0]; + p[3] += i[0] + 1.0; + p = permute_vec4(p); + + // float n_ = 0.142857142857f; // 1.0/7.0 + // vec3 ns = n_ * vec3(D.w, D.y, D.z) - vec3(D.x, D.z, D.x); +// var n_ = 0.142857142857; // 1.0/7.0 +// var ns = [ +// n_ * D[3] - D[0], +// n_ * D[1] - D[2], +// n_ * D[2] - D[0] +// ]; + var ns = [ + 0.28571430, + -0.92857140, + 0.14285715 + ]; + + // vec4 j = p - 49.0f * floor(p * ns.z * ns.z); // mod(p,7*7) + var j = [ + p[0] - 49.0 * Math.floor(p[0] * ns[2] * ns[2]), + p[1] - 49.0 * Math.floor(p[1] * ns[2] * ns[2]), + p[2] - 49.0 * Math.floor(p[2] * ns[2] * ns[2]), + p[3] - 49.0 * Math.floor(p[3] * ns[2] * ns[2]) + ]; + + // vec4 x_ = floor(j * ns.z); + // vec4 y_ = floor(j - 7.0f * x_ ); // mod(j,N) + var x_ = [ + Math.floor(j[0] * ns[2]), + Math.floor(j[1] * ns[2]), + Math.floor(j[2] * ns[2]), + Math.floor(j[3] * ns[2]) + ]; + var y_ = [ + Math.floor(j[0] - 7.0 * x_[0] ), + Math.floor(j[1] - 7.0 * x_[1] ), + Math.floor(j[2] - 7.0 * x_[2] ), + Math.floor(j[3] - 7.0 * x_[3] ) + ]; + + // vec4 x = x_ *ns.x + vec4(ns.y, ns.y, ns.y, ns.y); + // vec4 y = y_ *ns.x + vec4(ns.y, ns.y, ns.y, ns.y); + // vec4 h = 1.0f - abs(x) - abs(y); + var x = [ + x_[0] *ns[0] + ns[1], + x_[1] *ns[0] + ns[1], + x_[2] *ns[0] + ns[1], + x_[3] *ns[0] + ns[1] + ]; + var y = [ + y_[0] *ns[0] + ns[1], + y_[1] *ns[0] + ns[1], + y_[2] *ns[0] + ns[1], + y_[3] *ns[0] + ns[1] + ]; + var h = [ + 1.0 - Math.abs(x[0]) - Math.abs(y[0]), + 1.0 - Math.abs(x[1]) - Math.abs(y[1]), + 1.0 - Math.abs(x[2]) - Math.abs(y[2]), + 1.0 - Math.abs(x[3]) - Math.abs(y[3]) + ]; + + // vec4 b0 = vec4( vec2(x.x, x.y), vec2(y.x, y.y) ); + // vec4 b1 = vec4( vec2(x.z, x.w), vec2(y.z, y.w) ); + var b0 = [x[0], x[1], y[0], y[1]]; + var b1 = [x[2], x[3], y[2], y[3]]; + + // vec4 s0 = floor(b0)*2.0f + 1.0f; + // vec4 s1 = floor(b1)*2.0f + 1.0f; + // vec4 sh = -step(h, vec4(0.0)); + + var s0 = [ + Math.floor(b0[0])*2.0 + 1.0, + Math.floor(b0[1])*2.0 + 1.0, + Math.floor(b0[2])*2.0 + 1.0, + Math.floor(b0[3])*2.0 + 1.0 + ]; + var s1 = [ + Math.floor(b1[0])*2.0 + 1.0, + Math.floor(b1[1])*2.0 + 1.0, + Math.floor(b1[2])*2.0 + 1.0, + Math.floor(b1[3])*2.0 + 1.0 + ]; + var sh = step_vec4(h, [0.0, 0.0, 0.0, 0.0]); + sh[0] = -sh[0]; + sh[1] = -sh[1]; + sh[2] = -sh[2]; + sh[3] = -sh[3]; + + // vec4 a0 = vec4(b0.x, b0.z, b0.y, b0.w) + vec4(s0.x, s0.z, s0.y, s0.w) * vec4(sh.x, sh.x, sh.y, sh.y) ; + // vec4 a1 = vec4(b1.x, b1.z, b1.y, b1.w) + vec4(s1.x, s1.z, s1.y, s1.w) * vec4(sh.z, sh.z, sh.w, sh.w) ; + var a0 = [ + b0[0] + s0[0] * sh[0], + b0[2] + s0[2] * sh[0], + b0[1] + s0[1] * sh[1], + b0[3] + s0[3] * sh[1] + ]; + var a1 = [ + b1[0] + s1[0] * sh[2], + b1[2] + s1[2] * sh[2], + b1[1] + s1[1] * sh[3], + b1[3] + s1[3] * sh[3] + ]; + + // vec3 p0 = vec3(a0.x, a0.y, h.x); + // vec3 p1 = vec3(a0.z, a0.w, h.y); + // vec3 p2 = vec3(a1.x, a1.y, h.z); + // vec3 p3 = vec3(a1.z, a1.w, h.w); + var p0 = [a0[0], a0[1], h[0]]; + var p1 = [a0[2], a0[3], h[1]]; + var p2 = [a1[0], a1[1], h[2]]; + var p3 = [a1[2], a1[3], h[3]]; + + // vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + // p0 *= norm.x; + // p1 *= norm.y; + // p2 *= norm.z; + // p3 *= norm.w; + var norm = taylorInvSqrt_vec4([vec3.dot(p0,p0), vec3.dot(p1,p1), vec3.dot(p2, p2), vec3.dot(p3,p3)]); + p0 = [p0[0]*norm[0], p0[1]*norm[0], p0[2]*norm[0]]; + p1 = [p1[0]*norm[1], p1[1]*norm[1], p1[2]*norm[1]]; + p2 = [p2[0]*norm[2], p2[1]*norm[2], p2[2]*norm[2]]; + p3 = [p3[0]*norm[3], p3[1]*norm[3], p3[2]*norm[3]]; + + // vec4 m = max(0.6f - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + // m = m * m; + var m = max_vec4([ + 0.6 - vec3.dot(x0,x0), + 0.6 - vec3.dot(x1,x1), + 0.6 - vec3.dot(x2,x2), + 0.6 - vec3.dot(x3,x3) + ], [ + 0.0, + 0.0, + 0.0, + 0.0 + ]); + m[0] *= m[0]; + m[1] *= m[1]; + m[2] *= m[2]; + m[3] *= m[3]; + + // return 42.0f * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), + // dot(p2,x2), dot(p3,x3) ) ); + return 42.0 * vec4_dot([ + m[0] * m[0], + m[1] * m[1], + m[2] * m[2], + m[3] * m[3] + ], [ + vec3.dot(p0,x0), + vec3.dot(p1,x1), + vec3.dot(p2,x2), + vec3.dot(p3,x3) + ]); + }; + +}()); diff --git a/resources/butterfly0.png b/resources/butterfly0.png new file mode 100644 index 0000000..01818e6 Binary files /dev/null and b/resources/butterfly0.png differ diff --git a/resources/butterfly1.png b/resources/butterfly1.png new file mode 100644 index 0000000..dbfcd98 Binary files /dev/null and b/resources/butterfly1.png differ diff --git a/resources/fully_featured_globe.png b/resources/fully_featured_globe.png new file mode 100644 index 0000000..1d0dca1 Binary files /dev/null and b/resources/fully_featured_globe.png differ diff --git a/resources/globe_best_water.png b/resources/globe_best_water.png new file mode 100644 index 0000000..0dca5d4 Binary files /dev/null and b/resources/globe_best_water.png differ diff --git a/resources/water0.png b/resources/water0.png new file mode 100644 index 0000000..ebc47b7 Binary files /dev/null and b/resources/water0.png differ diff --git a/resources/water1.png b/resources/water1.png new file mode 100644 index 0000000..c5653de Binary files /dev/null and b/resources/water1.png differ diff --git a/resources/water2.png b/resources/water2.png new file mode 100644 index 0000000..a48afdf Binary files /dev/null and b/resources/water2.png differ