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

如何为CSS2DRenderer添加重置函数清除已渲染的CSS2DObject?

如何实现CSS2DRenderer的重置功能以移除所有CSS2DObject

问题描述

我使用以下Three.js类创建场景、相机、渲染器及CSS2DRenderer,希望添加一个重置函数(删除并重新添加CSS2DRenderer)以移除所有之前渲染的CSS2DObject,请问该如何正确实现?

import {
    Scene,
    Color,
    Vector3,
    AxesHelper,
    PerspectiveCamera,
    WebGLRenderer,
    DirectionalLight,
    HemisphereLight,
    AmbientLight,
    sRGBEncoding
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { CSS2DRenderer } from "three/examples/jsm/renderers/CSS2DRenderer.js";
// import Stats from 'three/examples/jsm/libs/stats.module.js';

export default class SceneCreator {
    /**
     * 
     * @param {*} container 
     */
    constructor(container) { 
        this.container = container;
        this.scene = null;
        this.camera = null;
        this.renderer = null;
        this.css_renderer = new CSS2DRenderer();
        this.controls = null; // 新增:存储OrbitControls实例
        // this.stats = new Stats();
        this.initScene();
    };

    initScene=()=> { 
        this.scene = new Scene();
        this.scene.background = new Color(0x21252d);

        this.createCamera();
        this.createLights();
        this.createControls();
        this.createRenderer();
        this.createAxe();
        // this.container.appendChild(this.stats.dom);
        this.renderer.setAnimationLoop(() => {
            this.renderer.render(this.scene, this.camera);
            this.css_renderer.render(this.scene, this.camera);
            // this.stats.update();
        });

        this.css_renderer.setSize( this.container.clientWidth, this.container.clientHeight );
        this.css_renderer.domElement.style.position = 'absolute';
        this.css_renderer.domElement.style.top = '0px';
        this.container.appendChild(this.css_renderer.domElement);
        
        window.addEventListener("resize", this.onWindowResize, false);
    }

    createCamera=()=> { 
        const fov = 60; 
        const near = 1;
        const far = 1000;
        const aspect_ratio = this.container.clientWidth/this.container.clientHeight
        this.camera = new PerspectiveCamera(fov, aspect_ratio, near, far);
        this.camera.position.set(0.1, 10, 10);
        this.camera.lookAt(0, 0, 0);
    }

    createControls=()=> {
        /* Create Controls to allow for scene control */
        // const controls = new OrbitControls(this.camera, this.container);
        this.controls = new OrbitControls( this.camera, this.css_renderer.domElement ); // 修改:将controls存储为实例属性
        this.controls.update();
    }

    createLights= ()=> {
        const mainLight = new DirectionalLight(0xffffff, 5);
        mainLight.position.set(10, 10, 10);

        const hemisphereLight = new HemisphereLight(0xddeeff, 0x202020, 5);
        const ambientLight = new AmbientLight(0x404040, 5);

        this.scene.add(mainLight, hemisphereLight, ambientLight);
    }

    createAxe = (len=1.6, pos=null) => { 
        const axis = new AxesHelper(len);

        const red   = new Color(0xff0000);
        const green = new Color(0x00ff00);
        const blue  = new Color(0x0000ff);
        
        axis.setColors(green, blue, red);

        if (pos === null) { 
            pos = new Vector3(8.0, 5.0, -3.2);
        }
        axis.position.x = pos.x;
        axis.position.y = pos.y;
        axis.position.z = pos.z;
       
        this.scene.add(axis);
    }
    createRenderer = ()=> {
        this.renderer = new WebGLRenderer('webgl2',{ antialias: true, alpha: true });
        this.renderer.setClearColor( 0xA3A3A3, 0 );
        this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
        this.renderer.setPixelRatio(window.devicePixelRatio);
        this.renderer.physicallyCorrectLights = true;
        this.renderer.outputEncoding = sRGBEncoding;
        this.container.appendChild(this.renderer.domElement);
    }

    onWindowResize = ()=> {
        this.camera.aspect = this.container.clientWidth / this.container.clientHeight;
    
        // Update camera frustum
        this.camera.updateProjectionMatrix();
    
        this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
        this.css_renderer.setSize(this.container.clientWidth, this.container.clientHeight);
    }

    // 新增:重置CSS2DRenderer的方法
    resetCSSRenderer = () => {
        // 1. 移除旧的CSS渲染器DOM元素
        if (this.css_renderer?.domElement.parentNode) {
            this.css_renderer.domElement.parentNode.removeChild(this.css_renderer.domElement);
        }

        // 2. 销毁旧渲染器,释放资源
        if (this.css_renderer) {
            this.css_renderer.dispose();
        }

        // 3. 创建并初始化新的CSS2DRenderer
        this.css_renderer = new CSS2DRenderer();
        this.css_renderer.setSize(this.container.clientWidth, this.container.clientHeight);
        this.css_renderer.domElement.style.position = 'absolute';
        this.css_renderer.domElement.style.top = '0px';
        this.container.appendChild(this.css_renderer.domElement);

        // 4. 更新轨道控制器的绑定元素
        if (this.controls) {
            this.controls.domElement = this.css_renderer.domElement;
        }

        // 5. 清理场景中所有CSS2DObject(可选但推荐)
        this.scene.children = this.scene.children.filter(child => !child.isCSS2DObject);
    }

    getScene = () => { 
        return this.scene;
    }

    getCamera = () => { 
        return this.camera;
    }

    getRenderer = () => { 
        return this.renderer;
    }

    getCSS2DRenderer = () => { 
        return this.css_renderer;
    }
}

关键说明

  1. 存储OrbitControls实例:将controls改为实例属性this.controls,以便重置时更新其绑定的DOM元素,避免控制器失效。
  2. 完整清理旧渲染器:不仅移除DOM元素,还调用dispose()方法释放内部资源,防止内存泄漏。
  3. 场景对象清理:通过过滤场景子元素,移除所有isCSS2DObject标记的对象,确保新渲染器不会渲染旧内容。
  4. 同步控制器绑定:更新this.controls.domElement为新的CSS渲染器DOM元素,保证轨道控制正常工作。

使用时直接调用sceneCreatorInstance.resetCSSRenderer()即可完成重置。

内容的提问来源于stack exchange,提问作者Bilal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 07:00:59