当前位置: 首页 > news >正文

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

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>
    <!--引入three.js三维引擎-->
    <!-- <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script> -->
    <script src="../../three.js-master/build/three.js"></script>
    <script src="../../three.js-master/examples/js/controls/OrbitControls.js"></script>
    <!-- <script src="http://www.yanhuangxueyuan.com/threejs/build/three.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>

在这里插入图片描述

相关文章:

  • 超全面试汇总——Hadoop(二)
  • Android辅助功能(Accessibility)简介
  • SSM网约车管理系统毕业设计-附源码051630
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • 第11章Linux实操篇-Linux磁盘分区、挂载
  • Kotlin协程:Flow的融合、Channel容量、溢出策略
  • android毕业设计选题基于Uniapp+SSM实现的互联网云数据环境下的供销APP购物商城电商
  • 超级详细的mysql安装和配置教程
  • 超级详细的Maven使用教程
  • 界面组件DevExpress WPF Data Grid哪些功能还能增强?一起来看
  • 爱上开源之golang入门至实战第四章函数(Func)(十)
  • SQL Dblink SQL
  • 超级无敌详细使用ubuntu搭建hadoop完全分布式集群
  • Flink学习22:窗口的划分
  • 【卫朋】产品管理:如何做缺陷(漏洞)管理?
  • AngularJS指令开发(1)——参数详解
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • PaddlePaddle-GitHub的正确打开姿势
  • SpiderData 2019年2月16日 DApp数据排行榜
  • zookeeper系列(七)实战分布式命名服务
  • 基于webpack 的 vue 多页架构
  • 那些年我们用过的显示性能指标
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 推荐一个React的管理后台框架
  • 一个JAVA程序员成长之路分享
  • 用Python写一份独特的元宵节祝福
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • #1015 : KMP算法
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #图像处理
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (a /b)*c的值
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (六)激光线扫描-三维重建
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • **python多态
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .FileZilla的使用和主动模式被动模式介绍
  • .net MVC中使用angularJs刷新页面数据列表
  • .NET 中让 Task 支持带超时的异步等待
  • .net反编译的九款神器
  • .NET开发不可不知、不可不用的辅助类(三)(报表导出---终结版)
  • .NET开源快速、强大、免费的电子表格组件
  • .NET框架设计—常被忽视的C#设计技巧
  • /bin/bash^M: bad interpreter: No such file or directory
  • @取消转义
  • [ CTF ] WriteUp- 2022年第三届“网鼎杯”网络安全大赛(朱雀组)
  • [17]JAVAEE-HTTP协议
  • [2021 蓝帽杯] One Pointer PHP
  • [Android View] 可绘制形状 (Shape Xml)
  • [AutoSAR系列] 1.3 AutoSar 架构
  • [BZOJ5250][九省联考2018]秘密袭击(DP)
  • [C#][DevPress]事件委托的使用
  • [Excel]如何找到非固定空白格數列的條件數據? 以月份報價表單為例