1+ /**
2+ * Based on http://www.emagix.net/academic/mscs-project/item/camera-sync-with-css3-and-webgl-threejs
3+ * @author mrdoob / http://mrdoob.com/
4+ */
5+
6+ THREE . CSS3DObject = function ( element ) {
7+
8+ THREE . Object3D . call ( this ) ;
9+
10+ this . element = element ;
11+ this . element . style . position = 'absolute' ;
12+
13+ this . addEventListener ( 'removed' , function ( ) {
14+
15+ if ( this . element . parentNode !== null ) {
16+
17+ this . element . parentNode . removeChild ( this . element ) ;
18+
19+ }
20+
21+ } ) ;
22+
23+ } ;
24+
25+ THREE . CSS3DObject . prototype = Object . create ( THREE . Object3D . prototype ) ;
26+ THREE . CSS3DObject . prototype . constructor = THREE . CSS3DObject ;
27+
28+ THREE . CSS3DSprite = function ( element ) {
29+
30+ THREE . CSS3DObject . call ( this , element ) ;
31+
32+ } ;
33+
34+ THREE . CSS3DSprite . prototype = Object . create ( THREE . CSS3DObject . prototype ) ;
35+ THREE . CSS3DSprite . prototype . constructor = THREE . CSS3DSprite ;
36+
37+ //
38+
39+ THREE . CSS3DRenderer = function ( ) {
40+
41+ console . log ( 'THREE.CSS3DRenderer' , THREE . REVISION ) ;
42+
43+ var _width , _height ;
44+ var _widthHalf , _heightHalf ;
45+
46+ var matrix = new THREE . Matrix4 ( ) ;
47+
48+ var cache = {
49+ camera : { fov : 0 , style : '' } ,
50+ objects : { }
51+ } ;
52+
53+ var domElement = document . createElement ( 'div' ) ;
54+ domElement . style . overflow = 'hidden' ;
55+
56+ this . domElement = domElement ;
57+
58+ var cameraElement = document . createElement ( 'div' ) ;
59+
60+ cameraElement . style . WebkitTransformStyle = 'preserve-3d' ;
61+ cameraElement . style . MozTransformStyle = 'preserve-3d' ;
62+ cameraElement . style . transformStyle = 'preserve-3d' ;
63+
64+ domElement . appendChild ( cameraElement ) ;
65+
66+ var isIE = / T r i d e n t / i. test ( navigator . userAgent ) ;
67+
68+ this . getSize = function ( ) {
69+
70+ return {
71+ width : _width ,
72+ height : _height
73+ } ;
74+
75+ } ;
76+
77+ this . setSize = function ( width , height ) {
78+
79+ _width = width ;
80+ _height = height ;
81+ _widthHalf = _width / 2 ;
82+ _heightHalf = _height / 2 ;
83+
84+ domElement . style . width = width + 'px' ;
85+ domElement . style . height = height + 'px' ;
86+
87+ cameraElement . style . width = width + 'px' ;
88+ cameraElement . style . height = height + 'px' ;
89+
90+ } ;
91+
92+ function epsilon ( value ) {
93+
94+ return Math . abs ( value ) < 1e-10 ? 0 : value ;
95+
96+ }
97+
98+ function getCameraCSSMatrix ( matrix ) {
99+
100+ var elements = matrix . elements ;
101+
102+ return 'matrix3d(' +
103+ epsilon ( elements [ 0 ] ) + ',' +
104+ epsilon ( - elements [ 1 ] ) + ',' +
105+ epsilon ( elements [ 2 ] ) + ',' +
106+ epsilon ( elements [ 3 ] ) + ',' +
107+ epsilon ( elements [ 4 ] ) + ',' +
108+ epsilon ( - elements [ 5 ] ) + ',' +
109+ epsilon ( elements [ 6 ] ) + ',' +
110+ epsilon ( elements [ 7 ] ) + ',' +
111+ epsilon ( elements [ 8 ] ) + ',' +
112+ epsilon ( - elements [ 9 ] ) + ',' +
113+ epsilon ( elements [ 10 ] ) + ',' +
114+ epsilon ( elements [ 11 ] ) + ',' +
115+ epsilon ( elements [ 12 ] ) + ',' +
116+ epsilon ( - elements [ 13 ] ) + ',' +
117+ epsilon ( elements [ 14 ] ) + ',' +
118+ epsilon ( elements [ 15 ] ) +
119+ ')' ;
120+
121+ }
122+
123+ function getObjectCSSMatrix ( matrix , cameraCSSMatrix ) {
124+
125+ var elements = matrix . elements ;
126+ var matrix3d = 'matrix3d(' +
127+ epsilon ( elements [ 0 ] ) + ',' +
128+ epsilon ( elements [ 1 ] ) + ',' +
129+ epsilon ( elements [ 2 ] ) + ',' +
130+ epsilon ( elements [ 3 ] ) + ',' +
131+ epsilon ( - elements [ 4 ] ) + ',' +
132+ epsilon ( - elements [ 5 ] ) + ',' +
133+ epsilon ( - elements [ 6 ] ) + ',' +
134+ epsilon ( - elements [ 7 ] ) + ',' +
135+ epsilon ( elements [ 8 ] ) + ',' +
136+ epsilon ( elements [ 9 ] ) + ',' +
137+ epsilon ( elements [ 10 ] ) + ',' +
138+ epsilon ( elements [ 11 ] ) + ',' +
139+ epsilon ( elements [ 12 ] ) + ',' +
140+ epsilon ( elements [ 13 ] ) + ',' +
141+ epsilon ( elements [ 14 ] ) + ',' +
142+ epsilon ( elements [ 15 ] ) +
143+ ')' ;
144+
145+ if ( isIE ) {
146+
147+ return 'translate(-50%,-50%)' +
148+ 'translate(' + _widthHalf + 'px,' + _heightHalf + 'px)' +
149+ cameraCSSMatrix +
150+ matrix3d ;
151+
152+ }
153+
154+ return 'translate(-50%,-50%)' + matrix3d ;
155+
156+ }
157+
158+ function renderObject ( object , camera , cameraCSSMatrix ) {
159+
160+ if ( object instanceof THREE . CSS3DObject ) {
161+
162+ var style ;
163+
164+ if ( object instanceof THREE . CSS3DSprite ) {
165+
166+ // http://swiftcoder.wordpress.com/2008/11/25/constructing-a-billboard-matrix/
167+
168+ matrix . copy ( camera . matrixWorldInverse ) ;
169+ matrix . transpose ( ) ;
170+ matrix . copyPosition ( object . matrixWorld ) ;
171+ matrix . scale ( object . scale ) ;
172+
173+ matrix . elements [ 3 ] = 0 ;
174+ matrix . elements [ 7 ] = 0 ;
175+ matrix . elements [ 11 ] = 0 ;
176+ matrix . elements [ 15 ] = 1 ;
177+
178+ style = getObjectCSSMatrix ( matrix , cameraCSSMatrix ) ;
179+
180+ } else {
181+
182+ style = getObjectCSSMatrix ( object . matrixWorld , cameraCSSMatrix ) ;
183+
184+ }
185+
186+ var element = object . element ;
187+ var cachedStyle = cache . objects [ object . id ] && cache . objects [ object . id ] . style ;
188+
189+ if ( cachedStyle === undefined || cachedStyle !== style ) {
190+
191+ element . style . WebkitTransform = style ;
192+ element . style . MozTransform = style ;
193+ element . style . transform = style ;
194+
195+ cache . objects [ object . id ] = { style : style } ;
196+
197+ if ( isIE ) {
198+
199+ cache . objects [ object . id ] . distanceToCameraSquared = getDistanceToSquared ( camera , object ) ;
200+
201+ }
202+
203+ }
204+
205+ if ( element . parentNode !== cameraElement ) {
206+
207+ cameraElement . appendChild ( element ) ;
208+
209+ }
210+
211+ }
212+
213+ for ( var i = 0 , l = object . children . length ; i < l ; i ++ ) {
214+
215+ renderObject ( object . children [ i ] , camera , cameraCSSMatrix ) ;
216+
217+ }
218+
219+ }
220+
221+ var getDistanceToSquared = function ( ) {
222+
223+ var a = new THREE . Vector3 ( ) ;
224+ var b = new THREE . Vector3 ( ) ;
225+
226+ return function ( object1 , object2 ) {
227+
228+ a . setFromMatrixPosition ( object1 . matrixWorld ) ;
229+ b . setFromMatrixPosition ( object2 . matrixWorld ) ;
230+
231+ return a . distanceToSquared ( b ) ;
232+
233+ } ;
234+
235+ } ( ) ;
236+
237+ function zOrder ( scene ) {
238+
239+ var order = Object . keys ( cache . objects ) . sort ( function ( a , b ) {
240+
241+ return cache . objects [ a ] . distanceToCameraSquared - cache . objects [ b ] . distanceToCameraSquared ;
242+
243+ } ) ;
244+ var zMax = order . length ;
245+
246+ scene . traverse ( function ( object ) {
247+
248+ var index = order . indexOf ( object . id + '' ) ;
249+
250+ if ( index !== - 1 ) {
251+
252+ object . element . style . zIndex = zMax - index ;
253+
254+ }
255+
256+ } ) ;
257+
258+ }
259+
260+ this . render = function ( scene , camera ) {
261+
262+ var fov = camera . projectionMatrix . elements [ 5 ] * _heightHalf ;
263+
264+ if ( cache . camera . fov !== fov ) {
265+
266+ domElement . style . WebkitPerspective = fov + 'px' ;
267+ domElement . style . MozPerspective = fov + 'px' ;
268+ domElement . style . perspective = fov + 'px' ;
269+
270+ cache . camera . fov = fov ;
271+
272+ }
273+
274+ scene . updateMatrixWorld ( ) ;
275+
276+ if ( camera . parent === null ) camera . updateMatrixWorld ( ) ;
277+
278+ var cameraCSSMatrix = 'translateZ(' + fov + 'px)' +
279+ getCameraCSSMatrix ( camera . matrixWorldInverse ) ;
280+
281+ var style = cameraCSSMatrix +
282+ 'translate(' + _widthHalf + 'px,' + _heightHalf + 'px)' ;
283+
284+ if ( cache . camera . style !== style && ! isIE ) {
285+
286+ cameraElement . style . WebkitTransform = style ;
287+ cameraElement . style . MozTransform = style ;
288+ cameraElement . style . transform = style ;
289+
290+ cache . camera . style = style ;
291+
292+ }
293+
294+ renderObject ( scene , camera , cameraCSSMatrix ) ;
295+
296+ if ( isIE ) {
297+
298+ // IE10 and 11 does not support 'preserve-3d'.
299+ // Thus, z-order in 3D will not work.
300+ // We have to calc z-order manually and set CSS z-index for IE.
301+ // FYI: z-index can't handle object intersection
302+ zOrder ( scene ) ;
303+
304+ }
305+
306+ } ;
307+
308+ } ;
0 commit comments