如何在Three.js中让CSS3D渲染平面充当地板?
解决CSS3D平面与WebGL立方体位置/旋转不匹配问题
我来帮你搞定这个问题!你遇到的核心问题是CSS3DRenderer和WebGLRenderer的坐标系差异,再加上几个小细节没处理好,导致两者的位置和旋转对不上。咱们一步步来修正:
问题根源
- Y轴方向相反:WebGLRenderer里Y轴是向上的,而CSS3DRenderer遵循网页的坐标系——Y轴是向下的,这直接导致位置和旋转的表现不一致。
- 旋转单位错误:你给平面的
rotation.x = 270是角度值,但Three.js的rotation属性需要用弧度,直接写角度会导致旋转异常。 - 渲染层级遮挡:WebGL的canvas默认在CSS3D元素的下方,会被蓝色地板挡住,需要调整层级让立方体显示出来。
修正后的完整代码
<!DOCTYPE html> <html lang="en"> <head> <title>3JS CODE</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <style> body { font-family: Monospace; background-color: #f0f0f0; margin: 0px; overflow: hidden; } /* 给WebGL画布设置更高层级,避免被CSS3D元素遮挡 */ .webgl-renderer { position: absolute; top: 0; left: 0; z-index: 1; } </style> </head> <body> <script src="js/three.js"></script> <script src="js/controls/TrackballControls.js"></script> <script src="js/renderers/CSS3DRenderer.js"></script> <script src="js/libs/stats.min.js"></script> <script> var HtmlElement = function ( id, x, y, z, rx ) { var div = document.createElement( 'div' ); div.innerHTML = "Hello"; div.id = id; div.style.width = '1200px'; div.style.height = '950px'; div.style.backgroundColor = 'blue'; var object = new THREE.CSS3DObject( div ); object.position.set( x, y, z ); // 把角度转换成弧度,同时适配CSS3D的坐标系 object.rotation.x = THREE.MathUtils.degToRad(rx); // 翻转Y轴,对齐WebGL的坐标系 object.scale.y = -1; return object; }; </script> <script> var container, stats; var camera, controls, mapScene, group, renderer1, renderer2; var objects = []; init(); animate(); function init() { container = document.createElement( 'div' ); document.body.appendChild( container ); camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 5000 ); camera.position.set(0.18348775328760136, -334.5971567493426, 800.8398185862801); controls = new THREE.TrackballControls( camera ); controls.rotateSpeed = 3.0; controls.zoomSpeed = 2.2; controls.panSpeed = 2.8; controls.noZoom = false; controls.noPan = false; controls.staticMoving = true; controls.dynamicDampingFactor = 1.3; mapScene = new THREE.Scene(); group = new THREE.Group(); // 创建CSS3D地板:调整位置,让它在立方体下方 var mapObject = new HtmlElement( 'googleMap', 0, 300, 240, 270 ); group.add( mapObject ); // 创建WebGL立方体 var geometry = new THREE.BoxGeometry( 200, 200, 200 ); for ( var i = 0; i < geometry.faces.length; i += 2 ) { var hex = Math.random() * 0xffffff; geometry.faces[ i ].color.setHex( hex ); geometry.faces[ i + 1 ].color.setHex( hex ); } var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5 } ); cube = new THREE.Mesh( geometry, material ); // 立方体位置:Y轴设置为0,地板在Y=300(因为CSS3D翻转了Y轴,对应WebGL的Y=-300下方) cube.position.set(0, 0, 500); group.add( cube ); mapScene.add( group ); // CSS3D渲染器 renderer1 = new THREE.CSS3DRenderer(); renderer1.setSize( window.innerWidth, window.innerHeight ); renderer1.domElement.style.position = 'absolute'; renderer1.domElement.style.top = 0; container.appendChild( renderer1.domElement ); // WebGL渲染器:添加类名设置层级 renderer2 = new THREE.WebGLRenderer( { antialias: true } ); renderer2.setSize( window.innerWidth, window.innerHeight ); renderer2.domElement.classList.add('webgl-renderer'); container.appendChild( renderer2.domElement ); stats = new Stats(); container.appendChild( stats.dom ); window.addEventListener( 'resize', onWindowResize, false ); render(); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer1.setSize( window.innerWidth, window.innerHeight ); renderer2.setSize( window.innerWidth, window.innerHeight ); } function animate() { requestAnimationFrame( animate ); render(); stats.update(); } function render() { controls.update(); renderer1.render( mapScene, camera ); renderer2.render( mapScene, camera ); } </script> </body> </html>
关键修改说明
- 坐标系对齐:给CSS3DObject添加
object.scale.y = -1,翻转Y轴,让它和WebGL的Y轴方向一致。 - 旋转值修正:用
THREE.MathUtils.degToRad(270)把角度转换成弧度,确保旋转正确。 - 位置调整:把立方体的Y轴位置设为0,地板的Y轴设为300(因为Y轴翻转后,对应WebGL里的Y=-300,正好在立方体下方)。
- 层级修复:给WebGL渲染器的canvas添加
webgl-renderer类,设置z-index:1,避免被CSS3D地板遮挡。
这样调整后,蓝色的CSS3D平面就会作为地板,立方体稳稳地放在它上方,而且两者的旋转会完全同步啦!
内容的提问来源于stack exchange,提问作者Dulya Murage
相关产品推荐
相关产品推荐

