Three.js開發指南---建立,加載高級網格和幾何體(第八章)

本章的主要內容:javascript

  一, 經過Three.js自帶的功能來組合和合並已有的幾何體,建立出新的幾何體html

  二, 從外部資源中加載網格和幾何體java

  1 前面的章節中,咱們學習到,一個幾何體建立的網格,想使用多個材質的方法:node

var mesh=THREE.SceneUtils.createMultiMaterialObject(geometry,[material1,,material2]);

  看似一個網格中有一個幾何體,多個材質,其實該網格擁有與材質數量相對應的幾何體,每一個幾何體都對應一種材質,造成一個網格,咱們獲得的是包含多個網格的組git

  在下面的demo中,咱們將建立一個網格組,該組包含多個網格,當這個組進行縮放,移動,旋轉,變形的時候,組內的網格都會跟着變化github

  注意點1:建立組,將球體和立方體都添加到該組中web

var group = new THREE.Group();group.add(sphereMesh);group.add(boxMesh)

  注意點2:計算組的邊界,生成一個邊界無限大的立方體,對組以及組內子對象應用矩陣變換,獲得組內子對象頂點改變後的座標,複製子對象的每一個頂點座標,從新設置立方體的邊界,參見函數setFromObjectjson

  注意點3:輔助線ArrowHelper,其參數的解讀,dir:方向,默認是法向量;origin:開始的座標位置;length:輔助線的長度;color:輔助線的顏色;headLength:頭部的長度;headWidth:頭部的寬度app

<!DOCTYPE html>

<html>

<head>
    <title>Example 08.01 - Grouping</title>
    <script type="text/javascript" src="../libs/three.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">

    // once everything is loaded, we run our Three.js stuff.
    function init() {

        var stats = initStats();

        // create a scene, that will hold all our elements such as objects, cameras and lights.
        var scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

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

        // add the sphere to the scene

        // position and point the camera to the center of the scene
        camera.position.x = 30;
        camera.position.y = 30;
        camera.position.z = 30;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var ground = new THREE.PlaneGeometry(100, 100, 50, 50);

        var groundMesh = THREE.SceneUtils.createMultiMaterialObject(ground,
                [new THREE.MeshBasicMaterial({wireframe: false, overdraw: true, color: 000000}),
                    new THREE.MeshBasicMaterial({color: 0x00ff00, transparent: true, opacity: 0.5}
                    )
                ]);
        groundMesh.rotation.x = -0.5 * Math.PI;
        scene.add(groundMesh);


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

        // call the render function
        var step = 0.03;

        var sphere;
        var cube;
        var group;
        var bboxMesh;

        // setup the control gui
        var controls = new function () {
            // we need the first child, since it's a multimaterial
            this.cubePosX = 0;
            this.cubePosY = 3;
            this.cubePosZ = 10;

            this.spherePosX = 10;
            this.spherePosY = 5;
            this.spherePosZ = 0;

            this.groupPosX = 10;
            this.groupPosY = 5;
            this.groupPosZ = 0;

            this.grouping = false;
            this.rotate = false;

            this.groupScale = 1;
            this.cubeScale = 1;
            this.sphereScale = 1;


            this.redraw = function () {
                // remove the old plane
                //scene.remove(sphere);
                //scene.remove(cube);
                scene.remove(group);

                // create a new one
                sphere = createMesh(new THREE.SphereGeometry(5, 10, 10));
                cube = createMesh(new THREE.BoxGeometry(6, 6, 6));

                sphere.position.set(controls.spherePosX, controls.spherePosY, controls.spherePosZ);
                cube.position.set(controls.cubePosX, controls.cubePosY, controls.cubePosZ);
                // add it to the scene.

                // also create a group, only used for rotating
 group = new THREE.Group(); group.add(sphere); group.add(cube); scene.add(group);
                controls.positionBoundingBox();
                //dir, origin, length, color, headLength, headWidth
                /*ArrowHelper的參數: dir:方向,默認是法向量 origin:開始的座標位置 length:輔助線的長度 color:輔助線的顏色 headLength:頭部的長度 headWidth:頭部的寬度 */ var arrow = new THREE.ArrowHelper(new THREE.Vector3(0, 1, 0), group.position, 10, 0x0000ff);
                scene.add(arrow);


            };

            this.positionBoundingBox = function () {
                scene.remove(bboxMesh);
                var box = setFromObject(group);//group中的子對象的座標變換完畢後,獲取到組group的新的邊界立方體
                var width = box.max.x - box.min.x;
                var height = box.max.y - box.min.y;
                var depth = box.max.z - box.min.z;
                //獲得group立方體邊界的寬高和深度,根據這些值,生成一個立方几何體

                var bbox = new THREE.BoxGeometry(width, height, depth);
                bboxMesh = new THREE.Mesh(bbox, new THREE.MeshBasicMaterial({
                    color: "red",
                    vertexColors: THREE.VertexColors,
                    wireframeLinewidth: 2,
                    wireframe: true
                }));
                scene.add(bboxMesh);
                bboxMesh.position.x = ((box.min.x + box.max.x) / 2);
                bboxMesh.position.y = ((box.min.y + box.max.y) / 2);
                bboxMesh.position.z = ((box.min.z + box.max.z) / 2);
            }
        };

        var gui = new dat.GUI();
        var sphereFolder = gui.addFolder("sphere");
        sphereFolder.add(controls, "spherePosX", -20, 20).onChange(function (e) {
            sphere.position.x = e;
            //當球體的座標發生變化時,應該從新計算組group的範圍
            //包含區域的最小矩形,該區域應在最小矩形內部
            controls.positionBoundingBox()
        });
        sphereFolder.add(controls, "spherePosZ", -20, 20).onChange(function (e) {
            sphere.position.z = e;
            controls.positionBoundingBox()
        });
        sphereFolder.add(controls, "spherePosY", -20, 20).onChange(function (e) {
            sphere.position.y = e;
            controls.positionBoundingBox()
        });
        sphereFolder.add(controls, "sphereScale", 0, 3).onChange(function (e) {
            sphere.scale.set(e, e, e);
            controls.positionBoundingBox()
        });

        var cubeFolder = gui.addFolder("cube");
        cubeFolder.add(controls, "cubePosX", -20, 20).onChange(function (e) {
            cube.position.x = e;
            controls.positionBoundingBox()
        });
        cubeFolder.add(controls, "cubePosZ", -20, 20).onChange(function (e) {
            cube.position.z = e;
            controls.positionBoundingBox()
        });
        cubeFolder.add(controls, "cubePosY", -20, 20).onChange(function (e) {
            cube.position.y = e;
            controls.positionBoundingBox()
        });
        cubeFolder.add(controls, "cubeScale", 0, 3).onChange(function (e) {
            cube.scale.set(e, e, e);
            controls.positionBoundingBox()
        });

        var cubeFolder = gui.addFolder("group");
        cubeFolder.add(controls, "groupPosX", -20, 20).onChange(function (e) {
            group.position.x = e;
            controls.positionBoundingBox()
        });
        cubeFolder.add(controls, "groupPosZ", -20, 20).onChange(function (e) {
            group.position.z = e;
            controls.positionBoundingBox()
        });
        cubeFolder.add(controls, "groupPosY", -20, 20).onChange(function (e) {
            group.position.y = e;
            controls.positionBoundingBox()
        });
        cubeFolder.add(controls, "groupScale", 0, 3).onChange(function (e) {
            group.scale.set(e, e, e);
            controls.positionBoundingBox()
        });

        gui.add(controls, "grouping");
        gui.add(controls, "rotate");
        controls.redraw();
        render();

        function createMesh(geom) {

            // assign two materials
            var meshMaterial = new THREE.MeshNormalMaterial();
            meshMaterial.side = THREE.DoubleSide;
            var wireFrameMat = new THREE.MeshBasicMaterial();
            wireFrameMat.wireframe = true;

            // 建立一個多種材質的網格
            var plane = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial, wireFrameMat]); return plane;
        }

        function render() {
            stats.update();


            if (controls.grouping && controls.rotate) {
                group.rotation.y += step;
            }

            if (controls.rotate && !controls.grouping) {
                sphere.rotation.y += step;
                cube.rotation.y += step;
            }

//        controls.positionBoundingBox();
            // render using requestAnimationFrame
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }

        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;
        }


        // http://jsfiddle.net/MREL4/
        function setFromObject(object) { //Box3對象的構造函數.用來在三維空間內建立一個立方體邊界對象 //參數min,max,若是沒有參數min,max將立方體邊界初始化爲Infinity,無窮大 var box = new THREE.Box3(); var v1 = new THREE.Vector3(); //設置全局變換,object,即該demo中的group以及子對象都應用矩陣變換.  object.updateMatrixWorld(true); //調用Box3.makeEmpty()方法,將立方體邊界設置成無窮大.  box.makeEmpty(); //而後遍歷組group中的每一個子對象  object.traverse(function (node) { //若是該子對象有幾何體且幾何體有頂點,則複製該幾何體的每一個頂點,而後對其進行矩陣變換 //矩陣變換後獲得的新的座標位置,再根據這些新的座標設置group的邊界 if (node.geometry !== undefined && node.geometry.vertices !== undefined) { var vertices = node.geometry.vertices; for (var i = 0, il = vertices.length; i < il; i++) { v1.copy(vertices[i]); v1.applyMatrix4(node.matrixWorld); //applyMatrix4方法經過傳遞變換矩陣matrix(旋轉,縮放,移動等變換矩陣) //對當前立方體對象的8個角點,應用變換.  box.expandByPoint(v1); //調用expandByPoint()方法從新設置立方體邊界  } } }); return box; }
    };

    window.onload = init;


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

   2 dom

 當頁面中網格的數量很大的時候,性能就成了瓶頸

下圖講解:FPS:每秒執行多少次,

  左側的是未使用merge,右側是使用merge

  從圖中能夠看出,未使用merge的時候,一秒鐘執行了23次刷新,使用merge後,一秒鐘執行了50次刷新,性能獲得了提升

這裏使用THREE.GeometryUtils.merge函數,將多個幾何體合併起來,建立一個聯合體,將會提升性能,

缺點:咱們只能獲得一個幾何體,因此不能爲每一個幾何體添加材質,而且失去了對每一個對象的單獨控制,想要移動,旋轉,刪除,縮放某一個幾何體是不可能的

<!DOCTYPE html>

<html>

<head>
    <title>Example 08.02 - Merge objects</title>
    <script type="text/javascript" src="../libs/three.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">

    // once everything is loaded, we run our Three.js stuff.
    function init() {

        var stats = initStats();

        // create a scene, that will hold all our elements such as objects, cameras and lights.
        var scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);

        // create a render and set the size
        var renderer = new THREE.WebGLRenderer();

        renderer.setClearColor(new THREE.Color(0x00000, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;

        // position and point the camera to the center of the scene
        camera.position.x = 0;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(scene.position);

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

        // call the render function
        var step = 0;

        var cubeMaterial = new THREE.MeshNormalMaterial({color: 0x00ff00, transparent: true, opacity: 0.5});
        var controls = new function () {
            this.cameraNear = camera.near;
            this.cameraFar = camera.far;
            this.rotationSpeed = 0.02;
            this.combined = false;


            this.numberOfObjects = 500;

            this.redraw = function () {
                var toRemove = [];
                scene.traverse(function (e) {
                    if (e instanceof THREE.Mesh) toRemove.push(e);
                });
                toRemove.forEach(function (e) {
                    scene.remove(e)
                });

                // add a large number of cubes
                if (controls.combined) {
                    var geometry = new THREE.Geometry(); for (var i = 0; i < controls.numberOfObjects; i++) { var cubeMesh = addcube(); cubeMesh.updateMatrix(); geometry.merge(cubeMesh.geometry, cubeMesh.matrix); } scene.add(new THREE.Mesh(geometry, cubeMaterial));

                } else {
                    for (var i = 0; i < controls.numberOfObjects; i++) {
                        scene.add(controls.addCube());
                    }
                }
            };


            this.addCube = addcube;

            this.outputObjects = function () {
                console.log(scene.children);
            }
        };

        var gui = new dat.GUI();

        gui.add(controls, 'numberOfObjects', 0, 20000);
        gui.add(controls, 'combined').onChange(controls.redraw);
        gui.add(controls, 'redraw');


        controls.redraw();

        render();

        var rotation = 0;

        function addcube() {

            var cubeSize = 1.0;
            var cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);

            var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
            cube.castShadow = true;

            // position the cube randomly in the scene
            cube.position.x = -60 + Math.round((Math.random() * 100));
            cube.position.y = Math.round((Math.random() * 10));
            cube.position.z = -150 + Math.round((Math.random() * 175));

            // add the cube to the scene
            return cube;
        }
        function render() {

            rotation += 0.005;

            stats.update();

//            scene.rotation.x+=0.02;

            // rotate the cubes around its axes
//            scene.traverse(function(e) {
//                if (e instanceof THREE.Mesh ) {
//
//                    e.rotation.x+=controls.rotationSpeed;
//                    e.rotation.y+=controls.rotationSpeed;
//                    e.rotation.z+=controls.rotationSpeed;
//                }
//            });

            camera.position.x = Math.sin(rotation) * 50;
            // camera.position.y = Math.sin(rotation) * 40;
            camera.position.z = Math.cos(rotation) * 50;
            camera.lookAt(scene.position);

            // render using requestAnimationFrame
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }

        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 從外部引入資源加載幾何體---方式一JSON

    首先,咱們先把咱們前面繪製的網格對象保存爲JSON格式,而後再在另一個文件中引入該JSON文件,進行解析繪製

 var mesh=new THREE.Mesh(geo,material); var json= mesh.toJSON(); //將mesh網格保存爲JSON格式

//將json繪製爲網格
var loader = new THREE.ObjectLoader(); loadedMesh = loader.parse(json); loadedMesh.position.x -= 50; scene.add(loadedMesh);

 

 

 

<!DOCTYPE html>

<html>

<head>
    <title>Example 08.03 - Save & Load</title>
    <script type="text/javascript" src="../libs/three.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">

    // once everything is loaded, we run our Three.js stuff.
    function init() {

        var stats = initStats();

        // create a scene, that will hold all our elements such as objects, cameras and lights.
        var scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

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

        var knot = createMesh(new THREE.TorusKnotGeometry(10, 1, 64, 8, 2, 3, 1));
        // add the sphere to the scene
        scene.add(knot);

        // position and point the camera to the center of the scene
        camera.position.x = -30;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(new THREE.Vector3(-20, 0, 0));

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

        // call the render function
        var step = 0;
        var json;

        var loadedMesh;

        // setup the control gui
        var controls = new function () {

            console.log(knot.geometry.parameters);
            // we need the first child, since it's a multimaterial
            this.radius = knot.geometry.parameters.radius;
            this.tube = 0.3;
            this.radialSegments = knot.geometry.parameters.radialSegments;
            this.tubularSegments = knot.geometry.parameters.tubularSegments;
            this.p = knot.geometry.parameters.p;
            this.q = knot.geometry.parameters.q;
            this.heightScale = knot.geometry.parameters.heightScale;

            this.redraw = function () {
                // remove the old plane
                scene.remove(knot);
                // create a new one
                knot = createMesh(new THREE.TorusKnotGeometry(controls.radius, controls.tube, Math.round(controls.radialSegments), Math.round(controls.tubularSegments), Math.round(controls.p), Math.round(controls.q), controls.heightScale));
                // add it to the scene.
                scene.add(knot);
            };

            this.save = function () {
                json = knot.toJSON();
            };

            this.load = function () {

                scene.remove(loadedMesh);

                

                if (json) {
                    var loader = new THREE.ObjectLoader(); loadedMesh = loader.parse(json); loadedMesh.position.x -= 50; scene.add(loadedMesh);
                }
            }
        };

        var gui = new dat.GUI();
        var ioGui = gui.addFolder('Save & Load');
        ioGui.add(controls, 'save').onChange(controls.save);
        ioGui.add(controls, 'load').onChange(controls.load);
        var meshGui = gui.addFolder('mesh');
        meshGui.add(controls, 'radius', 0, 40).onChange(controls.redraw);
        meshGui.add(controls, 'tube', 0, 40).onChange(controls.redraw);
        meshGui.add(controls, 'radialSegments', 0, 400).step(1).onChange(controls.redraw);
        meshGui.add(controls, 'tubularSegments', 1, 20).step(1).onChange(controls.redraw);
        meshGui.add(controls, 'p', 1, 10).step(1).onChange(controls.redraw);
        meshGui.add(controls, 'q', 1, 15).step(1).onChange(controls.redraw);
        meshGui.add(controls, 'heightScale', 0, 5).onChange(controls.redraw);


        render();

        function createMesh(geom) {

            // assign two materials
            var meshMaterial = new THREE.MeshBasicMaterial({
                vertexColors: THREE.VertexColors,
                wireframe: true,
                wireframeLinewidth: 2,
                color: 0xaaaaaa
            });
            meshMaterial.side = THREE.DoubleSide;

            // create a multimaterial
            var mesh = new THREE.Mesh(geom, meshMaterial);

            return mesh;
        }

        function render() {
            stats.update();

            knot.rotation.y = step += 0.01;

            // render using requestAnimationFrame
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }

        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.2 將場景保存爲JSON格式

  注意該demo須要引入SceneExporter.js和SceneLoader.js文件

              //生成一個場景輸出對象
                var exporter = new THREE.SceneExporter();
                //該對象將場景進行格式化爲JSON格式
                var sceneJson = JSON.stringify(exporter.parse(scene));

 

    //生成一個場景載入對象
                var sceneLoader = new THREE.SceneLoader();
                //將json格式的場景傳遞給場景載入對象,格式化爲場景
                sceneLoader.parse(JSON.parse(json), function (e) {
                    scene = e.scene;
                }, '.');

 

<!DOCTYPE html>

<html>

<head>
    <title>Example 08.04 - Load and save scene</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/SceneLoader.js"></script>
    <script type="text/javascript" src="../libs/SceneExporter.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">

    // once everything is loaded, we run our Three.js stuff.
    function init() {

        var stats = initStats();

        // create a scene, that will hold all our elements such as objects, cameras and lights.
        var scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        // create a render and set the size
        var renderer = new THREE.WebGLRenderer();

        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        //    renderer.shadowMapEnabled = true;

        // create the ground plane
        var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
        var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        //  plane.receiveShadow  = true;

        // rotate and position the plane
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 15;
        plane.position.y = 0;
        plane.position.z = 0;

        // add the plane to the scene
        scene.add(plane);

        // create a cube
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        // cube.castShadow = true;

        // position the cube
        cube.position.x = -4;
        cube.position.y = 3;
        cube.position.z = 0;

        // add the cube to the scene
        scene.add(cube);

        var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
        var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);

        // position the sphere
        sphere.position.x = 20;
        sphere.position.y = 0;
        sphere.position.z = 2;
        //  sphere.castShadow=true;

        // add the sphere to the scene
        scene.add(sphere);

        // position and point the camera to the center of the scene
        camera.position.x = -30;
        camera.position.y = 40;
        camera.position.z = 30;
        camera.lookAt(scene.position);

        // add subtle ambient lighting
        var ambientLight = new THREE.AmbientLight(0x0c0c0c);
        scene.add(ambientLight);

        // add spotlight for the shadows
        var spotLight = new THREE.PointLight(0xffffff);
        spotLight.position.set(-40, 60, -10);
        //  spotLight.castShadow = true;
        scene.add(spotLight);

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

        // call the render function
        var step = 0;

        var controls = new function () {
            this.exportScene = function () {
            //生成一個場景輸出對象
                var exporter = new THREE.SceneExporter();
                //該對象將場景進行格式化爲JSON格式
                var sceneJson = JSON.stringify(exporter.parse(scene));
                localStorage.setItem('scene', sceneJson);
            };

            this.clearScene = function () {
                scene = new THREE.Scene();
            };

            this.importScene = function () {
                var json = (localStorage.getItem('scene'));
                //生成一個場景載入對象
                var sceneLoader = new THREE.SceneLoader();
                //將json格式的場景傳遞給場景載入對象,格式化爲場景
                sceneLoader.parse(JSON.parse(json), function (e) {
                    scene = e.scene;
                }, '.');
            }
        };

        var gui = new dat.GUI();
        gui.add(controls, "exportScene");
        gui.add(controls, "clearScene");
        gui.add(controls, "importScene");


        render();

        function render() {
            stats.update();
            // rotate the cube around its axes


            // render using requestAnimationFrame
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }

        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.3 先使用Blender軟件進行建模,建模完成後,將該模型導出成three.js能夠識別的js文件格式,而後再將該js引入進行從新繪製

  準備工做:

      準備工做1:下載安裝Blender軟件:https://www.blender.org/download/

      準備工做2:下載Three.js的發佈包:https://github.com/timoxley/threejs,將io_mesh_threejs文件夾複製到Blender的安裝目錄:C:\Program Files\Blender Foundation\Blender\2.78\scripts\addons

    準備工做3:激活導出器

      File|User Preferences|搜索框輸入three|右側出現Import-export three.js Format|勾選複選框激活

    準備工做4:驗證three.js導出器是否激活成功:File|Export|Three.js(.js)

    準備工做5:使用Blender建模,再將模型保存爲*.js

  準備工做6:Blender軟件導出的js文件中,有些材質是有圖片的,因此咱們在導出的js文件的同時還要導出圖片,並保證圖片和js文件裏面的路徑已經名稱一致

  準備工做完成,下面咱們將使用導出的*.js和*.jpg在網頁中繪製圖形

 

代碼部分:

<!DOCTYPE html>

<html>

<head>
    <title>Example 08.05 - Load blender model </title>
    <script type="text/javascript" src="../libs/three.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">

    // once everything is loaded, we run our Three.js stuff.
    function init() {

        var stats = initStats();

        // create a scene, that will hold all our elements such as objects, cameras and lights.
        var scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

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

        // position and point the camera to the center of the scene
        camera.position.x = -30;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(new THREE.Vector3(0, 10, 0));


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

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

        // call the render function
        var step = 0;


        // setup the control gui
        var controls = new function () {
            // we need the first child, since it's a multimaterial


        };

        var gui = new dat.GUI();
        var mesh;
        
        var loader = new THREE.JSONLoader(); //loader.load(url,callback); loader.load('../assets/models/misc_chair01.js', function (geometry, mat) { mesh = new THREE.Mesh(geometry, mat[0]); mesh.scale.x = 15; mesh.scale.y = 15; mesh.scale.z = 15; scene.add(mesh); }, '../assets/models/'); 

        render();


        function render() {
            stats.update();

            if (mesh) {
                mesh.rotation.y += 0.02;
            }


            // render using requestAnimationFrame
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }

        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.4 先使用Blender軟件進行建模,建模完成後,將該模型導出成three.js能夠識別的OBJ和MTL文件格式,而後再將其引入進行從新繪製

     理論解釋:OBJ格式和MTL格式是相互配合使用的,OBJ文件定義了幾何體的格式 ,MTL定義了所使用的材質

    準備工做:同Blender導出*.js文件同樣,1 安裝Blender軟件,進行建模;2 導入OBJ/MTL下載包,激活導出器;3 導出模型文件 4 頁面中引入OBJLoader和MTLLoader

<!DOCTYPE html>

<html>

<head>
    <title>Example 08.07 - Load OBJ and MTL </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/MTLLoader.js"></script>
    <script type="text/javascript" src="../libs/OBJMTLLoader.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">

    // once everything is loaded, we run our Three.js stuff.
    function init() {

        var stats = initStats();

        // create a scene, that will hold all our elements such as objects, cameras and lights.
        var scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        // create a render and set the size
        var webGLRenderer = new THREE.WebGLRenderer();
        webGLRenderer.setClearColor(new THREE.Color(0xaaaaff, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;

        // position and point the camera to the center of the scene
        camera.position.x = -30;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(new THREE.Vector3(0, 10, 0));


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

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

        // call the render function
        var step = 0;


        // setup the control gui
        var controls = new function () {
            // we need the first child, since it's a multimaterial


        };

        var gui = new dat.GUI();
        var mesh;

        var loader = new THREE.OBJMTLLoader(); loader.load('../assets/models/butterfly.obj', '../assets/models/butterfly.mtl', function (object) { // configure the wings
            var wing2 = object.children[5].children[0];
            var wing1 = object.children[4].children[0];

            wing1.material.opacity = 0.6;
            wing1.material.transparent = true;
            wing1.material.depthTest = false;
            wing1.material.side = THREE.DoubleSide;

            wing2.material.opacity = 0.6;
            wing2.material.depthTest = false;
            wing2.material.transparent = true;
            wing2.material.side = THREE.DoubleSide;

            object.scale.set(140, 140, 140);
            mesh = object;
            scene.add(mesh);

            object.rotation.x = 0.2;
            object.rotation.y = -1.3;
        });


        render();


        function render() {
            stats.update();

            if (mesh) {
                mesh.rotation.y += 0.006;
            }


            // render using requestAnimationFrame
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }

        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.5 加載Collada模型

    理論解釋:Collada模型是定義的場景,不只定義了幾何體,定義了材質,還定義了光源

    準備工做:1 下載安裝Blender軟件,若是已經安裝忽略此步驟,進行建模;2 激活導出器,若是已經有的話,此步驟省略;3 導出模型文件 4 頁面中引入ColladaLoader

 

 

 

 關鍵代碼:

var loader = new THREE.ColladaLoader();

        var mesh;
        loader.load("../assets/models/dae/Truck_dae.dae", function (result) {
            mesh = result.scene.children[0].children[0].clone();
            //因爲Collada模型定義的是場景,所以不只包含幾何體,材質還有光源等
            //所以此處咱們想引入具體的某個網格,須要console.log(result),肯定具體網格再添加到場景中
            mesh.scale.set(4, 4, 4);
            scene.add(mesh);
        });

 

  3.6 加載STL,CTM,VTK,PDB,PLY模型

 var loader = new THREE.STLLoader();
        var group = new THREE.Object3D();
        loader.load("../assets/models/SolidHead_2_lowPoly_42k.stl", function (geometry) {
            console.log(geometry);
            var mat = new THREE.MeshLambertMaterial({color: 0x7777ff});
            group = new THREE.Mesh(geometry, mat);
            group.rotation.x = -0.5 * Math.PI;
            group.scale.set(0.6, 0.6, 0.6);
            scene.add(group);
        });
  var loader = new THREE.CTMLoader();
        var group = new THREE.Object3D();

        loader.load("../assets/models/auditt_wheel.ctm", function (geometry) {
            var mat = new THREE.MeshLambertMaterial({color: 0xff8888});
            group = new THREE.Mesh(geometry, mat);
            group.scale.set(20, 20, 20);
            scene.add(group);
        }, {}); 
var loader = new THREE.VTKLoader();
        var group = new THREE.Object3D();
        loader.load("../assets/models/moai_fixed.vtk", function (geometry) {
            var mat = new THREE.MeshLambertMaterial({color: 0xaaffaa});
            group = new THREE.Mesh(geometry, mat);
            group.scale.set(9, 9, 9);
            scene.add(group);
        });

 

   var loader = new THREE.PDBLoader();
        var group = new THREE.Object3D();
        loader.load("../assets/models/aspirin.pdb", function (geometry, geometryBonds) {
//geometry是標識原子的位置  geometryBonds定義了原子之間的鍵
            var i = 0;

            geometry.vertices.forEach(function (position) {
                var sphere = new THREE.SphereGeometry(0.2);
                var material = new THREE.MeshPhongMaterial({color: geometry.colors[i++]});
                var mesh = new THREE.Mesh(sphere, material);
                mesh.position.copy(position);
                group.add(mesh);
            });

            for (var j = 0; j < geometryBonds.vertices.length; j += 2) {
                var path = new THREE.SplineCurve3([geometryBonds.vertices[j], geometryBonds.vertices[j + 1]]);
                var tube = new THREE.TubeGeometry(path, 1, 0.04);
                var material = new THREE.MeshPhongMaterial({color: 0xcccccc});
                var mesh = new THREE.Mesh(tube, material);
                group.add(mesh);
            }

            scene.add(group);
        });
 var loader = new THREE.PLYLoader();//建立粒子系統
        var group = new THREE.Object3D();
        loader.load("../assets/models/test.ply", function (geometry) {
            var material = new THREE.PointCloudMaterial({
                color: 0xffffff,
                size: 0.4,
                opacity: 0.6,
                transparent: true,
                blending: THREE.AdditiveBlending,
                map: generateSprite()
            });

            group = new THREE.PointCloud(geometry, material);
            group.sortParticles = true;

            scene.add(group);
        });

 

模型格式 描述
JSON JSON不是一種正式的格式,可是很好用
OBJ,MTL OBJ定義的是幾何體,MTL定義的是材質
Collada 使用較爲普遍的格式,幾乎全部的三維軟件和渲染引擎都支持這種格式
STL 立體成型術,三維打印機的模型文件就是STL
CTM CTM格式用來壓縮保存3D網格的三角面片
PDB

蛋白質數據銀行建立的一種格式,用來定義蛋白質的形狀,

參數geometry的各個頂點標識的是各個原子的位置,geometryBonds:是各個原子之間的鍵

PLY 用來保存3D掃描儀的數據,該模型創建的是一個粒子系統,而不是網格
VTK vISUALIZATION Toolkit定義的文件格式,three.js支持舊版的ASCII版本的
相關文章
相關標籤/搜索