├── AssetManager.js
├── EffectShader.js
├── LICENSE
├── diamond.glb
├── index.html
├── main.js
├── skybox
├── Box_Back.bmp
├── Box_Bottom.bmp
├── Box_Front.bmp
├── Box_Left.bmp
├── Box_Right.bmp
└── Box_Top.bmp
└── stats.js
/AssetManager.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'https://cdn.skypack.dev/three@0.142.0';
2 | import {
3 | GLTFLoader
4 | } from 'https://unpkg.com/three@0.142.0/examples/jsm/loaders/GLTFLoader.js';
5 | const AssetManager = {};
6 | AssetManager.gltfLoader = new GLTFLoader();
7 | AssetManager.audioLoader = new THREE.AudioLoader();
8 | AssetManager.loadGLTFAsync = (url) => {
9 | return new Promise((resolve, reject) => {
10 | AssetManager.gltfLoader.load(url, obj => {
11 | resolve(obj);
12 | })
13 | });
14 | }
15 |
16 | AssetManager.loadAudioAsync = (url) => {
17 | return new Promise((resolve, reject) => {
18 | AssetManager.audioLoader.load(url, (buffer) => {
19 | resolve(buffer);
20 | });
21 | })
22 | }
23 |
24 | AssetManager.loadTextureAsync = (url) => {
25 | return new Promise((resolve, reject) => {
26 | THREE.ImageUtils.loadTexture(url, null, (tex) => {
27 | resolve(tex);
28 | })
29 | })
30 | }
31 | AssetManager.loadAll = (promiseArr, element, message) => {
32 | let count = promiseArr.length;
33 | let results = [];
34 | element.innerHTML = `${message} (${promiseArr.length - count} / ${promiseArr.length})...`
35 | return new Promise((resolve, reject) => {
36 | promiseArr.forEach((promise, i) => {
37 | promise.then(result => {
38 | results[i] = result;
39 | count--;
40 | element.innerHTML = `${message} (${promiseArr.length - count} / ${promiseArr.length})...`
41 | if (count === 0) {
42 | resolve(results);
43 | }
44 | })
45 | })
46 | });
47 | }
48 | export { AssetManager };
--------------------------------------------------------------------------------
/EffectShader.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'https://cdn.skypack.dev/three@0.142.0';
2 | const EffectShader = {
3 |
4 | uniforms: {
5 |
6 | 'sceneDiffuse': { value: null }
7 | },
8 |
9 | vertexShader: /* glsl */ `
10 | varying vec2 vUv;
11 | void main() {
12 | vUv = uv;
13 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
14 | }`,
15 |
16 | fragmentShader: /* glsl */ `
17 | uniform sampler2D sceneDiffuse;
18 | varying vec2 vUv;
19 | void main() {
20 | vec4 diffuse = texture2D(sceneDiffuse, vUv);
21 | gl_FragColor = vec4(diffuse.rgb, 1.0);
22 | }`
23 |
24 | };
25 |
26 | export { EffectShader };
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2022 N8python
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/diamond.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/N8python/diamonds/69b30cc5586195461f47e0b25ccf14578b292cc0/diamond.glb
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Total Internal Reflection
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'https://cdn.skypack.dev/three@0.142.0';
2 | import { EffectComposer } from 'https://unpkg.com/three@0.142.0/examples/jsm/postprocessing/EffectComposer.js';
3 | import { RenderPass } from 'https://unpkg.com/three@0.142.0/examples/jsm/postprocessing/RenderPass.js';
4 | import { ShaderPass } from 'https://unpkg.com/three@0.142.0/examples/jsm/postprocessing/ShaderPass.js';
5 | import { SMAAPass } from 'https://unpkg.com/three@0.142.0/examples/jsm/postprocessing/SMAAPass.js';
6 | import { GammaCorrectionShader } from 'https://unpkg.com/three@0.142.0/examples/jsm/shaders/GammaCorrectionShader.js';
7 | import { EffectShader } from "./EffectShader.js";
8 | import { OrbitControls } from 'https://unpkg.com/three@0.142.0/examples/jsm/controls/OrbitControls.js';
9 | import { AssetManager } from './AssetManager.js';
10 | import { Stats } from "./stats.js";
11 | import {
12 | MeshBVH,
13 | MeshBVHVisualizer,
14 | MeshBVHUniformStruct,
15 | FloatVertexAttributeTexture,
16 | shaderStructs,
17 | shaderIntersectFunction,
18 | SAH
19 | } from 'https://unpkg.com/three-mesh-bvh@0.5.10/build/index.module.js';
20 | import { GUI } from 'https://unpkg.com/three@0.138.0/examples/jsm/libs/lil-gui.module.min.js';
21 | async function main() {
22 | // Setup basic renderer, controls, and profiler
23 | const clientWidth = window.innerWidth * 0.99;
24 | const clientHeight = window.innerHeight * 0.98;
25 | const scene = new THREE.Scene();
26 | const camera = new THREE.PerspectiveCamera(75, clientWidth / clientHeight, 0.1, 1000);
27 | camera.position.set(50, 75, 50);
28 | const renderer = new THREE.WebGLRenderer();
29 | renderer.setSize(clientWidth, clientHeight);
30 | document.body.appendChild(renderer.domElement);
31 | renderer.shadowMap.enabled = true;
32 | renderer.shadowMap.type = THREE.VSMShadowMap;
33 | const controls = new OrbitControls(camera, renderer.domElement);
34 | controls.target.set(0, 25, 0);
35 | const stats = new Stats();
36 | stats.showPanel(0);
37 | document.body.appendChild(stats.dom);
38 | // Setup scene
39 | // Skybox
40 | const environment = await new THREE.CubeTextureLoader().loadAsync([
41 | "skybox/Box_Right.bmp",
42 | "skybox/Box_Left.bmp",
43 | "skybox/Box_Top.bmp",
44 | "skybox/Box_Bottom.bmp",
45 | "skybox/Box_Front.bmp",
46 | "skybox/Box_Back.bmp"
47 | ]);
48 | environment.encoding = THREE.sRGBEncoding;
49 | scene.background = environment;
50 | // Lighting
51 | const ambientLight = new THREE.AmbientLight(new THREE.Color(1.0, 1.0, 1.0), 0.25);
52 | scene.add(ambientLight);
53 | const directionalLight = new THREE.DirectionalLight(0xffffff, 0.35);
54 | directionalLight.position.set(150, 200, 50);
55 | // Shadows
56 | directionalLight.castShadow = true;
57 | directionalLight.shadow.mapSize.width = 1024;
58 | directionalLight.shadow.mapSize.height = 1024;
59 | directionalLight.shadow.camera.left = -75;
60 | directionalLight.shadow.camera.right = 75;
61 | directionalLight.shadow.camera.top = 75;
62 | directionalLight.shadow.camera.bottom = -75;
63 | directionalLight.shadow.camera.near = 0.1;
64 | directionalLight.shadow.camera.far = 500;
65 | directionalLight.shadow.bias = -0.001;
66 | directionalLight.shadow.blurSamples = 8;
67 | directionalLight.shadow.radius = 4;
68 | scene.add(directionalLight);
69 | const directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.15);
70 | directionalLight2.color.setRGB(1.0, 1.0, 1.0);
71 | directionalLight2.position.set(-50, 200, -150);
72 | scene.add(directionalLight2);
73 | // Objects
74 | const ground = new THREE.Mesh(new THREE.PlaneGeometry(100, 100).applyMatrix4(new THREE.Matrix4().makeRotationX(-Math.PI / 2)), new THREE.MeshStandardMaterial({ side: THREE.DoubleSide }));
75 | ground.castShadow = true;
76 | ground.receiveShadow = true;
77 | scene.add(ground);
78 | const box = new THREE.Mesh(new THREE.BoxGeometry(10, 10, 10), new THREE.MeshStandardMaterial({ side: THREE.DoubleSide, color: new THREE.Color(1.0, 0.0, 0.0) }));
79 | box.castShadow = true;
80 | box.receiveShadow = true;
81 | box.position.y = 5.01;
82 | //scene.add(box);
83 | const sphere = new THREE.Mesh(new THREE.SphereGeometry(6.25, 32, 32), new THREE.MeshStandardMaterial({ side: THREE.DoubleSide, envMap: environment, metalness: 1.0, roughness: 0.25 }));
84 | sphere.position.y = 7.5;
85 | sphere.position.x = 25;
86 | sphere.position.z = 25;
87 | sphere.castShadow = true;
88 | sphere.receiveShadow = true;
89 | //scene.add(sphere);
90 | const torusKnot = new THREE.Mesh(new THREE.TorusKnotGeometry(5, 1.5, 200, 32), new THREE.MeshStandardMaterial({ side: THREE.DoubleSide, envMap: environment, metalness: 0.5, roughness: 0.5, color: new THREE.Color(0.0, 1.0, 0.0) }));
91 | torusKnot.position.y = 10;
92 | torusKnot.position.x = -25;
93 | torusKnot.position.z = -25;
94 | torusKnot.castShadow = true;
95 | torusKnot.receiveShadow = true;
96 | // scene.add(torusKnot);
97 | let diamondGeo = (await AssetManager.loadGLTFAsync("diamond.glb")).scene.children[0].children[0].children[0].children[0].children[0].geometry;
98 | diamondGeo.scale(10, 10, 10);
99 | diamondGeo.translate(0, 5, 0);
100 | const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256, { generateMipmaps: true, minFilter: THREE.LinearMipmapLinearFilter });
101 | const cubeCamera = new THREE.CubeCamera(1, 100000, cubeRenderTarget);
102 | scene.add(cubeCamera);
103 | cubeCamera.position.set(0, 5, 0);
104 | cubeCamera.update(renderer, scene);
105 | //scene.background = cubeRenderTarget.texture;
106 | const makeDiamond = (geo, {
107 | color = new THREE.Color(1, 1, 1),
108 | ior = 2.4
109 | } = {}) => {
110 | const mergedGeometry = geo;
111 | mergedGeometry.boundsTree = new MeshBVH(mergedGeometry.toNonIndexed(), { lazyGeneration: false, strategy: SAH });
112 | const collider = new THREE.Mesh(mergedGeometry);
113 | collider.material.wireframe = true;
114 | collider.material.opacity = 0.5;
115 | collider.material.transparent = true;
116 | collider.visible = false;
117 | collider.boundsTree = mergedGeometry.boundsTree;
118 | scene.add(collider);
119 | const visualizer = new MeshBVHVisualizer(collider, 20);
120 | visualizer.visible = false;
121 | visualizer.update();
122 | scene.add(visualizer);
123 | const diamond = new THREE.Mesh(geo, new THREE.ShaderMaterial({
124 | uniforms: {
125 | envMap: { value: environment },
126 | bvh: { value: new MeshBVHUniformStruct() },
127 | bounces: { value: 3 },
128 | color: { value: color },
129 | ior: { value: ior },
130 | correctMips: { value: true },
131 | projectionMatrixInv: { value: camera.projectionMatrixInverse },
132 | viewMatrixInv: { value: camera.matrixWorld },
133 | chromaticAberration: { value: true },
134 | aberrationStrength: { value: 0.01 },
135 | resolution: { value: new THREE.Vector2(clientWidth, clientHeight) }
136 | },
137 | vertexShader: /*glsl*/ `
138 | varying vec3 vWorldPosition;
139 | varying vec3 vNormal;
140 | uniform mat4 viewMatrixInv;
141 | void main() {
142 | vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
143 | vNormal = (viewMatrixInv * vec4(normalMatrix * normal, 0.0)).xyz;
144 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
145 | }
146 | `,
147 | fragmentShader: /*glsl*/ `
148 | precision highp isampler2D;
149 | precision highp usampler2D;
150 | varying vec3 vWorldPosition;
151 | varying vec3 vNormal;
152 | uniform samplerCube envMap;
153 | uniform float bounces;
154 | ${ shaderStructs }
155 | ${ shaderIntersectFunction }
156 | uniform BVH bvh;
157 | uniform float ior;
158 | uniform vec3 color;
159 | uniform bool correctMips;
160 | uniform bool chromaticAberration;
161 | uniform mat4 projectionMatrixInv;
162 | uniform mat4 viewMatrixInv;
163 | uniform mat4 modelMatrix;
164 | uniform vec2 resolution;
165 | uniform bool chromaticAbberation;
166 | uniform float aberrationStrength;
167 | vec3 totalInternalReflection(vec3 ro, vec3 rd, vec3 normal, float ior, mat4 modelMatrixInverse) {
168 | vec3 rayOrigin = ro;
169 | vec3 rayDirection = rd;
170 | rayDirection = refract(rayDirection, normal, 1.0 / ior);
171 | rayOrigin = vWorldPosition + rayDirection * 0.001;
172 | rayOrigin = (modelMatrixInverse * vec4(rayOrigin, 1.0)).xyz;
173 | rayDirection = normalize((modelMatrixInverse * vec4(rayDirection, 0.0)).xyz);
174 | for(float i = 0.0; i < bounces; i++) {
175 | uvec4 faceIndices = uvec4( 0u );
176 | vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );
177 | vec3 barycoord = vec3( 0.0 );
178 | float side = 1.0;
179 | float dist = 0.0;
180 | bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist );
181 | vec3 hitPos = rayOrigin + rayDirection * max(dist - 0.001, 0.0);
182 | // faceNormal *= side;
183 | vec3 tempDir = refract(rayDirection, faceNormal, ior);
184 | if (length(tempDir) != 0.0) {
185 | rayDirection = tempDir;
186 | break;
187 | }
188 | rayDirection = reflect(rayDirection, faceNormal);
189 | rayOrigin = hitPos + rayDirection * 0.01;
190 | }
191 | rayDirection = normalize((modelMatrix * vec4(rayDirection, 0.0)).xyz);
192 | return rayDirection;
193 | }
194 | void main() {
195 | mat4 modelMatrixInverse = inverse(modelMatrix);
196 | vec2 uv = gl_FragCoord.xy / resolution;
197 | vec3 directionCamPerfect = (projectionMatrixInv * vec4(uv * 2.0 - 1.0, 0.0, 1.0)).xyz;
198 | directionCamPerfect = (viewMatrixInv * vec4(directionCamPerfect, 0.0)).xyz;
199 | directionCamPerfect = normalize(directionCamPerfect);
200 | vec3 normal = vNormal;
201 | vec3 rayOrigin = cameraPosition;
202 | vec3 rayDirection = normalize(vWorldPosition - cameraPosition);
203 | vec3 finalColor;
204 | if (chromaticAberration) {
205 | vec3 rayDirectionR = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior * (1.0 - aberrationStrength), 1.0), modelMatrixInverse);
206 | vec3 rayDirectionG = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior, 1.0), modelMatrixInverse);
207 | vec3 rayDirectionB = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior * (1.0 + aberrationStrength), 1.0), modelMatrixInverse);
208 | float finalColorR = textureGrad(envMap, rayDirectionR, dFdx(correctMips ? directionCamPerfect: rayDirection), dFdy(correctMips ? directionCamPerfect: rayDirection)).r;
209 | float finalColorG = textureGrad(envMap, rayDirectionG, dFdx(correctMips ? directionCamPerfect: rayDirection), dFdy(correctMips ? directionCamPerfect: rayDirection)).g;
210 | float finalColorB = textureGrad(envMap, rayDirectionB, dFdx(correctMips ? directionCamPerfect: rayDirection), dFdy(correctMips ? directionCamPerfect: rayDirection)).b;
211 | finalColor = vec3(finalColorR, finalColorG, finalColorB) * color;
212 | } else {
213 | rayDirection = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior, 1.0), modelMatrixInverse);
214 | finalColor = textureGrad(envMap, rayDirection, dFdx(correctMips ? directionCamPerfect: rayDirection), dFdy(correctMips ? directionCamPerfect: rayDirection)).rgb;
215 | finalColor *= color;
216 | }
217 | gl_FragColor = vec4(vec3(finalColor), 1.0);
218 | }
219 | `
220 | }));
221 | diamond.material.uniforms.bvh.value.updateFrom(collider.boundsTree);
222 | diamond.castShadow = true;
223 | diamond.receiveShadow = true;
224 | return diamond;
225 | }
226 | /*const gemGeo = new THREE.BufferGeometry();
227 | const baseX = 1;
228 | const baseY = 1;
229 | const height = 5;
230 | const heightTop = 3;
231 | const scale = 1.5;
232 | const positions = [];
233 | positions.push(baseX / 2, baseY / 2, 0);
234 | positions.push(baseX / 2, -baseY / 2, 0);
235 | positions.push(-baseX / 2, -baseY / 2, 0);
236 | positions.push(-baseX / 2, -baseY / 2, 0);
237 | positions.push(-baseX / 2, baseY / 2, 0);
238 | positions.push(baseX / 2, baseY / 2, 0);
239 |
240 | positions.push(baseX / 2 * scale, -baseY / 2 * scale, height);
241 | positions.push(-baseX / 2 * scale, -baseY / 2 * scale, height);
242 | positions.push(-baseX / 2, -baseY / 2, 0);
243 | positions.push(-baseX / 2, -baseY / 2, 0);
244 | positions.push(baseX / 2, -baseY / 2, 0);
245 | positions.push(baseX / 2 * scale, -baseY / 2 * scale, height);
246 |
247 | positions.push(baseX / 2 * scale, baseY / 2 * scale, height);
248 | positions.push(baseX / 2 * scale, -baseY / 2 * scale, height);
249 | positions.push(baseX / 2, -baseY / 2, 0);
250 | positions.push(baseX / 2, -baseY / 2, 0);
251 | positions.push(baseX / 2, baseY / 2, 0);
252 | positions.push(baseX / 2 * scale, baseY / 2 * scale, height);
253 |
254 | positions.push(-baseX / 2 * scale, baseY / 2 * scale, height);
255 | positions.push(baseX / 2 * scale, baseY / 2 * scale, height);
256 | positions.push(baseX / 2, baseY / 2, 0);
257 | positions.push(baseX / 2, baseY / 2, 0);
258 | positions.push(-baseX / 2, baseY / 2, 0);
259 | positions.push(-baseX / 2 * scale, baseY / 2 * scale, height);
260 |
261 | positions.push(-baseX / 2 * scale, -baseY / 2 * scale, height);
262 | positions.push(-baseX / 2 * scale, baseY / 2 * scale, height);
263 | positions.push(-baseX / 2, baseY / 2, 0);
264 | positions.push(-baseX / 2, baseY / 2, 0);
265 | positions.push(-baseX / 2, -baseY / 2, 0);
266 | positions.push(-baseX / 2 * scale, -baseY / 2 * scale, height);
267 |
268 | positions.push(-baseX / 2 * scale, -baseY / 2 * scale, height);
269 | positions.push(baseX / 2 * scale, -baseY / 2 * scale, height);
270 | positions.push(0, 0, height + heightTop);
271 | positions.push(baseX / 2 * scale, -baseY / 2 * scale, height);
272 | positions.push(baseX / 2 * scale, baseY / 2 * scale, height);
273 | positions.push(0, 0, height + heightTop);
274 | positions.push(baseX / 2 * scale, baseY / 2 * scale, height);
275 | positions.push(-baseX / 2 * scale, baseY / 2 * scale, height);
276 | positions.push(0, 0, height + heightTop);
277 | positions.push(-baseX / 2 * scale, baseY / 2 * scale, height);
278 | positions.push(-baseX / 2 * scale, -baseY / 2 * scale, height);
279 | positions.push(0, 0, height + heightTop);
280 |
281 | gemGeo.setAttribute("position", new THREE.BufferAttribute(new Float32Array(positions), 3));
282 | gemGeo.computeVertexNormals();
283 | //gemGeo.scale(10, 10, 10);
284 | //gemGeo.rotateX(-Math.PI / 2);
285 |
286 | //const gem
287 | for (let x = 0; x < 5; x++) {
288 | for (let y = 0; y < 5; y++) {
289 | const clusterColor = new THREE.Vector3(Math.random(), Math.random(), Math.random());
290 | for (let i = 0; i < 10; i++) {
291 | const newGeo = gemGeo.clone();
292 | newGeo.scale(1.0 + Math.random(), 1.0 + Math.random(), 1.0 + Math.random());
293 | newGeo.rotateX(-Math.PI / 2 * (0.85 + 0.3 * Math.random()));
294 | newGeo.rotateZ((2.5 / 1.5) * (Math.random() - 0.5));
295 | newGeo.rotateY((3.0 / 1.5) * (Math.random() - 0.5));
296 | newGeo.translate(-32 + x * 16, 0, -32 + y * 16);
297 | const diamond = makeDiamond(newGeo, {
298 | color: clusterColor.add(new THREE.Vector3(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).multiplyScalar(0.25)),
299 | });
300 | scene.add(diamond);
301 | }
302 | }
303 | }*/
304 | const diamond = makeDiamond(diamondGeo);
305 | scene.add(diamond);
306 | // Build postprocessing stack
307 | // Render Targets
308 | const defaultTexture = new THREE.WebGLRenderTarget(clientWidth, clientHeight, {
309 | minFilter: THREE.LinearFilter,
310 | magFilter: THREE.NearestFilter
311 | });
312 | defaultTexture.depthTexture = new THREE.DepthTexture(clientWidth, clientHeight, THREE.FloatType);
313 | // Post Effects
314 | const composer = new EffectComposer(renderer);
315 | const smaaPass = new SMAAPass(clientWidth, clientHeight);
316 | const effectPass = new ShaderPass(EffectShader);
317 | composer.addPass(effectPass);
318 | composer.addPass(new ShaderPass(GammaCorrectionShader));
319 | composer.addPass(smaaPass);
320 | const effectController = {
321 | bounces: 3.0,
322 | ior: 2.4,
323 | correctMips: true,
324 | chromaticAberration: true,
325 | aberrationStrength: 0.01
326 | };
327 | const gui = new GUI();
328 | gui.add(effectController, "bounces", 1.0, 10.0, 1.0).name("Bounces");
329 | gui.add(effectController, "ior", 1.0, 5.0, 0.01).name("IOR");
330 | gui.add(effectController, "correctMips");
331 | gui.add(effectController, "chromaticAberration");
332 | gui.add(effectController, "aberrationStrength", 0.00, 1.0, 0.0001).name("Aberration Strength");
333 |
334 | function animate() {
335 | diamond.material.uniforms.bounces.value = effectController.bounces;
336 | diamond.material.uniforms.ior.value = effectController.ior;
337 | diamond.material.uniforms.correctMips.value = effectController.correctMips;
338 | diamond.material.uniforms.chromaticAberration.value = effectController.chromaticAberration;
339 | diamond.material.uniforms.aberrationStrength.value = effectController.aberrationStrength;
340 | diamond.rotation.y += 0.01;
341 | diamond.updateMatrix();
342 | diamond.updateMatrixWorld();
343 | renderer.setRenderTarget(defaultTexture);
344 | renderer.clear();
345 | renderer.render(scene, camera);
346 | effectPass.uniforms["sceneDiffuse"].value = defaultTexture.texture;
347 | composer.render();
348 | controls.update();
349 | stats.update();
350 | requestAnimationFrame(animate);
351 | }
352 | requestAnimationFrame(animate);
353 | }
354 | main();
--------------------------------------------------------------------------------
/skybox/Box_Back.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/N8python/diamonds/69b30cc5586195461f47e0b25ccf14578b292cc0/skybox/Box_Back.bmp
--------------------------------------------------------------------------------
/skybox/Box_Bottom.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/N8python/diamonds/69b30cc5586195461f47e0b25ccf14578b292cc0/skybox/Box_Bottom.bmp
--------------------------------------------------------------------------------
/skybox/Box_Front.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/N8python/diamonds/69b30cc5586195461f47e0b25ccf14578b292cc0/skybox/Box_Front.bmp
--------------------------------------------------------------------------------
/skybox/Box_Left.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/N8python/diamonds/69b30cc5586195461f47e0b25ccf14578b292cc0/skybox/Box_Left.bmp
--------------------------------------------------------------------------------
/skybox/Box_Right.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/N8python/diamonds/69b30cc5586195461f47e0b25ccf14578b292cc0/skybox/Box_Right.bmp
--------------------------------------------------------------------------------
/skybox/Box_Top.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/N8python/diamonds/69b30cc5586195461f47e0b25ccf14578b292cc0/skybox/Box_Top.bmp
--------------------------------------------------------------------------------
/stats.js:
--------------------------------------------------------------------------------
1 | var Stats = function() {
2 |
3 | var mode = 0;
4 |
5 | var container = document.createElement('div');
6 | container.style.cssText = 'position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000';
7 | container.addEventListener('click', function(event) {
8 |
9 | event.preventDefault();
10 | showPanel(++mode % container.children.length);
11 |
12 | }, false);
13 |
14 | //
15 |
16 | function addPanel(panel) {
17 |
18 | container.appendChild(panel.dom);
19 | return panel;
20 |
21 | }
22 |
23 | function showPanel(id) {
24 |
25 | for (var i = 0; i < container.children.length; i++) {
26 |
27 | container.children[i].style.display = i === id ? 'block' : 'none';
28 |
29 | }
30 |
31 | mode = id;
32 |
33 | }
34 |
35 | //
36 |
37 | var beginTime = (performance || Date).now(),
38 | prevTime = beginTime,
39 | frames = 0;
40 |
41 | var fpsPanel = addPanel(new Stats.Panel('FPS', '#0ff', '#002'));
42 | var msPanel = addPanel(new Stats.Panel('MS', '#0f0', '#020'));
43 |
44 | if (self.performance && self.performance.memory) {
45 |
46 | var memPanel = addPanel(new Stats.Panel('MB', '#f08', '#201'));
47 |
48 | }
49 |
50 | showPanel(0);
51 |
52 | return {
53 |
54 | REVISION: 16,
55 |
56 | dom: container,
57 |
58 | addPanel: addPanel,
59 | showPanel: showPanel,
60 |
61 | begin: function() {
62 |
63 | beginTime = (performance || Date).now();
64 |
65 | },
66 |
67 | end: function() {
68 |
69 | frames++;
70 |
71 | var time = (performance || Date).now();
72 |
73 | msPanel.update(time - beginTime, 200);
74 |
75 | if (time >= prevTime + 1000) {
76 |
77 | fpsPanel.update((frames * 1000) / (time - prevTime), 100);
78 |
79 | prevTime = time;
80 | frames = 0;
81 |
82 | if (memPanel) {
83 |
84 | var memory = performance.memory;
85 | memPanel.update(memory.usedJSHeapSize / 1048576, memory.jsHeapSizeLimit / 1048576);
86 |
87 | }
88 |
89 | }
90 |
91 | return time;
92 |
93 | },
94 |
95 | update: function() {
96 |
97 | beginTime = this.end();
98 |
99 | },
100 |
101 | // Backwards Compatibility
102 |
103 | domElement: container,
104 | setMode: showPanel
105 |
106 | };
107 |
108 | };
109 |
110 | Stats.Panel = function(name, fg, bg) {
111 |
112 | var min = Infinity,
113 | max = 0,
114 | round = Math.round;
115 | var PR = round(window.devicePixelRatio || 1);
116 |
117 | var WIDTH = 80 * PR,
118 | HEIGHT = 48 * PR,
119 | TEXT_X = 3 * PR,
120 | TEXT_Y = 2 * PR,
121 | GRAPH_X = 3 * PR,
122 | GRAPH_Y = 15 * PR,
123 | GRAPH_WIDTH = 74 * PR,
124 | GRAPH_HEIGHT = 30 * PR;
125 |
126 | var canvas = document.createElement('canvas');
127 | canvas.width = WIDTH;
128 | canvas.height = HEIGHT;
129 | canvas.style.cssText = 'width:80px;height:48px';
130 |
131 | var context = canvas.getContext('2d');
132 | context.font = 'bold ' + (9 * PR) + 'px Helvetica,Arial,sans-serif';
133 | context.textBaseline = 'top';
134 |
135 | context.fillStyle = bg;
136 | context.fillRect(0, 0, WIDTH, HEIGHT);
137 |
138 | context.fillStyle = fg;
139 | context.fillText(name, TEXT_X, TEXT_Y);
140 | context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);
141 |
142 | context.fillStyle = bg;
143 | context.globalAlpha = 0.9;
144 | context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);
145 |
146 | return {
147 |
148 | dom: canvas,
149 |
150 | update: function(value, maxValue) {
151 |
152 | min = Math.min(min, value);
153 | max = Math.max(max, value);
154 |
155 | context.fillStyle = bg;
156 | context.globalAlpha = 1;
157 | context.fillRect(0, 0, WIDTH, GRAPH_Y);
158 | context.fillStyle = fg;
159 | context.fillText(round(value) + ' ' + name + ' (' + round(min) + '-' + round(max) + ')', TEXT_X, TEXT_Y);
160 |
161 | context.drawImage(canvas, GRAPH_X + PR, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT, GRAPH_X, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT);
162 |
163 | context.fillRect(GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, GRAPH_HEIGHT);
164 |
165 | context.fillStyle = bg;
166 | context.globalAlpha = 0.9;
167 | context.fillRect(GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, round((1 - (value / maxValue)) * GRAPH_HEIGHT));
168 |
169 | }
170 |
171 | };
172 |
173 | };
174 | export { Stats };
--------------------------------------------------------------------------------