Skip to content

Commit 202bbb7

Browse files
authored
enable camera view offset in CSS3DRenderer (#25508)
* support camera setViewOffset in CSS3DRenderer * fix viewheight sync * CSS3D examples: add viewOffset controls * simplify * update examples
1 parent 0f340f6 commit 202bbb7

File tree

3 files changed

+155
-5
lines changed

3 files changed

+155
-5
lines changed

examples/css3d_orthographic.html

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
4141
import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js';
42+
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
4243

4344
let camera, scene, renderer;
4445

@@ -131,6 +132,7 @@
131132
}
132133

133134
window.addEventListener( 'resize', onWindowResize );
135+
createPanel();
134136

135137
}
136138

@@ -160,6 +162,66 @@
160162

161163
}
162164

165+
function createPanel() {
166+
167+
const panel = new GUI();
168+
const folder1 = panel.addFolder( 'camera setViewOffset' ).close();
169+
170+
const settings = {
171+
'setViewOffset'() {
172+
173+
folder1.children[ 1 ].enable().setValue( window.innerWidth );
174+
folder1.children[ 2 ].enable().setValue( window.innerHeight );
175+
folder1.children[ 3 ].enable().setValue( 0 );
176+
folder1.children[ 4 ].enable().setValue( 0 );
177+
folder1.children[ 5 ].enable().setValue( window.innerWidth );
178+
folder1.children[ 6 ].enable().setValue( window.innerHeight );
179+
180+
},
181+
'fullWidth': 0,
182+
'fullHeight': 0,
183+
'offsetX': 0,
184+
'offsetY': 0,
185+
'width': 0,
186+
'height': 0,
187+
'clearViewOffset'() {
188+
189+
folder1.children[ 1 ].setValue( 0 ).disable();
190+
folder1.children[ 2 ].setValue( 0 ).disable();
191+
folder1.children[ 3 ].setValue( 0 ).disable();
192+
folder1.children[ 4 ].setValue( 0 ).disable();
193+
folder1.children[ 5 ].setValue( 0 ).disable();
194+
folder1.children[ 6 ].setValue( 0 ).disable();
195+
camera.clearViewOffset();
196+
197+
}
198+
};
199+
200+
folder1.add( settings, 'setViewOffset' );
201+
folder1.add( settings, 'fullWidth', window.screen.width / 4, window.screen.width * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { fullWidth: val } ) ).disable();
202+
folder1.add( settings, 'fullHeight', window.screen.height / 4, window.screen.height * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { fullHeight: val } ) ).disable();
203+
folder1.add( settings, 'offsetX', 0, 256, 1 ).onChange( ( val ) => updateCameraViewOffset( { x: val } ) ).disable();
204+
folder1.add( settings, 'offsetY', 0, 256, 1 ).onChange( ( val ) => updateCameraViewOffset( { y: val } ) ).disable();
205+
folder1.add( settings, 'width', window.screen.width / 4, window.screen.width * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { width: val } ) ).disable();
206+
folder1.add( settings, 'height', window.screen.height / 4, window.screen.height * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { height: val } ) ).disable();
207+
folder1.add( settings, 'clearViewOffset' );
208+
209+
}
210+
211+
function updateCameraViewOffset( { fullWidth, fullHeight, x, y, width, height } ) {
212+
213+
if ( ! camera.view ) {
214+
215+
camera.setViewOffset( fullWidth || window.innerWidth, fullHeight || window.innerHeight, x || 0, y || 0, width || window.innerWidth, height || window.innerHeight );
216+
217+
} else {
218+
219+
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 );
220+
221+
}
222+
223+
}
224+
163225
</script>
164226
</body>
165227
</html>

examples/css3d_sandbox.html

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
3737
import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js';
38+
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
3839

3940
let camera, scene, renderer;
4041

@@ -103,6 +104,7 @@
103104
controls = new TrackballControls( camera, renderer2.domElement );
104105

105106
window.addEventListener( 'resize', onWindowResize );
107+
createPanel();
106108

107109
}
108110

@@ -129,6 +131,70 @@
129131

130132
}
131133

134+
function createPanel() {
135+
136+
const panel = new GUI();
137+
const folder1 = panel.addFolder( 'camera setViewOffset' ).close();
138+
139+
const settings = {
140+
'setViewOffset'() {
141+
142+
folder1.children[ 1 ].enable().setValue( window.innerWidth );
143+
folder1.children[ 2 ].enable().setValue( window.innerHeight );
144+
folder1.children[ 3 ].enable().setValue( 0 );
145+
folder1.children[ 4 ].enable().setValue( 0 );
146+
folder1.children[ 5 ].enable().setValue( window.innerWidth );
147+
folder1.children[ 6 ].enable().setValue( window.innerHeight );
148+
149+
},
150+
'fullWidth': 0,
151+
'fullHeight': 0,
152+
'offsetX': 0,
153+
'offsetY': 0,
154+
'width': 0,
155+
'height': 0,
156+
'clearViewOffset'() {
157+
158+
folder1.children[ 1 ].setValue( 0 ).disable();
159+
folder1.children[ 2 ].setValue( 0 ).disable();
160+
folder1.children[ 3 ].setValue( 0 ).disable();
161+
folder1.children[ 4 ].setValue( 0 ).disable();
162+
folder1.children[ 5 ].setValue( 0 ).disable();
163+
folder1.children[ 6 ].setValue( 0 ).disable();
164+
camera.clearViewOffset();
165+
166+
}
167+
};
168+
169+
folder1.add( settings, 'setViewOffset' );
170+
folder1.add( settings, 'fullWidth', window.screen.width / 4, window.screen.width * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { fullWidth: val } ) ).disable();
171+
folder1.add( settings, 'fullHeight', window.screen.height / 4, window.screen.height * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { fullHeight: val } ) ).disable();
172+
folder1.add( settings, 'offsetX', 0, 256, 1 ).onChange( ( val ) => updateCameraViewOffset( { x: val } ) ).disable();
173+
folder1.add( settings, 'offsetY', 0, 256, 1 ).onChange( ( val ) => updateCameraViewOffset( { y: val } ) ).disable();
174+
folder1.add( settings, 'width', window.screen.width / 4, window.screen.width * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { width: val } ) ).disable();
175+
folder1.add( settings, 'height', window.screen.height / 4, window.screen.height * 2, 1 ).onChange( ( val ) => updateCameraViewOffset( { height: val } ) ).disable();
176+
folder1.add( settings, 'clearViewOffset' );
177+
178+
}
179+
180+
function updateCameraViewOffset( { fullWidth, fullHeight, x, y, width, height } ) {
181+
182+
if ( ! camera.view ) {
183+
184+
camera.setViewOffset( fullWidth || window.innerWidth, fullHeight || window.innerHeight, x || 0, y || 0, width || window.innerWidth, height || window.innerHeight );
185+
camera.aspect = window.innerWidth / window.innerHeight;
186+
camera.updateProjectionMatrix();
187+
188+
} else {
189+
190+
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 );
191+
camera.aspect = window.innerWidth / window.innerHeight;
192+
camera.updateProjectionMatrix();
193+
194+
}
195+
196+
}
197+
132198
</script>
133199
</body>
134200
</html>

examples/jsm/renderers/CSS3DRenderer.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,16 @@ class CSS3DRenderer {
105105

106106
this.domElement = domElement;
107107

108+
const viewElement = document.createElement( 'div' );
109+
viewElement.style.transformOrigin = '0 0';
110+
viewElement.style.pointerEvents = 'none';
111+
domElement.appendChild( viewElement );
112+
108113
const cameraElement = document.createElement( 'div' );
109114

110115
cameraElement.style.transformStyle = 'preserve-3d';
111-
cameraElement.style.pointerEvents = 'none';
112116

113-
domElement.appendChild( cameraElement );
117+
viewElement.appendChild( cameraElement );
114118

115119
this.getSize = function () {
116120

@@ -127,11 +131,25 @@ class CSS3DRenderer {
127131

128132
if ( cache.camera.fov !== fov ) {
129133

130-
domElement.style.perspective = camera.isPerspectiveCamera ? fov + 'px' : '';
134+
viewElement.style.perspective = camera.isPerspectiveCamera ? fov + 'px' : '';
131135
cache.camera.fov = fov;
132136

133137
}
134138

139+
if ( camera.view && camera.view.enabled ) {
140+
141+
// view offset
142+
viewElement.style.transform = `translate( ${ - camera.view.offsetX * ( _width / camera.view.width ) }px, ${ - camera.view.offsetY * ( _height / camera.view.height ) }px )`;
143+
144+
// view fullWidth and fullHeight, view width and height
145+
viewElement.style.transform += `scale( ${ camera.view.fullWidth / camera.view.width }, ${ camera.view.fullHeight / camera.view.height } )`;
146+
147+
} else {
148+
149+
viewElement.style.transform = '';
150+
151+
}
152+
135153
if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();
136154
if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();
137155

@@ -144,9 +162,10 @@ class CSS3DRenderer {
144162

145163
}
146164

165+
const scaleByViewOffset = camera.view && camera.view.enabled ? camera.view.height / camera.view.fullHeight : 1;
147166
const cameraCSSMatrix = camera.isOrthographicCamera ?
148-
'scale(' + fov + ')' + 'translate(' + epsilon( tx ) + 'px,' + epsilon( ty ) + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse ) :
149-
'translateZ(' + fov + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse );
167+
`scale( ${ scaleByViewOffset } )` + 'scale(' + fov + ')' + 'translate(' + epsilon( tx ) + 'px,' + epsilon( ty ) + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse ) :
168+
`scale( ${ scaleByViewOffset } )` + 'translateZ(' + fov + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse );
150169

151170
const style = cameraCSSMatrix +
152171
'translate(' + _widthHalf + 'px,' + _heightHalf + 'px)';
@@ -173,6 +192,9 @@ class CSS3DRenderer {
173192
domElement.style.width = width + 'px';
174193
domElement.style.height = height + 'px';
175194

195+
viewElement.style.width = width + 'px';
196+
viewElement.style.height = height + 'px';
197+
176198
cameraElement.style.width = width + 'px';
177199
cameraElement.style.height = height + 'px';
178200

0 commit comments

Comments
 (0)