Three.js構造一個簡單的房間

  主要研究three.js在3D場景中基本使用:畫一個簡單的房子、房子上畫門和玻璃、房間內放一個牀、定義鼠標事件能夠移動場景、動畫的使用等。javascript

1.Three.js畫的一個簡單的房子,模擬地板以及四堵牆 

準備素材:

3.jpg模擬地板html

 

4.jpg模擬牆java

 

 

代碼:

<!DOCTYPE html>

<html>

<head>
    <title>myHouse</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/OBJLoader.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
    var scene,camera,webGLRenderer,stats;

    function init() {
        stats = initStats();

        scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.x = 20;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(scene.position);
        scene.add(camera);

        // create a render and set the size
        webGLRenderer = new THREE.WebGLRenderer({
            antialias : true,
            alpha:true
        });
        webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;

        // add spotlight for the shadows
        var spotLight = new THREE.PointLight(0xffffff);
        spotLight.position.set(30, 40, 50);
        scene.add(spotLight);

        initObjects();

        // add the output of the renderer to the html element
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        render();
    }

    function initObjects(){
        paintFloor();
        paintWalls(40, 2, 10, 0, 0, -20, 1/2,0);//後面牆
        paintWalls(40, 2, 10, 0, 0, 20, 1/2, 0);//前面牆
        paintWalls(42, 2, 10, -20, 0, 0, 1/2, 0, 1/2);//左面牆
        paintWalls(42, 2, 10, 20, 0, 0, 1/2, 0, 1/2);//右面牆
    }

    var paintFloor = function (){
        var loader = new THREE.TextureLoader;
        loader.load('./img/3.jpg', function (texture) {
            //x和y超過圖片像素以後重複繪製圖片
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            //設置地板重複繪製的密度是1 * 1
            texture.repeat.set(1, 1);

            //設置材質是雙面材質
            var material = new THREE.MeshLambertMaterial({
                map : texture,
                side : THREE.DoubleSide
            });

            //建立普通的平面幾何體
            var gemotery = new THREE.PlaneGeometry(40,40);

            //建立網格對象
            var mesh = new THREE.Mesh(gemotery,material);
            mesh.position.y = 0;
            mesh.rotation.x = Math.PI/2;

            scene.add(mesh);
        });
    }

    var paintWalls = function (width, depth, height, x, y, z, rotationX, rotationY, rotationZ){
        var loader = new THREE.TextureLoader;
        loader.load('./img/4.jpg', function (texture) {
            //x和y超過圖片像素以後重複繪製圖片
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            //設置地板重複繪製的密度是1 * 1
            texture.repeat.set(1,1);

            var material = new THREE.MeshLambertMaterial({
                map : texture,
                side : THREE.DoubleSide
            });

            //建立長方體幾何體
            var gemotery = new THREE.BoxGeometry(width, depth, height);

            //建立網格對象以及進行位置的設定
            var mesh = new THREE.Mesh(gemotery,material);
            mesh.position.set(x,y,z)
            mesh.rotation.x = Math.PI * rotationX;
            mesh.rotation.y = Math.PI * rotationY;
            if(rotationZ){
                mesh.rotation.z = Math.PI * rotationZ;
            }

            scene.add(mesh);
        });
    }

    function render() {
        requestAnimationFrame(render);
        webGLRenderer.render(scene, camera);

        if(stats){
            stats.update();
        }
    }

    function initStats() {
        var stats = new Stats();
        stats.setMode(0); // 0: fps, 1: ms

        // Align top-left
        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';
        document.getElementById("Stats-output").appendChild(stats.domElement);

        return stats;
    }

    window.onload = init;
</script>
</body>
</html>

結果:jquery

 

 2.增長鼠標事件和鍵盤事件控制攝像頭進而模擬在房間內行走

  控制器的使用,主要的控制器以下:git

 

  • 軌跡球控制器的使用:(使用鼠標改變場景以及在界面實時顯示相機的位置)

可用的鼠標事件以下:github

 

(1)引入相關JS:web

 <script type="text/javascript" src="../libs/TrackballControls.js"></script>

(2)建立控制器並綁定到相機上app

    //鼠標控制動畫相關組件
    var trackballControls, clock;
    function initTrackballControls(){
        clock = new THREE.Clock();

        trackballControls = new THREE.TrackballControls(camera);

        trackballControls.rotateSpeed = 1.0;
        trackballControls.zoomSpeed = 1.0;
        trackballControls.panSpeed = 1.0;
        //        trackballControls.noZoom=false;
        //        trackballControls.noPan=false;
        trackballControls.staticMoving = true;
        //        trackballControls.dynamicDampingFactor=0.3;
    }

(3)攝像機的位置更新在render循環中完成dom

    function render() {
        requestAnimationFrame(render);
        webGLRenderer.render(scene, camera);

        //鼠標事件
        var delta = clock.getDelta();
        trackballControls.update(delta);
        logCameraPosition();

        if(stats){
            stats.update();
        }
    }

    function logCameraPosition(){
        var logInfo = "[info]: x - " + camera.position.x + " ;y - " + camera.position.y + " ;z - " + camera.position.z;
        $("#logInfo").html(logInfo);
    }

若是禁用鼠標縮放能夠將noZoom設爲true。 ide

 

代碼以下:

<!DOCTYPE html>

<html>

<head>
    <title>myHouse</title>
    <script type="text/javascript" src="../libs/jquery-1.9.0.js"></script>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/OBJLoader.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <script type="text/javascript" src="../libs/TrackballControls.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<div id="logInfo" style="position: absolute; top: 0px; left: 20%; width: 50%; padding: 5px;"></div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
    //基本組件
    var scene, camera, webGLRenderer, stats;
    //鼠標控制動畫相關組件
    var trackballControls, clock;

    function init() {
        stats = initStats();

        scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.x = 20;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(scene.position);
        scene.add(camera);

        // create a render and set the size
        webGLRenderer = new THREE.WebGLRenderer({
            antialias : true,
            alpha:true
        });
        webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;

        // add spotlight for the shadows
        var spotLight = new THREE.PointLight(0xffffff);
        spotLight.position.set(30, 40, 50);
        scene.add(spotLight);

        initObjects();

        // add the output of the renderer to the html element
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        render();
    }

    function initObjects(){
        paintFloor();

        //畫牆--通常y取高度的1/2
        paintWalls(40, 2, 10, 0, 5, -20, 1/2,0);//後面牆
        paintWalls(40, 2, 10, 0, 5, 20, 1/2, 0);//前面牆
        paintWalls(42, 2, 10, -20, 5, 0, 1/2, 0, 1/2);//左面牆
        paintWalls(42, 2, 10, 20, 5, 0, 1/2, 0, 1/2);//右面牆

        initTrackballControls();
    }


    function render() {
        requestAnimationFrame(render);
        webGLRenderer.render(scene, camera);

        //鼠標事件
        var delta = clock.getDelta();
        trackballControls.update(delta);
        logCameraPosition();

        if(stats){
            stats.update();
        }
    }

    function logCameraPosition(){
        var logInfo = "[info]: x - " + camera.position.x + " ;y - " + camera.position.y + " ;z - " + camera.position.z;
        $("#logInfo").html(logInfo);
    }

    function initTrackballControls(){
        clock = new THREE.Clock();

        trackballControls = new THREE.TrackballControls(camera);

        trackballControls.rotateSpeed = 1.0;
        trackballControls.zoomSpeed = 1.0;
        trackballControls.panSpeed = 1.0;
        //        trackballControls.noZoom=false;
        //        trackballControls.noPan=false;
        trackballControls.staticMoving = true;
        //        trackballControls.dynamicDampingFactor=0.3;
    }

    var paintFloor = function (){
        var loader = new THREE.TextureLoader;
        loader.load('./img/3.jpg', function (texture) {
            //x和y超過圖片像素以後重複繪製圖片
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            //設置地板重複繪製的密度是1 * 1
            texture.repeat.set(1, 1);

            //設置材質是雙面材質
            var material = new THREE.MeshLambertMaterial({
                map : texture,
                side : THREE.DoubleSide
            });

            //建立普通的平面幾何體
            var gemotery = new THREE.PlaneGeometry(40,40);

            //建立網格對象
            var mesh = new THREE.Mesh(gemotery,material);
            mesh.position.y = 0;
            mesh.rotation.x = Math.PI/2;

            scene.add(mesh);
        });
    }

    var paintWalls = function (width, depth, height, x, y, z, rotationX, rotationY, rotationZ){
        var loader = new THREE.TextureLoader;
        loader.load('./img/4.jpg', function (texture) {
            //x和y超過圖片像素以後重複繪製圖片
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            //設置地板重複繪製的密度是1 * 1
            texture.repeat.set(1,1);

            var material = new THREE.MeshLambertMaterial({
                map : texture,
                side : THREE.DoubleSide
            });

            //建立長方體幾何體
            var gemotery = new THREE.BoxGeometry(width, depth, height);

            //建立網格對象以及進行位置的設定
            var mesh = new THREE.Mesh(gemotery,material);
            mesh.position.set(x,y,z)
            mesh.rotation.x = Math.PI * rotationX;
            mesh.rotation.y = Math.PI * rotationY;
            if(rotationZ){
                mesh.rotation.z = Math.PI * rotationZ;
            }

            scene.add(mesh);
        });
    }

    function initStats() {
        var stats = new Stats();
        stats.setMode(0); // 0: fps, 1: ms

        // Align top-left
        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';
        document.getElementById("Stats-output").appendChild(stats.domElement);

        return stats;
    }

    window.onload = init;
</script>
</body>
</html>

效果:

 

  • 軌道控制器(支持鼠標和鍵盤事件)

其支持的事件以下:

(1)使用的類庫是:https://github.com/mrdoob/three.js/blob/dev/examples/js/controls/OrbitControls.js

(2)初始化control便可

    function initOrbitControls(){
        controls = new THREE.OrbitControls(camera,webGLRenderer.domElement);

        controls.minDistance = 1;
        controls.maxDistance = 5000;
    }

代碼以下:

<!DOCTYPE html>
<!--房子中間加個牀,採用封裝過的API實現 (採用軌道控制器)-->
<html>

<head>
    <title>myHouse</title>
    <script type="text/javascript" src="../libs/jquery-1.9.0.js"></script>
    <script type="text/javascript" src="../libs2/three.js"></script>
    <script type="text/javascript" src="../libs2/OBJLoader.js"></script>
    <script type="text/javascript" src="../libs2/stats.js"></script>
    <script type="text/javascript" src="../libs2/WebGL.js"></script>
    <script type="text/javascript" src="../libs2/OrbitControls.js"></script>
    <script type="text/javascript" src="../libs2/onEvent.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<div id="logInfo" style="position: absolute; top: 0px; left: 20%; width: 50%; padding: 5px;"></div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
    //基本組件
    var scene, camera, webGLRenderer, stats;
    //鼠標控制動畫相關組件
    var controls;
    //事件相關
    var threeOnEvent;

    function init() {
        stats = initStats();

        scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.x = 20;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(scene.position);
        scene.add(camera);

        // create a render and set the size
        webGLRenderer = new THREE.WebGLRenderer({
            antialias : true,
            alpha:true
        });
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.setPixelRatio(window.devicePixelRatio);
        webGLRenderer.setClearColor(0xEEEEEE, 1.0);
        webGLRenderer.shadowMapEnabled = true;

        // add spotlight for the shadows
        var spotLight = new THREE.PointLight(0xffffff);
        spotLight.position.set(30, 40, 50);
        scene.add(spotLight);

        initObjects();

        // add the output of the renderer to the html element
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        render();
    }

    function initObjects(){
        initEvent();

        paintFloor();

        //畫牆--通常y取高度的1/2
        paintWalls(40, 2, 10, 0, 5, -20, 1/2,0);//後面牆
        paintWalls(40, 2, 10, 0, 5, 20, 1/2, 0);//前面牆
        paintWalls(42, 2, 10, -20, 5, 0, 1/2, 0, 1/2);//左面牆
        paintWalls(42, 2, 10, 20, 5, 0, 1/2, 0, 1/2);//右面牆

        initOrbitControls();

        paintBed();
    }

    var paintBed = function(){
        var textures = [];
        loadBedTextures(textures, 0, "./img/bedplate.jpg"); //right
        loadBedTextures(textures, 1, "./img/bedplate.jpg"); //left
        loadBedTextures(textures, 2, "./img/bedplate.jpg"); //front
        loadBedTextures(textures, 3, "./img/bedplate.jpg");//back
        loadBedTextures(textures, 4, "./img/bedplate.jpg"); //bottom
        loadBedTextures(textures, 5, "./img/mattess.jpg"); //top

        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(10, 10, 5);

        //建立網格對象以及進行位置的設定
        var mesh = new THREE.Mesh(gemotery, textures);
        mesh.position.set(0, 2.5, 0)
        mesh.rotation.x = Math.PI * 1/2;

        //綁定一些數據
        mesh.tags = "bed";
        mesh.userData.ID = 1;
        mesh.name = "myBed";

        //增長事件(點擊事件)
        mesh.on('click',function(m) {//m表明mesh對象
           alert('1');
        })

        // hover eventLisener(鼠標懸浮事件)
        mesh.on('hover',function(m) {
            // mouse enter the mesh
            alert(m.name + "  " + m.tags + " " + mesh.userData.ID);
        },function(m) {
            // mouse leave out the mesh
        });

        scene.add(mesh);
    }

    function loadBedTextures(textures, index, url){
        textures[index] = new THREE.MeshBasicMaterial({
           map : new THREE.TextureLoader().load(url)
        });
    }

    function initEvent(){
        threeOnEvent = new THREE.onEvent(scene,camera);
    }


    function render() {
        requestAnimationFrame(render);
        webGLRenderer.render(scene, camera);

        //鼠標事件
        logCameraPosition();

        if(stats){
            stats.update();
        }

        //更新事件
        threeOnEvent.update();
    }

    function logCameraPosition(){
        var logInfo = "[info]: x - " + camera.position.x + " ;y - " + camera.position.y + " ;z - " + camera.position.z;
        $("#logInfo").html(logInfo);
    }

    function initOrbitControls(){
        controls = new THREE.OrbitControls(camera,webGLRenderer.domElement);

        controls.minDistance = 1;
        controls.maxDistance = 5000;
    }

    var paintFloor = function (){
        var loader = new THREE.TextureLoader;
        loader.load('./img/3.jpg', function (texture) {
            //x和y超過圖片像素以後重複繪製圖片
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            //設置地板重複繪製的密度是1 * 1
            texture.repeat.set(1, 1);

            //設置材質是雙面材質
            var material = new THREE.MeshLambertMaterial({
                map : texture,
                side : THREE.DoubleSide
            });

            //建立普通的平面幾何體
            var gemotery = new THREE.PlaneGeometry(40,40);

            //建立網格對象
            var mesh = new THREE.Mesh(gemotery,material);
            mesh.position.y = 0;
            mesh.rotation.x = Math.PI/2;

            scene.add(mesh);
        });
    }

    var paintWalls = function (width, depth, height, x, y, z, rotationX, rotationY, rotationZ){
        var loader = new THREE.TextureLoader;
        loader.load('./img/4.jpg', function (texture) {
            //x和y超過圖片像素以後重複繪製圖片
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            //設置地板重複繪製的密度是1 * 1
            texture.repeat.set(1,1);

            var material = new THREE.MeshLambertMaterial({
                map : texture,
                side : THREE.DoubleSide
            });

            //建立長方體幾何體
            var gemotery = new THREE.BoxGeometry(width, depth, height);

            //建立網格對象以及進行位置的設定
            var mesh = new THREE.Mesh(gemotery,material);
            mesh.position.set(x,y,z)
            mesh.rotation.x = Math.PI * rotationX;
            mesh.rotation.y = Math.PI * rotationY;
            if(rotationZ){
                mesh.rotation.z = Math.PI * rotationZ;
            }

            scene.add(mesh);
        });
    }

    function initStats() {
        var stats = new Stats();
        stats.setMode(0); // 0: fps, 1: ms

        // Align top-left
        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';
        document.getElementById("Stats-output").appendChild(stats.domElement);

        return stats;
    }

    window.onload = init;
</script>
</body>
</html>

 

 

3.場景中添加一個牀 (六面體),而且自定義鼠標點擊事件懸浮在牀上的時候彈出框

   這個都採用的是git上封裝過的JS庫來實現的,參考git地址:https://github.com/mrdoob/three.js/

  three.js的事件機制用到的是onEvent,參考:https://github.com/YoneChen/three-onEvent

  也經過tags、userData、name進行數據的綁定。

 

代碼以下:

<!DOCTYPE html>
<!--房子中間加個牀,採用封裝過的API實現-->
<html>

<head>
    <title>myHouse</title>
    <script type="text/javascript" src="../libs/jquery-1.9.0.js"></script>
    <script type="text/javascript" src="../libs2/three.js"></script>
    <script type="text/javascript" src="../libs2/OBJLoader.js"></script>
    <script type="text/javascript" src="../libs2/stats.js"></script>
    <script type="text/javascript" src="../libs2/WebGL.js"></script>
    <script type="text/javascript" src="../libs2/TrackballControls.js"></script>
    <script type="text/javascript" src="../libs2/onEvent.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<div id="logInfo" style="position: absolute; top: 0px; left: 20%; width: 50%; padding: 5px;"></div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
    //基本組件
    var scene, camera, webGLRenderer, stats;
    //鼠標控制動畫相關組件
    var trackballControls, clock;
    //事件相關
    var threeOnEvent;

    function init() {
        stats = initStats();

        scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.x = 20;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(scene.position);
        scene.add(camera);

        // create a render and set the size
        webGLRenderer = new THREE.WebGLRenderer({
            antialias : true,
            alpha:true
        });
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.setPixelRatio(window.devicePixelRatio);
        webGLRenderer.setClearColor(0xEEEEEE, 1.0);
        webGLRenderer.shadowMapEnabled = true;

        // add spotlight for the shadows
        var spotLight = new THREE.PointLight(0xffffff);
        spotLight.position.set(30, 40, 50);
        scene.add(spotLight);

        initObjects();

        // add the output of the renderer to the html element
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        render();
    }

    function initObjects(){
        initEvent();

        paintFloor();

        //畫牆--通常y取高度的1/2
        paintWalls(40, 2, 10, 0, 5, -20, 1/2,0);//後面牆
        paintWalls(40, 2, 10, 0, 5, 20, 1/2, 0);//前面牆
        paintWalls(42, 2, 10, -20, 5, 0, 1/2, 0, 1/2);//左面牆
        paintWalls(42, 2, 10, 20, 5, 0, 1/2, 0, 1/2);//右面牆

        initTrackballControls();

        paintBed();
    }

    var paintBed = function(){
        var textures = [];
        loadBedTextures(textures, 0, "./img/bedplate.jpg"); //right
        loadBedTextures(textures, 1, "./img/bedplate.jpg"); //left
        loadBedTextures(textures, 2, "./img/bedplate.jpg"); //front
        loadBedTextures(textures, 3, "./img/bedplate.jpg");//back
        loadBedTextures(textures, 4, "./img/bedplate.jpg"); //bottom
        loadBedTextures(textures, 5, "./img/mattess.jpg"); //top

        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(10, 10, 5);

        //建立網格對象以及進行位置的設定
        var mesh = new THREE.Mesh(gemotery, textures);
        mesh.position.set(0, 2.5, 0)
        mesh.rotation.x = Math.PI * 1/2;

        //綁定一些數據
        mesh.tags = "bed";
        mesh.userData.ID = 1;
        mesh.name = "myBed";

        //增長事件(點擊事件)
        mesh.on('click',function(m) {//m表明mesh對象
           alert('1');
        })

        // hover eventLisener(鼠標懸浮事件)
        mesh.on('hover',function(m) {
            // mouse enter the mesh
            alert(m.name + "  " + m.tags + " " + mesh.userData.ID);
        },function(m) {
            // mouse leave out the mesh
        });

        scene.add(mesh);
    }

    function loadBedTextures(textures, index, url){
        textures[index] = new THREE.MeshBasicMaterial({
           map : new THREE.TextureLoader().load(url)
        });
    }

    function initEvent(){
        threeOnEvent = new THREE.onEvent(scene,camera);
    }


    function render() {
        requestAnimationFrame(render);
        webGLRenderer.render(scene, camera);

        //鼠標事件
        var delta = clock.getDelta();
        trackballControls.update(delta);
        logCameraPosition();

        if(stats){
            stats.update();
        }

        //更新事件
        threeOnEvent.update();
    }

    function logCameraPosition(){
        var logInfo = "[info]: x - " + camera.position.x + " ;y - " + camera.position.y + " ;z - " + camera.position.z;
        $("#logInfo").html(logInfo);
    }

    function initTrackballControls(){
        clock = new THREE.Clock();

        trackballControls = new THREE.TrackballControls(camera);

        trackballControls.rotateSpeed = 1.0;
        trackballControls.zoomSpeed = 1.0;
        trackballControls.panSpeed = 1.0;
        //        trackballControls.noZoom=false;
        //        trackballControls.noPan=false;
        trackballControls.staticMoving = true;
        //        trackballControls.dynamicDampingFactor=0.3;
    }

    var paintFloor = function (){
        var loader = new THREE.TextureLoader;
        loader.load('./img/3.jpg', function (texture) {
            //x和y超過圖片像素以後重複繪製圖片
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            //設置地板重複繪製的密度是1 * 1
            texture.repeat.set(1, 1);

            //設置材質是雙面材質
            var material = new THREE.MeshLambertMaterial({
                map : texture,
                side : THREE.DoubleSide
            });

            //建立普通的平面幾何體
            var gemotery = new THREE.PlaneGeometry(40,40);

            //建立網格對象
            var mesh = new THREE.Mesh(gemotery,material);
            mesh.position.y = 0;
            mesh.rotation.x = Math.PI/2;

            scene.add(mesh);
        });
    }

    var paintWalls = function (width, depth, height, x, y, z, rotationX, rotationY, rotationZ){
        var loader = new THREE.TextureLoader;
        loader.load('./img/4.jpg', function (texture) {
            //x和y超過圖片像素以後重複繪製圖片
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            //設置地板重複繪製的密度是1 * 1
            texture.repeat.set(1,1);

            var material = new THREE.MeshLambertMaterial({
                map : texture,
                side : THREE.DoubleSide
            });

            //建立長方體幾何體
            var gemotery = new THREE.BoxGeometry(width, depth, height);

            //建立網格對象以及進行位置的設定
            var mesh = new THREE.Mesh(gemotery,material);
            mesh.position.set(x,y,z)
            mesh.rotation.x = Math.PI * rotationX;
            mesh.rotation.y = Math.PI * rotationY;
            if(rotationZ){
                mesh.rotation.z = Math.PI * rotationZ;
            }

            scene.add(mesh);
        });
    }

    function initStats() {
        var stats = new Stats();
        stats.setMode(0); // 0: fps, 1: ms

        // Align top-left
        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';
        document.getElementById("Stats-output").appendChild(stats.domElement);

        return stats;
    }

    window.onload = init;
</script>
</body>
</html>

結果:

4.  在牆上挖一個玻璃

  在牆上挖玻璃須要用到ThreeBSP.js,實際上就是求兩個物體的差集以後進行添加;若是須要挖一個門,須要作的操做是:先在牆上求牆和門的差集獲得一個mesh對象添加到scene中,並將門也添加到scene便可實現。

代碼以下:

<!DOCTYPE html>
<!--房子中間加個牀,採用封裝過的API實現-->
<html>

<head>
    <title>myHouse</title>
    <script type="text/javascript" src="../libs/jquery-1.9.0.js"></script>
    <script type="text/javascript" src="../libs2/three.js"></script>
    <script type="text/javascript" src="../libs2/OBJLoader.js"></script>
    <script type="text/javascript" src="../libs2/stats.js"></script>
    <script type="text/javascript" src="../libs2/WebGL.js"></script>
    <script type="text/javascript" src="../libs2/TrackballControls.js"></script>
    <script type="text/javascript" src="../libs2/onEvent.js"></script>
    <script type="text/javascript" src="../libs2/ThreeBSP.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<div id="logInfo" style="position: absolute; top: 0px; left: 20%; width: 50%; padding: 5px;"></div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
    //基本組件
    var scene, camera, webGLRenderer, stats;
    //鼠標控制動畫相關組件
    var trackballControls, clock;
    //事件相關
    var threeOnEvent;

    function init() {
        stats = initStats();

        scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.x = 20;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(scene.position);
        scene.add(camera);

        // create a render and set the size
        webGLRenderer = new THREE.WebGLRenderer({
            antialias : true,
            alpha:true
        });
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.setPixelRatio(window.devicePixelRatio);
        webGLRenderer.setClearColor(0xEEEEEE, 1.0);
        webGLRenderer.shadowMapEnabled = true;

        // add spotlight for the shadows
        var spotLight = new THREE.PointLight(0xffffff);
        spotLight.position.set(30, 40, 50);
        scene.add(spotLight);

        initObjects();

        // add the output of the renderer to the html element
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        render();
    }

    function initObjects(){
        initEvent();

        paintFloor();

        //畫牆--通常y取高度的1/2
        paintWalls(40, 2, 10, 0, 5, -20, 1/2, 0, 0,true);//後面牆
        paintWalls(40, 2, 10, 0, 5, 20, 1/2, 0, 0,true);//前面牆
        paintWalls(42, 2, 10, -20, 5, 0, 1/2, 0, 1/2, true);//左面牆
        //添加帶玻璃的牆
        var wallMesh = paintWalls(42, 2, 10, 20, 5, 0, 1/2, 0, 1/2, false);//右面牆
        var windowMesh = paintGlass(10, 2, 6, 20, 3, 0, 1/2, 0, 1/2, false);
        var resultMesh = createResultMesh(wallMesh, windowMesh, true);
        scene.add(resultMesh);

        initTrackballControls();

        paintBed();
    }

    function createResultMesh(srcMesh, destMesh, addDest){
        var srcBSP = new ThreeBSP(srcMesh);
        var destBSP = new ThreeBSP(destMesh);
        var resultBSP = srcBSP.subtract(destBSP);
        var result = resultBSP.toMesh(srcMesh.material);
        result.geometry.computeFaceNormals();
        result.geometry.computeVertexNormals();
        if(addDest){
            scene.add(destMesh);
        }

        return result;
    }

    var paintBed = function(){
        var textures = [];
        loadBedTextures(textures, 0, "./img/bedplate.jpg"); //right
        loadBedTextures(textures, 1, "./img/bedplate.jpg"); //left
        loadBedTextures(textures, 2, "./img/bedplate.jpg"); //front
        loadBedTextures(textures, 3, "./img/bedplate.jpg");//back
        loadBedTextures(textures, 4, "./img/bedplate.jpg"); //bottom
        loadBedTextures(textures, 5, "./img/mattess.jpg"); //top

        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(10, 10, 5);

        //建立網格對象以及進行位置的設定
        var mesh = new THREE.Mesh(gemotery, textures);
        mesh.position.set(0, 2.5, 0)
        mesh.rotation.x = Math.PI * 1/2;

        //綁定一些數據
        mesh.tags = "bed";
        mesh.userData.ID = 1;
        mesh.name = "myBed";

        //增長事件(點擊事件)
        mesh.on('click',function(m) {//m表明mesh對象
           alert('1');
        })

        // hover eventLisener(鼠標懸浮事件)
        mesh.on('hover',function(m) {
            // mouse enter the mesh
            alert(m.name + "  " + m.tags + " " + mesh.userData.ID);
        },function(m) {
            // mouse leave out the mesh
        });

        scene.add(mesh);
    }

    function loadBedTextures(textures, index, url){
        textures[index] = new THREE.MeshBasicMaterial({
           map : new THREE.TextureLoader().load(url)
        });
    }

    function initEvent(){
        threeOnEvent = new THREE.onEvent(scene,camera);
    }


    function render() {
        requestAnimationFrame(render);
        webGLRenderer.render(scene, camera);

        //鼠標事件
        var delta = clock.getDelta();
        trackballControls.update(delta);
        logCameraPosition();

        if(stats){
            stats.update();
        }

        //更新事件
        threeOnEvent.update();
    }

    function logCameraPosition(){
        var logInfo = "[info]: x - " + camera.position.x + " ;y - " + camera.position.y + " ;z - " + camera.position.z;
        $("#logInfo").html(logInfo);
    }

    function initTrackballControls(){
        clock = new THREE.Clock();

        trackballControls = new THREE.TrackballControls(camera);

        trackballControls.rotateSpeed = 1.0;
        trackballControls.zoomSpeed = 1.0;
        trackballControls.panSpeed = 1.0;
        //        trackballControls.noZoom=false;
        //        trackballControls.noPan=false;
        trackballControls.staticMoving = true;
        //        trackballControls.dynamicDampingFactor=0.3;
    }

    var paintFloor = function (){
        var loader = new THREE.TextureLoader;
        loader.load('./img/3.jpg', function (texture) {
            //x和y超過圖片像素以後重複繪製圖片
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            //設置地板重複繪製的密度是1 * 1
            texture.repeat.set(1, 1);

            //設置材質是雙面材質
            var material = new THREE.MeshLambertMaterial({
                map : texture,
                side : THREE.DoubleSide
            });

            //建立普通的平面幾何體
            var gemotery = new THREE.PlaneGeometry(40,40);

            //建立網格對象
            var mesh = new THREE.Mesh(gemotery,material);
            mesh.position.y = 0;
            mesh.rotation.x = Math.PI/2;

            scene.add(mesh);
        });
    }

    var paintWalls = function (width, depth, height, x, y, z, rotationX, rotationY, rotationZ, addMesh){
        var loader = new THREE.TextureLoader;
        var texture = new THREE.TextureLoader().load('./img/4.jpg');
        texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
        //設置地板重複繪製的密度是1 * 1
        texture.repeat.set(1,1);

        var material = new THREE.MeshLambertMaterial({
            map : texture,
            side : THREE.DoubleSide
        });

        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(width, depth, height);

        //建立網格對象以及進行位置的設定
        var mesh = new THREE.Mesh(gemotery,material);
        mesh.position.set(x,y,z)
        mesh.rotation.x = Math.PI * rotationX;
        mesh.rotation.y = Math.PI * rotationY;
        if(rotationZ) {
            mesh.rotation.z = Math.PI * rotationZ;
        }

        if(addMesh) {
            scene.add(mesh);
        }

        return mesh;
    }

    var paintGlass = function (width, depth, height, x, y, z, rotationX, rotationY, rotationZ, addMesh){
        var material = new THREE.MeshBasicMaterial({
            color : 0x58ACFA,
            transparent : true,
            opacity : 0.6
        });

        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(width, depth, height);

        //建立網格對象以及進行位置的設定
        var mesh = new THREE.Mesh(gemotery,material);
        mesh.position.set(x,y,z)
        mesh.rotation.x = Math.PI * rotationX;
        mesh.rotation.y = Math.PI * rotationY;
        if(rotationZ) {
            mesh.rotation.z = Math.PI * rotationZ;
        }

        if(addMesh) {
            scene.add(mesh);
        }

        return mesh;
    }

    function initStats() {
        var stats = new Stats();
        stats.setMode(0); // 0: fps, 1: ms

        // Align top-left
        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';
        document.getElementById("Stats-output").appendChild(stats.domElement);

        return stats;
    }

    window.onload = init;
</script>
</body>
</html>

結果:

5.Tween動畫實現旋轉牀

  tween.js是一款可生成平滑動畫效果的js動畫庫。你只須要告訴tween你想修改什麼值,以及動畫結束時它的最終值是什麼,動畫花費多少時間等信息,tween引擎就能夠計算從開始動畫點到結束動畫點之間值,來產平生滑的動畫效果。  其詳細用法參考: http://www.javashuo.com/article/p-mvfhypgv-cx.html

 代碼:

<!DOCTYPE html>
<!--房子中間加個牀,採用封裝過的API實現,動態改變牀的位置-->
<html>

<head>
    <title>myHouse</title>
    <script type="text/javascript" src="../libs/jquery-1.9.0.js"></script>
    <script type="text/javascript" src="../libs2/three.js"></script>
    <script type="text/javascript" src="../libs2/OBJLoader.js"></script>
    <script type="text/javascript" src="../libs2/stats.js"></script>
    <script type="text/javascript" src="../libs2/WebGL.js"></script>
    <script type="text/javascript" src="../libs2/TrackballControls.js"></script>
    <script type="text/javascript" src="../libs2/onEvent.js"></script>
    <script type="text/javascript" src="../libs2/ThreeBSP.js"></script>
    <script type="text/javascript" src="../libs2/tween.min.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<div id="logInfo" style="position: absolute; top: 0px; left: 20%; width: 50%; padding: 5px;"></div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
    //基本組件
    var scene, camera, webGLRenderer, stats;
    //鼠標控制動畫相關組件
    var trackballControls, clock;
    //事件相關
    var threeOnEvent;

    function init() {
        stats = initStats();

        scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.x = 20;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(scene.position);
        scene.add(camera);

        // create a render and set the size
        webGLRenderer = new THREE.WebGLRenderer({
            antialias : true,
            alpha:true
        });
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.setPixelRatio(window.devicePixelRatio);
        webGLRenderer.setClearColor(0xEEEEEE, 1.0);
        webGLRenderer.shadowMapEnabled = true;

        // add spotlight for the shadows
        var spotLight = new THREE.PointLight(0xffffff);
        spotLight.position.set(30, 40, 50);
        scene.add(spotLight);

        initObjects();

        // add the output of the renderer to the html element
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        render();
    }

    function initObjects(){
        initEvent();

        paintFloor();

        //畫牆--通常y取高度的1/2
        paintWalls(40, 2, 10, 0, 5, -20, 1/2, 0, 0,true);//後面牆
        paintWalls(40, 2, 10, 0, 5, 20, 1/2, 0, 0,true);//前面牆
        paintWalls(42, 2, 10, -20, 5, 0, 1/2, 0, 1/2, true);//左面牆
        //添加帶玻璃的牆
        var wallMesh = paintWalls(42, 2, 10, 20, 5, 0, 1/2, 0, 1/2, false);//右面牆
        var windowMesh = paintGlass(10, 2, 6, 20, 3, 0, 1/2, 0, 1/2, false);
        var resultMesh = createResultMesh(wallMesh, windowMesh, true);
        scene.add(resultMesh);

        initTrackballControls();

        paintBed();
    }

    function createResultMesh(srcMesh, destMesh, addDest) {
        var srcBSP = new ThreeBSP(srcMesh);
        var destBSP = new ThreeBSP(destMesh);
        var resultBSP = srcBSP.subtract(destBSP);
        var result = resultBSP.toMesh(srcMesh.material);
        result.geometry.computeFaceNormals();
        result.geometry.computeVertexNormals();
        if(addDest){
            scene.add(destMesh);
        }

        return result;
    }

    var paintBed = function(){
        var textures = [];
        loadBedTextures(textures, 0, "./img/bedplate.jpg"); //right
        loadBedTextures(textures, 1, "./img/bedplate.jpg"); //left
        loadBedTextures(textures, 2, "./img/bedplate.jpg"); //front
        loadBedTextures(textures, 3, "./img/bedplate.jpg");//back
        loadBedTextures(textures, 4, "./img/bedplate.jpg"); //bottom
        loadBedTextures(textures, 5, "./img/mattess.jpg"); //top

        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(10, 10, 5);

        //建立網格對象以及進行位置的設定
        var mesh = new THREE.Mesh(gemotery, textures);
        mesh.position.set(0, 2.5, 0)
        mesh.rotation.x = Math.PI * 1/2;

        //綁定一些數據
        mesh.tags = "bed";
        mesh.userData.ID = 1;
        mesh.name = "myBed";

        //增長事件(點擊事件)
        mesh.on('click',function(m) {//m表明mesh對象
           alert('1');
        })

        // hover eventLisener(鼠標懸浮事件)
        mesh.on('hover',function(m) {
            // mouse enter the mesh
            alert(m.name + "  " + m.tags + " " + mesh.userData.ID);
        },function(m) {
            // mouse leave out the mesh
        });

        scene.add(mesh);

        startAnnotation(mesh);
    }

    function startAnnotation(mesh) {
        var indexNumber = {
            indexNumber : 0
        };
        var currentTween = new TWEEN.Tween(indexNumber).to({
            indexNumber : 2
        },5000);
        currentTween.easing(TWEEN.Easing.Sinusoidal.InOut);
        currentTween.repeat(60);//重複次數
        currentTween.yoyo(true);//結束以後反方向反彈

        currentTween.onUpdate(function(){
            var indexNumber = this.indexNumber;
            //改變牀的旋轉角度實現旋轉牀
            mesh.rotation.z = Math.PI * indexNumber;

            //也能夠根據數字的範圍進行一些其餘動畫(好比說實現閃爍效果等)
            if(indexNumber < 1){
            } else {
            }
        });
        currentTween.start();
    }

    function loadBedTextures(textures, index, url){
        textures[index] = new THREE.MeshBasicMaterial({
           map : new THREE.TextureLoader().load(url)
        });
    }

    function initEvent(){
        threeOnEvent = new THREE.onEvent(scene,camera);
    }


    function render() {
        requestAnimationFrame(render);
        webGLRenderer.render(scene, camera);

        //鼠標事件
        var delta = clock.getDelta();
        trackballControls.update(delta);
        logCameraPosition();

        if(stats){
            stats.update();
        }

        //更新事件
        threeOnEvent.update();

        //動畫
        TWEEN.update();
    }

    function logCameraPosition(){
        var logInfo = "[info]: x - " + camera.position.x + " ;y - " + camera.position.y + " ;z - " + camera.position.z;
        $("#logInfo").html(logInfo);
    }

    function initTrackballControls(){
        clock = new THREE.Clock();

        trackballControls = new THREE.TrackballControls(camera);

        trackballControls.rotateSpeed = 1.0;
        trackballControls.zoomSpeed = 1.0;
        trackballControls.panSpeed = 1.0;
        //        trackballControls.noZoom=false;
        //        trackballControls.noPan=false;
        trackballControls.staticMoving = true;
        //        trackballControls.dynamicDampingFactor=0.3;
    }

    var paintFloor = function (){
        var loader = new THREE.TextureLoader;
        loader.load('./img/3.jpg', function (texture) {
            //x和y超過圖片像素以後重複繪製圖片
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            //設置地板重複繪製的密度是1 * 1
            texture.repeat.set(1, 1);

            //設置材質是雙面材質
            var material = new THREE.MeshLambertMaterial({
                map : texture,
                side : THREE.DoubleSide
            });

            //建立普通的平面幾何體
            var gemotery = new THREE.PlaneGeometry(40,40);

            //建立網格對象
            var mesh = new THREE.Mesh(gemotery,material);
            mesh.position.y = 0;
            mesh.rotation.x = Math.PI/2;

            scene.add(mesh);
        });
    }

    var paintWalls = function (width, depth, height, x, y, z, rotationX, rotationY, rotationZ, addMesh){
        var loader = new THREE.TextureLoader;
        var texture = new THREE.TextureLoader().load('./img/4.jpg');
        texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
        //設置地板重複繪製的密度是1 * 1
        texture.repeat.set(1,1);

        var material = new THREE.MeshLambertMaterial({
            map : texture,
            side : THREE.DoubleSide
        });

        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(width, depth, height);

        //建立網格對象以及進行位置的設定
        var mesh = new THREE.Mesh(gemotery,material);
        mesh.position.set(x,y,z)
        mesh.rotation.x = Math.PI * rotationX;
        mesh.rotation.y = Math.PI * rotationY;
        if(rotationZ) {
            mesh.rotation.z = Math.PI * rotationZ;
        }

        if(addMesh) {
            scene.add(mesh);
        }

        return mesh;
    }

    var paintGlass = function (width, depth, height, x, y, z, rotationX, rotationY, rotationZ, addMesh){
        var material = new THREE.MeshBasicMaterial({
            color : 0x58ACFA,
            transparent : true,
            opacity : 0.6
        });

        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(width, depth, height);

        //建立網格對象以及進行位置的設定
        var mesh = new THREE.Mesh(gemotery,material);
        mesh.position.set(x,y,z)
        mesh.rotation.x = Math.PI * rotationX;
        mesh.rotation.y = Math.PI * rotationY;
        if(rotationZ) {
            mesh.rotation.z = Math.PI * rotationZ;
        }

        if(addMesh) {
            scene.add(mesh);
        }

        return mesh;
    }

    function initStats() {
        var stats = new Stats();
        stats.setMode(0); // 0: fps, 1: ms

        // Align top-left
        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';
        document.getElementById("Stats-output").appendChild(stats.domElement);

        return stats;
    }

    window.onload = init;
</script>
</body>
</html>

結果:

  牀會一直旋轉。。。

 

6.   增長一個玻璃天窗,完成最終的房子 

  旋轉牀、鼠標和鍵盤對場景縮放。

<!DOCTYPE html>
<!--房子中間加個牀,採用封裝過的API實現,動態改變牀的位置-->
<html>

<head>
    <title>myHouse</title>
    <script type="text/javascript" src="../libs/jquery-1.9.0.js"></script>
    <script type="text/javascript" src="../libs2/three.js"></script>
    <script type="text/javascript" src="../libs2/OBJLoader.js"></script>
    <script type="text/javascript" src="../libs2/stats.js"></script>
    <script type="text/javascript" src="../libs2/WebGL.js"></script>
    <script type="text/javascript" src="../libs2/OrbitControls.js"></script>
    <script type="text/javascript" src="../libs2/onEvent.js"></script>
    <script type="text/javascript" src="../libs2/ThreeBSP.js"></script>
    <script type="text/javascript" src="../libs2/tween.min.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<div id="logInfo" style="position: absolute; top: 0px; left: 20%; width: 50%; padding: 5px;"></div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
    //基本組件
    var scene, camera, webGLRenderer, stats;
    //鼠標控制動畫相關組件
    var controls;
    //事件相關
    var threeOnEvent;

    function init() {
        stats = initStats();

        scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.x = 20;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(scene.position);
        scene.add(camera);

        // create a render and set the size
        webGLRenderer = new THREE.WebGLRenderer({
            antialias : true,
            alpha:true
        });
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.setPixelRatio(window.devicePixelRatio);
        webGLRenderer.setClearColor(0xEEEEEE, 1.0);
        webGLRenderer.shadowMapEnabled = true;

        // add spotlight for the shadows
        var spotLight = new THREE.PointLight(0xffffff);
        spotLight.position.set(30, 40, 50);
        scene.add(spotLight);

        initObjects();

        // add the output of the renderer to the html element
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        render();
    }

    function initObjects(){
        initEvent();

        paintFloor();
        paintCell();

        //畫牆--通常y取高度的1/2
        paintWalls(40, 2, 10, 0, 5, -20, 1/2, 0, 0,true);//後面牆
        paintWalls(40, 2, 10, 0, 5, 20, 1/2, 0, 0,true);//前面牆
        paintWalls(42, 2, 10, -20, 5, 0, 1/2, 0, 1/2, true);//左面牆
        //添加帶玻璃的牆
        var wallMesh = paintWalls(42, 2, 10, 20, 5, 0, 1/2, 0, 1/2, false);//右面牆
        var windowMesh = paintGlass(10, 2, 6, 20, 3, 0, 1/2, 0, 1/2, false);
        var resultMesh = createResultMesh(wallMesh, windowMesh, true);
        scene.add(resultMesh);

        initOrbitControls();

        paintBed();
    }

    function createResultMesh(srcMesh, destMesh, addDest) {
        var srcBSP = new ThreeBSP(srcMesh);
        var destBSP = new ThreeBSP(destMesh);
        var resultBSP = srcBSP.subtract(destBSP);
        var result = resultBSP.toMesh(srcMesh.material);
        result.geometry.computeFaceNormals();
        result.geometry.computeVertexNormals();
        if(addDest){
            scene.add(destMesh);
        }

        return result;
    }

    var paintBed = function(){
        var textures = [];
        loadBedTextures(textures, 0, "./img/bedplate.jpg"); //right
        loadBedTextures(textures, 1, "./img/bedplate.jpg"); //left
        loadBedTextures(textures, 2, "./img/bedplate.jpg"); //front
        loadBedTextures(textures, 3, "./img/bedplate.jpg");//back
        loadBedTextures(textures, 4, "./img/bedplate.jpg"); //bottom
        loadBedTextures(textures, 5, "./img/mattess.jpg"); //top

        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(10, 10, 5);

        //建立網格對象以及進行位置的設定
        var mesh = new THREE.Mesh(gemotery, textures);
        mesh.position.set(0, 2.5, 0)
        mesh.rotation.x = Math.PI * 1/2;

        //綁定一些數據
        mesh.tags = "bed";
        mesh.userData.ID = 1;
        mesh.name = "myBed";

        //增長事件(點擊事件)
        mesh.on('click',function(m) {//m表明mesh對象
           alert('1');
        })

        // hover eventLisener(鼠標懸浮事件)
        mesh.on('hover',function(m) {
            // mouse enter the mesh
            alert(m.name + "  " + m.tags + " " + mesh.userData.ID);
        },function(m) {
            // mouse leave out the mesh
        });

        scene.add(mesh);

        startAnnotation(mesh);
    }

    function startAnnotation(mesh) {
        var indexNumber = {
            indexNumber : 0
        };
        var currentTween = new TWEEN.Tween(indexNumber).to({
            indexNumber : 2
        },5000);
        currentTween.easing(TWEEN.Easing.Sinusoidal.InOut);
        currentTween.repeat(60);//重複次數
        currentTween.yoyo(true);//結束以後反方向反彈

        currentTween.onUpdate(function(){
            var indexNumber = this.indexNumber;
            //改變牀的旋轉角度實現旋轉牀
            mesh.rotation.z = Math.PI * indexNumber;

            //也能夠根據數字的範圍進行一些其餘動畫(好比說實現閃爍效果等)
            if(indexNumber < 1){
            } else {
            }
        });
        currentTween.start();
    }

    function loadBedTextures(textures, index, url){
        textures[index] = new THREE.MeshBasicMaterial({
           map : new THREE.TextureLoader().load(url)
        });
    }

    function initEvent(){
        threeOnEvent = new THREE.onEvent(scene,camera);
    }


    function render() {
        requestAnimationFrame(render);
        webGLRenderer.render(scene, camera);

        logCameraPosition();

        if(stats){
            stats.update();
        }

        //更新事件
        threeOnEvent.update();

        //動畫
        TWEEN.update();
    }

    function logCameraPosition(){
        var logInfo = "[info]: x - " + camera.position.x + " ;y - " + camera.position.y + " ;z - " + camera.position.z;
        $("#logInfo").html(logInfo);
    }

    function initOrbitControls(){
        controls = new THREE.OrbitControls(camera,webGLRenderer.domElement);

        controls.minDistance = 1;
        controls.maxDistance = 5000;
    }

    var paintFloor = function (){
        var loader = new THREE.TextureLoader;
        loader.load('./img/3.jpg', function (texture) {
            //x和y超過圖片像素以後重複繪製圖片
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            //設置地板重複繪製的密度是1 * 1
            texture.repeat.set(1, 1);

            //設置材質是雙面材質
            var material = new THREE.MeshLambertMaterial({
                map : texture,
                side : THREE.DoubleSide
            });

            //建立普通的平面幾何體
            var gemotery = new THREE.PlaneGeometry(40,40);

            //建立網格對象
            var mesh = new THREE.Mesh(gemotery,material);
            mesh.position.y = 0;
            mesh.rotation.x = Math.PI/2;

            scene.add(mesh);
        });
    }

    var paintCell = function (){
        //設置材質是雙面材質
        var material = new THREE.MeshBasicMaterial({
            color : 0x58ACFA,
            transparent : true,
            opacity : 0.6
        });

        //建立普通的平面幾何體
        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(40, 40, 1);

        //建立網格對象
        var mesh = new THREE.Mesh(gemotery,material);
        mesh.position.y = 9;
        mesh.rotation.x = Math.PI/2;

        scene.add(mesh);
    }

    var paintWalls = function (width, depth, height, x, y, z, rotationX, rotationY, rotationZ, addMesh){
        var loader = new THREE.TextureLoader;
        var texture = new THREE.TextureLoader().load('./img/4.jpg');
        texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
        //設置地板重複繪製的密度是1 * 1
        texture.repeat.set(1,1);

        var material = new THREE.MeshLambertMaterial({
            map : texture,
            side : THREE.DoubleSide
        });

        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(width, depth, height);

        //建立網格對象以及進行位置的設定
        var mesh = new THREE.Mesh(gemotery,material);
        mesh.position.set(x,y,z)
        mesh.rotation.x = Math.PI * rotationX;
        mesh.rotation.y = Math.PI * rotationY;
        if(rotationZ) {
            mesh.rotation.z = Math.PI * rotationZ;
        }

        if(addMesh) {
            scene.add(mesh);
        }

        return mesh;
    }

    var paintGlass = function (width, depth, height, x, y, z, rotationX, rotationY, rotationZ, addMesh){
        var material = new THREE.MeshBasicMaterial({
            color : 0x58ACFA,
            transparent : true,
            opacity : 0.6
        });

        //建立長方體幾何體
        var gemotery = new THREE.BoxGeometry(width, depth, height);

        //建立網格對象以及進行位置的設定
        var mesh = new THREE.Mesh(gemotery,material);
        mesh.position.set(x,y,z)
        mesh.rotation.x = Math.PI * rotationX;
        mesh.rotation.y = Math.PI * rotationY;
        if(rotationZ) {
            mesh.rotation.z = Math.PI * rotationZ;
        }

        if(addMesh) {
            scene.add(mesh);
        }

        return mesh;
    }

    function initStats() {
        var stats = new Stats();
        stats.setMode(0); // 0: fps, 1: ms

        // Align top-left
        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';
        document.getElementById("Stats-output").appendChild(stats.domElement);

        return stats;
    }

    window.onload = init;
</script>
</body>
</html>

結果:

 

git源碼地址: https://github.com/qiao-zhi/threejsDemo

效果演示

 

總結:

  通常物體的y取的是高度是1/2;

  旋轉角度的單位是Math.PI (乘以對應的角度,1就是180度,0.5就是90度)

相關文章
相關標籤/搜索