You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Three.js中让CSS3D渲染平面充当地板?

解决CSS3D平面与WebGL立方体位置/旋转不匹配问题

我来帮你搞定这个问题!你遇到的核心问题是CSS3DRenderer和WebGLRenderer的坐标系差异,再加上几个小细节没处理好,导致两者的位置和旋转对不上。咱们一步步来修正:

问题根源

  1. Y轴方向相反:WebGLRenderer里Y轴是向上的,而CSS3DRenderer遵循网页的坐标系——Y轴是向下的,这直接导致位置和旋转的表现不一致。
  2. 旋转单位错误:你给平面的rotation.x = 270是角度值,但Three.js的rotation属性需要用弧度,直接写角度会导致旋转异常。
  3. 渲染层级遮挡: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:20:50