简体   繁体   中英

three.js - how to render scene.background before a mesh?

I am a novice to Javascript and ThreeJS. I have a 3D rotating cube that appears on top of a static background, but one frustrating property is that the cube typically appears first and then the background image appears. How do I ensure the background is rendered first? Specifically, I always want the background image to appear before the cube.

My code:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>My first three.js app</title>
    <style>
        body { margin: 0; }
    </style>
</head>
<body>
<script src="js/three.js"></script>
<script>

    function resize() {

        var aspect = window.innerWidth / window.innerHeight;
        let texAspect = bgWidth / bgHeight;
        let relAspect = aspect / texAspect;

        bgTexture.repeat = new THREE.Vector2( Math.max(relAspect, 1), Math.max(1/relAspect,1) );
        bgTexture.offset = new THREE.Vector2( -Math.max(relAspect-1, 0)/2, -Math.max(1/relAspect-1, 0)/2 );

        renderer.setSize(window.innerWidth, window.innerHeight);
        camera.aspect = aspect;
        camera.updateProjectionMatrix();
    }

    const scene = new THREE.Scene();

    // Arguments:
    //      1) Field of Value (degrees)
    //      2) Aspect ratio
    //      3) Near clipping plane
    //      4) Far clipping plane
    const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

    const renderer = new THREE.WebGLRenderer();
    // Need to set size of renderer. For performance, may want to reduce size.
    // Can also reduce resolution by passing false as third arg to .setSize
    renderer.setSize( window.innerWidth, window.innerHeight );

    // Add the rendered to the HTML
    document.body.appendChild( renderer.domElement );

    // A BoxGeometry is an object that contains all points (vertices) and fill (faces)
    // of the cube
    const geometry = new THREE.BoxGeometry();

    // Determines surface color (maybe texture?)
    const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );

    // Mesh takes a geometry and applies the material to it
    const cube = new THREE.Mesh( geometry, material );

    // Add background image
    const loader = new THREE.TextureLoader();
    bgTexture = loader.load('https://images.pexels.com/photos/1205301/pexels-photo-1205301.jpeg' ,
        function(texture) {
            // Resize image to fit in window
            // Code from https://stackoverflow.com/a/48126806/4570472
            var img = texture.image;
            var bgWidth = img.width;
            var bgHeight = img.height;
            resize();
    });

    scene.background = bgTexture;

    // By default, whatever we add to the scene will be at coordinates (0, 0, 0)
    scene.add( cube );

    camera.position.z = 5;



    // This somehow creates a loop that causes the rendered to draw the scene
    // every time the screen is refreshed (typically 60fps)
    function animate() {
        requestAnimationFrame( animate );
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;
        renderer.render( scene, camera );
    }
    animate();
</script>
</body>
</html>

This is happening because the texture is taking longer to load than it takes for Three.js to set up the rest of the scene. You already have a handler for the onLoad callback of TextureLoader.load() , so we can use that to adjust the behavior.

Before scene.add( cube ); , add a new line:

cube.visible = false;

Now the cube will still be added to the scene, but it won't be visible. Now after the resize() call at the end of function(texture) , add

cube.visible = true;

While testing the problem and solution locally, I ran into a few other, less significant issues with your code. You can see all of the changes I had to make to get it running properly at this Gist .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM