16 | Above you will find two movies; which are actively ray traced withn a WebGL fragment shader. The tracer operates in two dimensions, shooting a ray at each pixel every single frame. WebGL is easily capable of performing this operation at 60FPS, as opposed to traditional CPU implementations. Our CPU-based C# version, from which we originally ported the core logic, runs at a mere 5FPS. We've ported that shader to OpenGL, which supports a more modern shading language, in order to hit 60FPS.
17 |
18 |
19 | We wanted to run this project on the web, which is why we ported it to WebGL. However, due to WebGL's limited support for shaders, we wrote our own shader preprocessor in order to add variable-sized arrays to GLSL 1.0
20 |
21 |
22 | The movie consists of a set of static scenes, which are interpolated to generate fluid motion.
23 |
24 |
25 | As part of our assignment, we first implemented the 2D tracer in C#, after porting the provided template project, removing deprecated OpenGL practices. Next we reimplemented the same ray tracer using OpenGL in a fragment shader. Lastly we ported our OpenGL 3.0 fragment shader to WebGL (which uses OpenGL 1.0 ES). Running the WebGL shader requires NPM and Node, the options are explained in the README.
26 |
27 |
28 |
29 | DISCLAIMER: works best on desktop browsers.
30 |
31 |
32 |
33 |
34 |
35 |
99 |
100 |
179 |
--------------------------------------------------------------------------------
/src/raytracer/shaders/shader.frag:
--------------------------------------------------------------------------------
1 | precision highp float;
2 |
3 | #define M_PI 3.1415926535897932384626433832795
4 |
5 | varying mediump vec2 screenPosition;
6 |
7 | struct Camera
8 | {
9 | vec2 position;
10 | float zoom;
11 | } camera = Camera (vec2(0.0, 0.0), 0.5);
12 |
13 | struct Ray
14 | {
15 | vec2 origin;
16 | vec2 direction;
17 | float magnitude;
18 | };
19 |
20 | struct Light
21 | {
22 | vec2 position;
23 | vec3 color;
24 | };
25 |
26 | struct Circle
27 | {
28 | vec2 position;
29 | float radius;
30 | };
31 |
32 | #define LIGHT_COUNT 42//$LIGHT_COUNT$//
33 | uniform Light lights[LIGHT_COUNT];
34 |
35 | #define CIRCLE_COUNT 42//$CIRCLE_COUNT$//
36 | uniform Circle circles[CIRCLE_COUNT];
37 |
38 |
39 | // INTERSECTION CHECKS
40 | bool circleIntersects(Circle circle, Ray ray)
41 | {
42 | vec2 posToOrigin = ray.origin - circle.position;
43 | float a = dot(ray.direction, ray.direction);
44 | float b = dot(ray.direction, posToOrigin);
45 | float c = dot(posToOrigin, posToOrigin) - (circle.radius * circle.radius);
46 | float d = (b * b) - (a * c);
47 |
48 | if (d < 0.0) return false;
49 |
50 | float sqrtD = sqrt(d);
51 | float distance = (-b - sqrtD) / a;
52 | if (distance < 0.0) distance = (-b + sqrtD) / a;
53 |
54 | return distance > 0.0 && distance < ray.magnitude;
55 | }
56 |
57 | struct Rectangle {
58 | vec2 lu;
59 | vec2 ru;
60 | vec2 rl;
61 | vec2 ll;
62 | };
63 |
64 | Rectangle newRectangle(in vec2 position, float width, float height, float angle) {
65 | vec2 corners[4];
66 | corners[0] = vec2(-width * 0.5, height * 0.5); //lu
67 | corners[1] = vec2(width * 0.5, height * 0.5); // ru
68 | corners[2] = vec2(width * 0.5, -height * 0.5); // rl
69 | corners[3] = vec2(-width * 0.5, -height * 0.5); // ll
70 |
71 | if (angle != 0.0) {
72 | for (int i = 0; i < 4; i++) {
73 | vec2 corner = corners[i];
74 | corners[i] = vec2(
75 | corner.x * cos(angle) - corner.y * sin(angle),
76 | corner.xy * sin(angle) + corner.y * cos(angle)
77 | );
78 | }
79 | }
80 |
81 | for (int i = 0; i < 4; i++) {
82 | corners[i] += position;
83 | }
84 |
85 | return Rectangle(corners[0], corners[1], corners[2], corners[3]);
86 | }
87 |
88 | struct RawRect {
89 | vec2 position;
90 | float width;
91 | float height;
92 | float angle;
93 | };
94 |
95 | #define RECTANGLE_COUNT 42//$RECTANGLE_COUNT$//
96 | uniform RawRect rectangles[RECTANGLE_COUNT];
97 | Rectangle rects[RECTANGLE_COUNT];
98 | bool lineIntersects(Ray ray, vec2 lineStart, vec2 lineEnd) {
99 | vec2 rayStart = ray.origin;
100 | vec2 rayEnd = ray.origin + ray.direction;
101 |
102 | vec2 rayStoLineS = lineStart - rayStart;
103 | vec2 r = ray.direction * ray.magnitude;
104 | vec2 s = lineEnd - lineStart;
105 |
106 | float crossR = (rayStoLineS.x * r.y) - (rayStoLineS.y * r.x);
107 | float crossS = (rayStoLineS.x * s.y) - (rayStoLineS.y * s.x);
108 | float rCrossS = r.x * s.y - r.y * s.x;
109 |
110 | if (crossR == 0.0) {
111 | return ((lineStart.x - rayStart.x < 0.0) != (lineStart.x - rayEnd.x < 0.0)) ||
112 | ((lineStart.y - rayStart.y < 0.0) != (lineStart.y - rayEnd.y < 0.0));
113 | }
114 |
115 | if (rCrossS == 0.0) return false;
116 |
117 | float t = crossS / rCrossS;
118 | float u = crossR / rCrossS;
119 |
120 | return (t >= 0.0) && (t <= 1.0) && (u >= 0.0) && (u <= 1.0);
121 | }
122 |
123 | bool rectangleIntersect(Ray ray, Rectangle rect) {
124 | return lineIntersects(ray, rect.ll, rect.lu) ||
125 | lineIntersects(ray, rect.lu, rect.ru) ||
126 | lineIntersects(ray, rect.ru, rect.rl) ||
127 | lineIntersects(ray, rect.rl, rect.ll);
128 | }
129 |
130 | vec2 ToWorldSpace(vec2 screenSpacePoint)
131 | {
132 | return (screenSpacePoint + camera.position) / camera.zoom;
133 | }
134 |
135 | vec3 Trace(vec2 worldPoint)
136 | {
137 | vec3 colorAtPixel = vec3(0.0, 0.0, 0.0);
138 |
139 | // Cache the rectangle transformations.
140 | Rectangle rects[RECTANGLE_COUNT];
141 | for (int i = 0; i < RECTANGLE_COUNT; i++) {
142 | RawRect raw = rectangles[i];
143 | rects[i] = newRectangle(raw.position, raw.width, raw.height, raw.angle);
144 | }
145 |
146 | for (int i = 0; i < LIGHT_COUNT; i++) {
147 |
148 | vec2 vectorToLight = lights[i].position - worldPoint;
149 |
150 | // Don't forget to normalize the ray's direction
151 | Ray ray = Ray(worldPoint, vectorToLight, length(vectorToLight));
152 | ray.direction = normalize(ray.direction);
153 |
154 | // Check for occlusions between ray
155 | bool occluded = false;
156 | for (int c = 0; c < CIRCLE_COUNT; c++) {
157 | Circle circle = circles[c];
158 | if (circleIntersects(circle, ray)) {
159 | occluded = true;
160 | break;
161 | }
162 | }
163 | if (occluded) continue;
164 |
165 | for (int r = 0; r < RECTANGLE_COUNT; r++) {
166 | Rectangle rect = rects[r];
167 | if (rectangleIntersect(ray, rect)) {
168 | occluded = true;
169 | break;
170 | }
171 | }
172 | if (occluded) continue;
173 |
174 |
175 | float distanceToLight = length(vectorToLight);
176 | float intensity = 1.0 / (4.0 * M_PI * distanceToLight);
177 |
178 | colorAtPixel += lights[i].color * intensity;
179 | }
180 |
181 |
182 | return colorAtPixel;
183 | }
184 |
185 |
186 | void main() {
187 | gl_FragColor = vec4(Trace(ToWorldSpace(screenPosition)), 1.0);
188 | }
189 |
--------------------------------------------------------------------------------
/docs/img/icons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
150 |
--------------------------------------------------------------------------------
/public/img/icons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
150 |
--------------------------------------------------------------------------------
/docs/js/app.4f999ba6.js:
--------------------------------------------------------------------------------
1 | (function(e){function t(t){for(var n,s,a=t[0],c=t[1],l=t[2],h=0,g=[];h 0.0 && distance < ray.magnitude;\n}\n\nstruct Rectangle {\n vec2 lu;\n vec2 ru;\n vec2 rl;\n vec2 ll;\n};\n\nRectangle newRectangle(in vec2 position, float width, float height, float angle) {\n vec2 corners[4];\n corners[0] = vec2(-width * 0.5, height * 0.5); //lu\n corners[1] = vec2(width * 0.5, height * 0.5); // ru\n corners[2] = vec2(width * 0.5, -height * 0.5); // rl\n corners[3] = vec2(-width * 0.5, -height * 0.5); // ll\n\n if (angle != 0.0) {\n for (int i = 0; i < 4; i++) {\n vec2 corner = corners[i];\n corners[i] = vec2(\n corner.x * cos(angle) - corner.y * sin(angle),\n corner.xy * sin(angle) + corner.y * cos(angle)\n );\n }\n }\n\n for (int i = 0; i < 4; i++) {\n corners[i] += position;\n }\n\n return Rectangle(corners[0], corners[1], corners[2], corners[3]);\n}\n\nstruct RawRect {\n vec2 position;\n float width;\n float height;\n float angle;\n};\n\n#define RECTANGLE_COUNT 42//$RECTANGLE_COUNT$//\nuniform RawRect rectangles[RECTANGLE_COUNT];\nRectangle rects[RECTANGLE_COUNT];\nbool lineIntersects(Ray ray, vec2 lineStart, vec2 lineEnd) {\n vec2 rayStart = ray.origin;\n vec2 rayEnd = ray.origin + ray.direction;\n\n vec2 rayStoLineS = lineStart - rayStart;\n vec2 r = ray.direction * ray.magnitude;\n vec2 s = lineEnd - lineStart;\n\n float crossR = (rayStoLineS.x * r.y) - (rayStoLineS.y * r.x);\n float crossS = (rayStoLineS.x * s.y) - (rayStoLineS.y * s.x);\n float rCrossS = r.x * s.y - r.y * s.x;\n\n if (crossR == 0.0) {\n return ((lineStart.x - rayStart.x < 0.0) != (lineStart.x - rayEnd.x < 0.0)) ||\n ((lineStart.y - rayStart.y < 0.0) != (lineStart.y - rayEnd.y < 0.0));\n }\n\n if (rCrossS == 0.0) return false;\n\n float t = crossS / rCrossS;\n float u = crossR / rCrossS;\n\n return (t >= 0.0) && (t <= 1.0) && (u >= 0.0) && (u <= 1.0);\n}\n\nbool rectangleIntersect(Ray ray, Rectangle rect) {\n return lineIntersects(ray, rect.ll, rect.lu) ||\n lineIntersects(ray, rect.lu, rect.ru) ||\n lineIntersects(ray, rect.ru, rect.rl) ||\n lineIntersects(ray, rect.rl, rect.ll);\n}\n\nvec2 ToWorldSpace(vec2 screenSpacePoint)\n{\n return (screenSpacePoint + camera.position) / camera.zoom;\n}\n\nvec3 Trace(vec2 worldPoint)\n{\n vec3 colorAtPixel = vec3(0.0, 0.0, 0.0);\n\n // Cache the rectangle transformations.\n Rectangle rects[RECTANGLE_COUNT];\n for (int i = 0; i < RECTANGLE_COUNT; i++) {\n RawRect raw = rectangles[i];\n rects[i] = newRectangle(raw.position, raw.width, raw.height, raw.angle);\n }\n\n for (int i = 0; i < LIGHT_COUNT; i++) {\n\n vec2 vectorToLight = lights[i].position - worldPoint;\n\n // Don't forget to normalize the ray's direction\n Ray ray = Ray(worldPoint, vectorToLight, length(vectorToLight));\n ray.direction = normalize(ray.direction);\n\n // Check for occlusions between ray\n bool occluded = false;\n for (int c = 0; c < CIRCLE_COUNT; c++) {\n Circle circle = circles[c];\n if (circleIntersects(circle, ray)) {\n occluded = true;\n break;\n }\n }\n if (occluded) continue;\n\n for (int r = 0; r < RECTANGLE_COUNT; r++) {\n Rectangle rect = rects[r];\n if (rectangleIntersect(ray, rect)) {\n occluded = true;\n break;\n }\n }\n if (occluded) continue;\n\n\n float distanceToLight = length(vectorToLight);\n float intensity = 1.0 / (4.0 * M_PI * distanceToLight);\n\n colorAtPixel += lights[i].color * intensity;\n }\n\n\n return colorAtPixel;\n}\n\n\nvoid main() {\n gl_FragColor = vec4(Trace(ToWorldSpace(screenPosition)), 1.0);\n}\n",C="precision highp float;\n\nattribute vec4 aVertexPosition;\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\n\nvarying mediump vec2 screenPosition;\n\nvoid main() {\n screenPosition = aVertexPosition.xy;\n gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;\n}\n",T=function(){function e(t,i){Object(m["a"])(this,e),Object(S["a"])(this,"gl",void 0),Object(S["a"])(this,"shader",void 0),Object(S["a"])(this,"buffers",void 0),this.gl=t,this.shader=new w(t,C,O,i),this.buffers=this.initBuffers()}return Object(y["a"])(e,[{key:"recompileShader",value:function(e){this.shader.delete(),this.shader=new w(this.gl,C,O,e)}},{key:"initBuffers",value:function(){var e=this.gl.createBuffer();this.gl.bindBuffer(this.gl.ARRAY_BUFFER,e);var t=[-1,1,1,1,-1,-1,1,-1];return this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array(t),this.gl.STATIC_DRAW),{position:e}}},{key:"drawScene",value:function(e){this.gl.clearColor(0,0,0,1),this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.clearDepth(1),this.gl.enable(this.gl.DEPTH_TEST),this.gl.depthFunc(this.gl.LEQUAL),this.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT);var t=43.5*Math.PI/180,i=this.gl.canvas.clientWidth/this.gl.canvas.clientHeight,n=.1,r=100,o=b["a"].create();b["a"].perspective(o,t,i,n,r);var s=b["a"].create();b["a"].translate(s,s,[0,0,-2.5]);var a=this.shader.getAttribLocation("aVertexPosition");this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.buffers.position),this.gl.vertexAttribPointer(a,2,this.gl.FLOAT,!1,0,0),this.gl.enableVertexAttribArray(a),this.shader.use(),this.setLightUniforms(e),this.setCircleUniforms(e),this.setRectUniforms(e),this.shader.setUniformMatrix4fv("uProjectionMatrix",o),this.shader.setUniformMatrix4fv("uModelViewMatrix",s);var c=0,l=4;this.gl.drawArrays(this.gl.TRIANGLE_STRIP,c,l)}},{key:"setLightUniforms",value:function(e){var t,i=Object(v["a"])(e.lights.entries());try{for(i.s();!(t=i.n()).done;){var n=Object(p["a"])(t.value,2),r=n[0],o=n[1];this.shader.setUniform2fv("lights[".concat(r,"].position"),new Float32Array(o.position)),this.shader.setUniform3fv("lights[".concat(r,"].color"),new Float32Array(o.color))}}catch(s){i.e(s)}finally{i.f()}}},{key:"setCircleUniforms",value:function(e){var t,i=Object(v["a"])(e.circles.entries());try{for(i.s();!(t=i.n()).done;){var n=Object(p["a"])(t.value,2),r=n[0],o=n[1];this.shader.setUniform2fv("circles[".concat(r,"].position"),new Float32Array(o.position)),this.shader.setUniform1f("circles[".concat(r,"].radius"),o.radius)}}catch(s){i.e(s)}finally{i.f()}}},{key:"setRectUniforms",value:function(e){var t,i=Object(v["a"])(e.rectangles.entries());try{for(i.s();!(t=i.n()).done;){var n=Object(p["a"])(t.value,2),r=n[0],o=n[1];this.shader.setUniform2fv("rectangles[".concat(r,"].position"),new Float32Array(o.position)),this.shader.setUniform1f("rectangles[".concat(r,"].width"),o.width),this.shader.setUniform1f("rectangles[".concat(r,"].height"),o.height),this.shader.setUniform1f("rectangles[".concat(r,"].angle"),o.angle)}}catch(s){i.e(s)}finally{i.f()}}}]),e}(),L=T;i("d81d"),i("13d5"),i("4160"),i("159b"),i("3410");function R(e){return Object.assign(Object.create(Object.getPrototypeOf(e)),JSON.parse(JSON.stringify(e)))}var _=function(){function e(){Object(m["a"])(this,e),Object(S["a"])(this,"lights",[{position:[1,1],color:[1,1,1]}]),Object(S["a"])(this,"circles",[{position:[0,0],radius:.1}]),Object(S["a"])(this,"rectangles",[{position:[0,0],width:.1,height:.1,angle:0}]),Object(S["a"])(this,"duration",1)}return Object(y["a"])(e,[{key:"clone",value:function(){return R(this)}},{key:"interpolate",value:function(e,t){var i=arguments.length>2&&void 0!==arguments[2]&&arguments[2],n=this.clone();return i||(t=(Math.sin((t-.5)*Math.PI)+1)/2),this.lights.forEach((function(i,r){for(var o in n.lights[r].position)n.lights[r].position[o]=i.position[o]+t*(e.lights[r].position[o]-i.position[o]);for(var s in n.lights[r].color)n.lights[r].color[s]=i.color[s]+t*(e.lights[r].color[s]-i.color[s])})),this.circles.forEach((function(i,r){for(var o in n.circles[r].position)n.circles[r].position[o]=i.position[o]+t*(e.circles[r].position[o]-i.position[o]);n.circles[r].radius=i.radius+t*(e.circles[r].radius-i.radius)})),this.rectangles.forEach((function(i,r){for(var o in n.rectangles[r].position)n.rectangles[r].position[o]=i.position[o]+t*(e.rectangles[r].position[o]-i.position[o]);n.rectangles[r].width=i.width+t*(e.rectangles[r].width-i.width),n.rectangles[r].height=i.height+t*(e.rectangles[r].height-i.height),n.rectangles[r].angle=i.angle+t*(e.rectangles[r].angle-i.angle)})),n}},{key:"addLight",value:function(){this.lights.push(R(this.lights[this.lights.length-1]))}},{key:"addCircle",value:function(){this.circles.push(R(this.circles[this.circles.length-1]))}},{key:"addRectangle",value:function(){this.rectangles.push(R(this.rectangles[this.rectangles.length-1]))}}]),e}(),E=function(){function e(t,i,n,r){Object(m["a"])(this,e),Object(S["a"])(this,"id",void 0),Object(S["a"])(this,"scenes",[new _]),Object(S["a"])(this,"shaderSourceVars",void 0),this.id=t,this.shaderSourceVars={LIGHT_COUNT:i,CIRCLE_COUNT:n,RECTANGLE_COUNT:r};for(var o=1;o sourceVars[varName])\n }\n\n //\n // creates a shader of the given type, uploads the source and\n // compiles it.\n //\n loadShader (gl, type, source) {\n const shader = gl.createShader(type)\n\n // Send the source to the shader object\n gl.shaderSource(shader, source)\n\n // Compile the shader program\n gl.compileShader(shader)\n\n // See if it compiled successfully\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n console.error(`An error occurred compiling the shaders:\\n${gl.getShaderInfoLog(shader)}`)\n gl.deleteShader(shader)\n return null\n }\n\n return shader\n }\n\n use () {\n this.gl.useProgram(this.program)\n }\n\n setUniform1f (name, value) {\n this.gl.uniform1f(this.getUniformLocation(name), value)\n }\n\n setUniformMatrix4fv (name, value) {\n this.gl.uniformMatrix4fv(this.getUniformLocation(name), false, value)\n }\n\n setUniform2fv (name, value) {\n this.gl.uniform2fv(this.getUniformLocation(name), value)\n }\n\n setUniform3fv (name, value) {\n this.gl.uniform3fv(this.getUniformLocation(name), value)\n }\n\n getUniformLocation (name) {\n // TODO: Cache uniform locations\n return this.gl.getUniformLocation(this.program, name)\n }\n\n getAttribLocation (name) {\n // TODO: Cache attrib locations\n return this.gl.getAttribLocation(this.program, name)\n }\n\n delete () {\n this.gl.deleteProgram(this.program)\n }\n}\n","export default \"precision highp float;\\n\\n#define M_PI 3.1415926535897932384626433832795\\n\\nvarying mediump vec2 screenPosition;\\n\\nstruct Camera\\n{\\n vec2 position;\\n float zoom;\\n} camera = Camera (vec2(0.0, 0.0), 0.5);\\n\\nstruct Ray\\n{\\n vec2 origin;\\n vec2 direction;\\n float magnitude;\\n};\\n\\nstruct Light\\n{\\n vec2 position;\\n vec3 color;\\n};\\n\\nstruct Circle\\n{\\n vec2 position;\\n float radius;\\n};\\n\\n#define LIGHT_COUNT 42//$LIGHT_COUNT$//\\nuniform Light lights[LIGHT_COUNT];\\n\\n#define CIRCLE_COUNT 42//$CIRCLE_COUNT$//\\nuniform Circle circles[CIRCLE_COUNT];\\n\\n\\n// INTERSECTION CHECKS\\nbool circleIntersects(Circle circle, Ray ray)\\n{\\n vec2 posToOrigin = ray.origin - circle.position;\\n float a = dot(ray.direction, ray.direction);\\n float b = dot(ray.direction, posToOrigin);\\n float c = dot(posToOrigin, posToOrigin) - (circle.radius * circle.radius);\\n float d = (b * b) - (a * c);\\n\\n if (d < 0.0) return false;\\n\\n float sqrtD = sqrt(d);\\n float distance = (-b - sqrtD) / a;\\n if (distance < 0.0) distance = (-b + sqrtD) / a;\\n\\n return distance > 0.0 && distance < ray.magnitude;\\n}\\n\\nstruct Rectangle {\\n vec2 lu;\\n vec2 ru;\\n vec2 rl;\\n vec2 ll;\\n};\\n\\nRectangle newRectangle(in vec2 position, float width, float height, float angle) {\\n vec2 corners[4];\\n corners[0] = vec2(-width * 0.5, height * 0.5); //lu\\n corners[1] = vec2(width * 0.5, height * 0.5); // ru\\n corners[2] = vec2(width * 0.5, -height * 0.5); // rl\\n corners[3] = vec2(-width * 0.5, -height * 0.5); // ll\\n\\n if (angle != 0.0) {\\n for (int i = 0; i < 4; i++) {\\n vec2 corner = corners[i];\\n corners[i] = vec2(\\n corner.x * cos(angle) - corner.y * sin(angle),\\n corner.xy * sin(angle) + corner.y * cos(angle)\\n );\\n }\\n }\\n\\n for (int i = 0; i < 4; i++) {\\n corners[i] += position;\\n }\\n\\n return Rectangle(corners[0], corners[1], corners[2], corners[3]);\\n}\\n\\nstruct RawRect {\\n vec2 position;\\n float width;\\n float height;\\n float angle;\\n};\\n\\n#define RECTANGLE_COUNT 42//$RECTANGLE_COUNT$//\\nuniform RawRect rectangles[RECTANGLE_COUNT];\\nRectangle rects[RECTANGLE_COUNT];\\nbool lineIntersects(Ray ray, vec2 lineStart, vec2 lineEnd) {\\n vec2 rayStart = ray.origin;\\n vec2 rayEnd = ray.origin + ray.direction;\\n\\n vec2 rayStoLineS = lineStart - rayStart;\\n vec2 r = ray.direction * ray.magnitude;\\n vec2 s = lineEnd - lineStart;\\n\\n float crossR = (rayStoLineS.x * r.y) - (rayStoLineS.y * r.x);\\n float crossS = (rayStoLineS.x * s.y) - (rayStoLineS.y * s.x);\\n float rCrossS = r.x * s.y - r.y * s.x;\\n\\n if (crossR == 0.0) {\\n return ((lineStart.x - rayStart.x < 0.0) != (lineStart.x - rayEnd.x < 0.0)) ||\\n ((lineStart.y - rayStart.y < 0.0) != (lineStart.y - rayEnd.y < 0.0));\\n }\\n\\n if (rCrossS == 0.0) return false;\\n\\n float t = crossS / rCrossS;\\n float u = crossR / rCrossS;\\n\\n return (t >= 0.0) && (t <= 1.0) && (u >= 0.0) && (u <= 1.0);\\n}\\n\\nbool rectangleIntersect(Ray ray, Rectangle rect) {\\n return lineIntersects(ray, rect.ll, rect.lu) ||\\n lineIntersects(ray, rect.lu, rect.ru) ||\\n lineIntersects(ray, rect.ru, rect.rl) ||\\n lineIntersects(ray, rect.rl, rect.ll);\\n}\\n\\nvec2 ToWorldSpace(vec2 screenSpacePoint)\\n{\\n return (screenSpacePoint + camera.position) / camera.zoom;\\n}\\n\\nvec3 Trace(vec2 worldPoint)\\n{\\n vec3 colorAtPixel = vec3(0.0, 0.0, 0.0);\\n\\n // Cache the rectangle transformations.\\n Rectangle rects[RECTANGLE_COUNT];\\n for (int i = 0; i < RECTANGLE_COUNT; i++) {\\n RawRect raw = rectangles[i];\\n rects[i] = newRectangle(raw.position, raw.width, raw.height, raw.angle);\\n }\\n\\n for (int i = 0; i < LIGHT_COUNT; i++) {\\n\\n vec2 vectorToLight = lights[i].position - worldPoint;\\n\\n // Don't forget to normalize the ray's direction\\n Ray ray = Ray(worldPoint, vectorToLight, length(vectorToLight));\\n ray.direction = normalize(ray.direction);\\n\\n // Check for occlusions between ray\\n bool occluded = false;\\n for (int c = 0; c < CIRCLE_COUNT; c++) {\\n Circle circle = circles[c];\\n if (circleIntersects(circle, ray)) {\\n occluded = true;\\n break;\\n }\\n }\\n if (occluded) continue;\\n\\n for (int r = 0; r < RECTANGLE_COUNT; r++) {\\n Rectangle rect = rects[r];\\n if (rectangleIntersect(ray, rect)) {\\n occluded = true;\\n break;\\n }\\n }\\n if (occluded) continue;\\n\\n\\n float distanceToLight = length(vectorToLight);\\n float intensity = 1.0 / (4.0 * M_PI * distanceToLight);\\n\\n colorAtPixel += lights[i].color * intensity;\\n }\\n\\n\\n return colorAtPixel;\\n}\\n\\n\\nvoid main() {\\n gl_FragColor = vec4(Trace(ToWorldSpace(screenPosition)), 1.0);\\n}\\n\";","export default \"precision highp float;\\n\\nattribute vec4 aVertexPosition;\\n\\nuniform mat4 uModelViewMatrix;\\nuniform mat4 uProjectionMatrix;\\n\\nvarying mediump vec2 screenPosition;\\n\\nvoid main() {\\n screenPosition = aVertexPosition.xy;\\n gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;\\n}\\n\";","import { mat4 } from 'gl-matrix'\nimport Shader from './shader'\n\nimport fsSource from './shaders/shader.frag'\nimport vsSource from './shaders/shader.vert'\n\nexport default class Raytracer {\n gl\n shader\n buffers\n\n constructor (gl, shaderSourceVars) {\n this.gl = gl\n this.shader = new Shader(gl, vsSource, fsSource, shaderSourceVars)\n this.buffers = this.initBuffers()\n }\n\n recompileShader (shaderSourceVars) {\n this.shader.delete()\n this.shader = new Shader(this.gl, vsSource, fsSource, shaderSourceVars)\n }\n\n initBuffers () {\n // Create a buffer for the square's positions.\n\n const positionBuffer = this.gl.createBuffer()\n\n // Select the positionBuffer as the one to apply buffer\n // operations to from here out.\n\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer)\n\n // Now create an array of positions for the square.\n\n const positions = [\n -1.0, 1.0,\n 1.0, 1.0,\n -1.0, -1.0,\n 1.0, -1.0\n ]\n\n // Now pass the list of positions into WebGL to build the\n // shape. We do this by creating a Float32Array from the\n // JavaScript array, then use it to fill the current buffer.\n this.gl.bufferData(this.gl.ARRAY_BUFFER,\n new Float32Array(positions),\n this.gl.STATIC_DRAW)\n\n return {\n position: positionBuffer\n }\n }\n\n drawScene (scene) {\n this.gl.clearColor(0.0, 0.0, 0.0, 1.0) // Clear to black, fully opaque\n this.gl.clear(this.gl.COLOR_BUFFER_BIT)\n this.gl.clearDepth(1.0) // Clear everything\n this.gl.enable(this.gl.DEPTH_TEST) // Enable depth testing\n this.gl.depthFunc(this.gl.LEQUAL) // Near things obscure far things\n\n // Clear the canvas before we start drawing on it.\n\n this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT)\n\n // Create a perspective matrix, a special matrix that is\n // used to simulate the distortion of perspective in a camera.\n const fieldOfView = 43.5 * Math.PI / 180 // in radians\n const aspect = this.gl.canvas.clientWidth / this.gl.canvas.clientHeight\n const zNear = 0.1\n const zFar = 100.0\n const projectionMatrix = mat4.create()\n\n // gl-matrix.js always has the first argument as the destination to receive the result.\n mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar)\n\n // Set the drawing position to the \"identity\" point, which is\n // the center of the scene.\n const modelViewMatrix = mat4.create()\n\n // Now move the drawing position a bit to where we want to\n // start drawing the square.\n mat4.translate(modelViewMatrix, // destination matrix\n modelViewMatrix, // matrix to translate\n [0.0, 0.0, -2.5]) // amount to translate\n\n // Tell WebGL how to pull out the positions from the position\n // buffer into the vertexPosition attribute.\n const vertexPositionLocation = this.shader.getAttribLocation('aVertexPosition')\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffers.position)\n this.gl.vertexAttribPointer(vertexPositionLocation, 2, this.gl.FLOAT, false, 0, 0)\n this.gl.enableVertexAttribArray(vertexPositionLocation)\n\n // Tell WebGL to use our program when drawing\n this.shader.use()\n\n this.setLightUniforms(scene)\n this.setCircleUniforms(scene)\n this.setRectUniforms(scene)\n\n // Set the shader uniforms\n this.shader.setUniformMatrix4fv('uProjectionMatrix', projectionMatrix)\n this.shader.setUniformMatrix4fv('uModelViewMatrix', modelViewMatrix)\n {\n const offset = 0\n const vertexCount = 4\n this.gl.drawArrays(this.gl.TRIANGLE_STRIP, offset, vertexCount)\n }\n }\n\n setLightUniforms (scene) {\n for (const [i, light] of scene.lights.entries()) {\n this.shader.setUniform2fv(`lights[${i}].position`, new Float32Array(light.position))\n this.shader.setUniform3fv(`lights[${i}].color`, new Float32Array(light.color))\n }\n }\n\n setCircleUniforms (scene) {\n for (const [i, circle] of scene.circles.entries()) {\n this.shader.setUniform2fv(`circles[${i}].position`, new Float32Array(circle.position))\n this.shader.setUniform1f(`circles[${i}].radius`, circle.radius)\n }\n }\n\n setRectUniforms (scene) {\n for (const [i, rect] of scene.rectangles.entries()) {\n this.shader.setUniform2fv(`rectangles[${i}].position`, new Float32Array(rect.position))\n this.shader.setUniform1f(`rectangles[${i}].width`, rect.width)\n this.shader.setUniform1f(`rectangles[${i}].height`, rect.height)\n this.shader.setUniform1f(`rectangles[${i}].angle`, rect.angle)\n }\n }\n}\n","import Raytracer from './raytracer'\n\nexport default Raytracer\n","/**\n * @function\n * @description Deep clone a class instance.\n * @param {object} instance The class instance you want to clone.\n * @returns {object} A new cloned instance.\n */\nexport default function clone (instance) {\n return Object.assign(\n Object.create(\n // Set the prototype of the new object to the prototype of the instance.\n // Used to allow new object behave like class instance.\n Object.getPrototypeOf(instance)\n ),\n // Prevent shallow copies of nested structures like arrays, etc\n JSON.parse(JSON.stringify(instance))\n )\n}\n","import clone from '../helpers/clone'\n\nexport default class Scene {\n lights = [\n {\n position: [1, 1],\n color: [1, 1, 1]\n }\n ]\n\n circles = [\n {\n position: [0, 0],\n radius: 0.1\n }\n ]\n\n rectangles = [\n {\n position: [0, 0],\n width: 0.1,\n height: 0.1,\n angle: 0\n }\n ]\n\n duration = 1\n\n clone () {\n return clone(this)\n }\n\n interpolate (nextScene, t, linear = false) {\n const interpolatedScene = this.clone()\n\n if (!linear) { // Ease in and ease out\n t = (Math.sin((t - 0.5) * Math.PI) + 1) / 2\n }\n\n // Interpolated = Current + t(Next-Current)\n this.lights.forEach((light, i) => {\n for (const p in interpolatedScene.lights[i].position) {\n interpolatedScene.lights[i].position[p] =\n light.position[p] + t * (nextScene.lights[i].position[p] - light.position[p])\n }\n\n for (const c in interpolatedScene.lights[i].color) {\n interpolatedScene.lights[i].color[c] =\n light.color[c] + t * (nextScene.lights[i].color[c] - light.color[c])\n }\n })\n\n this.circles.forEach((circle, i) => {\n for (const p in interpolatedScene.circles[i].position) {\n interpolatedScene.circles[i].position[p] =\n circle.position[p] + t * (nextScene.circles[i].position[p] - circle.position[p])\n }\n\n interpolatedScene.circles[i].radius =\n circle.radius + t * (nextScene.circles[i].radius - circle.radius)\n })\n\n this.rectangles.forEach((rectangle, i) => {\n for (const p in interpolatedScene.rectangles[i].position) {\n interpolatedScene.rectangles[i].position[p] =\n rectangle.position[p] + t * (nextScene.rectangles[i].position[p] - rectangle.position[p])\n }\n\n interpolatedScene.rectangles[i].width =\n rectangle.width + t * (nextScene.rectangles[i].width - rectangle.width)\n\n interpolatedScene.rectangles[i].height =\n rectangle.height + t * (nextScene.rectangles[i].height - rectangle.height)\n\n interpolatedScene.rectangles[i].angle =\n rectangle.angle + t * (nextScene.rectangles[i].angle - rectangle.angle)\n })\n\n return interpolatedScene\n }\n\n addLight () {\n this.lights.push(clone(this.lights[this.lights.length - 1]))\n }\n\n addCircle () {\n this.circles.push(clone(this.circles[this.circles.length - 1]))\n }\n\n addRectangle () {\n this.rectangles.push(clone(this.rectangles[this.rectangles.length - 1]))\n }\n}\n","import Scene from './scene'\n\nexport default class Movie {\n id\n scenes = [new Scene()]\n shaderSourceVars\n\n constructor (id, lightCount, circleCount, rectangleCount) {\n this.id = id\n this.shaderSourceVars = {\n LIGHT_COUNT: lightCount,\n CIRCLE_COUNT: circleCount,\n RECTANGLE_COUNT: rectangleCount\n }\n\n for (let i = 1; i < lightCount; i++) {\n this.lastScene().addLight()\n }\n\n for (let i = 1; i < circleCount; i++) {\n this.lastScene().addCircle()\n }\n\n for (let i = 1; i < rectangleCount; i++) {\n this.lastScene().addRectangle()\n }\n }\n\n sceneDurations () {\n return this.scenes.map(s => s.duration)\n }\n\n duration () {\n return this.sceneDurations().reduce((d0, d1) => d0 + d1, 0)\n }\n\n lastScene () {\n return this.scenes[this.scenes.length - 1]\n }\n\n addScene () {\n this.scenes.push(this.lastScene().clone())\n return this.lastScene()\n }\n\n currentScene (time) {\n const sceneDurations = this.sceneDurations()\n const sceneCount = this.scenes.length\n\n time %= this.duration()\n\n let timeSum = 0\n let sceneIndex = -1\n while (timeSum < time) {\n sceneIndex++\n timeSum += sceneDurations[sceneIndex]\n sceneIndex %= sceneCount\n }\n\n const scene0 = this.scenes[sceneIndex]\n const scene1 = sceneIndex + 1 === sceneCount\n ? this.scenes[0] // go back to scene 0 at the end\n : this.scenes[sceneIndex + 1] // otherwise, go the the succeeding scene\n\n const normalizedTime = (time - timeSum + scene0.duration) / scene0.duration\n return scene0.interpolate(scene1, normalizedTime)\n }\n}\n","import Movie from '../movie'\n\nexport default function rectangleMovie () {\n const m = new Movie('Rectangle Movie', 2, 1, 9)\n let s = m.lastScene()\n\n const brightness = 2\n\n s.lights[0].position = [1, 1]\n s.lights[0].color = [brightness, 0, brightness]\n\n s.lights[1].position = [-1, 0]\n s.lights[1].color = [0, 0, 0]\n\n s.circles[0].radius = 0\n\n const spacing = 0.4\n const sideDimension = 0.2\n\n const combinedWidth = spacing * 3 - sideDimension\n\n for (let i = 0; i < 9; i++) {\n const x = i % 3\n const y = ~~(i / 3)\n\n s.rectangles[i].width = 0\n s.rectangles[i].height = 0\n s.rectangles[i].position[0] = spacing * x - spacing\n s.rectangles[i].position[1] = spacing * y - spacing\n }\n\n s.rectangles[4].width = combinedWidth\n s.rectangles[4].height = combinedWidth\n\n s = m.addScene()\n s.lights[0].position[1] = -1\n\n s = m.addScene()\n s.lights[0].position[0] = -1\n\n // combine rects for split\n s.rectangles[1].width = combinedWidth\n s.rectangles[1].height = sideDimension\n\n s.rectangles[7].width = combinedWidth\n s.rectangles[7].height = sideDimension\n\n s = m.addScene()\n s.lights[0].position[1] = 0\n\n s = m.addScene()\n s.rectangles[4].height = sideDimension\n\n s = m.addScene()\n s.lights[0].color = [brightness, 0, 0]\n s.lights[1].color = [0, 0, brightness]\n\n s = m.addScene()\n s.lights[0].position[1] = spacing / 4\n s.lights[1].position[1] = -spacing / 4\n\n s = m.addScene()\n s.lights[0].position[1] = spacing / 2\n s.lights[1].position[1] = -spacing / 2\n\n s = m.addScene()\n s.lights[0].position[0] = 1\n\n s = m.addScene()\n s.lights[1].position[0] = -1\n\n s = m.addScene()\n s.lights[1].position[0] = 1\n s.lights[1].position[0] = -1\n\n const pointBetweenRects = spacing / 2\n s = m.addScene()\n s.lights[0].position[0] = pointBetweenRects\n s.lights[1].position[0] = -pointBetweenRects\n\n for (const i of [0, 2, 3, 5, 6, 8]) {\n s.rectangles[i].width = sideDimension\n s.rectangles[i].height = sideDimension\n }\n\n s = m.addScene()\n s.duration = 3\n for (const i of [1, 4, 7]) {\n s.rectangles[i].width = sideDimension\n s.rectangles[i].height = sideDimension\n }\n\n s = m.addScene()\n s.rectangles[4].angle = 3 * Math.PI\n s.duration = 0.5\n\n s = m.addScene()\n s.lights[0].position[1] = -pointBetweenRects\n s.lights[1].position[1] = pointBetweenRects\n\n s = m.addScene()\n s.lights[0].position[0] = -pointBetweenRects\n s.lights[1].position[0] = pointBetweenRects\n s.duration = 1\n\n s = m.addScene()\n s.lights[0].position[1] = 1\n s.lights[1].position[1] = -1\n\n s = m.addScene()\n s.lights[0].position[1] = -1\n s.lights[1].position[1] = 1\n\n s = m.addScene()\n s.lights[0].position[1] = pointBetweenRects\n s.lights[1].position[1] = -pointBetweenRects\n\n s = m.addScene()\n s.lights[0].position[1] = 1\n s.lights[1].position[1] = 1\n s.duration = 0.5\n\n s = m.addScene()\n s.lights[0].position[0] = -pointBetweenRects / 2\n s.lights[1].position[0] = pointBetweenRects / 2\n\n s = m.addScene()\n s.lights[0].position[0] = 0\n s.lights[1].position[0] = 0\n s.duration = 1\n\n s.rectangles[4].width = combinedWidth\n s.rectangles[4].height = combinedWidth\n\n s = m.addScene()\n s.lights[0].color = [2, 0, 2]\n s.lights[1].color = [0, 0, 0]\n for (const i of [0, 1, 2, 3, 5, 6, 7, 8]) {\n s.rectangles[i].width = 0\n s.rectangles[i].height = 0\n }\n s.duration = 2\n\n return m\n}\n","import Movie from '../movie'\n\nexport default function circleMovie () {\n const m = new Movie('Circle Movie', 4, 9, 1)\n\n // Setup inital scene\n let s = m.lastScene()\n s.rectangles[0].width = 0\n s.rectangles[0].height = 0\n s.rectangles[0].position = [-10, 0]\n s.addCircle()\n\n s.lights[0].position = [-2.5, 2.5]\n s.lights[0].color = [0, 0, 0]\n s.lights[1].position = [0, 0]\n s.lights[2].position = [0, 0]\n s.lights[3].position = [0, 0]\n s.lights[1].color = [0, 0, 0]\n s.lights[2].color = [0, 0, 0]\n s.lights[3].color = [0, 0, 0]\n\n s = m.addScene()\n s.lights[0].color = [2, 2, 2]\n s.duration = 2\n\n s = m.addScene()\n\n s = m.addScene()\n s.lights[0].position = [-0.5, 0.5]\n s.duration = 0.5\n\n s = m.addScene()\n\n s = m.addScene()\n s.lights[0].position = [0.5, 0.5]\n s.lights[0].color = [2, 0, 0]\n\n s = m.addScene()\n s.lights[0].position = [0.5, -0.5]\n s.lights[0].color = [1, 1, 0]\n\n s = m.addScene()\n s.lights[0].position = [-0.5, -0.5]\n s.lights[0].color = [0, 2, 0]\n\n s = m.addScene()\n s.lights[0].position = [-0.5, 0.5]\n s.lights[0].color = [0, 0, 2]\n\n s = m.addScene()\n s.lights[0].color = [2, 1, 3]\n s.duration = 2\n\n s = m.addScene()\n s.circles[0].position = [-1, -1]\n s.circles[1].position = [1, 1]\n s.circles[2].position = [1, -1]\n s.circles[3].position = [1, -1]\n s.circles[4].position = [1, -1]\n s.circles[5].position = [1, -1]\n s.circles[6].position = [1, -1]\n s.circles[7].position = [1, -1]\n s.circles[8].position = [1, -1]\n\n s.lights[0].position = [0, 0]\n\n s = m.addScene()\n s.circles[0].radius = 0.4\n s.circles[1].radius = 0.5\n s.lights[0].color = [9, 4, 8]\n s.circles[3].position = [1, 0]\n s.circles[4].position = [0, -1]\n\n s = m.addScene()\n s.circles[0].radius = 0.2\n s.circles[1].radius = 0.2\n s.circles[3].radius = 0.15\n s.circles[4].radius = 0.15\n\n s = m.addScene()\n s.lights[0].color = [1, 1, 4]\n\n s = m.addScene()\n s.lights[1].color = [9, 4, 8]\n\n s = m.addScene()\n s.lights[1].position = [0, 1.8]\n s.duration = 1\n\n s = m.addScene()\n s.lights[1].position = [1.8, 1.8]\n\n s = m.addScene()\n s.lights[1].position = [1.8, -1.8]\n\n s = m.addScene()\n s.lights[1].position = [-1.8, -1.8]\n\n s = m.addScene()\n s.lights[1].position = [-1.8, 0]\n\n s = m.addScene()\n s.lights[1].position = [0, 0]\n\n s = m.addScene()\n s.circles[0].radius = 0.1\n s.circles[1].radius = 0.1\n s.circles[2].radius = 0.1\n s.circles[3].radius = 0.1\n s.circles[4].radius = 0.1\n\n s = m.addScene()\n s.circles[5].position = [1, 0.5]\n s.circles[6].position = [1, -0.5]\n s.circles[7].position = [0.5, -1]\n s.circles[8].position = [-0.5, -1]\n\n s = m.addScene()\n s.lights[0].color = [0, 0, 0]\n s.lights[1].color = [0, 0, 0]\n s.lights[2].color = [0, 0, 0]\n s.lights[3].color = [0, 0, 0]\n\n s = m.addScene()\n s.lights[0].position = [1.8, 0.7]\n s.lights[1].position = [1.8, -0.7]\n s.lights[2].position = [0.7, -1.8]\n s.lights[3].position = [-0.7, -1.8]\n s.duration = 0.5\n\n s = m.addScene()\n s.lights[0].color = [0, 2, 0]\n\n s = m.addScene()\n s.lights[0].color = [0, 0, 0]\n s.lights[1].color = [0, 2, 0]\n\n s = m.addScene()\n s.lights[1].color = [0, 0, 0]\n s.lights[2].color = [0, 2, 0]\n\n s = m.addScene()\n s.lights[2].color = [0, 0, 0]\n s.lights[3].color = [0, 2, 0]\n\n s = m.addScene()\n s.lights[3].color = [0, 0, 0]\n\n s = m.addScene()\n s.lights[0].color = [0, 2, 0]\n s.lights[1].color = [0, 2, 0]\n s.lights[2].color = [0, 2, 0]\n s.lights[3].color = [0, 2, 0]\n s.duration = 3\n\n s = m.addScene()\n s.lights[0].position = [1.8, -1.8]\n s.lights[1].position = [1.8, -1.8]\n s.lights[2].position = [1.8, -1.8]\n s.lights[3].position = [1.8, -1.8]\n\n s = m.addScene()\n s.lights[0].position = [5, -5]\n s.lights[1].position = [5, -5]\n s.lights[2].position = [5, -5]\n s.lights[3].position = [5, -5]\n\n s = m.addScene()\n s.duration = 1\n s.lights[0].position = [-2.5, 2.5]\n s.lights[1].position = [-2.5, 2.5]\n s.lights[2].position = [-2.5, 2.5]\n s.lights[3].position = [-2.5, 2.5]\n s.lights[0].color = [0, 0, 0]\n s.lights[1].color = [0, 0, 0]\n s.lights[2].color = [0, 0, 0]\n s.lights[3].color = [0, 0, 0]\n\n return m\n}\n","\n
\n Above you will find two movies; which are actively ray traced withn a WebGL fragment shader. The tracer operates in two dimensions, shooting a ray at each pixel every single frame. WebGL is easily capable of performing this operation at 60FPS, as opposed to traditional CPU implementations. Our CPU-based C# version, from which we originally ported the core logic, runs at a mere 5FPS. We've ported that shader to OpenGL, which supports a more modern shading language, in order to hit 60FPS.\n
\n
\n We wanted to run this project on the web, which is why we ported it to WebGL. However, due to WebGL's limited support for shaders, we wrote our own shader preprocessor in order to add variable-sized arrays to GLSL 1.0\n
\n
\n The movie consists of a set of static scenes, which are interpolated to generate fluid motion.\n
\n
\n As part of our assignment, we first implemented the 2D tracer in C#, after porting the provided template project, removing deprecated OpenGL practices. Next we reimplemented the same ray tracer using OpenGL in a fragment shader. Lastly we ported our OpenGL 3.0 fragment shader to WebGL (which uses OpenGL 1.0 ES). Running the WebGL shader requires NPM and Node, the options are explained in the README.\n
\n\n
\n DISCLAIMER: works best on desktop browsers.\n
\n
\n
\n\n\n\n\n\n","import mod from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Home.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Home.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./Home.vue?vue&type=template&id=01506eff&\"\nimport script from \"./Home.vue?vue&type=script&lang=js&\"\nexport * from \"./Home.vue?vue&type=script&lang=js&\"\nimport style0 from \"./Home.vue?vue&type=style&index=0&lang=scss&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","import Vue from 'vue'\nimport VueRouter from 'vue-router'\nimport Home from '../views/Home.vue'\n\nVue.use(VueRouter)\n\nconst routes = [\n {\n path: '/',\n redirect: '/movie/0',\n name: 'Home',\n component: Home\n },\n {\n path: '/movie/:id',\n name: 'Movie',\n component: Home,\n props (route) {\n const props = { ...route.params }\n props.id = +props.id\n return props\n }\n },\n {\n path: '/about',\n name: 'About',\n // route level code-splitting\n // this generates a separate chunk (about.[hash].js) for this route\n // which is lazy-loaded when the route is visited.\n component: () => import(/* webpackChunkName: \"about\" */ '../views/About.vue')\n }\n]\n\nconst router = new VueRouter({\n mode: 'history',\n base: process.env.BASE_URL,\n routes\n})\n\nexport default router\n","import Vue from 'vue'\nimport Vuex from 'vuex'\n\nVue.use(Vuex)\n\nexport default new Vuex.Store({\n state: {\n },\n mutations: {\n },\n actions: {\n },\n modules: {\n }\n})\n","import Vue from 'vue'\nimport App from './App.vue'\nimport './registerServiceWorker'\nimport router from './router'\nimport store from './store'\n\nVue.config.productionTip = false\n\nnew Vue({\n router,\n store,\n render: h => h(App)\n}).$mount('#app')\n","import mod from \"-!../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../node_modules/cache-loader/dist/cjs.js??ref--0-0!../node_modules/vue-loader/lib/index.js??vue-loader-options!./App.vue?vue&type=style&index=0&lang=scss&\"; export default mod; export * from \"-!../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../node_modules/cache-loader/dist/cjs.js??ref--0-0!../node_modules/vue-loader/lib/index.js??vue-loader-options!./App.vue?vue&type=style&index=0&lang=scss&\""],"sourceRoot":""}
--------------------------------------------------------------------------------