WebGL three.js进修笔记 自定义极点竖立几何体

自定义极点竖立多少体与克隆

Three.js自身已有许多的网格模子,基础已够我们的运用,然则假如我们照样想本身依据极点坐标来竖立多少模子的话,Three.js也是能够的。

基础结果如图:
《WebGL three.js进修笔记 自定义极点竖立几何体》

点击检察demo演示

demo演示:https://nsytsqdtn.github.io/d…

实际上出于机能的斟酌,three.js是以为我们的多少体在全部生命周期中是不会转变的,然则我们照样想运用dat.gui.js去及时更新我们自定义多少体的极点信息。

当极点信息发生变化时,我们就须要运用
geometry.verticesNeedUpdate = true;
然则在每一帧衬着完后这个值又会变成false,所以我们须要每次衬着中都更新这个值。

完全代码以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Three.js</title>
    <script src="../../../Import/three.js"></script>
    <script src="../../../Import/stats.js"></script>
    <script src="../../../Import/Setting.js"></script>
    <script src="../../../Import/OrbitControls.js"></script>
    <script src="../../../Import/dat.gui.min.js"></script>
    <script src="../../../Import/SceneUtils.js"></script>
    <style type="text/css">
        div#canvas-frame {
            border: none;
            cursor: pointer;
            width: 100%;
            height: 850px;
            background-color: #333333;
        }
    </style>
</head>
<body onload="threeStart()">
<div id="canvas-frame"></div>
<script>
    let renderer, camera, scene;
    let controller;
    let controls;
    let vertices;
    let faces;
    let controlPoints = [];
    let geom;
    let mesh;

    //初始化衬着器
    function initThree() {
        renderer = new THREE.WebGLRenderer({
            antialias: true
        });//定义衬着器
        renderer.setSize(window.innerWidth, window.innerHeight);//设置衬着的宽度和高度
        document.getElementById("canvas-frame").appendChild(renderer.domElement);//将衬着器加在html中的div内里
        renderer.setClearColor(0x333333, 1.0);//衬着的色彩设置
        renderer.shadowMapEnabled = true;//开启暗影,默许是封闭的,太影响机能
        renderer.shadowMapType = THREE.PCFSoftShadowMap;//暗影的一个范例


        camera = new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight, 1, 10000);//perspective是透视摄像机,这类摄像机看上去画面有3D结果

        //摄像机的位置
        camera.position.x = 10;
        camera.position.y = 15;
        camera.position.z = 15;
        camera.up.x = 0;
        camera.up.y = 1;//摄像机的上方向是Y轴
        camera.up.z = 0;
        camera.lookAt(0, 0, 0);//摄像机对焦的位置
        //这三个参数配合作用才决议画面

        scene = new THREE.Scene();

        let light = new THREE.SpotLight(0xffffff, 1.0, 0);//点光源
        light.position.set(-40, 60, -10);
        light.castShadow = true;//开启暗影
        light.shadowMapWidth = 8192;//暗影的区分率,能够不设置对照看结果
        light.shadowMapHeight = 8192;
        scene.add(light);
        light = new THREE.AmbientLight(0xcccccc, 0.2);//环境光,假如不加,点光源照不到的处所就完全是黑色的
        scene.add(light);

        cameraControl();

         vertices = [
            new THREE.Vector3(1, 3, 1),
            new THREE.Vector3(1, 3, -1),
            new THREE.Vector3(1, -1, 1),
            new THREE.Vector3(1, -1, -1),
            new THREE.Vector3(-1, 3, -1),
            new THREE.Vector3(-1, 3, 1),
            new THREE.Vector3(-1, -1, -1),
            new THREE.Vector3(-1, -1, 1)
        ];//极点坐标,一共8个极点

         faces = [
             new THREE.Face3(0, 2, 1),
             new THREE.Face3(2, 3, 1),
             new THREE.Face3(4, 6, 5),
             new THREE.Face3(6, 7, 5),
             new THREE.Face3(4, 5, 1),
             new THREE.Face3(5, 0, 1),
             new THREE.Face3(7, 6, 2),
             new THREE.Face3(6, 3, 2),
             new THREE.Face3(5, 7, 0),
             new THREE.Face3(7, 2, 0),
             new THREE.Face3(1, 3, 4),
             new THREE.Face3(3, 6, 4),
        ];//极点索引,每一个面都邑依据极点索引的递次去绘制线条

        geom = new THREE.Geometry();
        geom.vertices = vertices;
        geom.faces = faces;
        geom.computeFaceNormals();//计算法向量,会对光照产生影响

        //两个材质放在一同运用
        let materials = [
            new THREE.MeshLambertMaterial({opacity: 0.6, color: 0x44ff44, transparent: true}),//透明度变动
            new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})//线条材质,让视察更直观一点

        ];
        //建立多材质对象,要引入SceneUtils.js文件,假如只要一个材质就不须要这个函数
        mesh = THREE.SceneUtils.createMultiMaterialObject(geom, materials);
        mesh.children.forEach(function (e) {
            e.castShadow = true
        });
        scene.add(mesh);

        initDat();
    }
   //可视化面板
    function initDat() {
        function addControl(x, y, z) {
            controls = new function () {
                this.x = x;
                this.y = y;
                this.z = z;
            };
            return controls;
        }
        controlPoints.push(addControl(3, 5, 3));
        controlPoints.push(addControl(3, 5, 0));
        controlPoints.push(addControl(3, 0, 3));
        controlPoints.push(addControl(3, 0, 0));
        controlPoints.push(addControl(0, 5, 0));
        controlPoints.push(addControl(0, 5, 3));
        controlPoints.push(addControl(0, 0, 0));
        controlPoints.push(addControl(0, 0, 3));

        //克隆一个多少体
        let addClone = new function () {
            this.clone = function () {

                let clonedGeometry = mesh.children[0].geometry.clone();
                let materials = [
                    new THREE.MeshLambertMaterial({opacity: 0.6, color: 0xff44ff, transparent: true}),
                    new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})

                ];

                let mesh2 = THREE.SceneUtils.createMultiMaterialObject(clonedGeometry, materials);
                mesh2.children.forEach(function (e) {
                    e.castShadow = true
                });

                mesh2.translateX(Math.random()*4+3);
                mesh2.translateZ(Math.random()*4+3);
                mesh2.name = "clone";
                //删掉场景中已存在的克隆体,再从新建立一个
                scene.remove(scene.getChildByName("clone"));
                scene.add(mesh2);


            }
        };

        let gui = new dat.GUI();

        gui.add(addClone, 'clone');

        for (let i = 0; i < 8; i++) {
            let f1 = gui.addFolder('Vertices ' + (i + 1));//把每一个极点的三个坐标都收拢在一个Folder内里,越发雅观轻易
            f1.add(controlPoints[i], 'x', -10, 10);
            f1.add(controlPoints[i], 'y', -10, 10);
            f1.add(controlPoints[i], 'z', -10, 10);

        }
    }

   // 摄像机的掌握,能够采纳鼠标拖动来掌握视野
    function cameraControl() {
        controller = new THREE.OrbitControls(camera, renderer.domElement);
        controller.target = new THREE.Vector3(0, 0, 0);
    }

    let plane;

    //初始化物体
    function initObject() {
        //定义了一个地面
        let planeGeometry = new THREE.PlaneGeometry(100, 100, 1, 1);
        let planeMaterial = new THREE.MeshLambertMaterial({
            color: 0xffffff,
        });
        plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 15;
        plane.receiveShadow = true;//开启地面的吸收暗影
        scene.add(plane);//添加到场景中
        // initCustomObj();
    }

    //定义的一个功用文件
    function initSetting() {
        loadAutoScreen(camera, renderer);
        loadFullScreen();
        loadStats();
    }

    //动画
    function render() {
        stats.update();
        //单材质多少体要更新极点的话运用这一段语句
        // for (let i = 0; i < 8; i++) {
        //     console.log(mesh);
        //     mesh.geometry.vertices[i].set(controlPoints[i].x, controlPoints[i].y, controlPoints[i].z);
        //     mesh.geometry.verticesNeedUpdate = true;
        //     mesh.geometry.computeFaceNormals();
        // }
        let vertices = [];
        for (let i = 0; i < 8; i++) {
            vertices.push(new THREE.Vector3(controlPoints[i].x, controlPoints[i].y, controlPoints[i].z));
        }
        mesh.children.forEach(function (e) {
            e.geometry.vertices = vertices;
            e.geometry.verticesNeedUpdate = true;//关照极点更新
            e.geometry.elementsNeedUpdate = true;//迥殊主要,关照线条衔接体式格局更新
            e.geometry.computeFaceNormals();
        });

        requestAnimationFrame(render);
        renderer.render(scene, camera);
    }
    //主函数
    function threeStart() {
        initThree();
        initObject();
        initSetting();
        render();
    }
</script>
</body>
</html>

*

迥殊要注重的是

在极点发生变化时,假如是多材质对象的话,须要运用遍历每一个子对象来举行更新极点数据。而且不仅要更新极点,还要更新线条的衔接体式格局geometry.elementsNeedUpdate = true,不然是没有结果的。(以至尝试了一下不更新极点,只更新线条也是能够到达及时更新的结果)

let vertices = [];
        for (let i = 0; i < 8; i++) {
            vertices.push(new THREE.Vector3(controlPoints[i].x, controlPoints[i].y, controlPoints[i].z));
        }
        mesh.children.forEach(function (e) {
            e.geometry.vertices = vertices;
            e.geometry.verticesNeedUpdate = true;//关照极点更新
            e.geometry.elementsNeedUpdate = true;//迥殊主要,关照线条衔接体式格局更新
            e.geometry.computeFaceNormals();
        });

假如是单一的材质多少体,就不须要去遍历每一个子物体,直接把多少体的每一个极点值变动,然后在关照极点更新,就能够了。

     //单材质多少体要更新极点的话运用这一段语句
         for (let i = 0; i < 8; i++) {
             console.log(mesh);
            mesh.geometry.vertices[i].set(controlPoints[i].x, controlPoints[i].y, controlPoints[i].z);
            mesh.geometry.verticesNeedUpdate = true;
            mesh.geometry.computeFaceNormals();
        }

注:

老版本的three.js,SceneUtils是没有零丁拿出来作为一个js文件的,是直接写在three.js里。
而且运用69版本的three.js时,不须要更新线条的衔接体式格局也能够完成及时更新。然则103版本试了许屡次,都不可。
别的,运用的OrbitControls.js和dat.gui.min.js最好都是和本身用的Three.js版本要一致,不然能够会报错。有一些教程的示例顺序版本能够就比较旧了,假如直接拿来用能够会出问题,注重区分一下。

    原文作者:nsytsqdtn
    原文地址: https://segmentfault.com/a/1190000018975019
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞