用Three.js創建一個簡易的天空盒

本文創建的天空盒是用六張圖片來創建的。筆者會論述兩種方法來創建,都是最簡單基本的方法,不涉及着色器的使用。
一種是創建一個盒子,然後將圖片作爲盒子6個面的紋理貼上來創建。
另一種則是簡單的將紋理作爲場景的背景來創建。
兩種方法視覺效果是幾乎沒區別的,會給人身臨其境的效果,感覺身處在這個3維空間裏,最明顯的區別就在於當你在用鼠標滾輪縮進的時候,天空盒會“原形畢露”,暴露出其盒子的本性,視覺效果原理展現在你的眼前。如圖所示:這裏寫圖片描述
而作爲背景的方法創建的話,則無論你怎麼縮進,都不會“原形畢露”。
當然,縮進的設置我們是可以自己調整的,規定縮進的範圍,用第一種方法也是可以不暴露出盒子的原型的。

好,接下來我們來看代碼部分。

<div id="WebGL-output"></div>
<script src="../build/three.js"></script>
<script src="../examples/js/controls/OrbitControls.js"></script>

第一步是引用文件,我們是用Three.js來創建天空盒,所以第一個引用的是three.js這個文件,第二引用的文件是OrbitControls.js,這裏面的函數是我們用來操控相機的,你可以通過調用這個文件裏的函數在天空盒中實現360°的轉換視角來觀看,前文所述的你如果要調整縮進的話,也是調用裏面的函數。
至於第一行的div,是作爲我們three.js的輸出對象。
寫完引用文件,接下來看下正文代碼的結構。

<script>

    var scene, camera, renderer;
    var container, controls;

    init();
    animate();

    // FUNCTIONS
    function init()
    {
        ······

    }

    function animate()
    {
        ······
    }

    function update()
    {
        ······
    }

    function render()
    {
        ······
    }

</script>

第一步創建會用到的全局變量
three.js不可缺少的三部分:scene(場景), camera(相機), renderer(渲染器);
至於另外兩個變量我們在代碼中去理解。筆者在此就不多述了。
核心部分是init()函數,先創立三維場景基本要素:

        // 創建場景
        scene = new THREE.Scene();
        // 定義透視相機的四個參數變量
        var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
        var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
        //創建相機
        camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
        camera.position.set(0,150,400);//將相機的位置擺放在(0,150,400)的位置。這裏位置你可以更改以下,放在(0,0,400)也是可以的
        camera.lookAt(scene.position);//讓相機對着場景中央
        //將相機加入場景之中
        scene.add(camera);

        //設置渲染器
        renderer = new THREE.WebGLRenderer( {antialias:true} );//設置爲抗鋸齒
        renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);//設置渲染器渲染的場景大小

        container = document.getElementById( 'WebGL-output' );
        container.appendChild( renderer.domElement );
        /*renderer的domElement元素,表示渲染器中的畫布,所有的渲染都是畫在domElement上的,所以這裏的appendChild表示將這個domElement掛接在id=WebGL-output的div下面,這樣渲染的結果就能夠在頁面中顯示了。*/

        //再設置相機控件,這行代碼能讓我們360°的旋轉相機
        controls = new THREE.OrbitControls( camera, renderer.domElement );

接着是創建天空盒的代碼:

        var path = "../examples/textures/cube/Park3Med/";//設置路徑
        var directions  = ["px", "nx", "py", "ny", "pz", "nz"];//獲取對象
        var format = ".jpg";//格式
        //創建盒子,並設置盒子的大小爲( 5000, 5000, 5000 )
        var skyGeometry = new THREE.BoxGeometry( 5000, 5000, 5000 );
        //設置盒子材質
        var materialArray = [];
        for (var i = 0; i < 6; i++)
            materialArray.push( new THREE.MeshBasicMaterial({
                map: THREE.ImageUtils.loadTexture( path + directions[i] + format ),//將圖片紋理貼上
                side: THREE.BackSide/*鏡像翻轉,如果設置鏡像翻轉,那麼只會看到黑漆漆的一片,因爲你身處在盒子的內部,所以一定要設置鏡像翻轉。*/
            }));
        var skyMaterial = new THREE.MeshFaceMaterial( materialArray );
        var skyBox = new THREE.Mesh( skyGeometry, skyMaterial );//創建一個完整的天空盒,填入幾何模型和材質的參數
        scene.add( skyBox );//在場景中加入天空盒

注意directions[]數組中的圖片順序是有要求而不是隨意的!否則加載的效果會錯亂。這張圖片會幫助你更好的理解:
這裏寫圖片描述
剩下的尾巴部分:

function animate()
    {
        requestAnimationFrame( animate );//渲染循環
        render();
        update();
    }

    function update()
    {
        controls.update();//實時更新相機操作
    }

    function render()
    {
        renderer.render( scene, camera );//實時渲染
    }

另一種作爲背景的方法的代碼如下:

        var path = "textures/cube/Park3Med/";       //設置路徑
        var format = '.jpg';                        //設定格式
        var urls = [
            path + 'px' + format, path + 'nx' + format,
            path + 'py' + format, path + 'ny' + format,
            path + 'pz' + format, path + 'nz' + format
        ];
        var textureCube = new THREE.CubeTextureLoader().load( urls );

        scene.background = textureCube; //作爲背景貼圖

還有另一種更簡潔的寫法是:

scene.background = new THREE.CubeTextureLoader()
         .setPath( 'textures/cube/Park3Med/' )
         .load( [ 'px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg' ] );

兩種方法只需要更換這部分代碼即可。
以下給出全部代碼:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Skybox</title>
    <style>
        body {
            background:#777;
            padding:0;
            margin:0;
            font-weight: bold;
            overflow:hidden;
        }
    </style>
</head>
<body>

<div id="WebGL-output"></div>
<script src="../build/three.js"></script>
<script src="../examples/js/controls/OrbitControls.js"></script>

<script>

    var scene, camera, renderer;
    var container, controls;


    init();
    animate();

    // FUNCTIONS
    function init()
    {
        // SCENE
        scene = new THREE.Scene();
        // CAMERA
        var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
        var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
        camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
        camera.position.set(0,150,400);
        camera.lookAt(scene.position);

        scene.add(camera);

        // RENDERER

        renderer = new THREE.WebGLRenderer( {antialias:true} );
        renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);

        container = document.getElementById( 'output' );
        container.appendChild( renderer.domElement );

        controls = new THREE.OrbitControls( camera, renderer.domElement );

        // LIGHT
        var light = new THREE.PointLight(0xffffff);
        light.position.set(0,250,0);
        scene.add(light);
        // FLOOR

        var path = "../examples/textures/cube/Park3Med/";
        var directions  = ["px", "nx", "py", "ny", "pz", "nz"];
        var format = ".jpg";
        var skyGeometry = new THREE.BoxGeometry( 5000, 5000, 5000 );

        var materialArray = [];
        for (var i = 0; i < 6; i++)
            materialArray.push( new THREE.MeshBasicMaterial({
                map: THREE.ImageUtils.loadTexture( path + directions[i] + format ),
                side: THREE.BackSide
            }));
        var skyMaterial = new THREE.MeshFaceMaterial( materialArray );
        var skyBox = new THREE.Mesh( skyGeometry, skyMaterial );
        //skyBox.scale.x=-1;也是鏡像翻轉,與上面的side一個效果
        scene.add( skyBox );

    }

    function animate()
    {
        requestAnimationFrame( animate );
        render();
        update();
    }

    function update()
    {
        controls.update();
    }

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

</script>
</body>
</html>

以上有一段代碼是燈光的設置加入,這裏可以註釋掉,不影響天空盒的效果。但是如果你要在天空盒中加入物體,則需要設置燈光,否則加入場景的物體將會是黑色的。
以上就是筆者的一些見解,若有不對的對方,歡迎指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章