Three.js开发指南---创建,加载高级网格和几何体(第八章)

Posted Amy-lover

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Three.js开发指南---创建,加载高级网格和几何体(第八章)相关的知识,希望对你有一定的参考价值。

本章的主要内容:

  一, 通过Three.js自带的功能来组合和合并已有的几何体,创建出新的几何体

  二, 从外部资源中加载网格和几何体

  1 前面的章节中,我们学习到,一个几何体创建的网格,想使用多个材质的方法:

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

  看似一个网格中有一个几何体,多个材质,其实该网格拥有与材质数量相对应的几何体,每个几何体都对应一种材质,形成一个网格,我们得到的是包含多个网格的组

  在下面的demo中,我们将创建一个网格组,该组包含多个网格,当这个组进行缩放,移动,旋转,变形的时候,组内的网格都会跟着变化

  注意点1:创建组,将球体和立方体都添加到该组中

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

  注意点2:计算组的边界,生成一个边界无限大的立方体,对组以及组内子对象应用矩阵变换,得到组内子对象顶点改变后的坐标,复制子对象的每个顶点坐标,重新设置立方体的边界,参见函数setFromObject

  注意点3:辅助线ArrowHelper,其参数的解读,dir:方向,默认是法向量;origin:开始的坐标位置;length:辅助线的长度;color:辅助线的颜色;headLength:头部的长度;headWidth:头部的宽度

<!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从对象创建一个网格数组(THREE.JS 和 GLTF)

Three.JS提升学习5:从外部加载几何体

three.js - 网格组示例? (THREE.Object3D() 高级)

Three.js 加载已经三角剖分的网格是不是比使用四边形的网格更高效?

Three.js - 大型网格的 BinaryLoader 与 BufferGeometry?

Three.js 子网格位置总是返回 (0,0,0)