soulbase
soulbase

Reputation: 1

How to correctly layer a 3D model and CSS3D divs in Three.js so the divs are placed in front and behind the model?

I'm trying to use both WebGL (a Three.js 3D model) and CSS3D (HTML divs) in the same scene. The goal is to render one div behind the 3D model and another in front of it. However, currently, the model itself renders on top of both divs, causing them to be hidden or improperly layered.

Using renderOrder to control the drawing order of objects. Assigning camera layers to differentiate between CSS3D and WebGL layers. Explicitly setting the layers of the CSS3D objects and WebGL model using layers.set(). However, despite these attempts, the model is still rendered on top of the divs, and I'm unable to properly layer the divs behind and in front of the model.

function main() {
    // Create WebGL & CSS3D Renderers
    const renderer = new THREE.WebGLRenderer({ alpha: true });
    const renderer_css3d = new CSS3DRenderer();

    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer_css3d.setSize(window.innerWidth, window.innerHeight);

    document.body.appendChild(renderer.domElement);
    document.body.appendChild(renderer_css3d.domElement);

    // Set CSS3D layer properties
    renderer.domElement.style.position = 'absolute';
    renderer.domElement.style.zIndex = '1';

    renderer_css3d.domElement.style.position = 'absolute';

    // Camera setup
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(0, 200, 300);
    camera.layers.enable(0);
    camera.layers.enable(1);
    console.log("Camera Layers:", camera.layers.mask); 

    // Controls
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.25;
    controls.minDistance = 300;
    controls.maxDistance = 1000;
    controls.maxPolarAngle = Math.PI / 2;

    // Scene setup
    const scene = new THREE.Scene();

    // Lighting
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
    directionalLight.position.set(0, 3, 3);
    scene.add(directionalLight);

    // Group to sync WebGL & CSS3D
    const group = new THREE.Group();
    scene.add(group);

    // 🔴 CSS3DObject (Behind Model)
    const divBack = document.createElement('div');
    divBack.style.width = '300px';
    divBack.style.height = '150px';
    divBack.innerText = 'Behind Model';
    divBack.style.background = 'rgba(255, 0, 0, 0.7)';
    divBack.style.color = 'white';
    divBack.style.display = 'flex';
    divBack.style.alignItems = 'center';
    divBack.style.justifyContent = 'center';
    divBack.style.fontSize = '20px';
    divBack.style.borderRadius = '10px';

    const css3dObjectBack = new CSS3DObject(divBack);
    css3dObjectBack.position.set(0, 50, -150);
    css3dObjectBack.renderOrder = 0;  // Ensures it's rendered first
    css3dObjectBack.layers.set(0);  // CSS3D Layer
    group.add(css3dObjectBack);

    // 🔵 CSS3DObject (In Front of Model)
    const divFront = document.createElement('div');
    divFront.style.width = '300px';
    divFront.style.height = '150px';
    divFront.innerText = 'In Front';
    divFront.style.background = 'rgba(0, 0, 255, 0.7)';
    divFront.style.color = 'white';
    divFront.style.display = 'flex';
    divFront.style.alignItems = 'center';
    divFront.style.justifyContent = 'center';
    divFront.style.fontSize = '20px';
    divFront.style.borderRadius = '10px';

    const css3dObjectFront = new CSS3DObject(divFront);
    css3dObjectFront.position.set(0, 50, 100);
    css3dObjectFront.renderOrder = 2; // Ensures it's rendered last
    css3dObjectFront.layers.set(0);  // CSS3D Layer
    group.add(css3dObjectFront);

console.log("CSS3D Object (Back) Layer:", css3dObjectBack.layers.mask);
console.log("CSS3D Object (Front) Layer:", css3dObjectFront.layers.mask);

    // Load GLTF Model
    const loader = new GLTFLoader();
    loader.load('/models/Xbot.glb', function (gltf) {
        const glbModel = gltf.scene;
        glbModel.sortObjects = true;
        glbModel.position.set(0, 0, 0);
        glbModel.scale.set(100, 100, 100);
        glbModel.renderOrder = 1; // Model should be between the divs
        glbModel.layers.set(1);  // WebGL Layer
        group.add(glbModel);

        // Set model color if available
        const newColor = initialModelColor ? new THREE.Color(initialModelColor) : new THREE.Color(0xffffff);
        glbModel.traverse((child) => {
            if (child.isMesh && child.material) {
                child.material.color = newColor;
                child.material.needsUpdate = true;
            }
        });

        // Add animation support
        const mixer = new THREE.AnimationMixer(glbModel);
        const animations = gltf.animations;
        if (animations.length > 0) {
            const walkAction = mixer.clipAction(animations[0]);
            walkAction.play();
        }

        console.log('Model Loaded:', glbModel);
    }, undefined, function (error) {
        console.error('Error loading model:', error);
        console.log("3D Model Layer:", glbModel ? glbModel.layers.mask : "Model not loaded");
    });

    // Resize handling
    window.onresize = () => {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer_css3d.setSize(window.innerWidth, window.innerHeight);
    };

    // Animation loop
    function render() {
        controls.update();
        renderer_css3d.render(scene, camera);
        renderer.render(scene, camera);
        requestAnimationFrame(render);
    }

    render();
   
}

main();

console.log Camera Layers: 3 ///////////////////////////////////this should not be 3 i think test.php:558 CSS3D Object (Back) Layer: 1 test.php:559 CSS3D Object (Front) Layer: 1

Upvotes: 0

Views: 29

Answers (0)

Related Questions