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


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

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

准備素材:

3.jpg模擬地板

 

4.jpg模擬牆

 

 

代碼:

<!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>

結果:

 

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

  控制器的使用,主要的控制器如下:

 

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

可用的鼠標事件如下:

 

(1)引入相關JS:

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

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

    //鼠標控制動畫相關組件
    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循環中完成

    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。 

 

代碼如下:

<!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引擎就可以計算從開始動畫點到結束動畫點之間值,來產生平滑的動畫效果。  其詳細用法參考: https://www.cnblogs.com/jiangxiaobo/p/6207264.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度)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM