• Three.js对模型进行多区域染色


    Three.js对模型进行多区域染色

    Three.js对模型进行多区域染色

    在项目中遇到一个对地形图进行多区域染色的需求,即在地形图上选中一个区域,改变该区域的颜色。以下测试代码为学习痕迹。

    测试程序:单机选取点,四个点自动停止选点。双击对区域染色。

    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="../../three.js-master/build/three.js">script>
        <script src="../../three.js-master/examples/js/controls/OrbitControls.js">script>
        
      head>
    
      <body>
        <script>
          /**
           * 创建场景对象Scene
           */
          var scene = new THREE.Scene();
          var posArr = [];
          var geometry = new THREE.PlaneGeometry(100, 100, 50, 50);
          const arr1 = new Array(geometry.attributes.position.count);
          const arr = arr1.fill(1);
          arr.forEach((a, index) => {
            if (index % 3 === 0) {
              geometry.attributes.position.setZ(index, 5 * -1);
            } else if (index % 23 === 0) {
              geometry.attributes.position.setZ(index, 10 * -1);
            }
          });
          const vertexShader = `
    precision highp float;
    varying vec3 fPosition;
    
    void main()
    {
      vec4 pos = modelViewMatrix * vec4(position, 1.0);
      gl_Position = projectionMatrix * pos;
      fPosition = (modelMatrix * vec4(position, 1.0)).xyz;
    }
    `;
    
          const fragmentShader = `
    precision highp float;
    uniform float time;
    varying vec3 fPosition;
    uniform int areaNum;
    struct Area {
      vec3 posList[16];
      int countNum;
      vec4 color;
    };
    uniform Area area[32];
    
    bool pointInPolygon(vec3 p, vec3 points[16], int pCount){
      if (pCount < 3 || pCount > 16) {
        return false;
      }
      bool inside = false;
      for (int i = 0; i < pCount; i++) {
        float xi = points[i].x;
        float yi = points[i].y;
        float xj;
        float yj;
        if (i == 0) {
          xj = points[pCount - 1].x;
          yj = points[pCount - 1].y;
        } else {
          xj = points[i - 1].x;
          yj = points[i - 1].y; 
        }
          bool intersect = ((yi > p.z) != (yj > p.z)) && (p.x < (xj - xi) * (p.z - yi) / (yj - yi) + xi);
          if (intersect) {
            inside = !inside;
          }
        }
      return inside;
    }
    
    void d_color() {
        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    }
    
    void main(){
      if (areaNum > 0) {
        bool f = false;
        for (int i = 0; i < areaNum; i++) {
          int countNum = area[i].countNum;
          vec3 posList[16] = area[i].posList;
          vec4 color = area[i].color;
          bool isInside=pointInPolygon(fPosition, posList, countNum);
          if (isInside) {
            gl_FragColor = color;
            f = true;
          }
          if (!f) {
            d_color();
          }
        }
      } else {
        d_color();
      }
    }`;
          let posArr1 = new Array(16);
          posArr1.fill(new THREE.Vector3(0.0, 0.0, 0.0));
          let area = new Array(32);
          area.fill({
            posList: posArr1,
            countNum: 0,
            color: new THREE.Vector4(0.2, 0.4, 0.3, 1.0),
          });
    
          let uniforms = {
            areaNum: {
              value: 0,
            }, // 染色区域的个数
            area: { value: area }, // 染色区域
          };
    
          var material = new THREE.ShaderMaterial({
            // wireframe: true,
            side: THREE.DoubleSide,
            uniforms: uniforms,
            vertexShader: vertexShader,
            fragmentShader: fragmentShader,
          });
    
          var mesh = new THREE.Mesh(geometry, material);
          mesh.rotation.x = Math.PI / 2;
          scene.add(mesh);
    
          // 辅助坐标系  参数250表示坐标系大小,可以根据场景大小去设置
          var axisHelper = new THREE.AxesHelper(250);
          scene.add(axisHelper);
          // 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对象
          //执行渲染操作   指定场景、相机作为参数
          // renderer.render(scene, camera);
          function render() {
            renderer.render(scene, camera); //执行渲染操作
            // mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
            requestAnimationFrame(render); //请求再次执行渲染函数render
          }
          render();
          var controls = new THREE.OrbitControls(camera, renderer.domElement); //创建控件对象
    
          // 单击事件,选取点
          renderer.domElement.addEventListener("click", (event) =>
            _onMouseClick(event)
          );
          // 双击事件,对选中范围进行渲染
          renderer.domElement.addEventListener("dblclick", (event) =>
            _onMouseDbClick(event)
          );
          function _onMouseClick(event) {
            _updateRaycaster(event);
          }
          function _onMouseDbClick(event) {
            var posVecArr = new Array(16);
            posVecArr.fill(new THREE.Vector3(0.0, 0.0, 0.0));
            for (let i = 0; i < 4; i++) {
              // x->x y->z z->y
              posVecArr[i] = new THREE.Vector3(
                posArr[i].x,
                posArr[i].z,
                posArr[i].y
              );
            }
            setupShaderUniforms(
              4,
              posVecArr,
              new THREE.Vector4(0.8, 0.8, 0.5, 1.0)
            );
          }
    
          function _updateRaycaster(event) {
            //更新拾取器
            raycaster = new THREE.Raycaster();
            const rect = renderer.domElement.getBoundingClientRect();
            let mouse = new THREE.Vector2();
            mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
            mouse.y = (-(event.clientY - rect.top) / rect.height) * 2 + 1;
            raycaster.setFromCamera(mouse, camera);
            //确定所点击位置上的物体数量
            var intersects = raycaster.intersectObjects(scene.children);
    
            const material = new THREE.MeshBasicMaterial({
              color: "#FF00FF",
              transparent: true,
              opacity: 0.5,
            });
    
            //选中后进行的操作
            if (intersects.length) {
              var selected = intersects[0]; //取第一个物体
    
              let pos = {
                x: selected.point.x,
                y: selected.point.y,
                z: selected.point.z,
              };
              console.log(this.posArr);
              posLength = this.posArr.length;
              if (posLength < 4) {
                this.posArr.push(pos);
                _point(pos);
                posLength = this.posArr.length;
                if (posLength > 1) {
                  _line(this.posArr[posLength - 1], this.posArr[posLength - 2]);
                  if (posLength === 4) {
                    console.log("点够了");
                    _line(this.posArr[0], this.posArr[posLength - 1]);
                  }
                }
              }
            }
          }
    
          // 更新shader的uniform
          function setupShaderUniforms(posCount, posVecArr, color) {
            let num = this.mesh.material.uniforms.areaNum.value;
            let area = this.mesh.material.uniforms.area.value;
    
            for (let i = 0; i < area.length; i++) {
              if (area[i].countNum === 0) {
                area[i] = {
                  posList: posVecArr,
                  countNum: posCount,
                  color: color,
                };
                break;
              }
            }
    
            this.mesh.material.uniforms.areaNum.value = num + 1;
            this.mesh.material.uniforms.area.value = area;
    
            this.posArr = [];
          }
    
          function _point(pos) {
            var geometry = new THREE.BufferGeometry();
            var vertices = new Float32Array([pos.x, pos.y, pos.z]);
            geometry.setAttribute(
              "position",
              new THREE.Float32BufferAttribute(vertices, 3)
            );
    
            var material = new THREE.PointsMaterial({ color: 0xff0000, size: 20 });
            var point = new THREE.Points(geometry, material);
            this.scene.add(point);
          }
    
          function _line(pos1, pos2) {
            var geometry = new THREE.BufferGeometry();
            var vertices = new Float32Array([
              pos1.x,
              pos1.y,
              pos1.z,
              pos2.x,
              pos2.y,
              pos2.z,
            ]);
    
            // 创建属性缓冲区对象
            var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组,表示一个顶点的xyz坐标
            // 设置几何体attributes属性的位置属性
            geometry.attributes.position = attribue;
    
            var material = new THREE.LineBasicMaterial({
              color: 0xff0000,
            });
    
            var line = new THREE.Line(geometry, material);
            this.scene.add(line);
          }
        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
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304

    在这里插入图片描述

  • 相关阅读:
    MySQL视图详解
    E. 矩阵第k大
    java计算机毕业设计ssm金华学校社团管理系统(源码+系统+mysql数据库+Lw文档)
    关于焊点检测SJ-BIST)模块实现
    数据的力量:Facebook如何通过数据分析驱动创新
    【初学不要怕】python是数据分析的一把利器(详解)
    基于Java+微信小程序实现《优购电商小程序》
    Vue框架之自定义钩子函数,nextTick,局部和全局,什么叫组件?什么是复用?,注册组件需要主要的点注册组件的属性,Css样式的覆盖解决
    【数据结构】顺序表---C语言版(数据结构开篇小菜,全网最详细!小白看一遍就学会!!!)
    面试题:打印课程
  • 原文地址:https://blog.csdn.net/wz122330/article/details/126610813