├── 1matmul.txt
├── Final Presentation.pdf
├── Links.txt
├── Pics
├── CUDA PathTracer 5000 iterations.bmp
├── DebugIntersectMatColor.bmp
├── DebugIntersectMatEmit.bmp
├── DebugIntersectNormal.bmp
├── DebugIntersectPos.bmp
├── DebugRayDir.bmp
├── FinalResultFromWebGL.bmp
├── SSAA comparison.bmp
├── cover.jpg
├── performance_firefox.JPG
└── subsurface+ssaa.bmp
├── README.md
├── WebGL_Path_Tracer.html
├── js
├── WebGL_Path_Tracer.js
├── lib
│ ├── dat.gui.min.js
│ ├── gl-matrix.js
│ └── stats.min.js
└── webGLUtility.js
├── left-arrow.png
└── right-arrow.png
/1matmul.txt:
--------------------------------------------------------------------------------
1 | vec3 randomDirectionInSphere(float seed) {
2 | float u = getrandom(vec3(12.9898, 78.233, 151.7182), seed);
3 | float v = getrandom(vec3(63.7264, 10.873, 623.6736), seed);
4 |
5 | float up = u * 2.0 - 1.0; // cos(theta)
6 | float over = sqrt(1.0 - up * up); // sin(theta)
7 | float around = v * 3.14;
8 |
9 | return vec3( up, cos(around) * over, sin(around) * over );
10 | }
11 |
12 |
13 | mat4 multiply(in mat4 mat, in mat4 mato) {
14 | mat4 dest;
15 |
16 | // Cache the matrix values (makes for huge speed increases!)
17 | float a00 = mat[0][0], a01 = mat[0][1], a02 = mat[0][2], a03 = mat[0][3];
18 | float a10 = mat[1][0], a11 = mat[1][1], a12 = mat[1][2], a13 = mat[1][3];
19 | float a20 = mat[2][0], a21 = mat[2][1], a22 = mat[2][2], a23 = mat[2][3];
20 | float a30 = mat[3][0], a31 = mat[3][1], a32 = mat[3][2], a33 = mat[3][3];
21 |
22 | // Cache only the current line of the second matrix
23 | float b0 = mato[0][0], b1 = mato[0][1], b2 = mato[0][2], b3 = mato[0][3];
24 | dest[0][0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
25 | dest[0][1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
26 | dest[0][2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
27 | dest[0][3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
28 |
29 |
30 | b0 = mato[1][0];
31 | b1 = mato[1][1];
32 | b2 = mato[1][2];
33 | b3 = mato[1][3];
34 | dest[1][0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
35 | dest[1][1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
36 | dest[1][2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
37 | dest[1][3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
38 |
39 | b0 = mato[2][0];
40 | b1 = mato[2][1];
41 | b2 = mato[2][2];
42 | b3 = mato[2][3];
43 | dest[2][0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
44 | dest[2][1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
45 | dest[2][2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
46 | dest[2][3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
47 |
48 | b0 = mato[3][0];
49 | b1 = mato[3][1];
50 | b2 = mato[3][2];
51 | b3 = mato[3][3];
52 | dest[3][0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
53 | dest[3][1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
54 | dest[3][2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
55 | dest[3][3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
56 |
57 | return dest;
58 | }
59 |
60 |
61 |
62 | vec3 getRandomPointOnSphere(in GEOM sphere, in float seed){
63 |
64 | float radius = 0.5;
65 |
66 | vec3 point;
67 |
68 | float theta, phi;
69 | theta = 180.0 * getrandom(vec3(12.9898, 78.233, 151.7182), seed); //0-180
70 | phi = 360.0 * getrandom(vec3(78.233, 12.9898, 151.7182), seed+1.0); //0-360
71 |
72 | float degToRad = PI / 180.0;
73 |
74 | point.x = radius * sin(theta * degToRad) * cos(phi * degToRad);
75 | point.y = radius * sin(theta * degToRad) * sin(phi * degToRad);
76 | point.z = radius * cos(theta * degToRad);
77 |
78 | vec3 randPoint = (sphere.model * vec4(point, 1.0)).xyz;
79 |
80 | return randPoint;
81 | }
82 |
83 | vec3 getRandomPointOnCube(in GEOM cube, in float seed){
84 |
85 | vec3 origin = (cube.model * vec4(0.0,0.0,0.0,1.0)).xyz;
86 | vec3 xmax = (cube.model * vec4(0.5,0.0,0.0,1.0)).xyz;
87 | vec3 ymax = (cube.model * vec4(0.0,0.5,0.0,1.0)).xyz;
88 | vec3 zmax = (cube.model * vec4(0.0,0.0,0.5,1.0)).xyz;
89 | float xradius = distance(origin, xmax);
90 | float yradius = distance(origin, ymax);
91 | float zradius = distance(origin, zmax);
92 |
93 | //get surface areas of sides
94 | vec3 radii = vec3(xradius,yradius,zradius);
95 | float side1 = radii.x * radii.y * 4.0; //x-y face
96 | float side2 = radii.z * radii.y * 4.0; //y-z face
97 | float side3 = radii.x * radii.z * 4.0; //x-z face
98 | float totalarea = 2.0 * (side1+side2+side3);
99 |
100 | //pick random face, weighted by surface area
101 | float russianRoulette = getrandom(vec3(12.9898, 78.233, 151.7182), seed); //0-1
102 |
103 | float rand1 = getrandom(vec3(78.233, 12.9898, 151.7182), seed + 1.0) - 0.5; //-0.5-0.5
104 | float rand2 = getrandom(vec3(151.7182, 12.9898, 78.233), seed + 2.0) - 0.5; //-0.5-0.5
105 |
106 | vec3 point = vec3(0.5,0.5,0.5);
107 |
108 | if(russianRoulette<(side1/totalarea))
109 | point = vec3(rand1, rand2, 0.5);
110 | else if(russianRoulette<((side1*2.0)/totalarea))
111 | point = vec3(rand1, rand2, -0.5);
112 | else if(russianRoulette<(((side1*2.0)+(side2))/totalarea))
113 | point = vec3(0.5, rand1, rand2);
114 | else if(russianRoulette<(((side1*2.0)+(side2*2.0))/totalarea))
115 | point = vec3(-0.5, rand1, rand2);
116 | else if(russianRoulette<(((side1*2.0)+(side2*2.0)+(side3))/totalarea))
117 | point = vec3( rand1, 0.5, rand2);
118 | else
119 | point = vec3( rand1, -0.5, rand2);
120 |
121 |
122 | vec3 randPoint = (cube.model * vec4(point,1.0)).xyz;
123 |
124 | return randPoint;
125 |
126 | }
127 |
128 |
--------------------------------------------------------------------------------
/Final Presentation.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Final Presentation.pdf
--------------------------------------------------------------------------------
/Links.txt:
--------------------------------------------------------------------------------
1 | http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/#The_Model__View_and_Projection_matrices
--------------------------------------------------------------------------------
/Pics/CUDA PathTracer 5000 iterations.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Pics/CUDA PathTracer 5000 iterations.bmp
--------------------------------------------------------------------------------
/Pics/DebugIntersectMatColor.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Pics/DebugIntersectMatColor.bmp
--------------------------------------------------------------------------------
/Pics/DebugIntersectMatEmit.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Pics/DebugIntersectMatEmit.bmp
--------------------------------------------------------------------------------
/Pics/DebugIntersectNormal.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Pics/DebugIntersectNormal.bmp
--------------------------------------------------------------------------------
/Pics/DebugIntersectPos.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Pics/DebugIntersectPos.bmp
--------------------------------------------------------------------------------
/Pics/DebugRayDir.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Pics/DebugRayDir.bmp
--------------------------------------------------------------------------------
/Pics/FinalResultFromWebGL.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Pics/FinalResultFromWebGL.bmp
--------------------------------------------------------------------------------
/Pics/SSAA comparison.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Pics/SSAA comparison.bmp
--------------------------------------------------------------------------------
/Pics/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Pics/cover.jpg
--------------------------------------------------------------------------------
/Pics/performance_firefox.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Pics/performance_firefox.JPG
--------------------------------------------------------------------------------
/Pics/subsurface+ssaa.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/Pics/subsurface+ssaa.bmp
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | WebGL PathTracer
3 | ================
4 |
5 | Members
6 | -------------------
7 | [Bo Zhang](https://www.linkedin.com/pub/bo-zhang/7b/767/815) , [Ying Li](https://www.linkedin.com/in/liying3)
8 |
9 | Introduction
10 | -------------------
11 | In this project, we implement a WebGL version path-tracer. Most of computation of path tracer are written in the shader and we also add UI on the webpage which enables users to make their own scene.
12 |
13 | ####Features implemented:
14 | - Basic path tracer
15 | - Diffuse surfaces
16 | - Diffuse reflection
17 | - Fresnel Based Reflection & Refraction
18 | - Camera interactivity
19 | - Subsurface scattering (Fake)
20 | - Super-Sample Anti alias
21 | - Realtime Add new primitives
22 |
23 | Demo
24 | -------------------
25 | Website: [WebGL PathTracer](http://wulinjiansheng.github.io/WebGL_PathTracer/)
26 | Video: \
27 | [](http://youtu.be/Hm6VyPIbKP0)
28 | \
29 | Slide: https://github.com/wulinjiansheng/WebGL_PathTracer/blob/master/Final%20Presentation.pdf
30 |
31 | Screenshots
32 | -------------------
33 | #### Final Result(5000 iterations):
34 | 
35 |
36 | #### Debug views:
37 | - Initray Direction Test
38 | 
39 |
40 | - Intersection Normal Test
41 | 
42 |
43 | - Intersection Position Test
44 | 
45 |
46 | - Intersection Geometry Color Test
47 | 
48 |
49 | - Intersection Geometry Emittance Test
50 | 
51 |
52 |
53 |
54 | Implementation Details:
55 | ------------------------
56 | ####1. WebGL framework
57 | - Ping-pong textures
58 | We use Ping-pong technique to mix each iteration's image with previous result. That we store the previous iteration's image in texture0 and after path tracer computation we mix texture0's color with the new computed result color and store this new iteration's image in texture1. Then we exchange texture0 and texture1 and run the next iteration, so on and so forth.
59 |
60 | - Texture parameters
61 | We store the objects' information in a texture and in the shader we read objects' parameters from this texture. More specifically, every 7 pixels of the texture image store one object's information. This enables us to pass only one uniform to pass all the objects' information, which enables users to add as many objects as they want in the scene. (We set the max number of objects as 30.)
62 |
63 | **Store Pattern:**
64 | ####
65 | |Pixel | Object's Parameter
66 | |---------|----------------------
67 | |0 | `Color`
68 | |1 | `Objtype,Texturetype`
69 | |2 | `Refelective,Refractive`
70 | |3 | `IOR,Subsurface Scattering,Emittance`
71 | |4 | `Translation`
72 | |5 | `Rotation`
73 | |6 | `Scale`
74 |
75 |
76 | ###2. Path tracer
77 | - Fresnel Based Reflection & Refraction
78 | **Reference**: http://en.wikipedia.org/wiki/Fresnel_equations
79 | We add fresnel reflection and refraction. And it enables us to add transparent objects in the scene. To do this, we just use the fresnel equations to compute the reflective and refractive coefficients whenever the ray hits a refractive object, and get the reflect ray and refract ray. Then we generate a random number to decide which ray to return, based on the reflective and refractive coefficients.
80 |
81 | - Super sample anti-alisasing
82 | **Reference**: http://en.wikipedia.org/wiki/Supersampling
83 | We add super sample anti-alisasing, which makes my render result smoother. To do this, just jitter the initial rays randomly in each iteration.
84 | (Right image is with SSAA; 1500 iterations)
85 | 
86 |
87 |
88 | - Subsurface scattering (Fake)
89 | **Reference**: https://machinesdontcare.wordpress.com/tag/subsurface/
90 | We use a fakery way to implement subsurface scattering.
91 | We can see that light is scattered by interacting with the transparent sphere. But the result is still not very realistic.
92 | (Right image is with subsurface scattering; 2500 iterations with SSAA)
93 | 
94 |
95 |
96 | - Utility functions
97 | **Reference**: https://github.com/toji/gl-matrix
98 | We also write some mat4 utility functions in the shader, including mat translate,rotate,scale,inverse and transpose.
99 |
100 | ###3. UI
101 | - We use dat.gui.js to provide UI for the path tracer scene. Users can resize the size of rendered image, add new objects, currently including cube and sphere, to the current scene; and change the attribute of the objects. Once the configuration of the scene is changed, the image will be clear and rendered again.
102 |
103 | - We also provide mouse interaction to translate, rotate and zoom in/ out the scene. We use plane to represent the wall, so the wall will be cur off if not faced to camera.
104 |
105 | Performance Evaluation
106 | -------------------------------------------------------------------------------
107 | ###1. Cuda-Path tracer vs Webgl-Path tracer
108 | Both test on default scene(Same objects parameters and same trace depth) and run for 5000 iterations.
109 |
110 | - Final result on cuda (800X800):
111 | 
112 | - Final result on WebGL (800X800):
113 | 
114 |
115 | **FPS Comparison:**
116 |
117 | |Version | Average FPS
118 | |---------|----------------------
119 | |CUDA | `6.47`
120 | |WebGL | `12`
121 |
122 | From the result we can see that the WebGl version has a better performace.
123 |
124 | ###2. Webgl (Timing of each Procedure)
125 | |Procedure| Timing (ms)
126 | |---------|----------------------
127 | |Initialize WebGL | `7`
128 | |Initialize Shader | `45`
129 | |Load Scene | `42`
130 | |Draw Scene (Avg.) | `42`
131 |
132 | ###3. Number of objects
133 | Scene size: 800 X 800
134 |
135 | |Number of Objects| Average FPS
136 | |---------|----------------------
137 | |Default(14) | `12`
138 | |20 | `9`
139 | |Max(30) | `6`
140 |
141 |
142 | Thrid Party Code
143 | -------------------------------------------------------------------------------
144 | * stas.js:
145 | It's a library to visualize realize fps and timing.
146 | https://github.com/mrdoob/stats.js/
147 | * dat.gui.js:
148 | A lightweight graphical user interface for changing variables in JavaScript.
149 | https://code.google.com/p/dat-gui/
150 | * gl-matrix.js:
151 | Javascript Matrix and Vector library for High Performance WebGL apps.
152 | https://github.com/toji/gl-matrix
153 |
154 |
155 | Install and Build Instructions
156 | -------------------------------------------------------------------------------
157 | Run well on Windows Chrome and Firefox browser.
158 |
159 | Future Work
160 | -------------------------------------------------------------------------------
161 | - Phyisically based Subsurface Scattering
162 | - Texturemap, bumpmap
163 | - Make the project more robustic
164 |
165 |
--------------------------------------------------------------------------------
/WebGL_Path_Tracer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | WebGL Path Tracing
4 |
5 |
6 |
7 |
25 |
26 |
27 |
31 |
36 |
37 |
38 |
44 |
50 |
51 | Path tracing is a method of rendering images faithful to reality. The core algorithm of this WebGL Path Tracer is implemented in GLSL fragment shader. Each ray bounces in the scene around five times.
A
Demo is uploaded in YouTube and code is provided in
GitHub .
52 |
Features:
53 |
54 | Diffuse and Blinn-Phong
55 | Fresnel Reflection and Refraction
56 | Subsurface Scattering
57 | Super Sampling Anti-aliasing
58 | Intersection
59 |
60 |
Interaction:
61 |
62 | Space: pause toggle
63 | Left button: rotate scene
64 | Middle button: translate scene
65 | Right button: zoom in/ out
66 | Control panel: add objects and change attributes
67 |
68 |
69 |
70 |
71 |
91 |
842 |
856 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
--------------------------------------------------------------------------------
/js/WebGL_Path_Tracer.js:
--------------------------------------------------------------------------------
1 | window.onload = runGL;
2 |
3 | "use strict";
4 |
5 | var gl;
6 | var canvas;
7 | var message;
8 |
9 | var shaderProgram;
10 | var angleX = 0;
11 | var angleY = 0;
12 | var zoomZ = 15.5;
13 |
14 | var eye = { x: 0.0, y: 0.0, z: 0.0 };
15 | var center = { x: 0.0, y: 0.0, z: 0.0 };
16 | var up = { x: 0.0, y: 1.0, z: 0.0 };
17 | var FOVY = 45.0;
18 |
19 | eye.x = zoomZ * Math.sin(angleY) * Math.cos(angleX);
20 | eye.y = zoomZ * Math.sin(angleX);
21 | eye.z = zoomZ * Math.cos(angleY) * Math.cos(angleX);
22 |
23 | //Texture
24 | var textures;
25 | var objattrtex;
26 |
27 | //Vertex Shader
28 | var VertexLocation;
29 | var u_veyeLocation;
30 | var u_vInvMPLocation;
31 |
32 | //Fragment Shader
33 | var u_numsLocation;
34 | var u_eyeLocation;
35 | var u_timeLocation;
36 | var u_itrLocation;
37 | var u_textureLocation;
38 | var u_attrtextureLocation;
39 | var u_texsizeLocation;
40 | var u_attrtexsizeLocation;
41 | var u_SSAALocation;
42 | var u_texLocations = [];
43 |
44 | //Added for attrtexture
45 | //width and height must be pow(2,n)
46 | var attw = 1024; //width
47 | var atth = 2; //height
48 | var attributes = new Uint8Array(attw * atth * 4);
49 | //bool for SSAA
50 | var SSAA = 0;
51 |
52 | //render shader
53 | var renderProgram;
54 | var renderVertexAttribute;
55 | var vertexPositionBuffer;
56 | var frameBuffer;
57 | var u_textureLocationc;
58 |
59 | var time = 0;
60 | var iterations = 0;
61 |
62 | var Datas = [];
63 | var DefaultDatas = [];
64 | var defaultSize = 6;
65 |
66 | //Added
67 | var stats = initStats();
68 |
69 | ///////////////////////////////////////////////////////////////////////////
70 |
71 | function runGL() {
72 | var begin = Date.now();
73 | initGL();
74 | var end = Date.now();
75 | document.getElementById("time").innerHTML += "Initialize WebGL: " + (end-begin).toString() + " ms ";
76 |
77 | begin = end;
78 | initializeShader();
79 | initBuffers();
80 |
81 | end = Date.now();
82 | document.getElementById("time").innerHTML += "Initialize Shader: " + (end-begin).toString() + " ms ";
83 |
84 | initGUI();
85 |
86 | begin = end;
87 | initDfaultScene();
88 | end = Date.now();
89 | document.getElementById("time").innerHTML += "Load Scene: " + (end-begin).toString() + " ms";
90 |
91 | animate();
92 |
93 | //register
94 | canvas.onmousedown = handleMouseDown;
95 | canvas.oncontextmenu = function (ev) { return false; };
96 | document.onmouseup = handleMouseUp;
97 | document.onmousemove = handleMouseMove;
98 | document.onkeydown = handleKeyDown;
99 | }
100 |
101 | ///////////////////////////////////////////////////////////////////////////
102 |
103 | function initGL(){
104 | message = document.getElementById("message");
105 | canvas = document.getElementById("canvas");
106 | gl = createWebGLContext(canvas, message);
107 |
108 | if (!gl) {
109 | alert("Could not initialise WebGL, sorry :-(");
110 | return;
111 | }
112 | gl.viewport(0, 0, canvas.width, canvas.height);
113 | gl.clearColor(0.0, 0.0, 0.0, 1.0);
114 | gl.enable(gl.DEPTH_TEST);
115 | }
116 |
117 | function initBuffers() {
118 | vertexPositionBuffer = gl.createBuffer();
119 | gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
120 | var vertices = [
121 | 1.0, 1.0,
122 | -1.0, 1.0,
123 | 1.0, -1.0,
124 | -1.0, -1.0,
125 | ];
126 |
127 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
128 | gl.vertexAttribPointer(VertexLocation, 2, gl.FLOAT, false, 0, 0);
129 |
130 |
131 | frameBuffer = gl.createFramebuffer();
132 | var type = gl.getExtension('OES_texture_float') ? gl.FLOAT : gl.UNSIGNED_BYTE;
133 |
134 | textures = [];
135 | for (var i = 0; i < 2; i++) {
136 | textures.push(gl.createTexture());
137 | gl.bindTexture(gl.TEXTURE_2D, textures[i]);
138 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
139 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
140 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, canvas.width, canvas.height, 0, gl.RGB, type, null);
141 | }
142 | gl.bindTexture(gl.TEXTURE_2D, null);
143 |
144 | objattrtex = gl.createTexture();
145 | gl.bindTexture(gl.TEXTURE_2D, objattrtex);
146 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
147 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
148 | gl.bindTexture(gl.TEXTURE_2D, null);
149 | }
150 |
151 |
152 | function initializeShader() {
153 | //create render shader
154 | var renderVs = getShaderSource(document.getElementById("vs_render"));
155 | var renderFs = getShaderSource(document.getElementById("fs_render"));
156 |
157 | renderProgram = createProgram(gl, renderVs, renderFs, message);
158 | renderVertexAttribute = gl.getAttribLocation(renderProgram, 'aVertex');
159 | gl.enableVertexAttribArray(renderVertexAttribute);
160 |
161 | u_textureLocationc = gl.getUniformLocation(renderProgram, "texture");
162 |
163 | //create path tracer shader
164 | var vs = getShaderSource(document.getElementById("vs_pathTracer"));
165 | var fs = getShaderSource(document.getElementById("fs_pathTracer"));
166 |
167 | shaderProgram = createProgram(gl, vs, fs, message);
168 |
169 | //Vertex Shader
170 | VertexLocation = gl.getAttribLocation(shaderProgram, "aVertex");
171 | gl.enableVertexAttribArray(VertexLocation);
172 |
173 | u_veyeLocation = gl.getUniformLocation(shaderProgram, "vcameraPos");
174 | u_vInvMPLocation = gl.getUniformLocation(shaderProgram, "u_vInvMP");
175 |
176 | //Fragment Shader
177 | u_timeLocation = gl.getUniformLocation(shaderProgram, "time");
178 | u_itrLocation = gl.getUniformLocation(shaderProgram, "u_iterations");
179 | //Don't k why this line doesn't work
180 | u_numsLocation = gl.getUniformLocation(shaderProgram, "objnums");
181 | u_eyeLocation = gl.getUniformLocation(shaderProgram, "cameraPos");
182 |
183 |
184 | u_textureLocation = gl.getUniformLocation(shaderProgram, "texture");
185 | u_attrtextureLocation = gl.getUniformLocation(shaderProgram, "attrtexture");
186 | u_texsizeLocation = gl.getUniformLocation(shaderProgram, "texsize");
187 | u_attrtexsizeLocation = gl.getUniformLocation(shaderProgram, "attrtexsize");
188 | u_SSAALocation = gl.getUniformLocation(shaderProgram, "SSAA");
189 | }
190 |
191 | function animate() {
192 |
193 | if (stats)
194 | stats.update();
195 |
196 | message.innerHTML = "Iterations: " + (iterations).toString();
197 |
198 | if (!pause || iterations == 0)
199 | {
200 | ///////////////////////////////////////////////////////////////////////////
201 | // Render
202 | gl.useProgram(shaderProgram);
203 |
204 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
205 |
206 | var modelview = mat4.create();
207 | mat4.lookAt([eye.x, eye.y, eye.z], [center.x, center.y, center.z], [up.x, up.y, up.z], modelview);
208 |
209 | var projection = mat4.create();
210 | mat4.perspective(FOVY, canvas.width / canvas.height, 0.1, 100.0, projection);
211 |
212 | var modelviewprojection = mat4.create();
213 | mat4.multiply(projection, modelview, modelviewprojection);
214 |
215 | var inversemp = mat4.create();
216 | mat4.inverse(modelviewprojection, inversemp);
217 |
218 | gl.uniformMatrix4fv(u_vInvMPLocation, false, inversemp);
219 | gl.uniform3f(u_veyeLocation, eye.x, eye.y, eye.z);
220 | gl.uniform3f(u_eyeLocation, eye.x, eye.y, eye.z);
221 | gl.uniform1f(u_timeLocation, time);
222 | gl.uniform1f(u_itrLocation, iterations);
223 | gl.uniform1i(u_numsLocation, Datas.length);
224 | gl.uniform1i(u_SSAALocation, SSAA);
225 | //Added for texture size
226 | gl.uniform2f(u_texsizeLocation, canvas.width,canvas.height);
227 | gl.uniform2f(u_attrtexsizeLocation, attw, atth);
228 |
229 | gl.activeTexture(gl.TEXTURE0);
230 | gl.bindTexture(gl.TEXTURE_2D, textures[0]);
231 | gl.uniform1i(u_textureLocation, 0);
232 |
233 |
234 | gl.activeTexture(gl.TEXTURE1); //attributes for objects
235 | gl.bindTexture(gl.TEXTURE_2D, objattrtex);
236 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, attw, atth, 0, gl.RGBA, gl.UNSIGNED_BYTE, attributes);
237 | gl.uniform1i(u_attrtextureLocation, 1);
238 |
239 |
240 | gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
241 | gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
242 | gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures[1], 0);
243 | gl.vertexAttribPointer(VertexLocation, 2, gl.FLOAT, false, 0, 0);
244 |
245 |
246 | gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
247 | gl.bindFramebuffer(gl.FRAMEBUFFER, null);
248 |
249 | textures.reverse();
250 |
251 | gl.useProgram(renderProgram);
252 | gl.activeTexture(gl.TEXTURE0);
253 | gl.bindTexture(gl.TEXTURE_2D, textures[0]);
254 | gl.uniform1i(u_textureLocationc, 0);
255 |
256 | gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
257 | gl.vertexAttribPointer(renderVertexAttribute, 2, gl.FLOAT, false, 0, 0);
258 | gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
259 |
260 | iterations++;
261 | time += 1.0;
262 |
263 | }
264 |
265 | window.requestAnimFrame(animate);
266 | }
267 |
268 | ///////////////////////////////////////////////////////////////////////////
269 |
270 |
271 | function AddObjsAttr(i) {
272 | gl.useProgram(shaderProgram);
273 | //color:No need for map
274 | attributes[28 * i + 0] = 255.0 * Datas[i].obj_color[0]; attributes[28 * i + 1] = 255.0 * Datas[i].obj_color[1]; attributes[28 * i + 2] = 255.0 * Datas[i].obj_color[2]; attributes[28 * i + 3] = 255.0;
275 | //objtype:[0.0,5.0] to [0,255] texturetype:[0.0,5.0] to [0,255]
276 | attributes[28 * i + 4] = 255.0 * Datas[i].obj_type / 5.0; attributes[28 * i + 5] = 255.0 * Datas[i].obj_textureType / 5.0; attributes[28 * i + 6] = 255.0; attributes[28 * i + 7] = 255.0;
277 | //mat1:No need for map
278 | attributes[28 * i + 8] = 255.0 * Datas[i].obj_reflective; attributes[28 * i + 9] = 255.0 * Datas[i].obj_refractive; attributes[28 * i + 10] = 255.0 * Datas[i].obj_reflectivity; attributes[28 * i + 11] = 255.0;
279 | //mat2:IOR[0,3] to [0,255] emittance [0,25] to [0,255]
280 | attributes[28 * i + 12] = 255.0/3.0 * Datas[i].obj_indexOfRefraction; attributes[28 * i + 13] = 255.0 * Datas[i].obj_subsurfaceScatter; attributes[28 * i + 14] = 255.0 * Datas[i].obj_emittance/25.0; attributes[28 * i + 15] = 255.0;
281 | //pos:[-10.0,10.0] to [0,255]
282 | var mind = -10.0;
283 | var maxd = 10.0;
284 | attributes[28 * i + 16] = 255.0 * (Datas[i].obj_pos[0] - mind) / (maxd - mind); attributes[28 * i + 17] = 255.0 * (Datas[i].obj_pos[1] - mind) / (maxd - mind);
285 | attributes[28 * i + 18] = 255.0 * (Datas[i].obj_pos[2] - mind) / (maxd - mind); attributes[28 * i + 19] = 255.0;
286 | //rot:[0.0,360.0] to [0,255]
287 | attributes[28 * i + 20] = 255.0 * Datas[i].obj_rotation[0] / 360.0; attributes[28 * i + 21] = 255.0 * Datas[i].obj_rotation[1] / 360.0; attributes[28 * i + 22] = 255.0 * Datas[i].obj_rotation[2]/360.0; attributes[28 * i + 23] = 255.0;
288 | //scale:[0.0,10.0] to [0,255]
289 | attributes[28 * i + 24] = 255.0 * Datas[i].obj_scale[0] / 10.0; attributes[28 * i + 25] = 255.0 * Datas[i].obj_scale[1] / 10.0; attributes[28 * i + 26] = 255.0 * Datas[i].obj_scale[2] / 10.0; attributes[28 * i + 27] = 255.0;
290 |
291 | }
292 |
293 | var cubeNum = 0;
294 | function addCube() {
295 | if (Datas.length == 31)
296 | return;
297 | Datas.push({
298 | obj_pos: [Math.random()*10-5, Math.random()*10-5, Math.random()*10-5],
299 | obj_scale: [1.0, 1.0, 1.0],
300 | obj_rotation: [Math.random()*360, Math.random()*360, Math.random()*360],
301 | obj_color: [Math.random(), Math.random(), Math.random()],
302 | obj_type: 2,
303 | obj_textureType: 0,
304 | obj_reflective: 0,
305 | obj_refractive: 0,
306 | obj_reflectivity: 1.0,
307 | obj_indexOfRefraction: 1.0,
308 | obj_emittance: 0,
309 | obj_subsurfaceScatter: 0
310 | });
311 |
312 | AddObjsAttr(Datas.length - 1);
313 |
314 | GUIAddObj("Cube " + ++cubeNum, Datas.length - 1);
315 |
316 | iterations = 0;
317 | }
318 |
319 | var sphereNum = 3;
320 |
321 | function addSphere() {
322 | if (Datas.length == 31)
323 | return;
324 | Datas.push({
325 | obj_pos: [Math.random()*10-5, Math.random()*10-5, Math.random()*10-5],
326 | obj_scale: [1.0, 1.0, 1.0],
327 | obj_rotation: [Math.random()*360, Math.random()*360, Math.random()*360],
328 | obj_color: [Math.random(), Math.random(), Math.random()],
329 | obj_type: 0,
330 | obj_textureType: 0,
331 | obj_reflective: 0,
332 | obj_refractive: 0,
333 | obj_reflectivity: 1.0,
334 | obj_indexOfRefraction: 1.0,
335 | obj_emittance: 0,
336 | obj_subsurfaceScatter: 0
337 | });
338 |
339 | AddObjsAttr(Datas.length - 1);
340 |
341 | GUIAddObj("Sphere " + ++sphereNum, Datas.length - 1);
342 |
343 | iterations = 0;
344 | }
345 |
346 | function initDfaultScene() {
347 |
348 | //Light For Subsurface Scattering,only one light and always at first
349 | DefaultDatas.push({
350 | obj_pos: [0.0, 4.95, 0.0],
351 | obj_scale: [3.8, 0.1, 3.8],
352 | obj_rotation: [0.0, 0.0, 0.0],
353 | obj_color: [1.0, 1.0, 1.0],
354 | obj_type: 2,
355 | obj_textureType: 0,
356 | obj_reflective: 0,
357 | obj_refractive: 0,
358 | obj_reflectivity: 1.0,
359 | obj_indexOfRefraction: 1.0,
360 | obj_emittance: 25,
361 | obj_subsurfaceScatter: 0
362 | });
363 |
364 | //Walls
365 | var WallScale = 10.0;
366 | var WallTrans = 5.0;
367 |
368 | DefaultDatas.push({
369 | obj_pos: [0.0, 0.0, -WallTrans+0.1],
370 | obj_scale: [WallScale, 1.0, WallScale],
371 | obj_rotation: [91.0, 0.0, 0.0],
372 | obj_color: [1.0, 1.0, 1.0],
373 | obj_type: 1,
374 | obj_textureType: 0,
375 | obj_reflective: 0,
376 | obj_refractive: 0,
377 | obj_reflectivity: 1.0,
378 | obj_indexOfRefraction: 1.0,
379 | obj_emittance: 0,
380 | obj_subsurfaceScatter: 0
381 | });
382 |
383 | DefaultDatas.push({
384 | obj_pos: [-WallTrans+0.1, 0.0, 0.0],
385 | obj_scale: [ WallScale,1.0, WallScale],
386 | obj_rotation: [0.0, 0.0, 271.0],
387 | obj_color: [0.75, 0.25, 0.25],
388 | obj_type: 1,
389 | obj_textureType: 0,
390 | obj_reflective: 0,
391 | obj_refractive: 0,
392 | obj_reflectivity: 1.0,
393 | obj_indexOfRefraction: 1.0,
394 | obj_emittance: 0,
395 | obj_subsurfaceScatter: 0
396 | });
397 |
398 | DefaultDatas.push({
399 | obj_pos: [WallTrans-0.1, 0.0, 0.0],
400 | obj_scale: [WallScale,1.0, WallScale],
401 | obj_rotation: [0.0, 0.0, 91.0],
402 | obj_color: [0.25, 0.25, 0.75],
403 | obj_type: 1,
404 | obj_textureType: 0,
405 | obj_reflective: 0,
406 | obj_refractive: 0,
407 | obj_reflectivity: 1.0,
408 | obj_indexOfRefraction: 1.0,
409 | obj_emittance: 0,
410 | obj_subsurfaceScatter: 0
411 | });
412 |
413 | DefaultDatas.push({
414 | obj_pos: [0.0, WallTrans, 0.0],
415 | obj_scale: [WallScale, 1.0, WallScale],
416 | obj_rotation: [180.0, 0.0, 0.0],
417 | obj_color: [0.75, 0.75, 0.75],
418 | obj_type: 1,
419 | obj_textureType: 0,
420 | obj_reflective: 0,
421 | obj_refractive: 0,
422 | obj_reflectivity: 1.0,
423 | obj_indexOfRefraction: 1.0,
424 | obj_emittance: 0,
425 | obj_subsurfaceScatter: 0
426 | });
427 |
428 | DefaultDatas.push({
429 | obj_pos: [0.0, -WallTrans, 0.0],
430 | obj_scale: [WallScale, 1.0, WallScale],
431 | obj_rotation: [0.0, 0.0, 0.0],
432 | obj_color: [0.75, 0.75, 0.75],
433 | obj_type: 1,
434 | obj_textureType: 0,
435 | obj_reflective: 0,
436 | obj_refractive: 0,
437 | obj_reflectivity: 1.0,
438 | obj_indexOfRefraction: 1.0,
439 | obj_emittance: 0,
440 | obj_subsurfaceScatter: 0
441 | });
442 |
443 |
444 | //Sphere1
445 | DefaultDatas.push({
446 | obj_pos: [-2.0, 0.0, 0.0],
447 | obj_scale: [1.8, 1.8, 1.8],
448 | obj_rotation: [30.0, 4.0, 0.0],
449 | obj_color: [1.0, 0.0, 0.0],
450 | obj_type: 0,
451 | obj_textureType: 0,
452 | obj_reflective: 0,
453 | obj_refractive: 0,
454 | obj_reflectivity: 1.0,
455 | obj_indexOfRefraction: 1.0,
456 | obj_emittance: 0,
457 | obj_subsurfaceScatter: 0
458 | });
459 |
460 | //Sphere2
461 | DefaultDatas.push({
462 | obj_pos: [0.0, 0.0, 0.0],
463 | obj_scale: [1.8, 1.8, 1.8],
464 | obj_rotation: [30.0, 4.0, 0.0],
465 | obj_color: [0.95, 0.5, 0.4],
466 | obj_type: 0,
467 | obj_textureType: 0,
468 | obj_reflective: 1,
469 | obj_refractive: 0,
470 | obj_reflectivity: 1.0,
471 | obj_indexOfRefraction: 1.0,
472 | obj_emittance: 0,
473 | obj_subsurfaceScatter: 1
474 | });
475 |
476 |
477 | //Sphere3
478 | DefaultDatas.push({
479 | obj_pos: [2.0, 0.0, 0.0],
480 | obj_scale: [1.8, 1.8, 1.8],
481 | obj_rotation: [30.0, 4.0, 0.0],
482 | obj_color: [1.0, 1.0, 1.0],
483 | obj_type: 0,
484 | obj_textureType: 0,
485 | obj_reflective: 1,
486 | obj_refractive: 1,
487 | obj_reflectivity: 1.0,
488 | obj_indexOfRefraction: 3.0,
489 | obj_emittance: 0,
490 | obj_subsurfaceScatter: 1
491 | });
492 |
493 | //Box
494 | DefaultDatas.push({
495 | obj_pos: [0.0, -1.5, 0.0],
496 | obj_scale: [6.8, 0.2, 4.8],
497 | obj_rotation: [0.0, 0.0, 0.0],
498 | obj_color: [0.8, 0.8, 0.8],
499 | obj_type: 2,
500 | obj_textureType: 0,
501 | obj_reflective: 0,
502 | obj_refractive: 0,
503 | obj_reflectivity: 1.0,
504 | obj_indexOfRefraction: 1.0,
505 | obj_emittance: 0,
506 | obj_subsurfaceScatter: 0
507 | });
508 |
509 | //Legs
510 | var legpos1 = 3.0, legpos2 = 1.8;
511 | DefaultDatas.push({
512 | obj_pos: [legpos1, -3.5, legpos2],
513 | obj_scale: [0.3, 4.0, 0.3],
514 | obj_rotation: [0.0, 0.0, 0.0],
515 | obj_color: [0.9, 0.4, 0.0],
516 | obj_type: 2,
517 | obj_textureType: 0,
518 | obj_reflective: 0,
519 | obj_refractive: 0,
520 | obj_reflectivity: 1.0,
521 | obj_indexOfRefraction: 1.0,
522 | obj_emittance: 0,
523 | obj_subsurfaceScatter: 0
524 | });
525 |
526 | DefaultDatas.push({
527 | obj_pos: [-legpos1, -3.5, legpos2],
528 | obj_scale: [0.3, 4.0, 0.3],
529 | obj_rotation: [0.0, 0.0, 0.0],
530 | obj_color: [0.9, 0.4, 0.0],
531 | obj_type: 2,
532 | obj_textureType: 0,
533 | obj_reflective: 0,
534 | obj_refractive: 0,
535 | obj_reflectivity: 1.0,
536 | obj_indexOfRefraction: 1.0,
537 | obj_emittance: 0,
538 | obj_subsurfaceScatter: 0
539 | });
540 |
541 | DefaultDatas.push({
542 | obj_pos: [legpos1, -3.5, -legpos2],
543 | obj_scale: [0.3, 4.0, 0.3],
544 | obj_rotation: [0.0, 0.0, 0.0],
545 | obj_color: [0.9, 0.4, 0.0],
546 | obj_type: 2,
547 | obj_textureType: 0,
548 | obj_reflective: 0,
549 | obj_refractive: 0,
550 | obj_reflectivity: 1.0,
551 | obj_indexOfRefraction: 1.0,
552 | obj_emittance: 0,
553 | obj_subsurfaceScatter: 0
554 | });
555 |
556 | DefaultDatas.push({
557 | obj_pos: [-legpos1, -3.5, -legpos2],
558 | obj_scale: [0.3, 4.0, 0.3],
559 | obj_rotation: [0.0, 0.0, 0.0],
560 | obj_color: [0.9, 0.4, 0.0],
561 | obj_type: 2,
562 | obj_textureType: 0,
563 | obj_reflective: 0,
564 | obj_refractive: 0,
565 | obj_reflectivity: 1.0,
566 | obj_indexOfRefraction: 1.0,
567 | obj_emittance: 0,
568 | obj_subsurfaceScatter: 0
569 | });
570 | defaultScene();
571 | }
572 |
573 | function defaultScene() {
574 | Datas.length = 0;
575 |
576 | for (var i = 0; i < DefaultDatas.length; i++) {
577 | Datas[i] = DefaultDatas[i];
578 | AddObjsAttr(i);
579 | }
580 |
581 | iterations = 0;
582 |
583 |
584 | var node = document.getElementById("gui2");
585 | if (node != null)
586 | node.parentNode.removeChild(node);
587 |
588 | GUIDefaultScene();
589 | }
590 |
591 | function resize() {
592 | canvas.width = width;
593 | canvas.height = height;
594 |
595 | gl.viewport(0, 0, canvas.width, canvas.height);
596 |
597 | var type = gl.getExtension('OES_texture_float') ? gl.FLOAT : gl.UNSIGNED_BYTE;
598 |
599 | gl.activeTexture(gl.TEXTURE0);
600 | gl.bindTexture(gl.TEXTURE_2D, textures[0]);
601 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
602 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
603 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
604 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
605 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, canvas.width, canvas.height, 0, gl.RGB, type, null);
606 |
607 | gl.bindTexture(gl.TEXTURE_2D, textures[1]);
608 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
609 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
610 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
611 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
612 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, canvas.width, canvas.height, 0, gl.RGB, type, null);
613 |
614 | gl.bindTexture(gl.TEXTURE_2D, null);
615 |
616 | iterations = 0;
617 | }
618 |
619 |
620 |
621 | /////////////////////////////////////////////////////////////////////////////
622 |
623 | /*************************** performance ***********************************/
624 | function initStats() {
625 | stats = new Stats();
626 | stats.setMode(0); // 0: fps, 1: ms
627 |
628 | // Align top-left
629 | stats.domElement.style.position = 'absolute';
630 | stats.domElement.style.left ='200px';
631 | stats.domElement.style.top = '0px';
632 |
633 | document.body.appendChild(stats.domElement);
634 |
635 |
636 | return stats;
637 | }
638 |
639 | ///////////////////////////////////////////////////////////////////////////
640 |
641 | /************************* interaction ********************************/
642 | var mouseLeftDown = false;
643 | var mouseRightDown = false;
644 | var mouseMidDown = false;
645 | var lastMouseX = null;
646 | var lastMouseY = null;
647 |
648 | var pause = false;
649 |
650 | function handleMouseDown(event) {
651 | if (event.button == 2) {
652 | mouseLeftDown = false;
653 | mouseRightDown = true;
654 | mouseMidDown = false;
655 | }
656 | else if (event.button == 0) {
657 | mouseLeftDown = true;
658 | mouseRightDown = false;
659 | mouseMidDown = false;
660 | }
661 | else if (event.button == 1) {
662 | mouseLeftDown = false;
663 | mouseRightDown = false;
664 | mouseMidDown = true;
665 | }
666 | lastMouseX = event.clientX;
667 | lastMouseY = event.clientY;
668 | }
669 |
670 | function handleMouseUp(event) {
671 | mouseLeftDown = false;
672 | mouseRightDown = false;
673 | mouseMidDown = false;
674 | }
675 |
676 | function handleMouseMove(event) {
677 | if (!(mouseLeftDown || mouseRightDown || mouseMidDown)) {
678 | return;
679 | }
680 | var newX = event.clientX;
681 | var newY = event.clientY;
682 |
683 | var deltaX = newX - lastMouseX;
684 | var deltaY = newY - lastMouseY;
685 |
686 | if (mouseLeftDown) {
687 | // update the angles based on how far we moved since last time
688 | angleY -= deltaX * 0.01;
689 | angleX += deltaY * 0.01;
690 |
691 | // don't go upside down
692 | angleX = Math.max(angleX, -Math.PI / 2 + 0.01);
693 | angleX = Math.min(angleX, Math.PI / 2 - 0.01);
694 |
695 | eye.x = zoomZ * Math.sin(angleY) * Math.cos(angleX);
696 | eye.y = zoomZ * Math.sin(angleX);
697 | eye.z = zoomZ * Math.cos(angleY) * Math.cos(angleX);
698 | }
699 | else if (mouseRightDown) {
700 | zoomZ += 0.01 * deltaY;
701 | zoomZ = Math.min(Math.max(zoomZ, 4.0), 20.0);
702 |
703 | eye.x = zoomZ * Math.sin(angleY) * Math.cos(angleX);
704 | eye.y = zoomZ * Math.sin(angleX);
705 | eye.z = zoomZ * Math.cos(angleY) * Math.cos(angleX);
706 | }
707 | else if (mouseMidDown) {
708 | center.x -= 0.01 * deltaX;
709 | center.y += 0.01 * deltaY;
710 | eye.x -= 0.01 * deltaX;
711 | eye.y += 0.01 * deltaY;
712 | }
713 |
714 | lastMouseX = newX;
715 | lastMouseY = newY;
716 |
717 | iterations = 0;
718 | }
719 |
720 | function handleKeyDown(event){
721 | if (event.keyCode == 32)
722 | pause = !pause;
723 | }
724 |
725 | var toHide = true;
726 | function toggleContorller(){
727 | if (toHide)
728 | {
729 | document.getElementById("icon").style.background = 'url("left-arrow.png")';
730 | document.getElementById("gui-left").style.display = "none";
731 | document.getElementById("gui-right").style.display = "none";
732 | }
733 | else
734 | {
735 | document.getElementById("icon").style.background = 'url("right-arrow.png")';
736 | document.getElementById("gui-left").style.display = "block";
737 | document.getElementById("gui-right").style.display = "block";
738 | }
739 | toHide = !toHide;
740 | }
741 |
742 |
743 | /////////////////////////////////////////////////////////////////////////
744 | /*******************************GUI*************************************/
745 | //gui
746 | var gui1;
747 | var guiConfig;
748 |
749 | var gui2;
750 | var guiObjs = [];
751 |
752 | var width;
753 | var height;
754 |
755 | function initGUI() {
756 | width = canvas.width;
757 | height = canvas.height;
758 |
759 | //gui
760 | gui1 = new dat.GUI({ autoPlace: false });
761 | var container = document.getElementById('gui-right');
762 | container.appendChild(gui1.domElement);
763 |
764 | guiConfig = new GUIConfig();
765 |
766 | gui1.add(guiConfig, 'width').onChange(function () {
767 | width = guiConfig.width;
768 | });
769 | gui1.add(guiConfig, 'height').onChange(function () {
770 | height = guiConfig.height;
771 | });
772 |
773 | gui1.add(guiConfig, 'antiAliasing').onChange(function () {
774 | SSAA = (guiConfig.antiAliasing == true) ? 1 : 0;
775 | iterations = 0;
776 | });
777 | }
778 |
779 | function GUIConfig() {
780 | this.width = width;
781 | this.height = height;
782 |
783 | this.antiAliasing = (SSAA == 1) ? true : false;
784 | }
785 |
786 | function GUIDefaultScene(){
787 | gui2 = new dat.GUI({ autoPlace: false });
788 | gui2.domElement.id = 'gui2';
789 | var container = document.getElementById('gui-left');
790 | container.appendChild(gui2.domElement);
791 |
792 | GUIAddObj("Light", 0);
793 | GUIAddObj("Sphere 1", defaultSize);
794 | GUIAddObj("Sphere 2", defaultSize+1);
795 | GUIAddObj("Sphere 3", defaultSize+2);
796 | }
797 |
798 | function GUIObj(id) {
799 | this.translateX = Datas[id].obj_pos[0];
800 | this.translateY = Datas[id].obj_pos[1];
801 | this.translateZ = Datas[id].obj_pos[2];
802 | this.scaleX = Datas[id].obj_scale[0];
803 | this.scaleY = Datas[id].obj_scale[1];
804 | this.scaleZ = Datas[id].obj_scale[2];
805 | this.rotateX = Datas[id].obj_rotation[0];
806 | this.rotateY = Datas[id].obj_rotation[1];
807 | this.rotateZ = Datas[id].obj_rotation[2];
808 | this.color = [Datas[id].obj_color[0] * 255.0, Datas[id].obj_color[1] * 255.0, Datas[id].obj_color[2] * 255.0];
809 | this.reflect = (Datas[id].obj_reflective == 1) ? true : false ;
810 | this.refract = (Datas[id].obj_refractive == 1) ? true : false ;
811 | this.IOR = Datas[id].obj_indexOfRefraction;
812 | this.emittance = Datas[id].obj_emittance;
813 | this.subsurfaceScatter = (Datas[id].obj_subsurfaceScatter == 1) ? true : false ;
814 | };
815 |
816 | function GUIAddObj(name, id) {
817 | var i = guiObjs.length;
818 | if (Datas.length == 31)
819 | return;
820 |
821 | guiObjs.push( new GUIObj(id));
822 |
823 | var folder = gui2.addFolder(name);
824 |
825 | folder.add(guiObjs[i], 'translateX').min(-5).max(5).onChange(function () {
826 | Datas[id].obj_pos[0] = guiObjs[i].translateX;
827 | AddObjsAttr(id);
828 | iterations = 0;
829 | });
830 | folder.add(guiObjs[i], 'translateY').min(-5).max(5).onChange(function () {
831 | Datas[id].obj_pos[1] = guiObjs[i].translateY;
832 | AddObjsAttr(id);
833 | iterations = 0;
834 | });
835 | folder.add(guiObjs[i], 'translateZ').min(-5).max(5).onChange(function () {
836 | Datas[id].obj_pos[2] = guiObjs[i].translateZ;
837 | AddObjsAttr(id);
838 | iterations = 0;
839 | });
840 | folder.add(guiObjs[i], 'scaleX').onChange(function () {
841 | Datas[id].obj_scale[0] = guiObjs[i].scaleX;
842 | AddObjsAttr(id);
843 | iterations = 0;
844 | });
845 | folder.add(guiObjs[i], 'scaleY').onChange(function () {
846 | Datas[id].obj_scale[1] = guiObjs[i].scaleY;
847 | AddObjsAttr(id);
848 | iterations = 0;
849 | });
850 | folder.add(guiObjs[i], 'scaleZ').onChange(function () {
851 | Datas[id].obj_scale[2] = guiObjs[i].scaleZ;
852 | AddObjsAttr(id);
853 | iterations = 0;
854 | });
855 | folder.add(guiObjs[i], 'rotateX').onChange(function () {
856 | Datas[id].obj_rotation[0] = guiObjs[i].rotateX;
857 | AddObjsAttr(id);
858 | iterations = 0;
859 | });
860 | folder.add(guiObjs[i], 'rotateY').onChange(function () {
861 | Datas[id].obj_rotation[1] = guiObjs[i].rotateY;
862 | AddObjsAttr(id);
863 | iterations = 0;
864 | });
865 | folder.add(guiObjs[i], 'rotateZ').onChange(function () {
866 | Datas[id].obj_rotation[2] = guiObjs[i].rotateZ;
867 | AddObjsAttr(id);
868 | iterations = 0;
869 | });
870 | folder.addColor(guiObjs[i], 'color').onChange(function () {
871 | Datas[id].obj_color = [guiObjs[i].color[0] / 255.0, guiObjs[i].color[1] / 255.0, guiObjs[i].color[2] / 255.0];
872 | AddObjsAttr(id);
873 | iterations = 0;
874 | });
875 | folder.add(guiObjs[i], 'reflect').onChange(function () {
876 | Datas[id].obj_reflective = guiObjs[i].reflect;
877 | AddObjsAttr(id);
878 | iterations = 0;
879 | });
880 | folder.add(guiObjs[i], 'refract').onChange(function () {
881 | Datas[id].obj_refractive = guiObjs[i].refract;
882 | AddObjsAttr(id);
883 | iterations = 0;
884 | });
885 | folder.add(guiObjs[i], 'IOR').min(1).onChange(function () {
886 | Datas[id].obj_indexOfRefraction = guiObjs[i].IOR;
887 | AddObjsAttr(id);
888 | iterations = 0;
889 | });
890 | folder.add(guiObjs[i], 'emittance').onChange(function () {
891 | Datas[id].obj_emittance = guiObjs[i].emittance;
892 | AddObjsAttr(id);
893 | iterations = 0;
894 | });
895 | folder.add(guiObjs[i], 'subsurfaceScatter').onChange(function () {
896 | Datas[id].obj_subsurfaceScatter = guiObjs[i].subsurfaceScatter;
897 | AddObjsAttr(id);
898 | iterations = 0;
899 | });
900 | }
--------------------------------------------------------------------------------
/js/lib/dat.gui.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * dat-gui JavaScript Controller Library
3 | * http://code.google.com/p/dat-gui
4 | *
5 | * Copyright 2011 Data Arts Team, Google Creative Lab
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | */
13 | var dat=dat||{};dat.gui=dat.gui||{};dat.utils=dat.utils||{};dat.controllers=dat.controllers||{};dat.dom=dat.dom||{};dat.color=dat.color||{};dat.utils.css=function(){return{load:function(e,a){var a=a||document,c=a.createElement("link");c.type="text/css";c.rel="stylesheet";c.href=e;a.getElementsByTagName("head")[0].appendChild(c)},inject:function(e,a){var a=a||document,c=document.createElement("style");c.type="text/css";c.innerHTML=e;a.getElementsByTagName("head")[0].appendChild(c)}}}();
14 | dat.utils.common=function(){var e=Array.prototype.forEach,a=Array.prototype.slice;return{BREAK:{},extend:function(c){this.each(a.call(arguments,1),function(a){for(var f in a)this.isUndefined(a[f])||(c[f]=a[f])},this);return c},defaults:function(c){this.each(a.call(arguments,1),function(a){for(var f in a)this.isUndefined(c[f])&&(c[f]=a[f])},this);return c},compose:function(){var c=a.call(arguments);return function(){for(var d=a.call(arguments),f=c.length-1;f>=0;f--)d=[c[f].apply(this,d)];return d[0]}},
15 | each:function(a,d,f){if(e&&a.forEach===e)a.forEach(d,f);else if(a.length===a.length+0)for(var b=0,n=a.length;b-1?d.length-d.indexOf(".")-1:0};c.superclass=e;a.extend(c.prototype,e.prototype,{setValue:function(a){if(this.__min!==void 0&&athis.__max)a=this.__max;this.__step!==void 0&&a%this.__step!=0&&(a=Math.round(a/this.__step)*this.__step);return c.superclass.prototype.setValue.call(this,a)},min:function(a){this.__min=a;return this},max:function(a){this.__max=a;return this},step:function(a){this.__step=a;return this}});return c}(dat.controllers.Controller,dat.utils.common);
29 | dat.controllers.NumberControllerBox=function(e,a,c){var d=function(f,b,e){function h(){var a=parseFloat(l.__input.value);c.isNaN(a)||l.setValue(a)}function j(a){var b=o-a.clientY;l.setValue(l.getValue()+b*l.__impliedStep);o=a.clientY}function m(){a.unbind(window,"mousemove",j);a.unbind(window,"mouseup",m)}this.__truncationSuspended=false;d.superclass.call(this,f,b,e);var l=this,o;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"change",h);
30 | a.bind(this.__input,"blur",function(){h();l.__onFinishChange&&l.__onFinishChange.call(l,l.getValue())});a.bind(this.__input,"mousedown",function(b){a.bind(window,"mousemove",j);a.bind(window,"mouseup",m);o=b.clientY});a.bind(this.__input,"keydown",function(a){if(a.keyCode===13)l.__truncationSuspended=true,this.blur(),l.__truncationSuspended=false});this.updateDisplay();this.domElement.appendChild(this.__input)};d.superclass=e;c.extend(d.prototype,e.prototype,{updateDisplay:function(){var a=this.__input,
31 | b;if(this.__truncationSuspended)b=this.getValue();else{b=this.getValue();var c=Math.pow(10,this.__precision);b=Math.round(b*c)/c}a.value=b;return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.NumberController,dat.dom.dom,dat.utils.common);
32 | dat.controllers.NumberControllerSlider=function(e,a,c,d,f){var b=function(d,c,f,e,l){function o(b){b.preventDefault();var d=a.getOffset(g.__background),c=a.getWidth(g.__background);g.setValue(g.__min+(g.__max-g.__min)*((b.clientX-d.left)/(d.left+c-d.left)));return false}function y(){a.unbind(window,"mousemove",o);a.unbind(window,"mouseup",y);g.__onFinishChange&&g.__onFinishChange.call(g,g.getValue())}b.superclass.call(this,d,c,{min:f,max:e,step:l});var g=this;this.__background=document.createElement("div");
33 | this.__foreground=document.createElement("div");a.bind(this.__background,"mousedown",function(b){a.bind(window,"mousemove",o);a.bind(window,"mouseup",y);o(b)});a.addClass(this.__background,"slider");a.addClass(this.__foreground,"slider-fg");this.updateDisplay();this.__background.appendChild(this.__foreground);this.domElement.appendChild(this.__background)};b.superclass=e;b.useDefaultStyles=function(){c.inject(f)};d.extend(b.prototype,e.prototype,{updateDisplay:function(){this.__foreground.style.width=
34 | (this.getValue()-this.__min)/(this.__max-this.__min)*100+"%";return b.superclass.prototype.updateDisplay.call(this)}});return b}(dat.controllers.NumberController,dat.dom.dom,dat.utils.css,dat.utils.common,".slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}");
35 | dat.controllers.FunctionController=function(e,a,c){var d=function(c,b,e){d.superclass.call(this,c,b);var h=this;this.__button=document.createElement("div");this.__button.innerHTML=e===void 0?"Fire":e;a.bind(this.__button,"click",function(a){a.preventDefault();h.fire();return false});a.addClass(this.__button,"button");this.domElement.appendChild(this.__button)};d.superclass=e;c.extend(d.prototype,e.prototype,{fire:function(){this.__onChange&&this.__onChange.call(this);this.__onFinishChange&&this.__onFinishChange.call(this,
36 | this.getValue());this.getValue().call(this.object)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common);
37 | dat.controllers.BooleanController=function(e,a,c){var d=function(c,b){d.superclass.call(this,c,b);var e=this;this.__prev=this.getValue();this.__checkbox=document.createElement("input");this.__checkbox.setAttribute("type","checkbox");a.bind(this.__checkbox,"change",function(){e.setValue(!e.__prev)},false);this.domElement.appendChild(this.__checkbox);this.updateDisplay()};d.superclass=e;c.extend(d.prototype,e.prototype,{setValue:function(a){a=d.superclass.prototype.setValue.call(this,a);this.__onFinishChange&&
38 | this.__onFinishChange.call(this,this.getValue());this.__prev=this.getValue();return a},updateDisplay:function(){this.getValue()===true?(this.__checkbox.setAttribute("checked","checked"),this.__checkbox.checked=true):this.__checkbox.checked=false;return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common);
39 | dat.color.toString=function(e){return function(a){if(a.a==1||e.isUndefined(a.a)){for(a=a.hex.toString(16);a.length<6;)a="0"+a;return"#"+a}else return"rgba("+Math.round(a.r)+","+Math.round(a.g)+","+Math.round(a.b)+","+a.a+")"}}(dat.utils.common);
40 | dat.color.interpret=function(e,a){var c,d,f=[{litmus:a.isString,conversions:{THREE_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return a===null?false:{space:"HEX",hex:parseInt("0x"+a[1].toString()+a[1].toString()+a[2].toString()+a[2].toString()+a[3].toString()+a[3].toString())}},write:e},SIX_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9]{6})$/i);return a===null?false:{space:"HEX",hex:parseInt("0x"+a[1].toString())}},write:e},CSS_RGB:{read:function(a){a=a.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);
41 | return a===null?false:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3])}},write:e},CSS_RGBA:{read:function(a){a=a.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/);return a===null?false:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3]),a:parseFloat(a[4])}},write:e}}},{litmus:a.isNumber,conversions:{HEX:{read:function(a){return{space:"HEX",hex:a,conversionName:"HEX"}},write:function(a){return a.hex}}}},{litmus:a.isArray,conversions:{RGB_ARRAY:{read:function(a){return a.length!=
42 | 3?false:{space:"RGB",r:a[0],g:a[1],b:a[2]}},write:function(a){return[a.r,a.g,a.b]}},RGBA_ARRAY:{read:function(a){return a.length!=4?false:{space:"RGB",r:a[0],g:a[1],b:a[2],a:a[3]}},write:function(a){return[a.r,a.g,a.b,a.a]}}}},{litmus:a.isObject,conversions:{RGBA_OBJ:{read:function(b){return a.isNumber(b.r)&&a.isNumber(b.g)&&a.isNumber(b.b)&&a.isNumber(b.a)?{space:"RGB",r:b.r,g:b.g,b:b.b,a:b.a}:false},write:function(a){return{r:a.r,g:a.g,b:a.b,a:a.a}}},RGB_OBJ:{read:function(b){return a.isNumber(b.r)&&
43 | a.isNumber(b.g)&&a.isNumber(b.b)?{space:"RGB",r:b.r,g:b.g,b:b.b}:false},write:function(a){return{r:a.r,g:a.g,b:a.b}}},HSVA_OBJ:{read:function(b){return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)&&a.isNumber(b.a)?{space:"HSV",h:b.h,s:b.s,v:b.v,a:b.a}:false},write:function(a){return{h:a.h,s:a.s,v:a.v,a:a.a}}},HSV_OBJ:{read:function(b){return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)?{space:"HSV",h:b.h,s:b.s,v:b.v}:false},write:function(a){return{h:a.h,s:a.s,v:a.v}}}}}];return function(){d=
44 | false;var b=arguments.length>1?a.toArray(arguments):arguments[0];a.each(f,function(e){if(e.litmus(b))return a.each(e.conversions,function(e,f){c=e.read(b);if(d===false&&c!==false)return d=c,c.conversionName=f,c.conversion=e,a.BREAK}),a.BREAK});return d}}(dat.color.toString,dat.utils.common);
45 | dat.GUI=dat.gui.GUI=function(e,a,c,d,f,b,n,h,j,m,l,o,y,g,i){function q(a,b,r,c){if(b[r]===void 0)throw Error("Object "+b+' has no property "'+r+'"');c.color?b=new l(b,r):(b=[b,r].concat(c.factoryArgs),b=d.apply(a,b));if(c.before instanceof f)c.before=c.before.__li;t(a,b);g.addClass(b.domElement,"c");r=document.createElement("span");g.addClass(r,"property-name");r.innerHTML=b.property;var e=document.createElement("div");e.appendChild(r);e.appendChild(b.domElement);c=s(a,e,c.before);g.addClass(c,k.CLASS_CONTROLLER_ROW);
46 | g.addClass(c,typeof b.getValue());p(a,c,b);a.__controllers.push(b);return b}function s(a,b,d){var c=document.createElement("li");b&&c.appendChild(b);d?a.__ul.insertBefore(c,params.before):a.__ul.appendChild(c);a.onResize();return c}function p(a,d,c){c.__li=d;c.__gui=a;i.extend(c,{options:function(b){if(arguments.length>1)return c.remove(),q(a,c.object,c.property,{before:c.__li.nextElementSibling,factoryArgs:[i.toArray(arguments)]});if(i.isArray(b)||i.isObject(b))return c.remove(),q(a,c.object,c.property,
47 | {before:c.__li.nextElementSibling,factoryArgs:[b]})},name:function(a){c.__li.firstElementChild.firstElementChild.innerHTML=a;return c},listen:function(){c.__gui.listen(c);return c},remove:function(){c.__gui.remove(c);return c}});if(c instanceof j){var e=new h(c.object,c.property,{min:c.__min,max:c.__max,step:c.__step});i.each(["updateDisplay","onChange","onFinishChange"],function(a){var b=c[a],H=e[a];c[a]=e[a]=function(){var a=Array.prototype.slice.call(arguments);b.apply(c,a);return H.apply(e,a)}});
48 | g.addClass(d,"has-slider");c.domElement.insertBefore(e.domElement,c.domElement.firstElementChild)}else if(c instanceof h){var f=function(b){return i.isNumber(c.__min)&&i.isNumber(c.__max)?(c.remove(),q(a,c.object,c.property,{before:c.__li.nextElementSibling,factoryArgs:[c.__min,c.__max,c.__step]})):b};c.min=i.compose(f,c.min);c.max=i.compose(f,c.max)}else if(c instanceof b)g.bind(d,"click",function(){g.fakeEvent(c.__checkbox,"click")}),g.bind(c.__checkbox,"click",function(a){a.stopPropagation()});
49 | else if(c instanceof n)g.bind(d,"click",function(){g.fakeEvent(c.__button,"click")}),g.bind(d,"mouseover",function(){g.addClass(c.__button,"hover")}),g.bind(d,"mouseout",function(){g.removeClass(c.__button,"hover")});else if(c instanceof l)g.addClass(d,"color"),c.updateDisplay=i.compose(function(a){d.style.borderLeftColor=c.__color.toString();return a},c.updateDisplay),c.updateDisplay();c.setValue=i.compose(function(b){a.getRoot().__preset_select&&c.isModified()&&B(a.getRoot(),true);return b},c.setValue)}
50 | function t(a,b){var c=a.getRoot(),d=c.__rememberedObjects.indexOf(b.object);if(d!=-1){var e=c.__rememberedObjectIndecesToControllers[d];e===void 0&&(e={},c.__rememberedObjectIndecesToControllers[d]=e);e[b.property]=b;if(c.load&&c.load.remembered){c=c.load.remembered;if(c[a.preset])c=c[a.preset];else if(c[w])c=c[w];else return;if(c[d]&&c[d][b.property]!==void 0)d=c[d][b.property],b.initialValue=d,b.setValue(d)}}}function I(a){var b=a.__save_row=document.createElement("li");g.addClass(a.domElement,
51 | "has-save");a.__ul.insertBefore(b,a.__ul.firstChild);g.addClass(b,"save-row");var c=document.createElement("span");c.innerHTML=" ";g.addClass(c,"button gears");var d=document.createElement("span");d.innerHTML="Save";g.addClass(d,"button");g.addClass(d,"save");var e=document.createElement("span");e.innerHTML="New";g.addClass(e,"button");g.addClass(e,"save-as");var f=document.createElement("span");f.innerHTML="Revert";g.addClass(f,"button");g.addClass(f,"revert");var m=a.__preset_select=document.createElement("select");
52 | a.load&&a.load.remembered?i.each(a.load.remembered,function(b,c){C(a,c,c==a.preset)}):C(a,w,false);g.bind(m,"change",function(){for(var b=0;b0){a.preset=this.preset;if(!a.remembered)a.remembered={};a.remembered[this.preset]=z(this)}a.folders={};i.each(this.__folders,function(b,
69 | c){a.folders[c]=b.getSaveObject()});return a},save:function(){if(!this.load.remembered)this.load.remembered={};this.load.remembered[this.preset]=z(this);B(this,false)},saveAs:function(a){if(!this.load.remembered)this.load.remembered={},this.load.remembered[w]=z(this,true);this.load.remembered[a]=z(this);this.preset=a;C(this,a,true)},revert:function(a){i.each(this.__controllers,function(b){this.getRoot().load.remembered?t(a||this.getRoot(),b):b.setValue(b.initialValue)},this);i.each(this.__folders,
70 | function(a){a.revert(a)});a||B(this.getRoot(),false)},listen:function(a){var b=this.__listening.length==0;this.__listening.push(a);b&&E(this.__listening)}});return k}(dat.utils.css,'\n\n Here\'s the new load parameter for your
GUI
\'s constructor:\n\n
\n\n
\n\n
Automatically save\n values to
localStorage
on exit.\n\n
The values saved to localStorage
will\n override those passed to dat.GUI
\'s constructor. This makes it\n easier to work incrementally, but localStorage
is fragile,\n and your friends may not see the same values you do.\n \n
\n \n
\n\n
',
71 | ".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear;border:0;position:absolute;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-x:hidden}.dg.a.has-save ul{margin-top:27px}.dg.a.has-save ul.closed{margin-top:0}.dg.a .save-row{position:fixed;top:0;z-index:1002}.dg li{-webkit-transition:height 0.1s ease-out;-o-transition:height 0.1s ease-out;-moz-transition:height 0.1s ease-out;transition:height 0.1s ease-out}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;overflow:hidden;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li > *{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:9px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2fa1d6}.dg .cr.number input[type=text]{color:#2fa1d6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2fa1d6}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n",
72 | dat.controllers.factory=function(e,a,c,d,f,b,n){return function(h,j,m,l){var o=h[j];if(n.isArray(m)||n.isObject(m))return new e(h,j,m);if(n.isNumber(o))return n.isNumber(m)&&n.isNumber(l)?new c(h,j,m,l):new a(h,j,{min:m,max:l});if(n.isString(o))return new d(h,j);if(n.isFunction(o))return new f(h,j,"");if(n.isBoolean(o))return new b(h,j)}}(dat.controllers.OptionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.StringController=function(e,a,c){var d=
73 | function(c,b){function e(){h.setValue(h.__input.value)}d.superclass.call(this,c,b);var h=this;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"keyup",e);a.bind(this.__input,"change",e);a.bind(this.__input,"blur",function(){h.__onFinishChange&&h.__onFinishChange.call(h,h.getValue())});a.bind(this.__input,"keydown",function(a){a.keyCode===13&&this.blur()});this.updateDisplay();this.domElement.appendChild(this.__input)};d.superclass=e;c.extend(d.prototype,
74 | e.prototype,{updateDisplay:function(){if(!a.isActive(this.__input))this.__input.value=this.getValue();return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common),dat.controllers.FunctionController,dat.controllers.BooleanController,dat.utils.common),dat.controllers.Controller,dat.controllers.BooleanController,dat.controllers.FunctionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.OptionController,
75 | dat.controllers.ColorController=function(e,a,c,d,f){function b(a,b,c,d){a.style.background="";f.each(j,function(e){a.style.cssText+="background: "+e+"linear-gradient("+b+", "+c+" 0%, "+d+" 100%); "})}function n(a){a.style.background="";a.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);";a.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";
76 | a.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";a.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";a.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}var h=function(e,l){function o(b){q(b);a.bind(window,"mousemove",q);a.bind(window,
77 | "mouseup",j)}function j(){a.unbind(window,"mousemove",q);a.unbind(window,"mouseup",j)}function g(){var a=d(this.value);a!==false?(p.__color.__state=a,p.setValue(p.__color.toOriginal())):this.value=p.__color.toString()}function i(){a.unbind(window,"mousemove",s);a.unbind(window,"mouseup",i)}function q(b){b.preventDefault();var c=a.getWidth(p.__saturation_field),d=a.getOffset(p.__saturation_field),e=(b.clientX-d.left+document.body.scrollLeft)/c,b=1-(b.clientY-d.top+document.body.scrollTop)/c;b>1?b=
78 | 1:b<0&&(b=0);e>1?e=1:e<0&&(e=0);p.__color.v=b;p.__color.s=e;p.setValue(p.__color.toOriginal());return false}function s(b){b.preventDefault();var c=a.getHeight(p.__hue_field),d=a.getOffset(p.__hue_field),b=1-(b.clientY-d.top+document.body.scrollTop)/c;b>1?b=1:b<0&&(b=0);p.__color.h=b*360;p.setValue(p.__color.toOriginal());return false}h.superclass.call(this,e,l);this.__color=new c(this.getValue());this.__temp=new c(0);var p=this;this.domElement=document.createElement("div");a.makeSelectable(this.domElement,
79 | false);this.__selector=document.createElement("div");this.__selector.className="selector";this.__saturation_field=document.createElement("div");this.__saturation_field.className="saturation-field";this.__field_knob=document.createElement("div");this.__field_knob.className="field-knob";this.__field_knob_border="2px solid ";this.__hue_knob=document.createElement("div");this.__hue_knob.className="hue-knob";this.__hue_field=document.createElement("div");this.__hue_field.className="hue-field";this.__input=
80 | document.createElement("input");this.__input.type="text";this.__input_textShadow="0 1px 1px ";a.bind(this.__input,"keydown",function(a){a.keyCode===13&&g.call(this)});a.bind(this.__input,"blur",g);a.bind(this.__selector,"mousedown",function(){a.addClass(this,"drag").bind(window,"mouseup",function(){a.removeClass(p.__selector,"drag")})});var t=document.createElement("div");f.extend(this.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"});
81 | f.extend(this.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:this.__field_knob_border+(this.__color.v<0.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1});f.extend(this.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1});f.extend(this.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"});f.extend(t.style,
82 | {width:"100%",height:"100%",background:"none"});b(t,"top","rgba(0,0,0,0)","#000");f.extend(this.__hue_field.style,{width:"15px",height:"100px",display:"inline-block",border:"1px solid #555",cursor:"ns-resize"});n(this.__hue_field);f.extend(this.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:this.__input_textShadow+"rgba(0,0,0,0.7)"});a.bind(this.__saturation_field,"mousedown",o);a.bind(this.__field_knob,"mousedown",o);a.bind(this.__hue_field,"mousedown",
83 | function(b){s(b);a.bind(window,"mousemove",s);a.bind(window,"mouseup",i)});this.__saturation_field.appendChild(t);this.__selector.appendChild(this.__field_knob);this.__selector.appendChild(this.__saturation_field);this.__selector.appendChild(this.__hue_field);this.__hue_field.appendChild(this.__hue_knob);this.domElement.appendChild(this.__input);this.domElement.appendChild(this.__selector);this.updateDisplay()};h.superclass=e;f.extend(h.prototype,e.prototype,{updateDisplay:function(){var a=d(this.getValue());
84 | if(a!==false){var e=false;f.each(c.COMPONENTS,function(b){if(!f.isUndefined(a[b])&&!f.isUndefined(this.__color.__state[b])&&a[b]!==this.__color.__state[b])return e=true,{}},this);e&&f.extend(this.__color.__state,a)}f.extend(this.__temp.__state,this.__color.__state);this.__temp.a=1;var h=this.__color.v<0.5||this.__color.s>0.5?255:0,j=255-h;f.extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toString(),border:this.__field_knob_border+
85 | "rgb("+h+","+h+","+h+")"});this.__hue_knob.style.marginTop=(1-this.__color.h/360)*100+"px";this.__temp.s=1;this.__temp.v=1;b(this.__saturation_field,"left","#fff",this.__temp.toString());f.extend(this.__input.style,{backgroundColor:this.__input.value=this.__color.toString(),color:"rgb("+h+","+h+","+h+")",textShadow:this.__input_textShadow+"rgba("+j+","+j+","+j+",.7)"})}});var j=["-moz-","-o-","-webkit-","-ms-",""];return h}(dat.controllers.Controller,dat.dom.dom,dat.color.Color=function(e,a,c,d){function f(a,
86 | b,c){Object.defineProperty(a,b,{get:function(){if(this.__state.space==="RGB")return this.__state[b];n(this,b,c);return this.__state[b]},set:function(a){if(this.__state.space!=="RGB")n(this,b,c),this.__state.space="RGB";this.__state[b]=a}})}function b(a,b){Object.defineProperty(a,b,{get:function(){if(this.__state.space==="HSV")return this.__state[b];h(this);return this.__state[b]},set:function(a){if(this.__state.space!=="HSV")h(this),this.__state.space="HSV";this.__state[b]=a}})}function n(b,c,e){if(b.__state.space===
87 | "HEX")b.__state[c]=a.component_from_hex(b.__state.hex,e);else if(b.__state.space==="HSV")d.extend(b.__state,a.hsv_to_rgb(b.__state.h,b.__state.s,b.__state.v));else throw"Corrupted color state";}function h(b){var c=a.rgb_to_hsv(b.r,b.g,b.b);d.extend(b.__state,{s:c.s,v:c.v});if(d.isNaN(c.h)){if(d.isUndefined(b.__state.h))b.__state.h=0}else b.__state.h=c.h}var j=function(){this.__state=e.apply(this,arguments);if(this.__state===false)throw"Failed to interpret color arguments";this.__state.a=this.__state.a||
88 | 1};j.COMPONENTS="r,g,b,h,s,v,hex,a".split(",");d.extend(j.prototype,{toString:function(){return c(this)},toOriginal:function(){return this.__state.conversion.write(this)}});f(j.prototype,"r",2);f(j.prototype,"g",1);f(j.prototype,"b",0);b(j.prototype,"h");b(j.prototype,"s");b(j.prototype,"v");Object.defineProperty(j.prototype,"a",{get:function(){return this.__state.a},set:function(a){this.__state.a=a}});Object.defineProperty(j.prototype,"hex",{get:function(){if(!this.__state.space!=="HEX")this.__state.hex=
89 | a.rgb_to_hex(this.r,this.g,this.b);return this.__state.hex},set:function(a){this.__state.space="HEX";this.__state.hex=a}});return j}(dat.color.interpret,dat.color.math=function(){var e;return{hsv_to_rgb:function(a,c,d){var e=a/60-Math.floor(a/60),b=d*(1-c),n=d*(1-e*c),c=d*(1-(1-e)*c),a=[[d,c,b],[n,d,b],[b,d,c],[b,n,d],[c,b,d],[d,b,n]][Math.floor(a/60)%6];return{r:a[0]*255,g:a[1]*255,b:a[2]*255}},rgb_to_hsv:function(a,c,d){var e=Math.min(a,c,d),b=Math.max(a,c,d),e=b-e;if(b==0)return{h:NaN,s:0,v:0};
90 | a=a==b?(c-d)/e:c==b?2+(d-a)/e:4+(a-c)/e;a/=6;a<0&&(a+=1);return{h:a*360,s:e/b,v:b/255}},rgb_to_hex:function(a,c,d){a=this.hex_with_component(0,2,a);a=this.hex_with_component(a,1,c);return a=this.hex_with_component(a,0,d)},component_from_hex:function(a,c){return a>>c*8&255},hex_with_component:function(a,c,d){return d<<(e=c*8)|a&~(255<c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div");
4 | k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display=
5 | "block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:12,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height=
6 | a+"px",m=b,r=0);return b},update:function(){l=this.end()}}};"object"===typeof module&&(module.exports=Stats);
7 |
--------------------------------------------------------------------------------
/js/webGLUtility.js:
--------------------------------------------------------------------------------
1 | // WebGL Utility
2 | // Javascript closure class that intializes context and creates program in the
3 | // context. Javascript analog to the glslUtility class that you are used to
4 | // seeing in the CUDA assignments.
5 | // University of Pennsylvania (c) 2014
6 |
7 | (function(exports) {
8 | "use strict";
9 |
10 | exports = exports || window;
11 |
12 | ///////////////////////////////////////////////////////////////////////////
13 | // Shim from http://paulirish.com/2011/requestanimationframe-for-smart-animating/
14 |
15 | exports.requestAnimFrame =
16 | window.requestAnimationFrame ||
17 | window.webkitRequestAnimationFrame ||
18 | window.mozRequestAnimationFrame ||
19 | window.oRequestAnimationFrame ||
20 | window.msRequestAnimationFrame ||
21 | function( callback ){
22 | window.setTimeout(callback, 1000 / 60);
23 | };
24 |
25 | ///////////////////////////////////////////////////////////////////////////
26 | // getShader based on http://learningwebgl.com/cookbook/index.php/Loading_shaders_from_HTML_script_tags
27 |
28 | // LOOK : Grabs the text shader source from the document for shader
29 | // compilation
30 | exports.getShaderSource = function(script) {
31 | var str = "";
32 | var k = script.firstChild;
33 | while (k) {
34 | if (k.nodeType == 3) {
35 | str += k.textContent;
36 | }
37 | k = k.nextSibling;
38 | }
39 |
40 | return str;
41 | };
42 |
43 | ///////////////////////////////////////////////////////////////////////////
44 |
45 | // LOOK : Like OpenGL, we will create a webGL context for renderering
46 |
47 | exports.createWebGLContext = function(canvas, message) {
48 | // Detect if browser supports WebGL
49 | if (!window.WebGLRenderingContext) {
50 | message.innerText = "The browser does not support WebGL. Visit http://get.webgl.org.";
51 | return undefined;
52 | }
53 | var options = { alpha: false };
54 | var context = canvas.getContext("webgl") || canvas.getContext("experimental-webgl", options);
55 |
56 | if (!context && message) {
57 | message.innerText = "The browser supports WebGL, but initialization failed.";
58 | }
59 |
60 | return context;
61 | };
62 |
63 | // LOOK : Create program from the vertex and fragment shaders passed in
64 | exports.createProgram = function(context, vertexShaderSource, fragmentShaderSource, message) {
65 | var program = context.createProgram();
66 | var vs = context.createShader(context.VERTEX_SHADER);
67 | var fs = context.createShader(context.FRAGMENT_SHADER);
68 |
69 | context.attachShader(program, vs);
70 | context.attachShader(program, fs);
71 |
72 | // Mark shader for deletion when the program is deleted
73 | context.deleteShader(vs);
74 | context.deleteShader(fs);
75 |
76 | context.shaderSource(vs, vertexShaderSource);
77 | context.compileShader(vs);
78 | if (!context.getShaderParameter(vs, context.COMPILE_STATUS)) {
79 | if (message) {
80 | message.innerText += context.getShaderInfoLog(vs) + "\n";
81 | alert(context.getShaderInfoLog(vs));
82 | }
83 | else
84 | {
85 | alert(context.getShaderInfoLog(vs));
86 | }
87 | context.deleteProgram(program);
88 | return;
89 | }
90 |
91 | context.shaderSource(fs, fragmentShaderSource);
92 | context.compileShader(fs);
93 | if (!context.getShaderParameter(fs, context.COMPILE_STATUS)) {
94 | if (message) {
95 | message.innerText += context.getShaderInfoLog(fs) + "\n";
96 | alert(context.getShaderInfoLog(fs));
97 | }
98 | else
99 | {
100 | alert(context.getShaderInfoLog(fs));
101 | }
102 | context.deleteProgram(program);
103 | return;
104 | }
105 |
106 | // Link program
107 | context.linkProgram(program);
108 | if (!context.getProgramParameter(program, context.LINK_STATUS)) {
109 | if (message) {
110 | message.innerText += context.getProgramInfoLog(program) + "\n";
111 | alert(context.getShaderInfoLog(program));
112 | }
113 | else
114 | {
115 | alert(context.getShaderInfoLog(program));
116 | }
117 | context.deleteProgram(program);
118 | return;
119 | }
120 |
121 | return program;
122 | };
123 |
124 | }());
125 |
--------------------------------------------------------------------------------
/left-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/left-arrow.png
--------------------------------------------------------------------------------
/right-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wulinjiansheng/WebGL_PathTracer/8c5fd06994cfdf025d50a2f22cc5eb510d631310/right-arrow.png
--------------------------------------------------------------------------------