<!DOCTYPE html> <!-- // Title: Fusioned Bismuth (TokyoDemoFest 2017 GLSL Graphics Compo 3rd place) // Copyright (c) 2017 gam0022 // License: Attribution-NonCommercial-ShareAlike (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US) --> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <title>three.js webgl - raymarching - carbon</title> <style type="text/css"> body { background-color: black; margin: 0; padding: 0; } a { color: skyblue } canvas { display: block; position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto; } #info { color: white; font-size: 13px; position: absolute; bottom: 10px; width: 100%; text-align: center; z-index: 100; } </style> </head> <body> <div id="info"> <a href="http://threejs.org" target="_blank">three.js</a> - webgl raymarching demo - Fusioned Bismuth by <a href="https://github.com/gam0022" target="_blank">gam0022</a><br> <a href="http://tokyodemofest.jp/2017/" target="_blank">Tokyo Demo Fest 2017</a> GLSL Graphics compo 3rd place (<a href="http://gam0022.net/blog/2017/02/24/tdf2017/" target="_blank">article in Japanese</a>) </div> <script id="fragment_shader" type="x-shader/x-fragment"> // Title: Fusioned Bismuth (TokyoDemoFest 2017 GLSL Graphics Compo 3rd place) // Copyright (c) 2017 gam0022 // License: Attribution-NonCommercial-ShareAlike (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US) // // Thanks // - DE used folding by gaz (https://www.shadertoy.com/view/Mlf3Wj) // - Just snow by baldand (https://www.shadertoy.com/view/ldsGDn) // - Sky and Ground by morgan3d (https://www.shadertoy.com/view/4sKGWt) precision highp float; #define DEBUG 1 #define SHADER_TOY 0 // uniforms #if SHADER_TOY == 0 uniform float time; uniform vec2 mouse; uniform vec2 resolution; #endif // debug for camera #if DEBUG uniform bool debugCamera; uniform vec3 cameraPos; uniform vec3 cameraDir; #endif // consts const float INF = 1e+10; const float EPS = 1e-2; const float EPS_N = 1e-3; const float OFFSET = EPS * 100.0; const float PI = 3.14159265359; const float PI2 = 6.28318530718; const float PIH = 1.57079632679; const float PIQ = 0.78539816339; // globals const vec3 lightDir = vec3( -0.48666426339228763, 0.8111071056538127, -0.3244428422615251 ); float lTime; // ray struct Ray { vec3 origin; vec3 direction; }; // camera struct Camera { vec3 eye, target; vec3 forward, right, up; float zoom; }; Ray cameraShootRay(Camera c, vec2 uv) { c.forward = normalize(c.target - c.eye); c.right = normalize(cross(c.forward, c.up)); c.up = normalize(cross(c.right, c.forward)); Ray r; r.origin = c.eye; r.direction = normalize(uv.x * c.right + uv.y * c.up + c.zoom * c.forward); return r; } // intersection struct Intersection { bool hit; vec3 position; float distance; vec3 normal; vec2 uv; float count; //int material; vec3 color; float metalness; }; //#define METAL_MATERIAL 0 //#define MIRROR_MATERIAL 1 // util #define saturate(x) clamp(x, 0.0, 1.0) float hash(vec2 p) { return fract(1e4 * sin(17.0 * p.x + p.y * 0.1) * (0.1 + abs(sin(p.y * 13.0 + p.x)))); } float noise(vec2 x) { vec2 i = floor(x), f = fract(x); float a = hash(i); float b = hash(i + vec2(1.0, 0.0)); float c = hash(i + vec2(0.0, 1.0)); float d = hash(i + vec2(1.0, 1.0)); vec2 u = f * f * (3.0 - 2.0 * f); return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y; } // https://www.shadertoy.com/view/4sKGWt float fbm(vec2 p) { const mat2 m2 = mat2(0.8, -0.6, 0.6, 0.8); p.xy += 0.1 * lTime; float f = 0.5000 * noise(p); p = m2 * p * 2.02; f += 0.2500 * noise(p); p = m2 * p * 2.03; f += 0.1250 * noise(p); p = m2 * p * 2.01; f += 0.0625 * noise(p); return f / 0.9375; } float easeInCubic( float t ) { return t * t * t; } float easeInOutCubic(float t) { return t < 0.5 ? 4.0 * t * t * t : (t - 1.0) * (2.0 * t - 2.0) * (2.0 * t - 2.0) + 1.0; } float gauss(float x) { float a = 50.0; return exp(-x * x / a); } // Distance Functions // operations //vec3 opRep( vec3 p, float interval ) { // return mod( p, interval ) - 0.5 * interval; //} #define opRep(p, interval) (mod(p, interval) - 0.5 * interval) //vec2 opRepLimit(vec2 p, float interval, float limit) { // return mod(clamp(p, -limit, limit), interval) - 0.5 * interval; //} #define opRepLimit(p, interval, limit) (mod(clamp(p, -limit, limit), interval) - 0.5 * interval) // https://www.shadertoy.com/view/Mlf3Wj mat2 rotate(in float a) { float s=sin(a),c=cos(a); return mat2(c,s,-s,c); } vec2 fold(in vec2 p, in float s) { float a = PI / s - atan(p.x, p.y); float n = PI2 / s; a = floor(a / n) * n; p *= rotate(a); return p; } float smin(float d1, float d2, float k) { float h = exp(-k * d1) + exp(-k * d2); return -log(h) / k; } // Distance Functions float sdBox( vec3 p, vec3 b ) { vec3 d = abs(p) - b; return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0)); } float dSphere(vec3 p, float r) { return length(p) - r; } float dBar( vec2 p, float interval, float width) { return length( max( abs( opRep( p, interval ) ) - width, 0.0 ) ); } #define META_SCENE_END_TIME (32.0) #define UFO_SCENE_END_TIME (117.0) #define SNOW_SCENE_END_TIME (182.0) float dFract(inout vec3 p) { float radius = 1.0; float radiusScale = 0.45 * abs(sin(0.3 * lTime)); float d = sdBox(p, vec3(radius)); for (int i = 0; i < 5; i++) { vec3 q = abs(p) + normalize(vec3(-1.0)) * radius * (1.0 + radiusScale); d = min(d, sdBox(p, vec3(radius))); p = q; radius *= radiusScale; } return d; } float dTree(vec3 p) { float scale = 0.6 * saturate(1.5 * sin(0.05 * (lTime - UFO_SCENE_END_TIME - 2.0))); float width = mix(0.3 * scale, 0.0, saturate(p.y)); vec3 size = vec3(width, 1.0, width); float d = sdBox(p, size); for (int i = 0; i < 10; i++) { vec3 q = p; q.x = abs(q.x); q.y -= 0.5 * size.y; q.xy *= rotate(-1.2); d = min(d, sdBox(p, size)); p = q; size *= scale; } return d; } float dSnowCrystal(inout vec3 p) { p.xy = fold(p.xy, 6.0); return dTree(p); } float dMix(inout vec3 p) { float sphere = dSphere(p, 1.5); float box = sdBox(p, vec3(1.1)); float d = mix(sphere, box, 0.5 + clamp(sin(PIQ * lTime), -0.5, 0.5)); return d; } float dMeta(inout vec3 p) { // copy from cameraControl vec3 target = vec3(0.0); float t1 = lTime - META_SCENE_END_TIME; target.y = clamp(-0.7 * t1, -2.8, 100.0); float a = max(0.0, 2.0 - lTime * 0.1) + cos(lTime * 0.3); float b = 0.2 * sin(lTime); float d1 = dSphere(p - target - vec3(a, 0, b), 1.0); float d2 = dSphere(p - target + vec3(a, 0, b), 1.0); float d = smin(d1, d2, 1.0); return d; } float hWave(vec2 p, float t) { float h = 1.0; float a = 1.0; float b = 6.0; for(float i = 0.0; i < 3.0; i++) { float f = pow(2.0, i); h += 1.0 / f * (sin(f * a * p.x + b * t) + sin(f * a * p.y + b * t)); } return h; } float dWing(in vec3 p) { float t = lTime - META_SCENE_END_TIME; float l = length(p.xz); float fusion = gauss((lTime - META_SCENE_END_TIME - 5.0) * 2.0); float a = 0.1 + 0.06 * (1.0 + sin(PI * t + l)); float b = min(0.2 * t, 10.0) * gauss(l) + 0.1 * fusion * hWave(p.xz, t); p.y += -b + 15.0; vec3 p1 = p; p1.xz = opRepLimit(p.xz, 1.0, 20.0); vec3 p2 = p; p2 = opRep(p, 0.5); float d = sdBox(p1, vec3(0.2 + a * 3.0, 12.0 - a, 0.2 + a)); d = min(d, sdBox(p1, vec3(0.4 - a, 13.0 - 4.0 * a, 0.1 + a))); d = max(d, -sdBox(p1, vec3(0.3 - a, 14.0 - 4.0 * a, a))); d = max(d, -sdBox(p2, vec3(0.8 * a, 1.0 - a, 0.8 * a))); return d; } float dUfo(inout vec3 p) { float t = max((lTime - META_SCENE_END_TIME - 10.0) * 0.5, 1.0); float t1 = floor(t); float t2 = t1 + easeInOutCubic(t - t1); p.xz = fold(p.xz, min(t2, 10.0)); p.z -= 0.5; float d = dWing(p); //float t3 = lTime - META_SCENE_END_TIME; //if (t3 < 10.0) { // d -= mix(0.08, 0.0, saturate(t3 * 0.1)) * fbm(10.0 * p.xz + 5.0 * p.y); //} return d; } float dScene(vec3 p) { if (lTime < UFO_SCENE_END_TIME - 2.0) { float d = dMeta(p); d = smin(d, dUfo(p), clamp(lTime - META_SCENE_END_TIME, 1.0, 15.0)); return d; } else { //return dFract(p); return dSnowCrystal(p); } } float dSceneBump(vec3 p) { float d = dScene(p); float t3 = lTime - META_SCENE_END_TIME; if (t3 < 10.0) { d -= mix(0.08, 0.0, saturate(t3 * 0.1)) * fbm(10.0 * p.xz + 5.0 * p.y); } return d; } // color functions vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, saturate(p - K.xxx), c.y); } //vec3 calcNormal( vec3 p ) { // vec2 e = vec2( 1.0, -1.0 ) * 0.001; // return normalize( // e.xyy * dScene( p + e.xyy ) + e.yyx * dScene( p + e.yyx ) + // e.yxy * dScene( p + e.yxy ) + e.xxx * dScene( p + e.xxx ) ); //} #define calcNormal(p, dFunc) normalize(vec2(EPS_N, -EPS_N).xyy * dFunc(p + vec2(EPS_N, -EPS_N).xyy) + vec2(EPS_N, -EPS_N).yyx * dFunc(p + vec2(EPS_N, -EPS_N).yyx ) + vec2(EPS_N, -EPS_N).yxy * dFunc(p + vec2(EPS_N, -EPS_N).yxy) + vec2(EPS_N, -EPS_N).xxx * dFunc(p + vec2(EPS_N, -EPS_N).xxx)) float calcRate(float a, float b) { return a / (a + b); } void setMaterialAndUv(inout Intersection intersection, vec3 p) { //intersection.material = METAL_MATERIAL; float d1 = dUfo(p); float d2 = dMeta(p); float rate = calcRate(abs(d1), abs(d2)); intersection.metalness = rate; float t = lTime - META_SCENE_END_TIME; intersection.metalness = mix(intersection.metalness, 1.0, saturate(t * 0.05)); intersection.metalness = mix(intersection.metalness, 2.0, gauss((t - 13.0) * 3.0)); //if ( false && lTime <= META_SCENE_END_TIME ) { // intersection.material = MIRROR_MATERIAL; //} else { // dUfo(p); // intersection.material = METAL_MATERIAL; // intersection.uv = p.xz; //} } void intersectScene(inout Intersection intersection, inout Ray ray ) { float d; intersection.distance = 0.0; vec3 p = ray.origin; for (float i = 0.0; i < 128.0; i++) { d = dScene(p); intersection.distance += d; p = ray.origin + intersection.distance * ray.direction; intersection.count = i; if (abs(d) < EPS || intersection.distance > 100.0) break; } if (abs(d) < EPS) { intersection.hit = true; intersection.position = p; intersection.normal = calcNormal(p, dScene); setMaterialAndUv(intersection, p); } } float calcAo(in vec3 p, in vec3 n){ float sca = 1.0, occ = 0.0; for(float i=0.; i<5.; i++){ float hr = 0.05 + i * 0.08; float dd = dScene(n * hr + p); occ += (hr - dd) * sca; sca *= 0.5; } return saturate(1.0 - occ); } float calcShadow(in vec3 p, in vec3 rd) { float d; float distance = OFFSET; float bright = 1.0; float shadowIntensity = 0.5; float shadowSharpness = 16.0; for (int i = 0; i < 30; i++) { d = dScene(p + rd * distance); if (d < EPS) return shadowIntensity; bright = min(bright, shadowSharpness * d / distance); distance += d; } return shadowIntensity + (1.0 - shadowIntensity) * bright; } // Just snow by baldand // https://www.shadertoy.com/view/ldsGDn #define LAYERS 50 #define DEPTH .5 #define WIDTH .3 #define SPEED .6 float screenSpaceSnow(vec2 uv) { const mat3 p = mat3(13.323122,23.5112,21.71123,21.1212,28.7312,11.9312,21.8112,14.7212,61.3934); float acc = 0.0; float dof = 5.*sin(lTime*.1); for (int i=0;i<LAYERS;i++) { float fi = float(i); vec2 q = uv*(1.+fi*DEPTH); q += vec2(q.y*(WIDTH*mod(fi*7.238917,1.)-WIDTH*.5),SPEED*lTime/(1.+fi*DEPTH*.03)); vec3 n = vec3(floor(q),31.189+fi); vec3 m = floor(n)*.00001 + fract(n); vec3 mp = (31415.9+m)/fract(p*m); vec3 r = fract(mp); vec2 s = abs(mod(q,1.)-.5+.9*r.xy-.45); s += .01*abs(2.*fract(10.*q.yx)-1.); float d = .6*max(s.x-s.y,s.x+s.y)+max(s.x,s.y)-.01; float edge = .005+.05*min(.5*abs(fi-5.-dof),1.); acc += smoothstep(edge,-edge,d)*(r.x/(1.+.02*fi*DEPTH)); } return acc; } void calcRadiance(inout Intersection intersection, inout Ray ray, int bounce) { intersection.hit = false; intersectScene(intersection, ray); if ( intersection.hit ) { float diffuse = clamp(dot(lightDir, intersection.normal), 0.2, 1.0) * 0.5 + 0.5; float specular = pow(saturate(dot(reflect(lightDir, intersection.normal), ray.direction)), 10.0); float ao = calcAo(intersection.position, intersection.normal); float shadow = calcShadow(intersection.position, lightDir); vec3 fleshNormal = calcNormal(intersection.position, dSceneBump); float fleshDiffuse = clamp(dot(lightDir, fleshNormal), 0.2, 1.0) * 0.5 + 0.5; vec3 fleshBase = mix(vec3(1.0, 0.2, 0.2), vec3(0.3, 0.0, 0.0), fbm(2.0 * intersection.position.xz)); vec3 flesh = fleshBase * fleshDiffuse * ao * shadow + 0.1 * specular; float v = (META_SCENE_END_TIME <= lTime && lTime <= UFO_SCENE_END_TIME) ? 0.8 : 0.5; vec3 metalBase = hsv2rgb(vec3(0.1 * intersection.count, 0.3 * sin(lTime), v)); vec3 metal = metalBase * diffuse * ao * shadow + 0.1 * specular; intersection.color = mix(flesh, metal, intersection.metalness); intersection.normal = mix(fleshNormal, intersection.normal, intersection.metalness); // fog intersection.color = mix(intersection.color, 0.8 * vec3(0.7, 0.75, 0.8), min(1.0, pow(0.02 * intersection.distance, 2.0))); } else { vec3 sunnySky = vec3(0.4, 0.55, 0.8); vec3 cloudySky = vec3(0.7); vec3 cloud = vec3(1.0, 0.95, 1.0); vec3 base = mix(sunnySky, cloudySky, step(UFO_SCENE_END_TIME - 20.0, lTime)) * (1.0 - 0.8 * ray.direction.y) * 0.9; // Sun float sundot = saturate(dot(ray.direction, lightDir)); base += 0.25 * vec3(1.0, 0.7, 0.4) * pow(sundot, 8.0); base += 0.75 * vec3(1.0, 0.8, 0.5) * pow(sundot, 64.0); // Clouds float rd = ray.direction.y + 0.3; intersection.color = mix(base, cloud, 0.5 * smoothstep(0.5, 0.8, fbm((ray.origin.xz + ray.direction.xz * (250000.0 - ray.origin.y) / rd) * 0.000008))); intersection.color = mix(intersection.color, vec3(0.7, 0.75, 0.8), pow(1.0 - max(rd, 0.0), 4.0)); } // Whiteout //intersection.color = mix(intersection.color, vec3(1.0), gauss((lTime - UFO_SCENE_END_TIME) * 1.0)); intersection.color = mix(intersection.color, vec3(1.0), gauss((lTime - SNOW_SCENE_END_TIME) * 0.5)); } void cameraControl(inout Camera camera) { // time float t1 = lTime - META_SCENE_END_TIME; float t2 = t1 - 25.0; float t3 = t2 - 16.0; float t4 = t3 - 20.0; float t5 = lTime - UFO_SCENE_END_TIME; float t6 = t5 - 7.0; float t7 = t6 - 10.0; // blend // ufo float b1 = easeInOutCubic(saturate(t1 * 0.2)); float b2 = easeInOutCubic(saturate(t2 * 0.4)); float b3 = easeInOutCubic(saturate(t3 * 0.4)); float b4 = easeInOutCubic(saturate(t4 * 0.2)); // snow float b5 = easeInOutCubic(saturate(t5 * 0.2)); float b6 = easeInOutCubic(saturate(t6 * 0.5)); float b7 = easeInOutCubic(saturate(t7)); // camera target camera.target = vec3(0.0); camera.target.y = clamp(-0.7 * t1, -2.8, 100.0); camera.target.y = mix(camera.target.y, 1.0 + t2 * 0.3, b2); camera.target.y = mix(camera.target.y, 0.0, b3); camera.target.y = mix(camera.target.y, 0.0 + 0.6 * t4, b4); camera.target.y = mix(camera.target.y, 0.0, b5); camera.target.x = mix(camera.target.x, -0.7, b6); camera.target.x = mix(camera.target.x, 0.0, b7); // camera position vec3 p0 = camera.target + vec3(0.0, 0.0, -5.0); // down vec3 p1 = vec3(1.0, 0.3 * abs(t1 - 0.5), 1.0); // look down vec3 p2 = vec3(2.5 + t2 * 0.9, 0.5 + t2 * 0.1, 0.0); // side vec3 p3 = vec3(0.01, 4.0 + t3 * 0.2, 0.0); // zoom vec3 p4 = vec3(1.5, 10.0 + t4 * 0.1, 2.0); // leave vec3 p5 = vec3(0.0, 0.1, 6.0 - t5 * 0.3); float v = 0.3 + t5 * 0.07; vec3 p6 = vec3(1.7 * cos(v) - 1.0, 0.1, (0.5 + t6 * 0.01) * sin(v)); vec3 p7 = vec3(0.0, 0.0, 0.5 + t7 * 0.1); camera.eye = mix(p0, p1, b1); camera.eye = mix(camera.eye, p2, b2); camera.eye = mix(camera.eye, p3, b3); camera.eye = mix(camera.eye, p4, b4); camera.eye = mix(camera.eye, p5, b5); camera.eye = mix(camera.eye, p6, b6); camera.eye = mix(camera.eye, p7, b7); } void main(void) { // local time lTime = mod(time, SNOW_SCENE_END_TIME + 1.0); // fragment position vec2 uv = ( gl_FragCoord.xy * 2.0 - resolution ) / min( resolution.x, resolution.y ); // camera and ray Camera camera; cameraControl(camera); #if DEBUG if (debugCamera) { camera.eye = cameraPos; camera.target = cameraPos + cameraDir; } #endif camera.up = vec3(0.0, 1.0, 0.0);// y-up camera.zoom = 1.3; Ray ray = cameraShootRay(camera, uv); vec3 color = vec3(0.0); float reflection = 1.0; Intersection intersection; for (int bounce = 0; bounce <= 2; bounce++) { calcRadiance(intersection, ray, bounce); color += reflection * intersection.color; if (!intersection.hit /* || intersection.material != METAL_MATERIAL*/) break; reflection *= (intersection.metalness * 0.7); ray.origin = intersection.position + intersection.normal * OFFSET; ray.direction = normalize(reflect(ray.direction, intersection.normal)); } color += screenSpaceSnow(uv) * saturate((lTime - UFO_SCENE_END_TIME + 20.0) * 0.1); gl_FragColor = vec4(color, 1.0); } </script> <script id="vertex_shader" type="x-shader/x-vertex"> attribute vec3 position; void main(void) { gl_Position = vec4(position, 1.0); } </script> <script src="js/three.min.js"></script> <script src="js/controls/FlyControls.js"></script> <script src="js/controls/OrbitControls.js"></script> <script src="js/libs/stats.min.js"></script> <script src="js/libs/dat.gui.min.js"></script> <script> var camera, scene, flyControls, orbitControls, renderer; var prevCameraMatrixWorld; var geometry, material, plane; var mouse = new THREE.Vector2( 0.5, 0.5 ); var canvas; var stats; var clock = new THREE.Clock(); var config = { saveImage: function() { render(true); window.open( canvas.toDataURL() ); }, soucePlain: function() { outputShaderToTab( function(text){ return text; }); }, souceRelease: function() { outputShaderToTab( function(text){ return text.replace(/#define DEBUG 1/, '#define DEBUG 0'); }); }, souceShaderToy: function() { outputShaderToTab( function(text){ return text. replace(/#define DEBUG 1/, '#define DEBUG 0'). replace(/#define SHADER_TOY 0/, '#define SHADER_TOY 1'). replace(/void main\(void\)/, 'void mainImage( out vec4 fragColor, in vec2 fragCoord )'). replace(/\b(resolution)\b/g, 'iResolution.xy'). replace(/\b(mouse)\b/g, 'iMouse'). replace(/\b(gl_FragCoord)\b/g, 'fragCoord'). replace(/\b(gl_FragColor)\b/g, 'fragColor'). replace(/\b(time)\b/g, 'iGlobalTime'); }); }, camera: 'Auto', resolution: 256, aspectRatio: 4/3, pixelRatio: 1, time: 0, //time: 105, //time: 142, pause: false, }; init(); animate(); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(35, 800/600); camera.position.z = 5; camera.lookAt( new THREE.Vector3( 0.0, 0.0, 0.0 ) ); geometry = new THREE.PlaneBufferGeometry( 2.0, 2.0 ); material = new THREE.RawShaderMaterial( { uniforms: { resolution: { type: 'v2', value: new THREE.Vector2( config.resolution, config.resolution ) }, mouse: { type: 'v2', value: mouse }, time: { type: 'f', value: 0.0 }, debugCamera: { type: 'i', value: config.camera !== 'Auto' }, cameraPos: { type: 'v3', value: camera.getWorldPosition() }, cameraDir: { type: 'v3', value: camera.getWorldDirection() }, }, vertexShader: document.getElementById( 'vertex_shader' ).textContent, fragmentShader: document.getElementById( 'fragment_shader' ).textContent } ); plane = new THREE.Mesh( geometry, material ); plane.frustumCulled = false; scene.add( plane ); renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio( config.pixelRatio ); renderer.setSize( config.resolution * config.aspectRatio, config.resolution ); canvas = renderer.domElement; canvas.addEventListener( 'mousemove', onMouseMove ); window.addEventListener( 'resize', onWindowResize ); document.body.appendChild( canvas ); //flyControls = new THREE.FlyControls( camera, canvas ); //flyControls.autoForward = true; //flyControls.dragToLook = false; //flyControls.rollSpeed = Math.PI / 12; //flyControls.movementSpeed = 0.1; orbitControls = new THREE.OrbitControls( camera, canvas ); orbitControls.enablePan = true; //orbitControls.keyPanSpeed = 0.01; orbitControls.enableDamping = false; //orbitControls.dampingFactor = 0.015; orbitControls.enableZoom = true; //orbitControls.zoomSpeed = 0.001; //orbitControls.rotateSpeed = 0.8; orbitControls.autoRotate = false; orbitControls.autoRotateSpeed = 0.0; orbitControls.target = new THREE.Vector3( 0.0, 0.0, 0.0 ); var gui = new dat.GUI(); gui.add( config, 'saveImage' ).name( 'Save as PNG' ); //gui.add( config, 'soucePlain' ).name( 'view Shader' ); gui.add( config, 'souceRelease' ).name( 'GLSL sandbox' ); gui.add( config, 'souceShaderToy' ).name( 'ShaderToy' ); gui.add( config, 'camera', [ 'Auto', 'Orbit' ] ).name( 'Camera' ); gui.add( config, 'resolution', [ 256, 512, 800, 'full' ] ).name( 'Resolution' ).onChange( function( value ) { onWindowResize(); render(true); } ); gui.add( config, 'aspectRatio', { '16:9': 16/9, '4:3' : 4/3, '2:1': 2, '1:1': 1.0 } ).name( 'Aspect Ratio' ).onChange( function( value ) { onWindowResize(); render(true); } ); gui.add( config, 'pixelRatio', { '1/4x': 0.25, '1/2x' : 0.5, '1x': 1.0, '2x': 2.0 } ).name( 'Pixel Ratio' ).onChange( function( value ) { onWindowResize(); render(true); } ); gui.add( config, 'time', 0, 182 ).step( 0.1 ).name( 'time' ).listen(); gui.add( config, 'pause' ).name( 'Pause' ); stats = new Stats(); document.body.appendChild( stats.domElement ); } function animate( timestamp ) { var delta = clock.getDelta(); if ( !config.pause ) { config.time += delta; } stats.begin(); var needsUpdate = config.time !== material.uniforms.time.value; switch ( config.camera ) { case 'Auto': // none break; case 'Orbit': orbitControls.update(); if (camera && prevCameraMatrixWorld && !camera.matrixWorld.equals(prevCameraMatrixWorld)) { needsUpdate = true; } prevCameraMatrixWorld = camera.matrixWorld.clone(); break; case 'Fly': flyControls.update(delta); break; } render(needsUpdate); stats.end(); requestAnimationFrame( animate ); } function render(needsUpdate) { material.uniforms.resolution.value = new THREE.Vector2( canvas.width, canvas.height ); material.uniforms.mouse.value = mouse; material.uniforms.debugCamera.value = config.camera !== 'Auto'; material.uniforms.cameraPos.value = camera.getWorldPosition(); material.uniforms.cameraDir.value = camera.getWorldDirection(); material.uniforms.time.value = config.time; if (needsUpdate) { renderer.render( scene, camera ); } if (false) { var pos = camera.getWorldPosition(); var dir = camera.getWorldDirection(); document.getElementById( 'info' ).innerHTML = '' + pos.x + ', ' + pos.y + ', ' + pos.z + '<br />' + dir.x + ', ' + dir.y + ', ' + dir.z + '<br />' + material.uniforms.time.value; } } function onMouseMove( e ) { mouse.x = e.offsetX / canvas.width; mouse.y = e.offsetY / canvas.height; } function onWindowResize( e ) { if ( config.resolution === 'full' ) { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } else { canvas.width = config.aspectRatio * config.resolution; canvas.height = config.resolution; } renderer.setSize( canvas.width, canvas.height ); renderer.setPixelRatio( config.pixelRatio ); } function outputTextToTab(text) { var type = 'text/plain'; window.open('data:' + type + ';base64,' + window.btoa(text)); } function outputShaderToTab(filter) { var rawShader = document.getElementById( 'fragment_shader' ).textContent; var text = filter( rawShader ); outputTextToTab( text ); } </script> </body> </html>