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度)

 

posted @ 2019-06-03 19:00  QiaoZhi  阅读(6408)  评论(1编辑  收藏  举报