├── style.css ├── README.md ├── index.html ├── LICENSE ├── script.js └── perlin.js /style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #d11713; 3 | } 4 | .scene { 5 | position: absolute; 6 | width: 100%; 7 | height: 100vh; 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Three.js blob 2 | 3 | ![blob](https://user-images.githubusercontent.com/12832880/134675596-4b433162-5f09-4ac2-bfdc-b257609a7e0a.gif) 4 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | The HTML5 Herald 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Eetu Eskelinen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | console.clear(); 2 | const canvas = document.querySelector('#bubble'); 3 | let width = canvas.offsetWidth, 4 | height = canvas.offsetHeight; 5 | const renderer = new THREE.WebGLRenderer({ 6 | canvas: canvas, 7 | antialias: true, 8 | alpha: true 9 | }); 10 | const scene = new THREE.Scene(); 11 | 12 | const setup = () => { 13 | renderer.setPixelRatio( window.devicePixelRatio ); 14 | renderer.setSize(width, height); 15 | renderer.setClearColor(0xebebeb, 0); 16 | renderer.shadowMap.enabled = true; 17 | renderer.shadowMapSoft = true; 18 | 19 | scene.fog = new THREE.Fog(0x000000, 10, 950); 20 | 21 | const aspectRatio = width / height; 22 | const fieldOfView = 100; 23 | const nearPlane = 0.1; 24 | const farPlane = 10000; 25 | camera = new THREE.PerspectiveCamera( 26 | fieldOfView, 27 | aspectRatio, 28 | nearPlane, 29 | farPlane 30 | ); 31 | camera.position.x = 0; 32 | camera.position.y = 0; 33 | camera.position.z = 300; 34 | } 35 | setup(); 36 | 37 | 38 | /*-------------------- 39 | Lights 40 | --------------------*/ 41 | let hemispshereLight, shadowLight, light2; 42 | const createLights = () => { 43 | hemisphereLight = new THREE.HemisphereLight(0xffffff,0x000000, .5) 44 | 45 | shadowLight = new THREE.DirectionalLight(0xffb0b0, .4); 46 | shadowLight.position.set(0, 450, 350); 47 | shadowLight.castShadow = true; 48 | 49 | shadowLight.shadow.camera.left = -650; 50 | shadowLight.shadow.camera.right = 650; 51 | shadowLight.shadow.camera.top = 650; 52 | shadowLight.shadow.camera.bottom = -650; 53 | shadowLight.shadow.camera.near = 1; 54 | shadowLight.shadow.camera.far = 1000; 55 | 56 | shadowLight.shadow.mapSize.width = 4096; 57 | shadowLight.shadow.mapSize.height = 4096; 58 | 59 | light2 = new THREE.DirectionalLight(0xfafafa, .25); 60 | light2.position.set(-600, 350, 350); 61 | 62 | light3 = new THREE.DirectionalLight(0xff2e2e, .15); 63 | light3.position.set(0, -250, 300); 64 | 65 | scene.add(hemisphereLight); 66 | scene.add(shadowLight); 67 | scene.add(light2); 68 | scene.add(light3); 69 | } 70 | createLights(); 71 | 72 | 73 | /*-------------------- 74 | Bubble 75 | --------------------*/ 76 | const vertex = width > 575 ? 80 : 40; 77 | const bubbleGeometry = new THREE.SphereGeometry( 120, vertex, vertex ); 78 | let bubble; 79 | const createBubble = () => { 80 | for(let i = 0; i < bubbleGeometry.vertices.length; i++) { 81 | let vector = bubbleGeometry.vertices[i]; 82 | vector.original = vector.clone(); 83 | } 84 | const bubbleMaterial = new THREE.MeshStandardMaterial({ 85 | emissive: 0xFFFFFF, 86 | emissiveIntensity: 0.5, 87 | roughness: 0.61, 88 | metalness: 0.21, 89 | side: THREE.FrontSide, 90 | //wireframe: true 91 | }); 92 | bubble = new THREE.Mesh(bubbleGeometry, bubbleMaterial); 93 | bubble.castShadow = true; 94 | bubble.receiveShadow = false; 95 | scene.add(bubble); 96 | } 97 | createBubble(); 98 | 99 | 100 | /*-------------------- 101 | Plane 102 | --------------------*/ 103 | const createPlane = () => { 104 | const planeGeometry = new THREE.PlaneBufferGeometry( 2000, 2000 ); 105 | const planeMaterial = new THREE.ShadowMaterial({ 106 | opacity: 0.15 107 | }); 108 | const plane = new THREE.Mesh( planeGeometry, planeMaterial ); 109 | plane.position.y = -150; 110 | plane.position.x = 0; 111 | plane.position.z = 0; 112 | plane.rotation.x = Math.PI / 180 * -90; 113 | plane.receiveShadow = true; 114 | scene.add(plane); 115 | } 116 | createPlane(); 117 | 118 | 119 | /*-------------------- 120 | Map 121 | --------------------*/ 122 | const map = (num, in_min, in_max, out_min, out_max) => { 123 | return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; 124 | } 125 | 126 | 127 | /*-------------------- 128 | Distance 129 | --------------------*/ 130 | const distance = (a, b) => { 131 | const dx = a.x - b.x; 132 | const dy = a.y - b.y; 133 | const d = Math.sqrt( dx * dx + dy * dy ); 134 | return d; 135 | } 136 | 137 | 138 | /*-------------------- 139 | Mouse 140 | --------------------*/ 141 | let mouse = new THREE.Vector2(0, 0); 142 | const onMouseMove = (e) => { 143 | TweenMax.to(mouse, 0.8, { 144 | x : e.clientX || e.pageX || e.touches[0].pageX || 0, 145 | y: e.clientY || e.pageY || e.touches[0].pageY || 0, 146 | ease: Power2.easeOut 147 | }); 148 | }; 149 | ['mousemove', 'touchmove'].forEach(event => { 150 | window.addEventListener(event, onMouseMove); 151 | }); 152 | 153 | 154 | /*-------------------- 155 | Spring 156 | --------------------*/ 157 | let spring = { 158 | scale: 1 159 | }; 160 | const clicking = { 161 | down: () => { 162 | TweenMax.to(spring, .7, { 163 | scale: .7, 164 | ease: Power3.easeOut 165 | }); 166 | }, 167 | up: () => { 168 | TweenMax.to(spring, .9, { 169 | scale: 1, 170 | ease: Elastic.easeOut 171 | }); 172 | } 173 | }; 174 | ['mousedown', 'touchstart'].forEach(event => { 175 | window.addEventListener(event, clicking.down); 176 | }); 177 | ['mouseup', 'touchend'].forEach(event => { 178 | window.addEventListener(event, clicking.up); 179 | }); 180 | 181 | 182 | /*-------------------- 183 | Resize 184 | --------------------*/ 185 | const onResize = () => { 186 | canvas.style.width = ''; 187 | canvas.style.height = ''; 188 | width = canvas.offsetWidth; 189 | height = canvas.offsetHeight; 190 | camera.aspect = width / height; 191 | camera.updateProjectionMatrix(); 192 | maxDist = distance(mouse, {x: width / 2, y: height / 2}); 193 | renderer.setSize(width, height); 194 | } 195 | let resizeTm; 196 | window.addEventListener('resize', function(){ 197 | resizeTm = clearTimeout(resizeTm); 198 | resizeTm = setTimeout(onResize, 200); 199 | }); 200 | 201 | 202 | /*-------------------- 203 | Noise 204 | --------------------*/ 205 | let dist = new THREE.Vector2(0, 0); 206 | let maxDist = distance(mouse, {x: width / 2, y: height / 2}); 207 | const updateVertices = (time) => { 208 | dist = distance(mouse, {x: width / 2, y: height / 2}); 209 | dist /= maxDist; 210 | dist = map(dist, 1, 0, 0, 1); 211 | for(let i = 0; i < bubbleGeometry.vertices.length; i++) { 212 | let vector = bubbleGeometry.vertices[i]; 213 | vector.copy(vector.original); 214 | let perlin = noise.simplex3( 215 | (vector.x * 0.006) + (time * 0.0005), 216 | (vector.y * 0.006) + (time * 0.0005), 217 | (vector.z * 0.006) 218 | ); 219 | let ratio = ((perlin * 0.3 * (dist + 0.1)) + 0.8); 220 | vector.multiplyScalar(ratio); 221 | } 222 | bubbleGeometry.verticesNeedUpdate = true; 223 | } 224 | 225 | 226 | /*-------------------- 227 | Animate 228 | --------------------*/ 229 | const render = (a) => { 230 | requestAnimationFrame(render); 231 | bubble.rotation.y= -4 + map(mouse.x, 0, width, 0, 4); 232 | bubble.rotation.z= 4 + map(mouse.y, 0, height, 0, -4); 233 | bubble.scale.set(spring.scale, spring.scale, spring.scale); 234 | updateVertices(a); 235 | renderer.clear(); 236 | renderer.render(scene, camera); 237 | } 238 | requestAnimationFrame(render); 239 | renderer.render(scene, camera); -------------------------------------------------------------------------------- /perlin.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A speed-improved perlin and simplex noise algorithms for 2D. 3 | * 4 | * Based on example code by Stefan Gustavson (stegu@itn.liu.se). 5 | * Optimisations by Peter Eastman (peastman@drizzle.stanford.edu). 6 | * Better rank ordering method by Stefan Gustavson in 2012. 7 | * Converted to Javascript by Joseph Gentle. 8 | * 9 | * Version 2012-03-09 10 | * 11 | * This code was placed in the public domain by its original author, 12 | * Stefan Gustavson. You may use it as you see fit, but 13 | * attribution is appreciated. 14 | * 15 | */ 16 | 17 | (function(global){ 18 | var module = global.noise = {}; 19 | 20 | function Grad(x, y, z) { 21 | this.x = x; this.y = y; this.z = z; 22 | } 23 | 24 | Grad.prototype.dot2 = function(x, y) { 25 | return this.x*x + this.y*y; 26 | }; 27 | 28 | Grad.prototype.dot3 = function(x, y, z) { 29 | return this.x*x + this.y*y + this.z*z; 30 | }; 31 | 32 | var grad3 = [new Grad(1,1,0),new Grad(-1,1,0),new Grad(1,-1,0),new Grad(-1,-1,0), 33 | new Grad(1,0,1),new Grad(-1,0,1),new Grad(1,0,-1),new Grad(-1,0,-1), 34 | new Grad(0,1,1),new Grad(0,-1,1),new Grad(0,1,-1),new Grad(0,-1,-1)]; 35 | 36 | var p = [151,160,137,91,90,15, 37 | 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 38 | 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 39 | 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, 40 | 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 41 | 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, 42 | 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 43 | 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 44 | 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, 45 | 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 46 | 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 47 | 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 48 | 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180]; 49 | // To remove the need for index wrapping, double the permutation table length 50 | var perm = new Array(512); 51 | var gradP = new Array(512); 52 | 53 | // This isn't a very good seeding function, but it works ok. It supports 2^16 54 | // different seed values. Write something better if you need more seeds. 55 | module.seed = function(seed) { 56 | if(seed > 0 && seed < 1) { 57 | // Scale the seed out 58 | seed *= 65536; 59 | } 60 | 61 | seed = Math.floor(seed); 62 | if(seed < 256) { 63 | seed |= seed << 8; 64 | } 65 | 66 | for(var i = 0; i < 256; i++) { 67 | var v; 68 | if (i & 1) { 69 | v = p[i] ^ (seed & 255); 70 | } else { 71 | v = p[i] ^ ((seed>>8) & 255); 72 | } 73 | 74 | perm[i] = perm[i + 256] = v; 75 | gradP[i] = gradP[i + 256] = grad3[v % 12]; 76 | } 77 | }; 78 | 79 | module.seed(0); 80 | 81 | /* 82 | for(var i=0; i<256; i++) { 83 | perm[i] = perm[i + 256] = p[i]; 84 | gradP[i] = gradP[i + 256] = grad3[perm[i] % 12]; 85 | }*/ 86 | 87 | // Skewing and unskewing factors for 2, 3, and 4 dimensions 88 | var F2 = 0.5*(Math.sqrt(3)-1); 89 | var G2 = (3-Math.sqrt(3))/6; 90 | 91 | var F3 = 1/3; 92 | var G3 = 1/6; 93 | 94 | // 2D simplex noise 95 | module.simplex2 = function(xin, yin) { 96 | var n0, n1, n2; // Noise contributions from the three corners 97 | // Skew the input space to determine which simplex cell we're in 98 | var s = (xin+yin)*F2; // Hairy factor for 2D 99 | var i = Math.floor(xin+s); 100 | var j = Math.floor(yin+s); 101 | var t = (i+j)*G2; 102 | var x0 = xin-i+t; // The x,y distances from the cell origin, unskewed. 103 | var y0 = yin-j+t; 104 | // For the 2D case, the simplex shape is an equilateral triangle. 105 | // Determine which simplex we are in. 106 | var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords 107 | if(x0>y0) { // lower triangle, XY order: (0,0)->(1,0)->(1,1) 108 | i1=1; j1=0; 109 | } else { // upper triangle, YX order: (0,0)->(0,1)->(1,1) 110 | i1=0; j1=1; 111 | } 112 | // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and 113 | // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where 114 | // c = (3-sqrt(3))/6 115 | var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords 116 | var y1 = y0 - j1 + G2; 117 | var x2 = x0 - 1 + 2 * G2; // Offsets for last corner in (x,y) unskewed coords 118 | var y2 = y0 - 1 + 2 * G2; 119 | // Work out the hashed gradient indices of the three simplex corners 120 | i &= 255; 121 | j &= 255; 122 | var gi0 = gradP[i+perm[j]]; 123 | var gi1 = gradP[i+i1+perm[j+j1]]; 124 | var gi2 = gradP[i+1+perm[j+1]]; 125 | // Calculate the contribution from the three corners 126 | var t0 = 0.5 - x0*x0-y0*y0; 127 | if(t0<0) { 128 | n0 = 0; 129 | } else { 130 | t0 *= t0; 131 | n0 = t0 * t0 * gi0.dot2(x0, y0); // (x,y) of grad3 used for 2D gradient 132 | } 133 | var t1 = 0.5 - x1*x1-y1*y1; 134 | if(t1<0) { 135 | n1 = 0; 136 | } else { 137 | t1 *= t1; 138 | n1 = t1 * t1 * gi1.dot2(x1, y1); 139 | } 140 | var t2 = 0.5 - x2*x2-y2*y2; 141 | if(t2<0) { 142 | n2 = 0; 143 | } else { 144 | t2 *= t2; 145 | n2 = t2 * t2 * gi2.dot2(x2, y2); 146 | } 147 | // Add contributions from each corner to get the final noise value. 148 | // The result is scaled to return values in the interval [-1,1]. 149 | return 70 * (n0 + n1 + n2); 150 | }; 151 | 152 | // 3D simplex noise 153 | module.simplex3 = function(xin, yin, zin) { 154 | var n0, n1, n2, n3; // Noise contributions from the four corners 155 | 156 | // Skew the input space to determine which simplex cell we're in 157 | var s = (xin+yin+zin)*F3; // Hairy factor for 2D 158 | var i = Math.floor(xin+s); 159 | var j = Math.floor(yin+s); 160 | var k = Math.floor(zin+s); 161 | 162 | var t = (i+j+k)*G3; 163 | var x0 = xin-i+t; // The x,y distances from the cell origin, unskewed. 164 | var y0 = yin-j+t; 165 | var z0 = zin-k+t; 166 | 167 | // For the 3D case, the simplex shape is a slightly irregular tetrahedron. 168 | // Determine which simplex we are in. 169 | var i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords 170 | var i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords 171 | if(x0 >= y0) { 172 | if(y0 >= z0) { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } 173 | else if(x0 >= z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } 174 | else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } 175 | } else { 176 | if(y0 < z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } 177 | else if(x0 < z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } 178 | else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } 179 | } 180 | // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), 181 | // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and 182 | // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where 183 | // c = 1/6. 184 | var x1 = x0 - i1 + G3; // Offsets for second corner 185 | var y1 = y0 - j1 + G3; 186 | var z1 = z0 - k1 + G3; 187 | 188 | var x2 = x0 - i2 + 2 * G3; // Offsets for third corner 189 | var y2 = y0 - j2 + 2 * G3; 190 | var z2 = z0 - k2 + 2 * G3; 191 | 192 | var x3 = x0 - 1 + 3 * G3; // Offsets for fourth corner 193 | var y3 = y0 - 1 + 3 * G3; 194 | var z3 = z0 - 1 + 3 * G3; 195 | 196 | // Work out the hashed gradient indices of the four simplex corners 197 | i &= 255; 198 | j &= 255; 199 | k &= 255; 200 | var gi0 = gradP[i+ perm[j+ perm[k ]]]; 201 | var gi1 = gradP[i+i1+perm[j+j1+perm[k+k1]]]; 202 | var gi2 = gradP[i+i2+perm[j+j2+perm[k+k2]]]; 203 | var gi3 = gradP[i+ 1+perm[j+ 1+perm[k+ 1]]]; 204 | 205 | // Calculate the contribution from the four corners 206 | var t0 = 0.6 - x0*x0 - y0*y0 - z0*z0; 207 | if(t0<0) { 208 | n0 = 0; 209 | } else { 210 | t0 *= t0; 211 | n0 = t0 * t0 * gi0.dot3(x0, y0, z0); // (x,y) of grad3 used for 2D gradient 212 | } 213 | var t1 = 0.6 - x1*x1 - y1*y1 - z1*z1; 214 | if(t1<0) { 215 | n1 = 0; 216 | } else { 217 | t1 *= t1; 218 | n1 = t1 * t1 * gi1.dot3(x1, y1, z1); 219 | } 220 | var t2 = 0.6 - x2*x2 - y2*y2 - z2*z2; 221 | if(t2<0) { 222 | n2 = 0; 223 | } else { 224 | t2 *= t2; 225 | n2 = t2 * t2 * gi2.dot3(x2, y2, z2); 226 | } 227 | var t3 = 0.6 - x3*x3 - y3*y3 - z3*z3; 228 | if(t3<0) { 229 | n3 = 0; 230 | } else { 231 | t3 *= t3; 232 | n3 = t3 * t3 * gi3.dot3(x3, y3, z3); 233 | } 234 | // Add contributions from each corner to get the final noise value. 235 | // The result is scaled to return values in the interval [-1,1]. 236 | return 32 * (n0 + n1 + n2 + n3); 237 | 238 | }; 239 | 240 | // ##### Perlin noise stuff 241 | 242 | function fade(t) { 243 | return t*t*t*(t*(t*6-15)+10); 244 | } 245 | 246 | function lerp(a, b, t) { 247 | return (1-t)*a + t*b; 248 | } 249 | 250 | // 2D Perlin Noise 251 | module.perlin2 = function(x, y) { 252 | // Find unit grid cell containing point 253 | var X = Math.floor(x), Y = Math.floor(y); 254 | // Get relative xy coordinates of point within that cell 255 | x = x - X; y = y - Y; 256 | // Wrap the integer cells at 255 (smaller integer period can be introduced here) 257 | X = X & 255; Y = Y & 255; 258 | 259 | // Calculate noise contributions from each of the four corners 260 | var n00 = gradP[X+perm[Y]].dot2(x, y); 261 | var n01 = gradP[X+perm[Y+1]].dot2(x, y-1); 262 | var n10 = gradP[X+1+perm[Y]].dot2(x-1, y); 263 | var n11 = gradP[X+1+perm[Y+1]].dot2(x-1, y-1); 264 | 265 | // Compute the fade curve value for x 266 | var u = fade(x); 267 | 268 | // Interpolate the four results 269 | return lerp( 270 | lerp(n00, n10, u), 271 | lerp(n01, n11, u), 272 | fade(y)); 273 | }; 274 | 275 | // 3D Perlin Noise 276 | module.perlin3 = function(x, y, z) { 277 | // Find unit grid cell containing point 278 | var X = Math.floor(x), Y = Math.floor(y), Z = Math.floor(z); 279 | // Get relative xyz coordinates of point within that cell 280 | x = x - X; y = y - Y; z = z - Z; 281 | // Wrap the integer cells at 255 (smaller integer period can be introduced here) 282 | X = X & 255; Y = Y & 255; Z = Z & 255; 283 | 284 | // Calculate noise contributions from each of the eight corners 285 | var n000 = gradP[X+ perm[Y+ perm[Z ]]].dot3(x, y, z); 286 | var n001 = gradP[X+ perm[Y+ perm[Z+1]]].dot3(x, y, z-1); 287 | var n010 = gradP[X+ perm[Y+1+perm[Z ]]].dot3(x, y-1, z); 288 | var n011 = gradP[X+ perm[Y+1+perm[Z+1]]].dot3(x, y-1, z-1); 289 | var n100 = gradP[X+1+perm[Y+ perm[Z ]]].dot3(x-1, y, z); 290 | var n101 = gradP[X+1+perm[Y+ perm[Z+1]]].dot3(x-1, y, z-1); 291 | var n110 = gradP[X+1+perm[Y+1+perm[Z ]]].dot3(x-1, y-1, z); 292 | var n111 = gradP[X+1+perm[Y+1+perm[Z+1]]].dot3(x-1, y-1, z-1); 293 | 294 | // Compute the fade curve value for x, y, z 295 | var u = fade(x); 296 | var v = fade(y); 297 | var w = fade(z); 298 | 299 | // Interpolate 300 | return lerp( 301 | lerp( 302 | lerp(n000, n100, u), 303 | lerp(n001, n101, u), w), 304 | lerp( 305 | lerp(n010, n110, u), 306 | lerp(n011, n111, u), w), 307 | v); 308 | }; 309 | 310 | })(this); 311 | --------------------------------------------------------------------------------