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

使用three.js 实现 自定义绘制平面的效果

使用three.js 实现 自定义绘制平面的效果 预览
在这里插入图片描述

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'const box = document.getElementById('box')const scene = new THREE.Scene()const camera = new THREE.PerspectiveCamera(75, box.clientWidth / box.clientHeight, 0.1, 1000)camera.position.set(0, 3, 3)const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true })renderer.setSize(box.clientWidth, box.clientHeight)box.appendChild(renderer.domElement)const controls = new OrbitControls(camera, renderer.domElement)controls.enableDamping = trueconst directionalLight = new THREE.DirectionalLight(0xffffff, 1)directionalLight.position.set(0, 20, 0)scene.add(directionalLight, new THREE.AmbientLight(0xffffff, 1))/* 增加一个面 */
const plane = new THREE.PlaneGeometry(5, 5)const material = new THREE.MeshStandardMaterial({ color: 0xffffff })const planeMesh = new THREE.Mesh(plane, material)planeMesh.rotation.x -= Math.PI / 2scene.add(planeMesh)animate()function animate() {requestAnimationFrame(animate)controls.update()renderer.render(scene, camera)}window.onresize = () => {renderer.setSize(box.clientWidth, box.clientHeight)camera.aspect = box.clientWidth / box.clientHeightcamera.updateProjectionMatrix()}// 事件
const raycaster = new THREE.Raycaster()const getPoint = event => {const mouse = new THREE.Vector2((event.offsetX / event.target.clientWidth) * 2 - 1,-(event.offsetY / event.target.clientHeight) * 2 + 1)raycaster.setFromCamera(mouse, camera)const intersects = raycaster.intersectObjects(scene.children)if (intersects.length > 0) return intersects[0].point}const setPointBox = point => {const box = new THREE.BoxGeometry(0.04, 0.04, 0.04)const material = new THREE.MeshStandardMaterial({ color: 0xff0000 })const boxMesh = new THREE.Mesh(box, material)boxMesh.position.copy(point)scene.add(boxMesh)}/* 开始绘制 */
const pointList = []; let drawMesh = null; let stop = falsebox.addEventListener('contextmenu', () => {stop = trueconst { indexGroup, faceGroup, uvGroup } = multShapeGroup(pointList)if (drawMesh) updateMultShapePlaneGeometry(drawMesh.geometry, faceGroup, indexGroup, uvGroup)})// 移动
box.addEventListener('mousemove', (event) => {if (stop) returnconst point = getPoint(event)if (!point || !drawMesh || pointList.length < 2) returnconst { indexGroup, faceGroup, uvGroup } = multShapeGroup([...pointList, point])updateMultShapePlaneGeometry(drawMesh.geometry, faceGroup, indexGroup, uvGroup)})box.addEventListener('click', (event) => {const point = getPoint(event)if (!point || stop) returnsetPointBox(point)point.y += 0.001pointList.push(point)const { indexGroup, faceGroup, uvGroup } = multShapeGroup(pointList)if (pointList.length < 3) returnif (!drawMesh) {const geometry = multShapePlaneGeometry(faceGroup, indexGroup, uvGroup)const material = new THREE.MeshStandardMaterial({ color: 0x00ff00, side: THREE.DoubleSide })drawMesh = new THREE.Mesh(geometry, material)scene.add(drawMesh)}else updateMultShapePlaneGeometry(drawMesh.geometry, faceGroup, indexGroup, uvGroup)})/* 处理顶点算法 */
function multShapeGroup(pList) {const indexGroup = pList.map((_, k) => (k >= 2) ? [0, k - 1, k] : false).filter((i) => i).reduce((i, j) => [...i, ...j], [])const faceGroup = pList.reduce((j, i) => [...j, i.x, i.y, i.z], [])const uvMaxMin = pList.reduce((p, i) => ({ x: [...p['x'], i['x']], y: [...p['y'], i['y']], z: [...p['z'], i['z']] }), { x: [], y: [], z: [] })// vu 点计算 二维面const Maxp = new THREE.Vector3(Math.max(...uvMaxMin.x), Math.max(...uvMaxMin.y), Math.max(...uvMaxMin.z))  // 最大点const Minp = new THREE.Vector3(Math.min(...uvMaxMin.x), Math.min(...uvMaxMin.y), Math.min(...uvMaxMin.z))  // 最小点const W = Maxp.x - Minp.xconst H = Maxp.y - Minp.yconst L = W > H ? W : H  // 以最大为基准// 顶点uv计算const uvGroup = pList.map(i => new THREE.Vector2((i.x - Minp.x) / L, (i.y - Minp.y) / L)).reduce((i, j) => [...i, ...j], [])return { indexGroup, faceGroup, uvGroup }}/* 根据顶点组生成物体 */
function multShapePlaneGeometry(faceGroup, indexGroup, uvGroup) {const geometry = new THREE.BufferGeometry()// 因为在两个三角面片里,这两个顶点都需要被用到。const vertices = new Float32Array(faceGroup)// itemSize = 3 因为每个顶点都是一个三元组。geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))// 索引组 面if (indexGroup) {// 格式化索引面组let indexs = new Uint16Array(indexGroup)// 添加索引组geometry.index = new THREE.BufferAttribute(indexs, 1)}// uv 是二维坐标相当于三维物体展开图if (uvGroup) geometry.attributes.uv = new THREE.Float32BufferAttribute(uvGroup, 2)geometry.computeVertexNormals()return geometry}/* 更新顶点 */
function updateMultShapePlaneGeometry(geometry, faceGroup, indexGroup, uvGroup) {geometry.setIndex(indexGroup)geometry.setAttribute('position', new THREE.Float32BufferAttribute(faceGroup, 3))geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvGroup, 2))delete geometry.attributes.normalgeometry.computeVertexNormals()}/*** 名称: 绘制面* 作者: 优雅永不过时 https://github.com/z2586300277
*/
http://www.lryc.cn/news/472439.html

相关文章:

  • 玩转Docker | 使用Docker部署捕鱼网页小游戏
  • 第2章 Android App开发基础
  • 通过 SYSENTER/SYSEXIT指令来学习系统调用
  • Nginx开发实战——网络通信(一)
  • w外链如何跳转微信小程序
  • 获取平台Redis各项性能指标
  • STM32 HAL 点灯
  • 【http作业】
  • WPF+MVVM案例实战(十一)- 环形进度条实现
  • 简述MCU微控制器
  • 微服务的雪崩问题
  • Java基础(4)——构建字符串(干货)
  • logback日志脱敏后异步写入文件
  • 电容的基本知识
  • 【Axure高保真原型】分级树筛选中继器表格
  • STM32 I2C通信:硬件I2C与软件模拟I2C的区别
  • 服务器新建用户
  • 鸿蒙开发融云demo发送图片消息
  • 音视频入门基础:AAC专题(11)——AudioSpecificConfig简介
  • OpenCV基本操作(python开发)——(8)实现芯片瑕疵检测
  • 聚水潭商品信息集成到MySQL的高效解决方案
  • # centos6.5 使用 yum list 报错Error Cannot find a valid baseurl for repo bas 解决方法
  • 【专题】2023-2024中国保险数字化营销调研报告汇总PDF洞察(附原数据表)
  • ““ 引用类型应用举例
  • 数字图像处理 - 基于ubuntu20.04运行.NET6+OpenCVSharp项目
  • git cherry-pick用法详解
  • HCIP-HarmonyOS Application Developer V1.0 笔记(一)
  • 开发流程初学者指南——需求分析
  • CRM平台排名:用户体验与客户满意度的深度解析
  • WIFI、NBIOT、4G模块调试AT指令连接华为云物联网服务器(MQTT协议)