• three.js之缓冲类型几何体顶点


    专栏目录请点击

    简介

    • 顶点一般使我们在创建模型的时候使用的,他一般对应buffer类型的几何体,使用BufferGeometry创建 点击
    • 我们还会用到BufferAttribute来设置相应的属性,如顶点位置向量,面片索引,法向量,颜色值,UV坐标以及任何自定义 attribute 点击

    构成

    顶点是由两个元素组成的

    1. 顶点的位置
    2. 顶点的颜色

    代码

    顶点构成图形

    DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>第一个three.js文件_WebGL三维场景title>
        <style>
            body {
                margin: 0;
                overflow: hidden;
                /* 隐藏body窗口区域滚动条 */
            }
        style>
        
        <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js">script>
        <script src="http://www.yanhuangxueyuan.com/threejs/examples/js/controls/OrbitControls.js">script>
    head>
    
    <body>
        <script>
            /**
             * 创建场景对象Scene
             */
            var scene = new THREE.Scene();
            /**
             * 创建网格模型
             */
            var geometry = new THREE.BufferGeometry(); //创建一个Buffer类型几何体对象
            //类型数组创建顶点数据
            var vertices = new Float32Array([
                0, 0, 0, //顶点1坐标
                50, 0, 0, //顶点2坐标
                0, 100, 0, //顶点3坐标
                0, 0, 10, //顶点4坐标
                0, 0, 100, //顶点5坐标
                50, 0, 10, //顶点6坐标
            ]);
            // 创建属性缓冲区对象
            var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组,表示一个顶点的xyz坐标
            // 设置几何体attributes属性的位置属性
            geometry.attributes.position = attribue;
            const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
            const mesh = new THREE.Mesh(geometry, material);
            scene.add(mesh);
            // 辅助坐标系  参数250表示坐标系大小,可以根据场景大小去设置
            var axisHelper = new THREE.AxisHelper(250);
            scene.add(axisHelper);
            /**
             * 光源设置
             */
            //点光源
            var point = new THREE.PointLight(0xffffff); // 参数为光照强度
            point.position.set(400, 200, 300); //点光源位置
            scene.add(point); //点光源添加到场景中
            //环境光
            var ambient = new THREE.AmbientLight(0x444444);
            scene.add(ambient);
            // console.log(scene)
            // console.log(scene.children)
            /**
             * 相机设置
             */
            var width = window.innerWidth; //窗口宽度
            var height = window.innerHeight; //窗口高度
            var k = width / height; //窗口宽高比
            var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
            //创建相机对象
            var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
            camera.position.set(200, 300, 200); //设置相机位置
            camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
            /**
             * 创建渲染器对象
             */
            var renderer = new THREE.WebGLRenderer();
            renderer.setSize(width, height);//设置渲染区域尺寸
            renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
            document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
            // 渲染函数
            function render() {
                renderer.render(scene, camera);//执行渲染操作
            }
            render();
            var controls = new THREE.OrbitControls(camera, renderer.domElement);//创建控件对象
            controls.addEventListener('change', render);//监听鼠标、键盘事件
        script>
    body>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    在这里插入图片描述

    核心代码

    var geometry = new THREE.BufferGeometry(); //创建一个Buffer类型几何体对象
    //类型数组创建顶点数据
    var vertices = new Float32Array([
        0, 0, 0, //顶点1坐标
        50, 0, 0, //顶点2坐标
        0, 100, 0, //顶点3坐标
        0, 0, 10, //顶点4坐标
        0, 0, 100, //顶点5坐标
        50, 0, 10, //顶点6坐标
    ]);
    // 创建属性缓冲区对象
    var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组,表示一个顶点的xyz坐标
    // 设置几何体attributes属性的位置属性
    geometry.attributes.position = attribue;
    const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
    const mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    顶点的位置与颜色

    var geometry = new THREE.BufferGeometry(); //声明一个缓冲几何体对象
    
    //类型数组创建顶点位置position数据
    var vertices = new Float32Array([
        0, 0, 0, //顶点1坐标
        50, 0, 0, //顶点2坐标
        0, 100, 0, //顶点3坐标
    
        0, 0, 10, //顶点4坐标
        0, 0, 100, //顶点5坐标
        50, 0, 10, //顶点6坐标
    ]);
    // 创建属性缓冲区对象
    var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组,作为一个顶点的xyz坐标
    // 设置几何体attributes属性的位置position属性
    geometry.attributes.position = attribue;
    //类型数组创建顶点颜色color数据
    var colors = new Float32Array([
        1, 0, 0, //顶点1颜色
        0, 1, 0, //顶点2颜色
        0, 0, 1, //顶点3颜色
    
        1, 1, 0, //顶点4颜色
        0, 1, 1, //顶点5颜色
        1, 0, 1, //顶点6颜色
    ]);
    // 设置几何体attributes属性的颜色color属性
    geometry.attributes.color = new THREE.BufferAttribute(colors, 3); //3个为一组,表示一个顶点的颜色数据RGB
    //材质对象
    var material = new THREE.PointsMaterial({
        // 使用顶点颜色数据渲染模型,不需要再定义color属性
        // color: 0xff0000,
        vertexColors: THREE.VertexColors, //以顶点颜色为准
        size: 10.0 //点对象像素尺寸
    });
    // 点渲染模式  点模型对象Points
    var points = new THREE.Points(geometry, material); //点模型对象
    scene.add(points); //点对象添加到场景
    // 辅助坐标系  参数250表示坐标系大小,可以根据场景大小去设置
    var axisHelper = new THREE.AxisHelper(250);
    scene.add(axisHelper);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    在这里插入图片描述
    我们会发现他是一一对应的关系

    • 这里的材质的颜色设置,我们使用的是VertexColors这个属性,并不是使用的color属性
      • 他的默认值是THREE.NoColor,也就是说模型的颜色渲染效果取决于材质属性.color,如果把材质属性VertexColors的值设置为THREE.VertexColors,那么他进行渲染的时候就会使用几何体顶点的颜色数据geometry.attributes.color

    BufferAttribute

    这个属性是为了提供各种各样符合顶点的数据,比如顶点的颜色,顶点的位置数据,提供顶点属性的值,如geometry.attributes.position

    颜色差值

    当我们把下面代码

    //材质对象
    var material = new THREE.PointsMaterial({
        // 使用顶点颜色数据渲染模型,不需要再定义color属性
        // color: 0xff0000,
        vertexColors: THREE.VertexColors, //以顶点颜色为准
        size: 10.0 //点对象像素尺寸
    });
    // 点渲染模式  点模型对象Points
    var points = new THREE.Points(geometry, material); //点模型对象
    scene.add(points); //点对象添加到场景
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    修改成

    //材质对象
    var material = new THREE.MeshBasicMaterial({vertexColors: THREE.VertexColors,});
    // 点渲染模式  点模型对象Points
    var points = new THREE.Mesh(geometry, material); //点模型对象
    scene.add(points); //点对象添加到场景
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们会发现他的渲染效果如下
    在这里插入图片描述

    • 他呈现出一种渐变效果,之所以成年初渐变效果,是因为webgl进行渲染的时候会对于颜色数据进行差值计算
      • 比如端点1设置为红色,端点2设置为蓝色,那么整个线条会呈现出点1到点2红色到蓝色的渐变
      • 对于网格模型Mesh来说,就是餐侥幸的三个顶点分别设置一个颜色,三角形内部的区域像素会根据这三个顶点的颜色进行渲染计算
    • 插值计算示意图
      • 在这里插入图片描述

    法向量

    • webgl中为了计算光线与物体表面入射角,首先要计算物体表面每个位置的法线方向
    • 在网格模型中,曲面是有一个一个三角形构成,为了表示物体表面各个位置的发现方向,我们可以给几何体的每个顶点定义一个方向向量

    在这里插入图片描述

    不设置法向量

    DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>顶点法向量光照计算title>
        <style>
            body {
                margin: 0;
                overflow: hidden;
                /* 隐藏body窗口区域滚动条 */
            }
        style>
        
        <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js">script>
        
        <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/controls/OrbitControls.js">script>
    head>
    
    <body>
        <script>
            /**
             * 创建场景对象Scene
             */
            var scene = new THREE.Scene();
            /**
             * 创建网格模型
             */
            var geometry = new THREE.BufferGeometry(); //声明一个空几何体对象
            //类型数组创建顶点位置position数据
            var vertices = new Float32Array([
                0, 0, 0, //顶点1坐标
                50, 0, 0, //顶点2坐标
                0, 100, 0, //顶点3坐标
    
                0, 0, 0, //顶点4坐标
                0, 0, 100, //顶点5坐标
                50, 0, 0, //顶点6坐标
    
            ]);
            // 创建属性缓冲区对象
            var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组
            // 设置几何体attributes属性的位置position属性
            geometry.attributes.position = attribue
    
            //材质对象
            var material = new THREE.MeshLambertMaterial({
                color: 0x0000ff, //三角面颜色
                side: THREE.DoubleSide //两面可见
            });
            var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
            scene.add(mesh); //网格模型添加到场景中
    
            // 辅助坐标系
            var axisHelper = new THREE.AxisHelper(250);
            scene.add(axisHelper);
            /**
             * 光源设置
             */
            //点光源
            var point = new THREE.PointLight(0xffffff);
            point.position.set(400, 200, 300); //点光源位置
            scene.add(point); //点光源添加到场景中
            //环境光
            var ambient = new THREE.AmbientLight(0x444444);
            scene.add(ambient);
            /**
             * 相机设置
             */
            var width = window.innerWidth; //窗口宽度
            var height = window.innerHeight; //窗口高度
            var k = width / height; //窗口宽高比
            var s = 150; //三维场景显示范围控制系数,系数越大,显示的范围越大
            //创建相机对象
            var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
            camera.position.set(200, 300, 200); //设置相机位置
            camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
            /**
             * 创建渲染器对象
             */
            var renderer = new THREE.WebGLRenderer();
            renderer.setSize(width, height); //设置渲染区域尺寸
            renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
            document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
    
            // 渲染函数
            function render() {
                renderer.render(scene, camera); //执行渲染操作
            }
            render();
            //创建控件对象  相机对象camera作为参数   控件可以监听鼠标的变化,改变相机对象的属性
            var controls = new THREE.OrbitControls(camera, renderer.domElement);
            //监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
            controls.addEventListener('change', render);
        script>
    
    body>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

    上面的代码没有设置法向量,他渲染的图形是下面这个样子的

    在这里插入图片描述

    • 我们可以看到,整个图形就像是没有光照一样,但是当我们加上了下面的代码
    var normals = new Float32Array([
        0, 0, 1, //顶点1法向量
        0, 0, 1, //顶点2法向量
        0, 0, 1, //顶点3法向量
    
        0, 1, 0, //顶点4法向量
        0, 1, 0, //顶点5法向量
        0, 1, 0, //顶点6法向量
    ]);
    // 设置几何体attributes属性的位置normal属性
    geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); //3个为一组,表示一个顶点的法向量数据
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    他的渲染就是下面这个样子的
    在这里插入图片描述
    这样就有了光的散射

    • 所以,我们在集合体中,常用的属性如下
    // 访问几何体顶点位置数据
    BufferGeometry.attributes.position
    // 访问几何体顶点颜色数据
    BufferGeometry.attributes.color
    // 访问几何体顶点法向量数据
    BufferGeometry.attributes.normal
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    顶点索引

    使用顶点索引的目的是用来复用顶点数据,什么是复用顶点数据呢,比如,下面这个矩形

    在这里插入图片描述

    1. 这个矩形是用两个三角形拼凑而成,如果要定义顶点的话,那么需要定义6个顶点
    2. 但是我们会发现两个三角形有两个顶点的位置是重合的,而对于这些重合的顶点,我们可以值定义一次

    不复用顶点

    如果不复用顶点的话,我们需要定义6个顶点

    /**
     * 创建网格模型
     */
    var geometry = new THREE.BufferGeometry(); //声明一个空几何体对象
    //类型数组创建顶点位置position数据
    var vertices = new Float32Array([
        0, 0, 0, //顶点1坐标
        80, 0, 0, //顶点2坐标
        80, 80, 0, //顶点3坐标
    
        0, 0, 0, //顶点4坐标   和顶点1位置相同
        80, 80, 0, //顶点5坐标  和顶点3位置相同
        0, 80, 0, //顶点6坐标
    ]);
    // 创建属性缓冲区对象
    var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组
    // 设置几何体attributes属性的位置position属性
    geometry.attributes.position = attribue
    var normals = new Float32Array([
        0, 0, 1, //顶点1法向量
        0, 0, 1, //顶点2法向量
        0, 0, 1, //顶点3法向量
    
        0, 0, 1, //顶点4法向量
        0, 0, 1, //顶点5法向量
        0, 0, 1, //顶点6法向量
    ]);
    // 设置几何体attributes属性的位置normal属性
    geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); //3个为一组,表示一个顶点的xyz坐标
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    渲染如下

    在这里插入图片描述

    复用顶点

    我们先定义顶点

    var geometry = new THREE.BufferGeometry(); //声明一个空几何体对象
    //类型数组创建顶点位置position数据
    var vertices = new Float32Array([
      0, 0, 0, //顶点1坐标
      80, 0, 0, //顶点2坐标
      80, 80, 0, //顶点3坐标
      0, 80, 0, //顶点4坐标
    ]);
    // 创建属性缓冲区对象
    var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组
    // 设置几何体attributes属性的位置position属性
    geometry.attributes.position = attribue
    var normals = new Float32Array([
      0, 0, 1, //顶点1法向量
      0, 0, 1, //顶点2法向量
      0, 0, 1, //顶点3法向量
      0, 0, 1, //顶点4法向量
    ]);
    // 设置几何体attributes属性的位置normal属性
    geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); //3个为一组,表示一个顶点的xyz坐标
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    然后我们去定义复用的索引

    // Uint16Array类型数组创建顶点索引数据
    var indexes = new Uint16Array([
      // 0对应第1个顶点位置数据、第1个顶点法向量数据
      // 1对应第2个顶点位置数据、第2个顶点法向量数据
      // 索引值3个为一组,表示一个三角形的3个顶点
      0, 1, 2,
      0, 2, 3,
    ])
    // 索引数据赋值给几何体的index属性
    geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    我们可以看注释,也可以看下面的解释

    1. 在数组中一个数字代表一个顶点,三个数字代表一个三角形数据
    2. 0表示第一个顶点数据,1表示第二个顶点的数据,一次类推
    3. 我们可以看到一个数组中有两个重复的数据即 0和2,也就是说第一个和第三个顶点被复用
    • 在创建顶点索引的时候,可以根据顶点的数量选择类型数组
    • 对于顶点索引而言要选择整形类的数组,非索引的顶点数据,可以选择浮点类型的数组,如Float32Array
    类型数组位数字节类型描述C语言等价类型
    Int8Array81有符号8位整型int8_t
    Uint8Array81无符号8位整型uint8_t
    Int16Array162有符号16位整型 int16_t
    Uint16Array162无符号16位整型int16_t
    Int32Array324有符号32位整型int32_t
    Uint32Array324无符号32位整型uint32_t
    Float32Array324单精度(32位)浮点数float
    Float64Array648双精度(64位)浮点数double
  • 相关阅读:
    【LeetCode: 2596. 检查骑士巡视方案:深度优先搜索】
    Linux C语言开发(续)
    如何查看自己的GPU型号以及配置信息
    MySQL - 一文解析 SQL 的执行顺序
    Linux应用-ElasticSearch安装
    Android项目打包aar(kts)
    计算机视觉(CV)技术的优势和挑战
    防御式编程介绍
    stream中map相关方法
    Linux安装各种应用服务程序
  • 原文地址:https://blog.csdn.net/youhebuke225/article/details/127926998