Ver código fonte

enable camera view offset in CSS3DRenderer (#25508)

* support camera setViewOffset in CSS3DRenderer

* fix viewheight sync

* CSS3D examples: add viewOffset controls

* simplify

* update examples
Akihiro Oyamada 2 anos atrás
pai
commit
202bbb72cb

+ 62 - 0
examples/css3d_orthographic.html

@@ -39,6 +39,7 @@
 
 			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 			import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js';
+			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 			let camera, scene, renderer;
 
@@ -131,6 +132,7 @@
 				}
 
 				window.addEventListener( 'resize', onWindowResize );
+				createPanel();
 
 			}
 
@@ -160,6 +162,66 @@
 
 			}
 
+			function createPanel() {
+
+				const panel = new GUI();
+				const folder1 = panel.addFolder( 'camera setViewOffset' ).close();
+
+				const settings = {
+					'setViewOffset'() {
+
+						folder1.children[ 1 ].enable().setValue( window.innerWidth );
+						folder1.children[ 2 ].enable().setValue( window.innerHeight );
+						folder1.children[ 3 ].enable().setValue( 0 );
+						folder1.children[ 4 ].enable().setValue( 0 );
+						folder1.children[ 5 ].enable().setValue( window.innerWidth );
+						folder1.children[ 6 ].enable().setValue( window.innerHeight );
+
+					},
+					'fullWidth': 0,
+					'fullHeight': 0,
+					'offsetX': 0,
+					'offsetY': 0,
+					'width': 0,
+					'height': 0,
+					'clearViewOffset'() {
+
+						folder1.children[ 1 ].setValue( 0 ).disable();
+						folder1.children[ 2 ].setValue( 0 ).disable();
+						folder1.children[ 3 ].setValue( 0 ).disable();
+						folder1.children[ 4 ].setValue( 0 ).disable();
+						folder1.children[ 5 ].setValue( 0 ).disable();
+						folder1.children[ 6 ].setValue( 0 ).disable();
+						camera.clearViewOffset();
+
+					}
+				};
+
+				folder1.add( settings, 'setViewOffset' );
+				folder1.add( settings, 'fullWidth', window.screen.width / 4, window.screen.width * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { fullWidth: val } ) ).disable();
+				folder1.add( settings, 'fullHeight', window.screen.height / 4, window.screen.height * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { fullHeight: val } ) ).disable();
+				folder1.add( settings, 'offsetX', 0, 256, 1 ).onChange( ( val ) => updateCameraViewOffset( { x: val } ) ).disable();
+				folder1.add( settings, 'offsetY', 0, 256, 1 ).onChange( ( val ) => updateCameraViewOffset( { y: val } ) ).disable();
+				folder1.add( settings, 'width', window.screen.width / 4, window.screen.width * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { width: val } ) ).disable();
+				folder1.add( settings, 'height', window.screen.height / 4, window.screen.height * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { height: val } ) ).disable();
+				folder1.add( settings, 'clearViewOffset' );
+
+			}
+
+			function updateCameraViewOffset( { fullWidth, fullHeight, x, y, width, height } ) {
+
+				if ( ! camera.view ) {
+
+					camera.setViewOffset( fullWidth || window.innerWidth, fullHeight || window.innerHeight, x || 0, y || 0, width || window.innerWidth, height || window.innerHeight );
+
+				} else {
+
+					camera.setViewOffset( fullWidth || camera.view.fullWidth, fullHeight || camera.view.fullHeight, x || camera.view.offsetX, y || camera.view.offsetY, width || camera.view.width, height || camera.view.height );
+
+				}
+
+			}
+
 		</script>
 	</body>
 </html>

+ 66 - 0
examples/css3d_sandbox.html

@@ -35,6 +35,7 @@
 
 			import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
 			import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js';
+			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 			let camera, scene, renderer;
 
@@ -103,6 +104,7 @@
 				controls = new TrackballControls( camera, renderer2.domElement );
 
 				window.addEventListener( 'resize', onWindowResize );
+				createPanel();
 
 			}
 
@@ -129,6 +131,70 @@
 
 			}
 
+			function createPanel() {
+
+				const panel = new GUI();
+				const folder1 = panel.addFolder( 'camera setViewOffset' ).close();
+
+				const settings = {
+					'setViewOffset'() {
+
+						folder1.children[ 1 ].enable().setValue( window.innerWidth );
+						folder1.children[ 2 ].enable().setValue( window.innerHeight );
+						folder1.children[ 3 ].enable().setValue( 0 );
+						folder1.children[ 4 ].enable().setValue( 0 );
+						folder1.children[ 5 ].enable().setValue( window.innerWidth );
+						folder1.children[ 6 ].enable().setValue( window.innerHeight );
+
+					},
+					'fullWidth': 0,
+					'fullHeight': 0,
+					'offsetX': 0,
+					'offsetY': 0,
+					'width': 0,
+					'height': 0,
+					'clearViewOffset'() {
+
+						folder1.children[ 1 ].setValue( 0 ).disable();
+						folder1.children[ 2 ].setValue( 0 ).disable();
+						folder1.children[ 3 ].setValue( 0 ).disable();
+						folder1.children[ 4 ].setValue( 0 ).disable();
+						folder1.children[ 5 ].setValue( 0 ).disable();
+						folder1.children[ 6 ].setValue( 0 ).disable();
+						camera.clearViewOffset();
+
+					}
+				};
+
+				folder1.add( settings, 'setViewOffset' );
+				folder1.add( settings, 'fullWidth', window.screen.width / 4, window.screen.width * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { fullWidth: val } ) ).disable();
+				folder1.add( settings, 'fullHeight', window.screen.height / 4, window.screen.height * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { fullHeight: val } ) ).disable();
+				folder1.add( settings, 'offsetX', 0, 256, 1 ).onChange( ( val ) => updateCameraViewOffset( { x: val } ) ).disable();
+				folder1.add( settings, 'offsetY', 0, 256, 1 ).onChange( ( val ) => updateCameraViewOffset( { y: val } ) ).disable();
+				folder1.add( settings, 'width', window.screen.width / 4, window.screen.width * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { width: val } ) ).disable();
+				folder1.add( settings, 'height', window.screen.height / 4, window.screen.height * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { height: val } ) ).disable();
+				folder1.add( settings, 'clearViewOffset' );
+
+			}
+
+			function updateCameraViewOffset( { fullWidth, fullHeight, x, y, width, height } ) {
+
+				if ( ! camera.view ) {
+
+					camera.setViewOffset( fullWidth || window.innerWidth, fullHeight || window.innerHeight, x || 0, y || 0, width || window.innerWidth, height || window.innerHeight );
+					camera.aspect = window.innerWidth / window.innerHeight;
+					camera.updateProjectionMatrix();
+
+				} else {
+
+					camera.setViewOffset( fullWidth || camera.view.fullWidth, fullHeight || camera.view.fullHeight, x || camera.view.offsetX, y || camera.view.offsetY, width || camera.view.width, height || camera.view.height );
+					camera.aspect = window.innerWidth / window.innerHeight;
+					camera.updateProjectionMatrix();
+
+				}
+
+			}
+
 		</script>
 	</body>
 </html>

+ 27 - 5
examples/jsm/renderers/CSS3DRenderer.js

@@ -105,12 +105,16 @@ class CSS3DRenderer {
 
 		this.domElement = domElement;
 
+		const viewElement = document.createElement( 'div' );
+		viewElement.style.transformOrigin = '0 0';
+		viewElement.style.pointerEvents = 'none';
+		domElement.appendChild( viewElement );
+
 		const cameraElement = document.createElement( 'div' );
 
 		cameraElement.style.transformStyle = 'preserve-3d';
-		cameraElement.style.pointerEvents = 'none';
 
-		domElement.appendChild( cameraElement );
+		viewElement.appendChild( cameraElement );
 
 		this.getSize = function () {
 
@@ -127,11 +131,25 @@ class CSS3DRenderer {
 
 			if ( cache.camera.fov !== fov ) {
 
-				domElement.style.perspective = camera.isPerspectiveCamera ? fov + 'px' : '';
+				viewElement.style.perspective = camera.isPerspectiveCamera ? fov + 'px' : '';
 				cache.camera.fov = fov;
 
 			}
 
+			if ( camera.view && camera.view.enabled ) {
+
+				// view offset
+				viewElement.style.transform = `translate( ${ - camera.view.offsetX * ( _width / camera.view.width ) }px, ${ - camera.view.offsetY * ( _height / camera.view.height ) }px )`;
+
+				// view fullWidth and fullHeight, view width and height
+				viewElement.style.transform += `scale( ${ camera.view.fullWidth / camera.view.width }, ${ camera.view.fullHeight / camera.view.height } )`;
+
+			} else {
+
+				viewElement.style.transform = '';
+
+			}
+
 			if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();
 			if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();
 
@@ -144,9 +162,10 @@ class CSS3DRenderer {
 
 			}
 
+			const scaleByViewOffset = camera.view && camera.view.enabled ? camera.view.height / camera.view.fullHeight : 1;
 			const cameraCSSMatrix = camera.isOrthographicCamera ?
-				'scale(' + fov + ')' + 'translate(' + epsilon( tx ) + 'px,' + epsilon( ty ) + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse ) :
-				'translateZ(' + fov + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse );
+				`scale( ${ scaleByViewOffset } )` + 'scale(' + fov + ')' + 'translate(' + epsilon( tx ) + 'px,' + epsilon( ty ) + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse ) :
+				`scale( ${ scaleByViewOffset } )` + 'translateZ(' + fov + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse );
 
 			const style = cameraCSSMatrix +
 				'translate(' + _widthHalf + 'px,' + _heightHalf + 'px)';
@@ -173,6 +192,9 @@ class CSS3DRenderer {
 			domElement.style.width = width + 'px';
 			domElement.style.height = height + 'px';
 
+			viewElement.style.width = width + 'px';
+			viewElement.style.height = height + 'px';
+
 			cameraElement.style.width = width + 'px';
 			cameraElement.style.height = height + 'px';