点 ponint

首先,我们如果需要在环境中画一个点.我们希望这个点是圆形的,那么我们就创建一个球体网格模型对象,设置我们希望的位置(position),下面的代码中,把y轴+1.是因为在业务场景中把圆点浮出面板,可以看到一个完整的球体点的位置.

  1. //- 添加点
  2. function addPoint(point) {
  3. if (scene) {
  4. scene.children.forEach(item => {
  5. if (item.type === "LineLoop") {
  6. scene.remove(item);
  7. tempData = []
  8. }
  9. })
  10. }
  11. let geometry233 = new THREE.SphereGeometry(1, 40, 40); //创建一个立方体几何对象Geometry
  12. // 点渲染模式
  13. let material233 = new THREE.PointsMaterial({
  14. color: 0xff0000,
  15. // size: 5.0 //点对象像素尺寸
  16. }); //材质对象
  17. let points233 = new THREE.Points(geometry233, material233); //点模型对象
  18. points233.position.set(point.x, point.y +1, point.z);
  19. scene.add(points233)
  20. }

核心代码是通过实例化three.js的Points对象,通过外部点击事件来获取需要放置点的位置,然后添加点对象到场景中

线 Line

有了点的位置,只需要添加线把点连接起来,就行了,下面的代码中包含了部分业务逻辑成分.
tempData变量为模型中的点的个数.通过循环,把实例化THREE.Vector3对象进行数组保存在tempData2变量中.
geometry.vertices需要一个数组,所以我们就直接把前面保存好的tempData2数组push进去即可.
vertices: 用来保存模型中所有顶点位置的数组。
要更新该数组,Geometry.verticesNeedUpdate 需要被设置为true。

  1. let geometry = new THREE.Geometry(); //声明一个空几何体对象
  2. tempData.forEach(item => {
  3. tempData2.push(new THREE.Vector3(item.x, item.y + 1, item.z))
  4. })
  5. geometry.vertices.push(...tempData2)
  6. let material = new THREE.MeshLambertMaterial({
  7. color: 0xfac15f,//三角面颜色
  8. side: THREE.DoubleSide//两面可见
  9. });//材质对象
  10. let line = new THREE.LineLoop(geometry, material);//线条模型对象
  11. scene.add(line);

通过添加点和线了,我们在点击后即可看到连线效果了.
image.png
由于这里用的是LineLoop对象,当点击第三个点的时候,会自动连线闭环,如果不希望自动闭环可以使用Line对象进行实例化

  1. var line = new THREE.Line( geometry, material );

在有线的部分绘制立方体

首先我们明白,绘制立方体和我们不同在(0,0)位置放置一个立方体并无不同,只是我们需要精确到线条的长度决定于墙体的长度,线条的角度决定了墙体的角度即可.
这里提供一个墙体绘制算法函数,通过传入4个点的方式计算长度和角度.

  1. //画墙
  2. function drawWall(objs) {
  3. //长度
  4. let lens = Math.sqrt(Math.pow((Number(objs.eZ) - Number(objs.sZ)), 2) + Math.pow((Number(objs.eX) - Number(objs.sX)), 2));
  5. //位置
  6. let posx = (objs.eX + objs.sX) / 2;
  7. let posz = (objs.eZ + objs.sZ) / 2;
  8. //- 纹理材质
  9. var texture = new THREE.TextureLoader().load("images/pink.png");
  10. texture.wrapS = THREE.RepeatWrapping;
  11. texture.wrapT = THREE.RepeatWrapping;
  12. texture.repeat.set(4, 4);
  13. //旋转角度
  14. let rotate = -Math.atan2((objs.eZ - objs.sZ), (objs.eX - objs.sX));
  15. console.log(Math.atan2((objs.eZ - objs.sZ), (objs.eX - objs.sX)))
  16. // return;
  17. let box = new THREE.CubeGeometry(lens, 15, 2); //- 墙体参数
  18. var material = new THREE.MeshBasicMaterial({
  19. // color: 0xe04747,
  20. transparent: true,
  21. opacity: 0.4,
  22. map: texture
  23. });
  24. var mesh = new THREE.Mesh(box, material);
  25. mesh.position.set(posx, 15 / 2, posz);
  26. mesh.rotation.y = rotate;
  27. this.scene.add(mesh);
  28. render();
  29. }

调用绘制墙体函数的时,就需要手动组装一下每个点的参数.

  1. document.getElementById('show3d').addEventListener('click', function (e) {
  2. if (scene) {
  3. scene.children.forEach(item => {
  4. //- 判断当前子对象是否是环形线
  5. if (item.type === 'LineLoop') {
  6. console.log(item.geometry.vertices)
  7. for (let i = 0; i < item.geometry.vertices.length; i++) {
  8. if (i !== item.geometry.vertices.length - 1) {
  9. let params = {
  10. eZ: item.geometry.vertices[i + 1].z,
  11. sZ: item.geometry.vertices[i].z,
  12. eX: item.geometry.vertices[i + 1].x,
  13. sX: item.geometry.vertices[i].x
  14. }
  15. drawWall(params)
  16. }
  17. }
  18. //- 如果不是一条线,至少是一个三角形的情况最后一条边
  19. if (item.geometry.vertices.length > 2) {
  20. let index = item.geometry.vertices.length - 1;
  21. let params = {
  22. eZ: item.geometry.vertices[0].z,
  23. sZ: item.geometry.vertices[index].z,
  24. eX: item.geometry.vertices[0].x,
  25. sX: item.geometry.vertices[index].x
  26. }
  27. drawWall(params)
  28. }
  29. // drawWall(item.geometry)
  30. }
  31. })
  32. }
  33. })

这个时候,我们就能够根据我们绘制的线进行生成墙体了.
效果;
image.png

完整代码

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>第一个three.js文件_WebGL三维场景</title>
  6. <style>
  7. body {
  8. margin: 0;
  9. overflow: hidden;
  10. /* 隐藏body窗口区域滚动条 */
  11. }
  12. .clickFn {
  13. position: fixed;
  14. top: 10px;
  15. right: 10px;
  16. padding: 4px 15px;
  17. background-color: #999;
  18. border-radius: 4px;
  19. }
  20. </style>
  21. <!--引入three.js三维引擎-->
  22. <script src="./js-r100/three.js"></script>
  23. <script src="./js-r100/controls/OrbitControls.js"></script>
  24. </head>
  25. <body>
  26. <div class='clickFn' id="show3d">显示3D墙体</div>
  27. <script>
  28. /**
  29. * 创建场景对象Scene
  30. */
  31. var scene = new THREE.Scene();
  32. /**
  33. * 创建网格模型
  34. */
  35. // var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
  36. var geometry = new THREE.BoxGeometry(100, 2, 100); //创建一个立方体几何对象Geometry
  37. var material = new THREE.MeshLambertMaterial({
  38. color: 0xffffff,
  39. name: 'belinebox'
  40. }); //材质对象Material
  41. var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
  42. scene.add(mesh); //网格模型添加到场景中
  43. /**
  44. * 光源设置
  45. */
  46. //点光源
  47. var point = new THREE.PointLight(0xffffff);
  48. point.position.set(400, 200, 300); //点光源位置
  49. scene.add(point); //点光源添加到场景中
  50. //环境光
  51. var ambient = new THREE.AmbientLight(0x444444);
  52. scene.add(ambient);
  53. /**
  54. * 相机设置
  55. */
  56. var width = window.innerWidth; //窗口宽度
  57. var height = window.innerHeight; //窗口高度
  58. var k = width / height; //窗口宽高比
  59. var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
  60. //创建相机对象
  61. var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
  62. camera.position.set(200, 300, 200); //设置相机位置
  63. camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
  64. /**
  65. * 创建渲染器对象
  66. */
  67. var renderer = new THREE.WebGLRenderer();
  68. renderer.setSize(width, height);//设置渲染区域尺寸
  69. renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
  70. document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
  71. //- 渲染函数
  72. function render() {
  73. //执行渲染操作 指定场景、相机作为参数
  74. renderer.render(scene, camera);
  75. }
  76. render();
  77. //- 添加鼠标对视觉相机的操作
  78. let controls = new THREE.OrbitControls(camera);
  79. //监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
  80. controls.addEventListener('change', render, { passive: true });
  81. // 获取与射线相交的对象数组
  82. function getIntersects(event) {
  83. event.preventDefault();
  84. // console.log("event.clientX:" + event.clientX)
  85. // console.log("event.clientY:" + event.clientY)
  86. // 声明 raycaster 和 mouse 变量
  87. var raycaster = new THREE.Raycaster();
  88. var mouse = new THREE.Vector2();
  89. // 通过鼠标点击位置,计算出 raycaster 所需点的位置,以屏幕为中心点,范围 -1 到 1
  90. mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  91. mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  92. //通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
  93. raycaster.setFromCamera(mouse, camera);
  94. // 获取与raycaster射线相交的数组集合,其中的元素按照距离排序,越近的越靠前
  95. var intersects = raycaster.intersectObjects(scene.children);
  96. //返回选中的对象数组
  97. return intersects;
  98. }
  99. //- 随机生成16进制颜色
  100. function getColor() {
  101. var colorElements = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f";
  102. var colorArray = colorElements.split(",");
  103. var color = "#";
  104. for (var i = 0; i < 6; i++) {
  105. color += colorArray[Math.floor(Math.random() * 16)];
  106. }
  107. return color;
  108. }
  109. //画墙
  110. function drawWall(objs) {
  111. //长度
  112. let lens = Math.sqrt(Math.pow((Number(objs.eZ) - Number(objs.sZ)), 2) + Math.pow((Number(objs.eX) - Number(objs.sX)), 2));
  113. //位置
  114. let posx = (objs.eX + objs.sX) / 2;
  115. let posz = (objs.eZ + objs.sZ) / 2;
  116. //- 纹理材质
  117. var texture = new THREE.TextureLoader().load("images/pink.png");
  118. texture.wrapS = THREE.RepeatWrapping;
  119. texture.wrapT = THREE.RepeatWrapping;
  120. texture.repeat.set(4, 4);
  121. //旋转角度
  122. let rotate = -Math.atan2((objs.eZ - objs.sZ), (objs.eX - objs.sX));
  123. console.log(Math.atan2((objs.eZ - objs.sZ), (objs.eX - objs.sX)))
  124. // return;
  125. let box = new THREE.CubeGeometry(lens, 15, 2); //- 墙体参数
  126. var material = new THREE.MeshBasicMaterial({
  127. // color: 0xe04747,
  128. transparent: true,
  129. opacity: 0.4,
  130. map: texture
  131. });
  132. var mesh = new THREE.Mesh(box, material);
  133. mesh.position.set(posx, 15 / 2, posz);
  134. mesh.rotation.y = rotate;
  135. this.scene.add(mesh);
  136. render();
  137. }
  138. document.getElementById('show3d').addEventListener('click', function (e) {
  139. if (scene) {
  140. scene.children.forEach(item => {
  141. //- 判断当前子对象是否是环形线
  142. if (item.type === 'LineLoop') {
  143. console.log(item.geometry.vertices)
  144. for (let i = 0; i < item.geometry.vertices.length; i++) {
  145. if (i !== item.geometry.vertices.length - 1) {
  146. let params = {
  147. eZ: item.geometry.vertices[i + 1].z,
  148. sZ: item.geometry.vertices[i].z,
  149. eX: item.geometry.vertices[i + 1].x,
  150. sX: item.geometry.vertices[i].x
  151. }
  152. drawWall(params)
  153. }
  154. }
  155. //- 如果不是一条线,至少是一个三角形的情况最后一条边
  156. if (item.geometry.vertices.length > 2) {
  157. let index = item.geometry.vertices.length - 1;
  158. let params = {
  159. eZ: item.geometry.vertices[0].z,
  160. sZ: item.geometry.vertices[index].z,
  161. eX: item.geometry.vertices[0].x,
  162. sX: item.geometry.vertices[index].x
  163. }
  164. drawWall(params)
  165. }
  166. // drawWall(item.geometry)
  167. }
  168. })
  169. }
  170. })
  171. let isdown = false, ismove = false;
  172. window.addEventListener('mousemove', function () {
  173. if (isdown) {
  174. ismove = true;
  175. //鼠标拖动事件执行函数
  176. }
  177. })
  178. window.addEventListener('mousedown', function () {
  179. isdown = true
  180. ismove = false
  181. })
  182. //- 点击事件
  183. window.addEventListener('mouseup', function (event) {
  184. if (!isdown && ismove) {
  185. return 0;
  186. }
  187. if (ismove) {
  188. return 0;
  189. }
  190. let intsersects = getIntersects(event)
  191. if (intsersects.length > 0) {
  192. if (intsersects[0].object.material.name === 'belinebox') {
  193. let mathColor = getColor();
  194. console.log(intsersects[0])
  195. // intsersects[0].object.material.color.set(mathColor)
  196. //- 添加点到点击的面板上
  197. addPoint(intsersects[0].point);
  198. render()
  199. }
  200. }
  201. })
  202. var tempData = []; //- 存放当前模型中的点的个数
  203. var tempData2 = [];
  204. //- 添加点
  205. function addPoint(point) {
  206. if (scene) {
  207. scene.children.forEach(item => {
  208. if (item.type === "LineLoop") {
  209. scene.remove(item);
  210. tempData = []
  211. }
  212. })
  213. }
  214. tempData.push(point)
  215. let geometry233 = new THREE.SphereGeometry(1, 40, 40); //创建一个立方体几何对象Geometry
  216. // 点渲染模式
  217. let material233 = new THREE.PointsMaterial({
  218. color: 0xff0000,
  219. // size: 5.0 //点对象像素尺寸
  220. }); //材质对象
  221. let points233 = new THREE.Points(geometry233, material233); //点模型对象
  222. points233.position.set(point.x, point.y +1, point.z);
  223. scene.add(points233)
  224. let geometry = new THREE.Geometry(); //声明一个空几何体对象
  225. tempData.forEach(item => {
  226. tempData2.push(new THREE.Vector3(item.x, item.y + 1, item.z))
  227. })
  228. console.log(tempData2, 999)
  229. geometry.vertices.push(...tempData2)
  230. let material = new THREE.MeshLambertMaterial({
  231. color: 0xfac15f,//三角面颜色
  232. side: THREE.DoubleSide//两面可见
  233. });//材质对象
  234. let line = new THREE.LineLoop(geometry, material);//线条模型对象
  235. scene.add(line);
  236. }
  237. </script>
  238. </body>
  239. </html>

绘制底部区域

绘制的区域底部是个多边形,我们可以通过前面画点的形式添加多个三角形来填充多边形,经常尝试发现,如果所有点在当前角度下都是最外侧,则显示正常,如果出现”凹”字类型的有部分挖空区域,则需要通过算法来实现三角形的绘制方法了,目前该代码存在算法bug

  1. //- 画不规则图形
  2. let geometry = new THREE.Geometry(); //声明一个几何体对象Geometry
  3. console.log(pointVector3Arr, 222);
  4. //顶点坐标添加到geometry对象
  5. geometry.vertices.push(...pointVector3Arr)
  6. if (pointVector3Arr.length > 2) {
  7. pointVector3Arr.forEach((item, index) => {
  8. if (index < pointVector3Arr.length - 2) {
  9. face3Arr.push(new THREE.Face3(0, index + 1, index + 2))
  10. face3Arr[index].color = new THREE.Color(0xff0000);
  11. }
  12. })
  13. }
  14. geometry.faces.push(...face3Arr);
  15. console.log(geometry);
  16. let material = new THREE.MeshBasicMaterial({
  17. color: 0xe04747,
  18. side: THREE.DoubleSide, // -两面可见
  19. });
  20. let mesh = new THREE.Mesh(geometry, material);
  21. scene.add(mesh);
  22. render();

呈现效果1: 当不存在凹面的情况
image.png
呈现效果2: 存在凹面的情况
image.png
这样肯定是不行的,项目中电子围栏的区域底部虽然绘制三角形的方式进行了填充,当遇到有向内部缺口时,底部区域范围就出现问题了.为了解决这个问题,我们需要换一个思路来填充底部区域

shape 绘制多边形底部区域

这里写了一个方法来实现底部区域绘制,只要通过shape对象,添加各点坐标,通过ShapeBufferGeometry创建一个多边形的几何体,放置到具体的位置上.
这里需要注意的是,shape.moveTo以及lineTo函数接收的都是一个平面坐标系.当直接通过ShapeBufferGeometry创建几何体添加到场景后,是竖直向下的,这里我们需要在生成Mesh对象后,对Mesh对象进行旋转.就可以正常显示了

  1. //- 画不规则多边形底座 -- 用于作业面底部区域颜色绘制
  2. function generatePloygon() {
  3. let pointArr = [];
  4. if (scene) {
  5. scene.children.forEach(item => {
  6. //- 判断当前子对象是否是环形线
  7. if (item.type === 'LineLoop') {
  8. item.geometry.vertices.forEach(item2 => {
  9. pointArr.push({ x: item2.x, y: item2.y, z: item2.z })
  10. })
  11. }
  12. })
  13. }
  14. //- 根据绘制的点来定义一个二维形状平面
  15. let shape = new THREE.Shape();
  16. console.log(pointArr, 111);
  17. shape.moveTo(pointArr[0].x, pointArr[0].z);
  18. for (let i = 1; i < pointArr.length; i++) {
  19. const element = pointArr[i];
  20. shape.lineTo(pointArr[i].x, pointArr[i].z);
  21. }
  22. shape.autoClose = true;
  23. //- 从一个或多个路径形状中创建一个单面多边形几何体
  24. let shapeGeometry = new THREE.ShapeBufferGeometry(shape, 25);
  25. let shapeMaterial = new THREE.MeshBasicMaterial({
  26. color: 0xe04747,
  27. side: THREE.DoubleSide,
  28. transparent: true,
  29. opacity: 0.4
  30. })
  31. let shapeMesh = new THREE.Mesh(shapeGeometry, shapeMaterial);
  32. shapeMesh.rotateX(Math.PI / 2); //- 按照X轴进行旋转90度
  33. shapeMesh.position.y = 2 //- 设置高度2,放置于地面重合看不到
  34. scene.add(shapeMesh);
  35. render();
  36. }

电子围栏效果:
image.png

完整代码:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>第一个three.js文件_WebGL三维场景</title>
  6. <style>
  7. body {
  8. margin: 0;
  9. overflow: hidden;
  10. /* 隐藏body窗口区域滚动条 */
  11. }
  12. .clickFn {
  13. position: fixed;
  14. top: 10px;
  15. right: 10px;
  16. padding: 4px 15px;
  17. background-color: #999;
  18. border-radius: 4px;
  19. }
  20. </style>
  21. <!--引入three.js三维引擎-->
  22. <script src="./js-r100/three.js"></script>
  23. <script src="./js-r100/controls/OrbitControls.js"></script>
  24. </head>
  25. <body>
  26. <div class='clickFn' id="show3d">显示3D墙体</div>
  27. <script>
  28. /**
  29. * 创建场景对象Scene
  30. */
  31. var scene = new THREE.Scene();
  32. /**
  33. * 创建网格模型
  34. */
  35. // var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
  36. var geometry = new THREE.BoxGeometry(100, 2, 100); //创建一个立方体几何对象Geometry
  37. var material = new THREE.MeshLambertMaterial({
  38. color: 0xffffff,
  39. name: 'belinebox',
  40. transparent: true,
  41. opacity: 0.4
  42. }); //材质对象Material
  43. var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
  44. scene.add(mesh); //网格模型添加到场景中
  45. /**
  46. * 光源设置
  47. */
  48. //点光源
  49. var point = new THREE.PointLight(0xffffff);
  50. point.position.set(400, 200, 300); //点光源位置
  51. scene.add(point); //点光源添加到场景中
  52. //环境光
  53. var ambient = new THREE.AmbientLight(0x444444);
  54. scene.add(ambient);
  55. /**
  56. * 相机设置
  57. */
  58. var width = window.innerWidth; //窗口宽度
  59. var height = window.innerHeight; //窗口高度
  60. var k = width / height; //窗口宽高比
  61. var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
  62. //创建相机对象
  63. var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
  64. camera.position.set(200, 300, 200); //设置相机位置
  65. camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
  66. /**
  67. * 创建渲染器对象
  68. */
  69. var renderer = new THREE.WebGLRenderer();
  70. renderer.setSize(width, height);//设置渲染区域尺寸
  71. renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
  72. document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
  73. //- 渲染函数
  74. function render() {
  75. //执行渲染操作 指定场景、相机作为参数
  76. renderer.render(scene, camera);
  77. }
  78. render();
  79. //- 添加鼠标对视觉相机的操作
  80. let controls = new THREE.OrbitControls(camera);
  81. //监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
  82. controls.addEventListener('change', render, { passive: true });
  83. // 获取与射线相交的对象数组
  84. function getIntersects(event) {
  85. event.preventDefault();
  86. // console.log("event.clientX:" + event.clientX)
  87. // console.log("event.clientY:" + event.clientY)
  88. // 声明 raycaster 和 mouse 变量
  89. var raycaster = new THREE.Raycaster();
  90. var mouse = new THREE.Vector2();
  91. // 通过鼠标点击位置,计算出 raycaster 所需点的位置,以屏幕为中心点,范围 -1 到 1
  92. mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  93. mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  94. //通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
  95. raycaster.setFromCamera(mouse, camera);
  96. // 获取与raycaster射线相交的数组集合,其中的元素按照距离排序,越近的越靠前
  97. var intersects = raycaster.intersectObjects(scene.children);
  98. //返回选中的对象数组
  99. return intersects;
  100. }
  101. //- 随机生成16进制颜色
  102. function getColor() {
  103. var colorElements = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f";
  104. var colorArray = colorElements.split(",");
  105. var color = "#";
  106. for (var i = 0; i < 6; i++) {
  107. color += colorArray[Math.floor(Math.random() * 16)];
  108. }
  109. return color;
  110. }
  111. // 辅助坐标系 参数250表示坐标系大小,可以根据场景大小去设置
  112. var axisHelper = new THREE.AxisHelper(250);
  113. scene.add(axisHelper);
  114. //画墙
  115. function drawWall(objs) {
  116. //长度
  117. let lens = Math.sqrt(Math.pow((Number(objs.eZ) - Number(objs.sZ)), 2) + Math.pow((Number(objs.eX) - Number(objs.sX)), 2));
  118. //位置
  119. let posx = (objs.eX + objs.sX) / 2;
  120. let posz = (objs.eZ + objs.sZ) / 2;
  121. //- 纹理材质
  122. // var texture = new THREE.TextureLoader().load("images/pink.png");
  123. // texture.wrapS = THREE.RepeatWrapping;
  124. // texture.wrapT = THREE.RepeatWrapping;
  125. // texture.repeat.set(4, 4);
  126. //旋转角度
  127. let rotate = -Math.atan2((objs.eZ - objs.sZ), (objs.eX - objs.sX));
  128. // return;
  129. let box = new THREE.CubeGeometry(lens, 15, 2); //- 墙体参数
  130. let material = new THREE.MeshBasicMaterial({
  131. // color: 0xe04747,
  132. transparent: true,
  133. opacity: 0.4,
  134. });
  135. let meshWall = new THREE.Mesh(box, material);
  136. meshWall.position.set(posx, 15 / 2, posz);
  137. meshWall.rotation.y = rotate;
  138. scene.add(meshWall);
  139. render();
  140. }
  141. document.getElementById('show3d').addEventListener('click', function (e) {
  142. let pointVector3Arr = [] //- 存放Vector3数组对象
  143. let pointVector2Arr = [] //- 存放Vector2数组对象
  144. let face3Arr = [] //- 存放三角形面对象
  145. if (scene) {
  146. scene.children.forEach(item => {
  147. //- 判断当前子对象是否是环形线
  148. if (item.type === 'LineLoop') {
  149. for (let i = 0; i < item.geometry.vertices.length; i++) {
  150. if (i !== item.geometry.vertices.length - 1) {
  151. let params = {
  152. eZ: item.geometry.vertices[i + 1].z,
  153. sZ: item.geometry.vertices[i].z,
  154. eX: item.geometry.vertices[i + 1].x,
  155. sX: item.geometry.vertices[i].x
  156. }
  157. drawWall(params)
  158. }
  159. //- 把每个点存在点对象中
  160. pointVector3Arr.push(new THREE.Vector3(item.geometry.vertices[i].x, item.geometry.vertices[i].y, item.geometry.vertices[i].z));
  161. pointVector2Arr.push(new THREE.Vector2(item.geometry.vertices[i].x, item.geometry.vertices[i].y));
  162. }
  163. //- 如果不是一条线,至少是一个三角形的情况最后一条边
  164. if (item.geometry.vertices.length > 2) {
  165. let index = item.geometry.vertices.length - 1;
  166. let params = {
  167. eZ: item.geometry.vertices[0].z,
  168. sZ: item.geometry.vertices[index].z,
  169. eX: item.geometry.vertices[0].x,
  170. sX: item.geometry.vertices[index].x
  171. }
  172. drawWall(params)
  173. }
  174. }
  175. })
  176. }
  177. //- 绘制多边形底座
  178. generatePloygon();
  179. })
  180. //- 画不规则多边形底座 -- 用于作业面底部区域颜色绘制
  181. function generatePloygon() {
  182. let pointArr = [];
  183. if (scene) {
  184. scene.children.forEach(item => {
  185. //- 判断当前子对象是否是环形线
  186. if (item.type === 'LineLoop') {
  187. item.geometry.vertices.forEach(item2 => {
  188. pointArr.push({ x: item2.x, y: item2.y, z: item2.z })
  189. })
  190. }
  191. })
  192. }
  193. //- 根据绘制的点来定义一个二维形状平面
  194. let shape = new THREE.Shape();
  195. console.log(pointArr, 111);
  196. shape.moveTo(pointArr[0].x, pointArr[0].z);
  197. for (let i = 1; i < pointArr.length; i++) {
  198. const element = pointArr[i];
  199. shape.lineTo(pointArr[i].x, pointArr[i].z);
  200. }
  201. shape.autoClose = true;
  202. //- 从一个或多个路径形状中创建一个单面多边形几何体
  203. let shapeGeometry = new THREE.ShapeBufferGeometry(shape, 25);
  204. let shapeMaterial = new THREE.MeshBasicMaterial({
  205. color: 0xe04747,
  206. side: THREE.DoubleSide,
  207. transparent: true,
  208. opacity: 0.4
  209. })
  210. let shapeMesh = new THREE.Mesh(shapeGeometry, shapeMaterial);
  211. shapeMesh.rotateX(Math.PI / 2)
  212. // shapeMesh.rotateY(Math.PI / 2)
  213. // shapeMesh.rotateZ(Math.PI / 2)
  214. shapeMesh.position.y = 2
  215. scene.add(shapeMesh);
  216. render();
  217. }
  218. let isdown = false, ismove = false;
  219. window.addEventListener('mousemove', function () {
  220. if (isdown) {
  221. ismove = true;
  222. //鼠标拖动事件执行函数
  223. }
  224. })
  225. window.addEventListener('mousedown', function () {
  226. isdown = true
  227. ismove = false
  228. })
  229. //- 点击事件
  230. window.addEventListener('mouseup', function (event) {
  231. if (!isdown && ismove) {
  232. return 0;
  233. }
  234. if (ismove) {
  235. return 0;
  236. }
  237. let intsersects = getIntersects(event)
  238. if (intsersects.length > 0) {
  239. if (intsersects[0].object.material.name === 'belinebox') {
  240. let mathColor = getColor();
  241. // intsersects[0].object.material.color.set(mathColor)
  242. //- 添加点到点击的面板上
  243. addPoint(intsersects[0].point);
  244. render()
  245. }
  246. }
  247. })
  248. var tempData = []; //- 存放当前模型中的点的个数
  249. var tempData2 = [];
  250. //- 添加点
  251. function addPoint(point) {
  252. if (scene) {
  253. scene.children.forEach(item => {
  254. if (item.type === "LineLoop") {
  255. scene.remove(item);
  256. tempData = []
  257. }
  258. })
  259. }
  260. tempData.push(point)
  261. let geometry233 = new THREE.SphereGeometry(1, 40, 40); //创建一个立方体几何对象Geometry
  262. // 点渲染模式
  263. let material233 = new THREE.PointsMaterial({
  264. color: 0xff0000,
  265. // size: 5.0 //点对象像素尺寸
  266. }); //材质对象
  267. let points233 = new THREE.Points(geometry233, material233); //点模型对象
  268. points233.position.set(point.x, point.y + 1, point.z);
  269. scene.add(points233)
  270. let geometry = new THREE.Geometry(); //声明一个空几何体对象
  271. tempData.forEach(item => {
  272. tempData2.push(new THREE.Vector3(item.x, item.y + 1, item.z))
  273. })
  274. geometry.vertices.push(...tempData2)
  275. let material = new THREE.MeshLambertMaterial({
  276. color: 0xfac15f,//三角面颜色
  277. side: THREE.DoubleSide//两面可见
  278. });//材质对象
  279. let line = new THREE.LineLoop(geometry, material);//线条模型对象
  280. scene.add(line);
  281. }
  282. </script>
  283. </body>
  284. </html>