1+ // scene/demo-specific variables go here
2+ let initialBoxGeometry ;
3+ let boxGeometry , boxMaterial , boxMesh ;
4+
5+ let torus ;
6+ let torusRotationAngle = 0 ;
7+ let torusScale = 0 ;
8+ let torusHeight = 0 ;
9+ let torusHoleSize = 0 ;
10+ let scaleFactor = 0 ;
11+
12+ let torus_ScaleObject , torus_ScaleController ;
13+ let needChangeTorusScale = false ;
14+ let torus_HeightObject , torus_HeightController ;
15+ let needChangeTorusHeight = false ;
16+ let torus_HoleSizeObject , torus_HoleSizeController ;
17+ let needChangeTorusHoleSize = false ;
18+ let torus_HoleSizeFineObject , torus_HoleSizeFineController ;
19+ let needChangeTorusHoleSizeFine = false ;
20+ let showTorusAABB_ToggleController , showTorusAABB_ToggleObject ;
21+ let needChangeShowTorusAABB = false ;
22+
23+ let material_TypeObject , material_TypeController ;
24+ let needChangeMaterialType = false ;
25+ let matType = 0 ;
26+ let material_ColorObject , material_ColorController ;
27+ let needChangeMaterialColor = false ;
28+ let matColor ;
29+ let rotation_Folder ;
30+ let transform_RotationXController , transform_RotationXObject ;
31+ let transform_RotationYController , transform_RotationYObject ;
32+ let transform_RotationZController , transform_RotationZObject ;
33+ let needChangeRotation = false ;
34+
35+
36+ function init_GUI ( )
37+ {
38+ torus_ScaleObject = { torusScale : 7 } ;
39+ torus_HeightObject = { torusHeight : 0.5 } ;
40+ torus_HoleSizeFineObject = { torusHoleSizeFine : 0.01 } ;
41+ torus_HoleSizeObject = { torusHoleSize : 0.01 } ;
42+ material_TypeObject = { torus_Material : 'Diffuse' } ;
43+ material_ColorObject = { torus_Color : [ 1 , 1 , 1 ] } ;
44+ showTorusAABB_ToggleObject = { show_torusAABB : false }
45+ transform_RotationXObject = { rotationX : 0 } ;
46+ transform_RotationYObject = { rotationY : 0 } ;
47+ transform_RotationZObject = { rotationZ : 0 } ;
48+
49+ function handleTorusScaleChange ( ) { needChangeTorusScale = true ; }
50+ function handleTorusHeightChange ( ) { needChangeTorusHeight = true ; }
51+ function handleTorusHoleSizeFineChange ( ) { needChangeTorusHoleSizeFine = true ; }
52+ function handleTorusHoleSizeChange ( ) { needChangeTorusHoleSize = true ; }
53+ function handleMaterialTypeChange ( ) { needChangeMaterialType = true ; }
54+ function handleMaterialColorChange ( ) { needChangeMaterialColor = true ; }
55+ function handleShowTorusAABBChange ( ) { needChangeShowTorusAABB = true ; }
56+ function handleRotationChange ( ) { needChangeRotation = true ; }
57+
58+ torus_ScaleController = gui . add ( torus_ScaleObject , 'torusScale' , 1 , 30 , 0.1 ) . onChange ( handleTorusScaleChange ) ;
59+
60+ rotation_Folder = gui . addFolder ( 'Rotation' ) ;
61+ transform_RotationXController = rotation_Folder . add ( transform_RotationXObject , 'rotationX' , 0 , 359 , 1 ) . onChange ( handleRotationChange ) ;
62+ transform_RotationYController = rotation_Folder . add ( transform_RotationYObject , 'rotationY' , 0 , 359 , 1 ) . onChange ( handleRotationChange ) ;
63+ transform_RotationZController = rotation_Folder . add ( transform_RotationZObject , 'rotationZ' , 0 , 359 , 1 ) . onChange ( handleRotationChange ) ;
64+
65+ torus_HeightController = gui . add ( torus_HeightObject , 'torusHeight' , 0.005 , 0.7 , 0.01 ) . onChange ( handleTorusHeightChange ) ;
66+ torus_HoleSizeFineController = gui . add ( torus_HoleSizeFineObject , 'torusHoleSizeFine' , 0 , 0.1 , 0.0001 ) . onChange ( handleTorusHoleSizeFineChange ) ;
67+ torus_HoleSizeController = gui . add ( torus_HoleSizeObject , 'torusHoleSize' , 0 , 0.99 , 0.001 ) . onChange ( handleTorusHoleSizeChange ) ;
68+ material_TypeController = gui . add ( material_TypeObject , 'torus_Material' , [ 'Diffuse' ,
69+ 'Metal' , 'ClearCoat Diffuse' , 'Transparent Refractive' ] ) . onChange ( handleMaterialTypeChange ) ;
70+ material_ColorController = gui . addColor ( material_ColorObject , 'torus_Color' ) . onChange ( handleMaterialColorChange ) ;
71+ showTorusAABB_ToggleController = gui . add ( showTorusAABB_ToggleObject , 'show_torusAABB' , false ) . onChange ( handleShowTorusAABBChange ) ;
72+
73+ handleTorusScaleChange ( ) ;
74+ handleTorusHeightChange ( ) ;
75+ handleTorusHoleSizeChange ( ) ;
76+ handleTorusHoleSizeFineChange ( ) ;
77+ handleMaterialTypeChange ( ) ;
78+ handleMaterialColorChange ( ) ;
79+ handleShowTorusAABBChange ( ) ;
80+ handleRotationChange ( ) ;
81+
82+ } // end function init_GUI()
83+
84+
85+
86+ // called automatically from within initTHREEjs() function (located in InitCommon.js file)
87+ function initSceneData ( )
88+ {
89+ demoFragmentShaderFileName = 'Cheap_Torus_Fragment.glsl' ;
90+
91+ // scene/demo-specific three.js objects setup goes here
92+ sceneIsDynamic = false ;
93+
94+ edgeSharpenSpeed = 0.1 ;
95+
96+ cameraFlightSpeed = 50 ;
97+
98+ // pixelRatio is resolution - range: 0.5(half resolution) to 1.0(full resolution)
99+ pixelRatio = mouseControl ? 0.75 : 0.75 ;
100+
101+ EPS_intersect = 0.001 ;
102+
103+ // set camera's field of view
104+ worldCamera . fov = 60 ;
105+ focusDistance = 100.0 ;
106+ apertureChangeSpeed = 10 ;
107+
108+ // position and orient camera
109+ cameraControlsObject . position . set ( 0 , 20 , 30 ) ;
110+ ///cameraControlsYawObject.rotation.y = 0.0;
111+ // look slightly up or down
112+ cameraControlsPitchObject . rotation . x = - 0.58 ;
113+
114+
115+ torus = new THREE . Object3D ( ) ;
116+ torus . position . set ( 0 , 0 , 0 ) ;
117+
118+ // even though this will eventually produce/render a box, instead of using THREE.BoxGeometry(2,2,2) (unit radius of 1 in all axes),
119+ // I found that using THREE.CylinderGeometry produces a tighter-fitting AABB when the torus shape is rotated
120+ initialBoxGeometry = new THREE . CylinderGeometry ( ) ; // use Cylinder as a starting point instead of Box
121+ boxGeometry = new THREE . CylinderGeometry ( ) ; // use Cylinder as a starting point instead of Box
122+ boxMaterial = new THREE . MeshBasicMaterial ( ) ;
123+ boxMesh = new THREE . Mesh ( boxGeometry , boxMaterial ) ;
124+
125+
126+ // scene/demo-specific uniforms go here
127+ pathTracingUniforms . uTorus_InvMatrix = { value : new THREE . Matrix4 ( ) } ;
128+ pathTracingUniforms . uBoxMinCorner = { value : new THREE . Vector3 ( ) } ;
129+ pathTracingUniforms . uBoxMaxCorner = { value : new THREE . Vector3 ( ) } ;
130+ pathTracingUniforms . uTorusHoleSize = { value : 0.01 } ;
131+ pathTracingUniforms . uMaterialType = { value : 0 } ;
132+ pathTracingUniforms . uMaterialColor = { value : new THREE . Color ( 1.0 , 0.0 , 1.0 ) } ;
133+ pathTracingUniforms . uShowTorusAABB = { type : "b1" , value : false } ;
134+
135+ init_GUI ( ) ;
136+
137+ } // end function initSceneData()
138+
139+
140+
141+
142+
143+ // called automatically from within the animate() function (located in InitCommon.js file)
144+ function updateVariablesAndUniforms ( )
145+ {
146+
147+ if ( needChangeMaterialType )
148+ {
149+ matType = material_TypeController . getValue ( ) ;
150+
151+ if ( matType == 'Diffuse' )
152+ {
153+ pathTracingUniforms . uMaterialType . value = 1 ;
154+ pathTracingUniforms . uMaterialColor . value . setRGB ( 0.01 , 0.6 , 0.6 ) ;
155+ }
156+ else if ( matType == 'Metal' )
157+ {
158+ pathTracingUniforms . uMaterialType . value = 3 ;
159+ //pathTracingUniforms.uMaterialColor.value.setRGB(1.000000, 0.765557, 0.336057);
160+ pathTracingUniforms . uMaterialColor . value . setRGB ( 0.955008 , 0.637427 , 0.538163 ) ;
161+ }
162+ else if ( matType == 'ClearCoat Diffuse' )
163+ {
164+ pathTracingUniforms . uMaterialType . value = 4 ;
165+ pathTracingUniforms . uMaterialColor . value . setRGB ( 0.3 , 0.01 , 0.8 ) ;
166+ }
167+ else if ( matType == 'Transparent Refractive' )
168+ {
169+ pathTracingUniforms . uMaterialType . value = 2 ;
170+ pathTracingUniforms . uMaterialColor . value . setRGB ( 0.1 , 1.0 , 0.6 ) ;
171+ }
172+
173+ material_ColorController . setValue ( [ pathTracingUniforms . uMaterialColor . value . r ,
174+ pathTracingUniforms . uMaterialColor . value . g ,
175+ pathTracingUniforms . uMaterialColor . value . b ] ) ;
176+
177+ cameraIsMoving = true ;
178+ needChangeMaterialType = false ;
179+ }
180+
181+ if ( needChangeMaterialColor )
182+ {
183+ matColor = material_ColorController . getValue ( ) ;
184+ pathTracingUniforms . uMaterialColor . value . setRGB ( matColor [ 0 ] , matColor [ 1 ] , matColor [ 2 ] ) ;
185+
186+ cameraIsMoving = true ;
187+ needChangeMaterialColor = false ;
188+ }
189+
190+ if ( needChangeRotation )
191+ {
192+ torus . rotation . set ( THREE . MathUtils . degToRad ( transform_RotationXController . getValue ( ) ) ,
193+ THREE . MathUtils . degToRad ( transform_RotationYController . getValue ( ) ) ,
194+ THREE . MathUtils . degToRad ( transform_RotationZController . getValue ( ) ) ) ;
195+
196+ torus . updateMatrixWorld ( true ) ;
197+ pathTracingUniforms . uTorus_InvMatrix . value . copy ( torus . matrixWorld ) . invert ( ) ;
198+
199+ boxMesh . rotation . copy ( torus . rotation ) ;
200+ boxMesh . updateMatrixWorld ( true ) ;
201+ boxMesh . geometry . copy ( initialBoxGeometry ) ;
202+ boxMesh . geometry . applyMatrix4 ( boxMesh . matrixWorld ) ;
203+ boxMesh . geometry . computeBoundingBox ( ) ;
204+ pathTracingUniforms . uBoxMinCorner . value . copy ( boxMesh . geometry . boundingBox . min ) ;
205+ pathTracingUniforms . uBoxMaxCorner . value . copy ( boxMesh . geometry . boundingBox . max ) ;
206+
207+ cameraIsMoving = true ;
208+ needChangeRotation = false ;
209+ }
210+
211+ if ( needChangeTorusScale || needChangeTorusHeight || needChangeTorusHoleSize || needChangeTorusHoleSizeFine )
212+ {
213+ if ( needChangeTorusHoleSizeFine )
214+ torus_HoleSizeController . setValue ( torus_HoleSizeFineController . getValue ( ) ) ;
215+
216+ if ( needChangeTorusHoleSize && torus_HoleSizeController . getValue ( ) <= 0.1 )
217+ torus_HoleSizeFineController . setValue ( torus_HoleSizeController . getValue ( ) ) ;
218+
219+ torusScale = torus_ScaleController . getValue ( ) ;
220+ torusHeight = torus_HeightController . getValue ( ) ;
221+ torusHoleSize = torus_HoleSizeController . getValue ( ) ;
222+
223+ if ( needChangeTorusHoleSize )
224+ {
225+ // note: I tried to be clever and come up with a function f(x) that hits the following points on the sort-of exponential-looking
226+ // curve which decreases the size of the torus height radius as a function of the torus hole getting bigger, but alas I failed.
227+ // Therefore, I did the next best thing and defined some points along that elbow-curve that I wanted to hit, and then did a
228+ // linear interpolation from point to point along the curve (kind of like moving a video game character/camera along a pre-defined
229+ // path). In the end though, 'torusHeight'(radius) is re-writable, if these points do not satisfy the torus shape you're after.
230+ if ( torusHoleSize < 0.01 ) torus_HeightController . setValue ( THREE . MathUtils . mapLinear ( torusHoleSize , 0.0 , 0.01 , 0.65 , 0.4 ) ) ;
231+ else if ( torusHoleSize < 0.03 ) torus_HeightController . setValue ( THREE . MathUtils . mapLinear ( torusHoleSize , 0.01 , 0.03 , 0.4 , 0.2 ) ) ;
232+ else if ( torusHoleSize < 0.05 ) torus_HeightController . setValue ( THREE . MathUtils . mapLinear ( torusHoleSize , 0.03 , 0.05 , 0.2 , 0.15 ) ) ;
233+ else if ( torusHoleSize < 0.1 ) torus_HeightController . setValue ( THREE . MathUtils . mapLinear ( torusHoleSize , 0.05 , 0.1 , 0.15 , 0.1 ) ) ;
234+ else if ( torusHoleSize < 0.2 ) torus_HeightController . setValue ( THREE . MathUtils . mapLinear ( torusHoleSize , 0.1 , 0.2 , 0.1 , 0.055 ) ) ;
235+ else if ( torusHoleSize < 0.3 ) torus_HeightController . setValue ( THREE . MathUtils . mapLinear ( torusHoleSize , 0.2 , 0.3 , 0.055 , 0.035 ) ) ;
236+ else if ( torusHoleSize < 0.4 ) torus_HeightController . setValue ( THREE . MathUtils . mapLinear ( torusHoleSize , 0.3 , 0.4 , 0.035 , 0.03 ) ) ;
237+ else if ( torusHoleSize < 0.5 ) torus_HeightController . setValue ( THREE . MathUtils . mapLinear ( torusHoleSize , 0.4 , 0.5 , 0.03 , 0.025 ) ) ;
238+ else if ( torusHoleSize < 0.6 ) torus_HeightController . setValue ( THREE . MathUtils . mapLinear ( torusHoleSize , 0.5 , 0.6 , 0.025 , 0.02 ) ) ;
239+ else if ( torusHoleSize < 0.8 ) torus_HeightController . setValue ( THREE . MathUtils . mapLinear ( torusHoleSize , 0.6 , 0.8 , 0.02 , 0.015 ) ) ;
240+ else if ( torusHoleSize < 1.01 ) torus_HeightController . setValue ( THREE . MathUtils . mapLinear ( torusHoleSize , 0.8 , 1.0 , 0.015 , 0.01 ) ) ;
241+
242+ torusHeight = torus_HeightController . getValue ( ) ;
243+ }
244+
245+
246+ //torus.rotation.set(0, 0, Math.PI * 0.5);
247+ scaleFactor = THREE . MathUtils . mapLinear ( torusHoleSize , 0 , 1 , 1 , 50 ) ;
248+ scaleFactor = 1 / Math . sqrt ( scaleFactor ) ;
249+ torus . scale . set ( torusScale * scaleFactor , torusScale * torusHeight , torusScale * scaleFactor ) ;
250+ torus . updateMatrixWorld ( true ) ;
251+ // the following multiplication (torusHoleSize * 100) is for the quadric shape definition of the hyperboloid inside the fragment shader
252+ pathTracingUniforms . uTorusHoleSize . value = torusHoleSize * 100 ;
253+ pathTracingUniforms . uTorus_InvMatrix . value . copy ( torus . matrixWorld ) . invert ( ) ;
254+
255+ boxMesh . scale . set ( torusScale * 1.45 , torusScale * torusHeight * 2 , torusScale * 1.45 ) ;
256+ boxMesh . updateMatrixWorld ( true ) ;
257+ boxMesh . geometry . copy ( initialBoxGeometry ) ;
258+ boxMesh . geometry . applyMatrix4 ( boxMesh . matrixWorld ) ;
259+ boxMesh . geometry . computeBoundingBox ( ) ;
260+ pathTracingUniforms . uBoxMinCorner . value . copy ( boxMesh . geometry . boundingBox . min ) ;
261+ pathTracingUniforms . uBoxMaxCorner . value . copy ( boxMesh . geometry . boundingBox . max ) ;
262+
263+
264+ cameraIsMoving = true ;
265+ needChangeTorusScale = false ;
266+ needChangeTorusHeight = false ;
267+ needChangeTorusHoleSize = false ;
268+ needChangeTorusHoleSizeFine = false ;
269+ } // end if (needChangeTorusScale || needChangeTorusHeight || needChangeTorusHoleSize || needChangeTorusHoleSizeFine)
270+
271+
272+ if ( needChangeShowTorusAABB )
273+ {
274+ pathTracingUniforms . uShowTorusAABB . value = showTorusAABB_ToggleController . getValue ( ) ;
275+ cameraIsMoving = true ;
276+ needChangeShowTorusAABB = false ;
277+ }
278+
279+ // torusRotationAngle += (0.4 * frameTime);
280+ // torusRotationAngle %= TWO_PI;
281+ // torus.rotation.set(0, torusRotationAngle, Math.PI * 0.1);
282+ // torus.updateMatrixWorld(true);
283+ // pathTracingUniforms.uTorus_InvMatrix.value.copy(torus.matrixWorld).invert();
284+
285+
286+ // INFO
287+ cameraInfoElement . innerHTML = "FOV: " + worldCamera . fov + " / Aperture: " + apertureSize . toFixed ( 2 ) + " / FocusDistance: " + focusDistance + "<br>" + "Samples: " + sampleCounter ;
288+
289+ } // end function updateVariablesAndUniforms()
290+
291+
292+
293+ init ( ) ; // init app and start animating
0 commit comments