@@ -14,11 +14,86 @@ var OrbitControls = require("../examples/controls/OrbitControls.js").OrbitContro
14
14
var BLACK = new THREE . Color ( 'black' ) ;
15
15
16
16
17
+ // Set camera near and far planes close to sphere with given center
18
+ // and radius, assuming the camera is already oriented to look at this
19
+ // sphere.
20
+ function shrinkFrustumPlanes ( camera , center , radius , distOffset = 0.1 ) {
21
+ // distOffset = 0.1 --> 10% of radius
22
+
23
+ // Find distance from camera to edges of sphere
24
+ const dist = camera . position . distanceTo ( center ) ;
25
+ const nearEdge = dist - radius ;
26
+ const farEdge = dist + radius ;
27
+
28
+ // Set near/far sufficiently close to edges of sphere
29
+ camera . near = ( 1 - distOffset ) * nearEdge ,
30
+ camera . far = ( 1 + distOffset ) * farEdge ;
31
+
32
+ // Bound near plane away from zero
33
+ camera . near = Math . max ( camera . near , 0.01 * radius ) ;
34
+ }
35
+
36
+ // Set camera near and far planes with some headroom around sphere
37
+ // with given center and radius, assuming the camera is already
38
+ // oriented to look at this sphere.
39
+ function safeFrustumPlanes ( camera , center , radius , allowZoom = 20 ) {
40
+ // Find distance from camera to edges of sphere
41
+ const dist = camera . position . distanceTo ( center ) ;
42
+ const nearEdge = dist - radius ;
43
+ const farEdge = dist + radius ;
44
+
45
+ // Set near/far sufficiently far from edge of sphere to allow some zooming
46
+ camera . near = ( 1 / allowZoom ) * nearEdge ;
47
+ camera . far = allowZoom * farEdge ;
48
+
49
+ // Bound near plane away from zero
50
+ camera . near = Math . max ( camera . near , 0.001 * radius ) ;
51
+ }
52
+
53
+ function lookAtSphere ( camera , center , radius ) {
54
+ if ( ! camera . isPerspectiveCamera ) {
55
+ console . error ( "Expecting a perspective camera." ) ;
56
+ }
57
+
58
+ // Compute distance based on FOV
59
+ const radScale = 1.5 ; // Include this much more than the sphere
60
+ const distance = ( radScale * radius ) / Math . tan ( 0.5 * camera . fov * Math . PI / 180 ) ;
61
+
62
+ // Place camera such that the model is in the -z direction from the camera
63
+ camera . position . setX ( center . x ) ;
64
+ camera . position . setY ( center . y ) ;
65
+ camera . position . setZ ( center . z + distance ) ;
66
+
67
+ // Look at scene center
68
+ camera . lookAt ( center . clone ( ) ) ;
69
+
70
+ // Set near and far planes to include sphere with a narrow margin
71
+ //shrinkFrustumPlanes(camera, center, radius);
72
+
73
+ // Set near and far planes to include sphere with a wide margin for zooming
74
+ safeFrustumPlanes ( camera , center , radius ) ;
75
+
76
+ // Update matrix
77
+ camera . updateProjectionMatrix ( ) ;
78
+ }
79
+
80
+ // TODO: Make this available as a general utility somewhere?
81
+ function computeSceneBoundingSphere ( scene ) {
82
+ // FIXME: The Box3.setFromObject implementation is not great,
83
+ // replace with something that reuses bounding box computations
84
+ // of the underlying objects
85
+ const box = new THREE . Box3 ( ) ;
86
+ box . setFromObject ( scene ) ;
87
+ return box . getBoundingSphere ( ) ;
88
+ }
89
+
90
+
17
91
var PreviewView = RenderableView . extend ( {
18
92
19
93
initialize : function ( ) {
20
94
RenderableView . prototype . initialize . apply ( this , arguments ) ;
21
95
96
+ this . _resetCameraNeeded = true ;
22
97
this . _rebuildNeeded = true ;
23
98
24
99
} ,
@@ -41,6 +116,10 @@ var PreviewView = RenderableView.extend({
41
116
} ,
42
117
43
118
onChildChange : function ( ) {
119
+ // Enabling this line will reset the camera
120
+ // when any changes are made to the child
121
+ //this._resetCameraNeeded = true;
122
+
44
123
this . _rebuildNeeded = true ;
45
124
} ,
46
125
@@ -49,8 +128,6 @@ var PreviewView = RenderableView.extend({
49
128
var obj = this . model . get ( 'child' ) . obj ;
50
129
51
130
this . clearScene ( ) ;
52
- // cameras need to be added to scene
53
- this . scene . add ( this . camera ) ;
54
131
55
132
if ( obj . isObject3D ) {
56
133
@@ -73,7 +150,7 @@ var PreviewView = RenderableView.extend({
73
150
shading : THREE . FlatShading ,
74
151
} ) ;
75
152
} else {
76
- material = new THREE . MeshStandardMaterial ( {
153
+ material = new THREE . MeshLambertMaterial ( {
77
154
color : '#ffffff' ,
78
155
} ) ;
79
156
}
@@ -109,13 +186,44 @@ var PreviewView = RenderableView.extend({
109
186
var mesh = new THREE . Mesh ( geometry , mat ) ;
110
187
this . scene . add ( mesh ) ;
111
188
189
+ } else {
190
+
191
+ console . log ( "Unexpected object in preview, scene will be empty:" , obj ) ;
192
+
193
+ }
194
+
195
+ // Reset camera initially and on later requests
196
+ if ( this . _resetCameraNeeded ) {
197
+ this . resetCamera ( ) ; // Depends on this.scene to be correctly set up
198
+ this . _resetCameraNeeded = false ;
112
199
}
113
200
201
+ // Cameras need to be added to scene
202
+ this . scene . add ( this . camera ) ;
203
+
114
204
// Clear at end to ensure that any changes to obj does not
115
205
// cause infinite rebuild chain.
116
206
this . _rebuildNeeded = false ;
117
207
} ,
118
208
209
+ resetCamera : function ( ) {
210
+ // Compute bounding sphere for entire scene
211
+ const sphere = computeSceneBoundingSphere ( this . scene ) ;
212
+
213
+ // Update camera to include bounding sphere
214
+ lookAtSphere ( this . camera , sphere . center , sphere . radius ) ;
215
+
216
+ // Update controls with new target
217
+ const control = this . controls [ 0 ] ;
218
+ control . target . copy ( sphere . center ) ;
219
+ control . target0 . copy ( sphere . center ) ;
220
+ control . update ( ) ;
221
+
222
+ // Position light up to the left and behind camera
223
+ const dist = 2.5 * ( this . camera . position . z - sphere . center . z ) ;
224
+ this . pointLight . position . set ( - dist , dist , dist ) ;
225
+ } ,
226
+
119
227
clearScene : function ( ) {
120
228
// this.controls.reset();
121
229
this . scene . remove . apply ( this . scene , this . scene . children . slice ( ) ) ;
@@ -131,9 +239,10 @@ var PreviewView = RenderableView.extend({
131
239
} ,
132
240
133
241
lazyRendererSetup : function ( ) {
134
- this . camera = new THREE . PerspectiveCamera ( 60 , 1.0 ) ; // aspect is updated by this.updateSize()
135
- this . camera . position . set ( - 40 , 40 , 40 ) ;
136
- this . camera . lookAt ( new THREE . Vector3 ( 0 , 0 , 0 ) ) ;
242
+ this . camera = new THREE . PerspectiveCamera ( 60 , 1.0 ) ;
243
+ // aspect is updated by this.updateSize()
244
+ // position and lookat target is updated to fit scene
245
+ // by this.resetCamera() via constructScene()
137
246
138
247
// Update aspect ratio of camera:
139
248
this . updateSize ( ) ;
@@ -144,9 +253,7 @@ var PreviewView = RenderableView.extend({
144
253
this . scene . background = BLACK ;
145
254
146
255
// Lights
147
- this . pointLight = new THREE . PointLight ( '#ffffff' , 1 , 0 ) ;
148
- this . pointLight . position . set ( - 100 , 100 , 100 ) ;
149
- this . pointLight . lookAt ( new THREE . Vector3 ( 0 , 0 , 0 ) ) ;
256
+ this . pointLight = new THREE . PointLight ( '#ffffff' , 1 , 0 , 0 ) ;
150
257
this . ambLight = new THREE . AmbientLight ( '#ffffff' , 0.5 ) ;
151
258
this . camera . add ( this . ambLight ) ;
152
259
this . camera . add ( this . pointLight ) ;
0 commit comments