Three.js開發指南---使用高級幾何體和二元操做(第六章)

本章的主要內容:javascript

  一,高級幾何體-凸面體ConvexGeometry,掃描體LatheGeometry,管狀幾何體TubeGeometry;html

  二,使用拉伸幾何體ExtrudeGeometry將一個二維圖形生成三維圖形,並基於從外部引入的SVG圖片生成一個三維圖形;java

  三,基於three.js提供的ParamtericGeometry對象的公式定製本身的圖形git

  四,使用TextGeometry建立三維文字github

  五,使用二元操做從已有的幾何體中建立出新的幾何體;web

1  ConvexGeometry--凸面體app

<!DOCTYPE html>

<html>

<head>
    <title>Example 06.01 - Advanced 3D geometries - Convex Hull</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/ConvexGeometry.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(10, 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;

        // the points group
        var spGroup;
        // the mesh
        var hullMesh;

        generatePoints();

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

            this.redraw = function () {
                scene.remove(spGroup);
                scene.remove(hullMesh);
                generatePoints();

            };

        };

        var gui = new dat.GUI();
        gui.add(controls, 'redraw');


        render();

        function generatePoints() {
            // add 10 random spheres
            var points = [];
            //生成20個隨機點
            for (var i = 0; i < 20; i++) {
                var randomX = -15 + Math.round(Math.random() * 30);
                var randomY = -15 + Math.round(Math.random() * 30);
                var randomZ = -15 + Math.round(Math.random() * 30);

                points.push(new THREE.Vector3(randomX, randomY, randomZ));
            }
            
            //將這些隨機點用紅色的小圓球來標識,將這些標識點的小圓球添加到集合中,而後再將該集合追加到場景中
 spGroup = new THREE.Object3D(); var material = new THREE.MeshBasicMaterial({color: 0xff0000, transparent: false});
            //每個點都生成一個紅色的圓球來標識該點
 points.forEach(function (point) { var spGeom = new THREE.SphereGeometry(0.2); var spMesh = new THREE.Mesh(spGeom, material); //網格的位置複製該點的位置  spMesh.position.copy(point); spGroup.add(spMesh); }); // add the points as a group to the scene
 scene.add(spGroup); // use the same points to create a convexgeometry
            //利用這些隨機點生成一個凸面體,注意這些隨機點是ConvexGeometry的參數
            var hullGeometry = new THREE.ConvexGeometry(points);
            hullMesh = createMesh(hullGeometry);
            scene.add(hullMesh);
        }

        function createMesh(geom) {

            // assign two materials
            var meshMaterial = new THREE.MeshBasicMaterial({color: 0x00ff00, transparent: true, opacity: 0.2});
            meshMaterial.side = THREE.DoubleSide;
            var wireFrameMat = new THREE.MeshBasicMaterial();
            wireFrameMat.wireframe = true;

            // create a multimaterial
            var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial, wireFrameMat]);

            return mesh;
        }

        function render() {
            stats.update();

            spGroup.rotation.y = step;
            hullMesh.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>

 2 LatheGeometry---掃描體dom

經過LatheGeometry你能夠從一條光滑曲線開始建立圖形,該曲線成爲樣條曲線,當該曲線繞一個固定點進行旋轉就造成一個相似於花瓶的圖形async

注意,該函數有兩個地方不明白,1 繞固定點進行旋轉,這個固定點是誰,是否能夠指定,2 gui中的segments中的step(1)是什麼含義ide

屬性 描述
points 構成樣條曲線的點的集合
segments 分段數,段數越高,圖形越光滑
phiStart 開始角度
phiLength 建立多大角度的圖形

 

 

<!DOCTYPE html>

<html>

<head>
    <title>Example 06.02 - Advanced 3D geometries - Lathe</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(10, 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;

        // the points group
        var spGroup;
        // the mesh
        var latheMesh;

        generatePoints(12, 2, 2 * Math.PI);

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

            this.segments = 12;
            this.phiStart = 0;
            this.phiLength = 2 * Math.PI;

            this.redraw = function () {
                scene.remove(spGroup);
                scene.remove(latheMesh);
                generatePoints(controls.segments, controls.phiStart, controls.phiLength);
            };
        };

        var gui = new dat.GUI();
        //以往gui的代碼大體都能看懂,可是這裏使用了一個step(1),不知道是什麼含義
        gui.add(controls, 'segments', 0, 50).step(1).onChange(controls.redraw);
        gui.add(controls, 'phiStart', 0, 2 * Math.PI).onChange(controls.redraw);
        gui.add(controls, 'phiLength', 0, 2 * Math.PI).onChange(controls.redraw);


        render();

        function generatePoints(segments, phiStart, phiLength) {
            // add 10 random spheres
            var points = [];
            var height = 5;
            var count = 30;
            for (var i = 0; i < count; i++) {
            //x軸是正弦函數與餘弦函數的結合
            //z軸是基於變量i和count
                var x=(Math.sin(i * 0.2) + Math.cos(i * 0.3)) * height + 12; var y=0; var z=( i - count ) + count / 2 var point=new THREE.Vector3(x, y, z);
                points.push(point);
            }

            spGroup = new THREE.Object3D(); var material = new THREE.MeshBasicMaterial({color: 0xff0000, transparent: false}); points.forEach(function (point) { var spGeom = new THREE.SphereGeometry(0.2); var spMesh = new THREE.Mesh(spGeom, material); spMesh.position.copy(point); spGroup.add(spMesh); }); // add the points as a group to the scene  scene.add(spGroup); // use the same points to create a LatheGeometry
           var latheGeometry = new THREE.LatheGeometry(points, segments, phiStart, phiLength);
            latheMesh = createMesh(latheGeometry);

            scene.add(latheMesh);
        }

        function createMesh(geom) {

            // assign two materials
            //  var meshMaterial = new THREE.MeshBasicMaterial({color:0x00ff00, transparent:true, opacity:0.6});
            var meshMaterial = new THREE.MeshNormalMaterial();
            meshMaterial.side = THREE.DoubleSide;
            var wireFrameMat = new THREE.MeshBasicMaterial();
            wireFrameMat.wireframe = true;

            // create a multimaterial
            var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial, wireFrameMat]);

            return mesh;
        }

        function render() {
            stats.update();

            spGroup.rotation.x = step;
            latheMesh.rotation.x = 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,TubeGeometry--管狀幾何體

  管狀幾何體是沿着一條三維樣條曲線拉伸出一根管子,能夠經過指定頂點來定義路徑,而後使用TubeGeometry來建立這根管子

屬性 描述
path

樣條曲線,

在下面的demo中,咱們使用SplineCurve對象對隨機生成的點進行加工,構建出一條光滑曲線,

來做爲TubeGeometry的樣條曲線

segments 管道的分段數,管道越長,分段數越多才能保持管道的光滑度
radius 管道的半徑
radiusSegmnts 管道圓周的分段數,分段數越多,管道越圓
closed 管道的頭尾是否鏈接起來
debug 額外的調試信息是否添加到管道上

 

 

  

<!DOCTYPE html>

<html>

<head>
    <title>Example 06.04 - Extrude TubeGeometry</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(10, 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;

        // the points group
        var spGroup;
        // the mesh
        var tubeMesh;


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

            this.numberOfPoints = 5;
            this.segments = 64;
            this.radius = 1;
            this.radiusSegments = 8;
            this.closed = false;
            this.points = [];
            // we need the first child, since it's a multimaterial

            this.newPoints = function () {
                var points = [];
                //生成必定數量的點,這些點的x,y,z的座標都是隨機生成的
                for (var i = 0; i < controls.numberOfPoints; i++) { var randomX = -20 + Math.round(Math.random() * 50); var randomY = -15 + Math.round(Math.random() * 40); var randomZ = -20 + Math.round(Math.random() * 40); var point=new THREE.Vector3(randomX, randomY, randomZ); points.push(point); } controls.points = points;
                controls.redraw();
            };

            this.redraw = function () {
                scene.remove(spGroup);
                scene.remove(tubeMesh);
                generatePoints(controls.points, controls.segments, controls.radius, controls.radiusSegments, controls.closed);
            };

        };

        var gui = new dat.GUI();
        gui.add(controls, 'newPoints');
        gui.add(controls, 'numberOfPoints', 2, 15).step(1).onChange(controls.newPoints);
        gui.add(controls, 'segments', 0, 200).step(1).onChange(controls.redraw);
        gui.add(controls, 'radius', 0, 10).onChange(controls.redraw);
        gui.add(controls, 'radiusSegments', 0, 100).step(1).onChange(controls.redraw);
        gui.add(controls, 'closed').onChange(controls.redraw);


        controls.newPoints();


        render();

        function generatePoints(points, segments, radius, radiusSegments, closed) {
            // add n random spheres


            spGroup = new THREE.Object3D();
            var material = new THREE.MeshBasicMaterial({color: 0xff0000, transparent: false});
            points.forEach(function (point) {

                var spGeom = new THREE.SphereGeometry(0.2);
                var spMesh = new THREE.Mesh(spGeom, material);
                spMesh.position.copy(point);
                spGroup.add(spMesh);
            });
            // add the points as a group to the scene
            scene.add(spGroup);

            // use the same points to create a convexgeometry
            //SplineCurve3函數的含義是經過一系列的點來建立一條平滑的曲線。
            //在這裏建立出這條平滑曲線,做爲樣條曲線參數傳遞給TubeGeometry,構建管狀幾何體
 points=new THREE.SplineCurve3(points); var tubeGeometry = new THREE.TubeGeometry(points, segments, radius, radiusSegments, closed);
            tubeMesh = createMesh(tubeGeometry);
            scene.add(tubeMesh);
        }

        function createMesh(geom) {

            // assign two materials
            //var meshMaterial = new THREE.MeshNormalMaterial();
            var meshMaterial = new THREE.MeshBasicMaterial({color: 0x00ff00, transparent: true, opacity: 0.2});

            var wireFrameMat = new THREE.MeshBasicMaterial();
            wireFrameMat.wireframe = true;

            // create a multimaterial
            var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial, wireFrameMat]);

            return mesh;
        }

        function render() {
            stats.update();

            spGroup.rotation.y = step;
            tubeMesh.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>

 

   4,ExtrudeGeometry--拉伸幾何體

 

屬性 描述
amount(數量) 該圖形能夠拉伸多高,只有一面跟着增減
bevelThickness(斜角厚度)

圖形拉伸後造成的中間的拉伸體,該屬性標示斜角的深度,斜角就是拉伸體與先後面之間的倒角

amount和bevelThickness的區別沒有看的很明白,暫時照抄下來,也許有一天突然領悟了呢,

不過看着demo,amount,只有一面跟着增減,bevelThickness是兩個面都跟着變化

 

 bevelSize(斜角尺寸) 指定斜角的高度,如圖所示,是內凹的仍是外凸的
 bevelSegments(斜角分段數)  

 

 

 bevelEnabled(是否應用斜角)  
 curveSegments(曲線分段數) 拉伸圖形時,二維曲線分爲多少段
 step(拉伸體的段數) 拉伸體被分爲多少段,該屬性也麼有看懂,demo也沒有看出差異來
 extrudePath(拉伸路徑) 該屬性定義了圖形沿着什麼路徑拉伸,沒有指定的話,就會沿着z軸拉伸
 material(材質) 拉伸後立體圖形的先後面所使用的材質
 extrudeMaterial(拉伸材質) 拉伸體所使用的材質

 

 

<!DOCTYPE html>

<html>

<head>
    <title>Example 06.03 - Extrude Geometry</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 shape = createMesh(new THREE.ShapeGeometry(drawShape()));
        // add the sphere to the scene
        scene.add(shape);

        // position and point the camera to the center of the scene
        camera.position.x = -20;
        camera.position.y = 60;
        camera.position.z = 60;
        camera.lookAt(new THREE.Vector3(20, 20, 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;


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

            this.amount = 2;
            this.bevelThickness = 2;
            this.bevelSize = 0.5;
            this.bevelEnabled = true;
            this.bevelSegments = 3;
            this.bevelEnabled = true;
            this.curveSegments = 12;
            this.steps = 1;

            this.asGeom = function () {
                // remove the old plane
                scene.remove(shape);
                // create a new one

                var options = {
                    amount: controls.amount,
                    bevelThickness: controls.bevelThickness,
                    bevelSize: controls.bevelSize,
                    bevelSegments: controls.bevelSegments,
                    bevelEnabled: controls.bevelEnabled,
                    curveSegments: controls.curveSegments,
                    steps: controls.steps
                };

                shape = createMesh(new THREE.ExtrudeGeometry(drawShape(), options));
                // add it to the scene.
                scene.add(shape);
            };

        };

        var gui = new dat.GUI();
        gui.add(controls, 'amount', 0, 20).onChange(controls.asGeom);
        gui.add(controls, 'bevelThickness', 0, 10).onChange(controls.asGeom);
        gui.add(controls, 'bevelSize', 0, 10).onChange(controls.asGeom);
        gui.add(controls, 'bevelSegments', 0, 30).step(1).onChange(controls.asGeom);
        gui.add(controls, 'bevelEnabled').onChange(controls.asGeom);
        gui.add(controls, 'curveSegments', 1, 30).step(1).onChange(controls.asGeom);
        gui.add(controls, 'steps', 1, 5).step(1).onChange(controls.asGeom);

        controls.asGeom();
        render();

        function drawShape() {

            // create a basic shape
            var shape = new THREE.Shape(); // startpoint
            shape.moveTo(10, 10);

            // straight line upwards
            shape.lineTo(10, 40);

            // the top of the figure, curve to the right
            shape.bezierCurveTo(15, 25, 25, 25, 30, 40);

            // spline back down
            shape.splineThru(
                    [new THREE.Vector2(32, 30),
                        new THREE.Vector2(28, 20),
                        new THREE.Vector2(30, 10),
                    ]);

            // curve at the bottom
            shape.quadraticCurveTo(20, 15, 10, 10);

            // add 'eye' hole one
            var hole1 = new THREE.Path();
            hole1.absellipse(16, 24, 2, 3, 0, Math.PI * 2, true);
            shape.holes.push(hole1);

            // add 'eye hole 2'
            var hole2 = new THREE.Path();
            hole2.absellipse(23, 24, 2, 3, 0, Math.PI * 2, true);
            shape.holes.push(hole2);

            // add 'mouth'
            var hole3 = new THREE.Path();
            hole3.absarc(20, 16, 2, 0, Math.PI, true);
            shape.holes.push(hole3);

            // return the shape
            return shape;
        }

        function createMesh(geom) {

            geom.applyMatrix(new THREE.Matrix4().makeTranslation(-20, 0, 0));

            // assign two materials
            var meshMaterial = new THREE.MeshNormalMaterial({
                shading: THREE.FlatShading,
                transparent: true,
                opacity: 0.7
            });

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

            // create a multimaterial
            var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial]);

            return mesh;
        }

        function createLine(shape, spaced) {
            if (!spaced) {
        //使用shape的createPointsGeometry方法,將圖形轉化爲一個點集,做爲參數傳遞給Line
var mesh = new THREE.Line(shape.createPointsGeometry(), new THREE.LineBasicMaterial({ color: 0xff3333, linewidth: 2 })); return mesh; } else { var mesh = new THREE.Line(shape.createSpacedPointsGeometry(20), new THREE.LineBasicMaterial({ color: 0xff3333, linewidth: 2 })); return mesh; } } function render() { stats.update(); shape.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>

 

5,引入svg文件構建路徑,而後使用extrudeGeometry來構創建體圖形,

  因爲本人是svg小白一隻,因此這裏不對svg作解讀,其實與上面的demo使用Shape構建路徑同樣,

  只是一個使用svg構建二維圖形,一個使用Shape構建二維圖形,二維圖形構建出來之後,使用ExtrudeGeometry對二維圖形進行拉伸就沒有區別了

 

<!DOCTYPE html>

<html>

<head>
    <title>Example 06.05 - Extrude SVG</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>
    <script type="text/javascript" src="../libs/d3-threeD.js"></script>
    <script type="text/javascript" src="../libs/OrbitControls.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="batman" style="display:none">
    <svg version="1.0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1152px" height="1152px" xml:space="preserve">
<g>
<path  id="batman-path" style="fill:rgb(0,0,0);" d="M 261.135 114.535 C 254.906 116.662 247.491 118.825 244.659 119.344 C 229.433 122.131 177.907 142.565 151.973 156.101 C 111.417 177.269 78.9808 203.399 49.2992 238.815 C 41.0479 248.66 26.5057 277.248 21.0148 294.418 C 14.873 313.624 15.3588 357.341 21.9304 376.806 C 29.244 398.469 39.6107 416.935 52.0865 430.524 C 58.2431 437.23 63.3085 443.321 63.3431 444.06 C 63.4748 446.883 102.278 479.707 120.51 492.418 C 131.003 499.734 148.168 509.93 158.654 515.075 C 169.139 520.22 179.431 525.34 181.524 526.454 C 187.725 529.754 187.304 527.547 179.472 515.713 C 164.806 493.553 158.448 464.659 164.322 446.861 C 169.457 431.303 192.013 421.501 214.324 425.132 C 234.042 428.341 252.142 439.186 270.958 459.064 C 286.677 475.67 292.133 482.967 295.31 491.634 C 297.466 497.514 298.948 495.91 304.862 481.293 C 313.673 459.519 329.808 445.735 346.35 445.851 C 367.654 446 399.679 478.239 412.801 512.745 C 414.093 516.144 416.593 522.632 418.355 527.163 C 420.118 531.695 423.604 542.319 426.103 550.773 C 430.848 566.832 432.355 566.851 434.872 550.88 C 436.395 541.215 451.403 502.522 455.655 497.298 C 457.038 495.599 460.63 489.896 463.636 484.625 C 471.696 470.498 492.318 452.688 505.387 448.568 C 514.602 445.663 517.533 445.549 525.51 447.782 C 539.676 451.749 553.43 467.773 560.706 488.788 L 563.242 496.114 L 567.096 490.012 C 577.709 473.208 593.665 453.899 602.47 447.206 C 607.884 443.09 613.378 438.825 614.679 437.729 C 615.98 436.632 622.927 433.259 630.118 430.233 C 655.159 419.693 681.195 423.407 693.273 439.241 C 697.957 445.382 698.932 448.971 699.538 462.294 C 700.174 476.284 699.51 479.864 693.686 493.854 C 690.073 502.533 684.912 512.883 682.217 516.854 C 679.523 520.825 678.172 524.074 679.215 524.074 C 681.932 524.074 718.787 504.481 732.525 495.734 C 760.018 478.228 788.909 452.599 803.9 432.418 C 807.266 427.886 810.569 423.715 811.239 423.149 C 814.498 420.395 828.253 393.099 833.17 379.627 C 838.223 365.782 838.713 361.822 838.741 334.582 C 838.776 300.425 836.431 291.124 820.154 260.873 C 810.649 243.207 807.498 239.005 788.417 218.543 C 751.511 178.968 688.147 142.549 621.582 122.654 C 581.7 110.734 580.388 110.465 580.388 114.195 C 580.388 115.328 581.302 116.255 582.418 116.255 C 584.279 116.255 587.705 122.106 603.399 152.085 C 613.977 172.29 618.077 189.427 618.264 214.21 C 618.42 234.928 617.88 238.368 612.285 252.269 C 604.327 272.04 590.066 286.889 572.829 293.352 C 558.526 298.714 549.193 297.86 535.704 289.955 C 526.777 284.723 512.304 267.644 509.816 259.404 C 509.132 257.138 507.129 251.358 505.366 246.558 C 503.602 241.759 501.646 231.564 501.018 223.902 C 500.39 216.24 498.491 198.402 496.797 184.261 C 495.104 170.121 493.307 152.047 492.803 144.097 C 492.299 136.147 491.292 125.625 490.565 120.715 L 489.242 111.787 L 483.323 118.267 C 480.067 121.832 477.404 125.618 477.404 126.681 C 477.404 127.744 476.603 128.613 475.624 128.613 C 474.645 128.613 471.275 132.321 468.135 136.852 L 462.426 145.091 L 431.038 145.091 L 399.65 145.091 L 386.811 128.494 C 379.749 119.365 373.509 112.36 372.943 112.926 C 372.377 113.491 371.57 118.875 371.15 124.888 C 370.73 130.902 368.94 147.744 367.172 162.315 C 365.405 176.887 363.523 195.424 362.99 203.509 C 360.283 244.622 352.784 266.044 335.323 282.544 C 326.456 290.923 312.488 297.497 303.508 297.518 C 294.864 297.539 278.732 290.063 269.473 281.748 C 246.952 261.521 238.846 229.614 245.481 187.314 C 247.894 171.928 266.562 131.612 275.927 121.56 C 277.987 119.348 279.673 116.786 279.673 115.867 C 279.673 114.947 279.905 113.593 280.188 112.856 C 281.28 110.017 271.977 110.837 261.136 114.536 L 261.135 114.535 "/>
</g>

</svg>
</div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">

    var orbit;

    // 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 shape = createMesh(new THREE.ShapeGeometry(drawShape()));
        // add the sphere to the scene
        scene.add(shape);

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

        var spotLight = new THREE.DirectionalLight(0xffffff);
        spotLight.position = new THREE.Vector3(70, 170, 70);
        spotLight.intensity = 0.7;

        spotLight.target = shape;

        scene.add(spotLight);

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

        orbit = new THREE.OrbitControls(camera, webGLRenderer.domElement);

        // call the render function
        var step = 0;


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

            this.amount = 2;
            this.bevelThickness = 2;
            this.bevelSize = 0.5;
            this.bevelEnabled = true;
            this.bevelSegments = 3;
            this.bevelEnabled = true;
            this.curveSegments = 12;
            this.steps = 1;

            this.asGeom = function () {
                // remove the old plane
                scene.remove(shape);
                // create a new one

                var options = {
                    amount: controls.amount,
                    bevelThickness: controls.bevelThickness,
                    bevelSize: controls.bevelSize,
                    bevelSegments: controls.bevelSegments,
                    bevelEnabled: controls.bevelEnabled,
                    curveSegments: controls.curveSegments,
                    steps: controls.steps
                };

                shape = createMesh(new THREE.ExtrudeGeometry(drawShape(), options));
                // add it to the scene.
                scene.add(shape);
            };

        };

        var gui = new dat.GUI();
        gui.add(controls, 'amount', 0, 20).onChange(controls.asGeom);
        gui.add(controls, 'bevelThickness', 0, 10).onChange(controls.asGeom);
        gui.add(controls, 'bevelSize', 0, 10).onChange(controls.asGeom);
        gui.add(controls, 'bevelSegments', 0, 30).step(1).onChange(controls.asGeom);
        gui.add(controls, 'bevelEnabled').onChange(controls.asGeom);
        gui.add(controls, 'curveSegments', 1, 30).step(1).onChange(controls.asGeom);
        gui.add(controls, 'steps', 1, 5).step(1).onChange(controls.asGeom);

        controls.asGeom();
        render();

        function drawShape() {


            var svgString = document.querySelector("#batman-path").getAttribute("d");

            var shape = transformSVGPathExposed(svgString);

            // return the shape
            return shape;
        }

        function createMesh(geom) {

            geom.applyMatrix(new THREE.Matrix4().makeTranslation(-390, -74, 0));


            // assign two materials
            var meshMaterial = new THREE.MeshPhongMaterial({color: 0x333333, shininess: 100, metal: true});
            var mesh = new THREE.Mesh(geom, meshMaterial);
            mesh.scale.x = 0.1;
            mesh.scale.y = 0.1;

            mesh.rotation.z = Math.PI;
            mesh.rotation.x = -1.1;
            return mesh;
        }


        function render() {
            stats.update();

            shape.rotation.y = step += 0.005;

            orbit.update();


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

 6 ParametricGeometry

屬性 描述
function 一個函數,以u,v爲參數,其中u,v的值是0-1,返回一個Vector3的點對象
slices u分爲多少份
stacks v分爲多少份,分的份數越多,建立出來的圖形越光滑
useTris 是否使用三角面片,在前面幾章中,咱們瞭解過構建面有兩種方法,三角面或者是四邊形

 

<!DOCTYPE html>

<html>

<head>
    <title>Example 06.06 - Parametric geometries</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 = 50;
        camera.position.z = 50;
        camera.lookAt(new THREE.Vector3(10, -20, 0));

        var spotLight = new THREE.DirectionalLight();
        spotLight.position = new THREE.Vector3(-20, 250, -50);
        spotLight.target.position.x = 30;
        spotLight.target.position.y = -40;
        spotLight.target.position.z = -20;
        spotLight.intensity = 0.3;

        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 () {

        };

        var gui = new dat.GUI();
        var width=10;var depth=10;
       pp=function(u,v){ var x=Math.cos(u*v)*width; var y=Math.sin(u)*width; var z=v*depth; return new THREE.Vector3(x,y,z); };
        klein = function (u, v) {
            u *= Math.PI;
            v *= 2 * Math.PI;

            u = u * 2;
            var x, y, z;
            if (u < Math.PI) {
                x = 3 * Math.cos(u) * (1 + Math.sin(u)) + (2 * (1 - Math.cos(u) / 2)) * Math.cos(u) * Math.cos(v);
                z = -8 * Math.sin(u) - 2 * (1 - Math.cos(u) / 2) * Math.sin(u) * Math.cos(v);
            } else {
                x = 3 * Math.cos(u) * (1 + Math.sin(u)) + (2 * (1 - Math.cos(u) / 2)) * Math.cos(v + Math.PI);
                z = -8 * Math.sin(u);
            }

            y = -2 * (1 - Math.cos(u) / 2) * Math.sin(v);

            return new THREE.Vector3(x, y, z);
        };

        radialWave = function (u, v) {
            var r = 50;

            var x = Math.sin(u) * r;
            var z = Math.sin(v / 2) * 2 * r;
            var y = (Math.sin(u * 4 * Math.PI) + Math.cos(v * 2 * Math.PI)) * 2.8;

            return new THREE.Vector3(x, y, z);
        };

        //var mesh = createMesh(new THREE.ParametricGeometry(radialWave, 120, 120, false));
        var mesh = createMesh(new THREE.ParametricGeometry(pp, 120, 120, false));
        scene.add(mesh);

        render();


        function createMesh(geom) {
            geom.applyMatrix(new THREE.Matrix4().makeTranslation(-25, 0, -25));
            // assign two materials
//            var meshMaterial = new THREE.MeshLambertMaterial({color: 0xff5555});
            //var meshMaterial = new THREE.MeshNormalMaterial();
            var meshMaterial = new THREE.MeshPhongMaterial({
                specular: 0xaaaafff,
                color: 0x3399ff,
                shininess: 40,
                metal: true
            });
            meshMaterial.side = THREE.DoubleSide;
            // create a multimaterial
            var plane = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial]);

            return plane;
        }

        function render() {
            stats.update();
            mesh.rotation.y = step += 0.01;
            mesh.rotation.x = step;
            // 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>

 

  7 TextGeometry---渲染文本

屬性 描述
size 文本大小
height 拉伸的長度
weight 字體權重,normal/bold/bolder等
font 字體名稱
style 字體樣式,normal/italic
bevelThickness 斜角深度
bevelSize 斜角高度
bevelSegments 斜角的分段數
bevelEnabled 是否使用斜角
curveSegments 曲線分段數
steps 拉伸分段數
extrudePath 拉伸路徑
material 拉伸體先後面的材質
extrudeMaterial 拉伸體中間的材質

 

<!DOCTYPE html>

<html>

<head>
    <title>Example 06.07 - Text geometry</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>
    <script type="text/javascript" src="../assets/fonts/helvetiker_regular.typeface.js"></script>
    <script type="text/javascript" src="../assets/fonts/helvetiker_bold.typeface.js"></script>
    <script type="text/javascript" src="../assets/fonts/bitstream_vera_sans_mono_roman.typeface.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(0x000000, 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 = 100;
        camera.position.y = 300;
        camera.position.z = 600;
        camera.lookAt(new THREE.Vector3(400, 0, -300));

        var dirLight = new THREE.DirectionalLight();
        dirLight.position.set(25, 23, 15);
        scene.add(dirLight);


        var dirLight2 = new THREE.DirectionalLight();
        dirLight2.position.set(-25, 23, 15);
        scene.add(dirLight2);

        // 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 text1;
        var text2;

        var controls = new function () {

            this.size = 90;
            this.height = 90;
            this.bevelThickness = 2;
            this.bevelSize = 0.5;
            this.bevelEnabled = true;
            this.bevelSegments = 3;
            this.bevelEnabled = true;
            this.curveSegments = 12;
            this.steps = 1;
            this.font = "helvetiker";
            this.weight = "normal";
//            this.style = "italics";

            this.asGeom = function () {
                // remove the old plane
                scene.remove(text1);
                scene.remove(text2);
                // create a new one

                var options = {
                    size: controls.size,
                    height: controls.height,
                    weight: controls.weight,
                    font: controls.font,
                    bevelThickness: controls.bevelThickness,
                    bevelSize: controls.bevelSize,
                    bevelSegments: controls.bevelSegments,
                    bevelEnabled: controls.bevelEnabled,
                    curveSegments: controls.curveSegments,
                    steps: controls.steps
                };

                console.log(THREE.FontUtils.faces);

                text1 = createMesh(new THREE.TextGeometry("Learning", options));
                text1.position.z = -100;
                text1.position.y = 100;
                scene.add(text1);

                text2 = createMesh(new THREE.TextGeometry("Three.js", options));
                scene.add(text2);
            };

        };

        controls.asGeom();

        var gui = new dat.GUI();
        gui.add(controls, 'size', 0, 200).onChange(controls.asGeom);
        gui.add(controls, 'height', 0, 200).onChange(controls.asGeom);
        gui.add(controls, 'font', ['bitstream vera sans mono', 'helvetiker']).onChange(controls.asGeom);
        gui.add(controls, 'bevelThickness', 0, 10).onChange(controls.asGeom);
        gui.add(controls, 'bevelSize', 0, 10).onChange(controls.asGeom);
        gui.add(controls, 'bevelSegments', 0, 30).step(1).onChange(controls.asGeom);
        gui.add(controls, 'bevelEnabled').onChange(controls.asGeom);
        gui.add(controls, 'curveSegments', 1, 30).step(1).onChange(controls.asGeom);
        gui.add(controls, 'steps', 1, 5).step(1).onChange(controls.asGeom);


        render();


        function createMesh(geom) {

            // assign two materials
//            var meshMaterial = new THREE.MeshLambertMaterial({color: 0xff5555});
//            var meshMaterial = new THREE.MeshNormalMaterial();
            var meshMaterial = new THREE.MeshPhongMaterial({
                specular: 0xffffff,
                color: 0xeeffff,
                shininess: 100,
                metal: true
            });
//            meshMaterial.side=THREE.DoubleSide;
            // create a multimaterial
            var plane = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial]);

            return plane;
        }

        function render() {
            stats.update();
            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>

   7 二元操做

  二元操做須要引入ThreeBSP庫,地址以下:https://github.com/skalnik/ThreeBSP

二元操做的名稱 描述
intersect相交 兩個幾何體相互交疊的部分就造成了一個相交幾何體

 

union聯合 兩個幾何體聯合起來一塊兒建立的幾何體就是聯合幾何體

 

subtract相減 從第一個幾何體中減去兩個幾何體交疊的部分就獲得了相減的幾何體

 

 

 

 

下面demo中的二元操做都是針對sphere1進行的

 

<!DOCTYPE html>

<html>

<head>
    <title>Example 06.08 - Binary operations</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>
    <script type="text/javascript" src="../libs/spin.js"></script>
    <script type="text/javascript" src="../libs/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>


<!-- 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(0x999999, 1.0);
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;

        var sphere1 = createMesh(new THREE.SphereGeometry(5, 20, 30));
        sphere1.position.x = -2;


        var sphere2 = createMesh(new THREE.SphereGeometry(5, 20, 30));
        sphere2.position.set(3, 0, 0);

        var cube = createMesh(new THREE.BoxGeometry(5, 5, 5));
        cube.position.x = -7;

        var result;


        // add the sphere to the scene
        scene.add(sphere1);
        scene.add(sphere2);
        scene.add(cube);

        // position and point the camera to the center of the scene
        camera.position.x = 0;
        camera.position.y = 20;
        camera.position.z = 20;
        camera.lookAt(new THREE.Vector3(0, 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;


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

            this.sphere1PosX = sphere1.position.x;
            this.sphere1PosY = sphere1.position.y;
            this.sphere1PosZ = sphere1.position.z;
            this.sphere1Scale = 1;

            this.sphere2PosX = sphere2.position.x;
            this.sphere2PosY = sphere2.position.y;
            this.sphere2PosZ = sphere2.position.z;
            this.sphere2Scale = 1;

            this.cubePosX = cube.position.x;
            this.cubePosY = cube.position.y;
            this.cubePosZ = cube.position.z;
            this.scaleX = 1;
            this.scaleY = 1;
            this.scaleZ = 1;

            this.actionCube = "subtract"; // add, substract, intersect
            this.actionSphere = "subtract";

            this.showResult = function () {
                redrawResult();
            };

            this.hideWireframes = false;
            this.rotateResult = false;


        };

        var gui = new dat.GUI();
        var guiSphere1 = gui.addFolder("Sphere1");
        guiSphere1.add(controls, "sphere1PosX", -15, 15).onChange(function () {
            sphere1.position.set(controls.sphere1PosX, controls.sphere1PosY, controls.sphere1PosZ)
        });
        guiSphere1.add(controls, "sphere1PosY", -15, 15).onChange(function () {
            sphere1.position.set(controls.sphere1PosX, controls.sphere1PosY, controls.sphere1PosZ)
        });
        guiSphere1.add(controls, "sphere1PosZ", -15, 15).onChange(function () {
            sphere1.position.set(controls.sphere1PosX, controls.sphere1PosY, controls.sphere1PosZ)
        });
        guiSphere1.add(controls, "sphere1Scale", 0, 10).onChange(function (e) {
            sphere1.scale.set(e, e, e)
        });

        var guiSphere2 = gui.addFolder("Sphere2");
        guiSphere2.add(controls, "sphere2PosX", -15, 15).onChange(function () {
            sphere2.position.set(controls.sphere2PosX, controls.sphere2PosY, controls.sphere2PosZ)
        });
        guiSphere2.add(controls, "sphere2PosY", -15, 15).onChange(function () {
            sphere2.position.set(controls.sphere2PosX, controls.sphere2PosY, controls.sphere2PosZ)
        });
        guiSphere2.add(controls, "sphere2PosZ", -15, 15).onChange(function () {
            sphere2.position.set(controls.sphere2PosX, controls.sphere2PosY, controls.sphere2PosZ)
        });
        guiSphere2.add(controls, "sphere2Scale", 0, 10).onChange(function (e) {
            sphere2.scale.set(e, e, e)
        });
        guiSphere2.add(controls, "actionSphere", ["subtract", "intersect", "union", "none"]);

        var guiCube = gui.addFolder("cube");
        guiCube.add(controls, "cubePosX", -15, 15).onChange(function () {
            cube.position.set(controls.cubePosX, controls.cubePosY, controls.cubePosZ)
        });
        guiCube.add(controls, "cubePosY", -15, 15).onChange(function () {
            cube.position.set(controls.cubePosX, controls.cubePosY, controls.cubePosZ)
        });
        guiCube.add(controls, "cubePosZ", -15, 15).onChange(function () {
            cube.position.set(controls.cubePosX, controls.cubePosY, controls.cubePosZ)
        });
        guiCube.add(controls, "scaleX", 0, 10).onChange(function (e) {
            cube.scale.x = e
        });
        guiCube.add(controls, "scaleY", 0, 10).onChange(function (e) {
            cube.scale.y = e
        });
        guiCube.add(controls, "scaleZ", 0, 10).onChange(function (e) {
            cube.scale.z = e
        });
        guiCube.add(controls, "actionCube", ["subtract", "intersect", "union", "none"]);

        gui.add(controls, "showResult");
        gui.add(controls, "rotateResult");
        gui.add(controls, "hideWireframes").onChange(function () {
            if (controls.hideWireframes) {
                sphere1.material.visible = false;
                sphere2.material.visible = false;
                cube.material.visible = false;
            } else {
                sphere1.material.visible = true;
                sphere2.material.visible = true;
                cube.material.visible = true;
            }
        });

        render();

        var spinner;

        function redrawResult() {

            showSpinner();

            // make the call async to avoid blocking the thread. Need
            // to set timeout > 1, if not executed immediately.
            setTimeout(function () {
                scene.remove(result);
                //生成球1,球2和方塊的BSP對象
              var sphere1BSP = new ThreeBSP(sphere1); var sphere2BSP = new ThreeBSP(sphere2); var cube2BSP = new ThreeBSP(cube); var resultBSP;


                // first do the sphere
                switch (controls.actionSphere) {
                    case "subtract":
                    //球1減去球2
 resultBSP = sphere1BSP.subtract(sphere2BSP); break;
                    case "intersect":
                    //球1與球2相交
                        resultBSP = sphere1BSP.intersect(sphere2BSP);
                        break;
                    case "union":
                    //球1與球2聯合
                        resultBSP = sphere1BSP.union(sphere2BSP);
                        break;
                    case "none": // noop;
                }

                // next do the cube
                if (!resultBSP) resultBSP = sphere1BSP;
                switch (controls.actionCube) {
                    case "subtract":
                    //若是球1與球2的二元操做已經進行完畢,那麼此處的操做,則是針對球1與球2二元操做後獲得的BSP對象的
 resultBSP = resultBSP.subtract(cube2BSP); break;
                    case "intersect":
                        resultBSP = resultBSP.intersect(cube2BSP);
                        break;
                    case "union":
                        resultBSP = resultBSP.union(cube2BSP);
                        break;
                    case "none": // noop;
                }


                if (controls.actionCube === "none" && controls.actionSphere === "none") {
                    // do nothing
                } else {
                    //BSP對象還須要使用toMesh函數,使得BSP對象轉化爲網格對象
 result = resultBSP.toMesh(); //因爲二元操做後獲得的幾何體的法向量發生了改變,因此這裏須要從新計算點和麪的法向量
 result.geometry.computeFaceNormals(); result.geometry.computeVertexNormals();
                    scene.add(result);
                }

                hideSpinner(spinner);
            }, 200);
        }

        function createMesh(geom) {

            // assign two materials
            var meshMaterial = new THREE.MeshNormalMaterial();
            meshMaterial.side = THREE.DoubleSide;
            var wireFrameMat = new THREE.MeshBasicMaterial({transparency: true, opacity: 0.5, wireframeLinewidth: 0.5});
            wireFrameMat.wireframe = true;

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

            return mesh;
        }


        function showSpinner() {

            var opts = {
                lines: 13, // The number of lines to draw
                length: 20, // The length of each line
                width: 10, // The line thickness
                radius: 30, // The radius of the inner circle
                corners: 1, // Corner roundness (0..1)
                rotate: 0, // The rotation offset
                direction: 1, // 1: clockwise, -1: counterclockwise
                color: '#000', // #rgb or #rrggbb or array of colors
                speed: 1, // Rounds per second
                trail: 60, // Afterglow percentage
                shadow: false, // Whether to render a shadow
                hwaccel: false, // Whether to use hardware acceleration
                className: 'spinner', // The CSS class to assign to the spinner
                zIndex: 2e9, // The z-index (defaults to 2000000000)
                top: 'auto', // Top position relative to parent in px
                left: 'auto' // Left position relative to parent in px
            };
            var target = document.getElementById('WebGL-output');
            spinner = new Spinner(opts).spin(target);//這個地方暫時沒有看明白,好像使用了另一個庫函數
            return spinner;
        }

        function hideSpinner(spinner) {
            spinner.stop();
        }

        function render() {
            stats.update();


//            sphere.rotation.y=step+=0.01;

//            if (typeof  ThreeBSP!='undefined') {console.log(ThreeBSP)};
//            console.log(ThreeBSP);

            if (controls.rotateResult && result) {
                result.rotation.y += 0.04;
                //      result.rotation.x+=0.04;
                result.rotation.z -= 0.005;
            }

            // 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>
相關文章
相關標籤/搜索