javascriptthree.jsskybox

three.js skybox: obvious corners and lots of distortion


Today I've been experimenting with building my first ever skybox in three.js. I've read a lot of tutorials and the code I've ended up with is based on this one: http://learningthreejs.com/blog/2011/08/15/lets-do-a-sky/ I did make a few changes in order to allow for the images to load first, and to make it compatible with the version of three.js which I am using.

I've overcome a lot of small problems to get to the point I am currently at, but cannot find any answer to my current issue despite having searched quite hard. My problem is that despite using purpose-built skybox textures downloaded from the internet, it is glaringly obvious that my skybox is a cube with corners and edges. The textures appear heavily distorted and are not at all convincing.

Here is a screenshot of how my skybox looks: Here is a screenshot of my skybox

And here is a link to the site from which I downloaded the images: http://www.humus.name/index.php?page=Cubemap&item=Yokohama3 As you can see, in their preview it looks much better.

I've tried this with a few different downloaded textures and every time it is very obvious that you are looking at the inside of a cube.

Here's my code (I'm including all my code, not just the section which creates the skybox):

    var scene;
    var camera;
    var renderer;

    function createRenderer () {
        renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(0x000000, 1.0)
        renderer.setSize(window.innerWidth, window.innerHeight)
        renderer.shadowMapEnabled = true;
        //renderer.shadowCameraNear = 0.5;
        //renderer.shadowCameraFar = 500;
    }

    function createCamera () {
        camera = new THREE.PerspectiveCamera(
            45, 
            window.innerWidth/window.innerHeight,
            0.1, 1000
        );
        camera.position.x = 50;
        camera.position.y = 30;
        camera.position.z = 40;
        camera.lookAt(scene.position);
    }

    function createPlane () {
        var material = new THREE.MeshLambertMaterial({
            color: 0xcccccc,
        })
        var geometry = new THREE.PlaneGeometry(40, 40)

        var plane = new THREE.Mesh(geometry, material)
        plane.receiveShadow = true;
        plane.rotation.x = -Math.PI/2
        plane.position.y = -6;
        scene.add(plane)
    }

    function createLight () {
        var spotLight = new THREE.DirectionalLight(0xffffff);
        spotLight.position.set( 0, 50, 20 );
        spotLight.shadowCameraVisible = true;
        spotLight.shadowDarkness = 0.5
        spotLight.shadowCameraNear = 0;
        spotLight.shadowCameraFar = 100;
        spotLight.shadowCameraLeft = -50;
        spotLight.shadowCameraRight = 50;
        spotLight.shadowCameraTop = 50;
        spotLight.shadowCameraBottom = -50;
        spotLight.castShadow = true;
        scene.add(spotLight);
    }

    function createSkyboxAndSphere () { 

        var urlPrefix = "Yokohama3/";
        var urls = [ urlPrefix + "posx.jpg", urlPrefix + "negx.jpg",
            urlPrefix + "posy.jpg", urlPrefix + "negy.jpg",
            urlPrefix + "posz.jpg", urlPrefix + "negz.jpg" ];
        var textureCube = THREE.ImageUtils.loadTextureCube( urls , undefined, function () {;

            var shader = THREE.ShaderLib["cube"];
            var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
            shader.uniforms['tCube'].value = textureCube;   // textureCube has been init before
            var material = new THREE.ShaderMaterial({
                fragmentShader    : shader.fragmentShader,
                vertexShader  : shader.vertexShader,
                uniforms  : shader.uniforms,
                depthWrite : false,
                side: THREE.BackSide,
            });


            var geometry = new THREE.BoxGeometry(100, 100, 100)
            var skybox = new THREE.Mesh(geometry, material)
            scene.add(skybox)


            var material = new THREE.MeshPhongMaterial({
                color: "red",
                envMap: textureCube,
                reflectivity: 0.3,
            })
            var geometry = new THREE.SphereGeometry(6, 30, 15)

            var sphere = new THREE.Mesh(geometry, material)
            sphere.castShadow = true;
            sphere.receiveShadow = true;
            scene.add(sphere)

            });
    }

    function init () {

        scene = new THREE.Scene();
        createRenderer();
        createCamera();
        createLight();
        createPlane ();
        createSkyboxAndSphere ();

        document.getElementById("container").appendChild(renderer.domElement)

        render ()
    }

    function render () {
        renderer.render(scene, camera)
        requestAnimationFrame(render);
    }

    window.onload = function () {
        init ();
    }

I suspect I am fundamentally misunderstanding something about how cubemapping and skyboxes work - I am very new to this in particular and javascript in general and am aware of huge gaps in my knowledge.

My apologies if the answer to this is obvious and/or the question has been asked before, and a pre-emptive thanks for your help!


Solution

  • Your camera needs to be in the center of the skybox -- or at least near the center.

    So either move your camera very close to the box center, or update the box position every frame to match the camera position.

    Or make the skybox much bigger relative to the camera offset from the origin.

    three.js r.74