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

【基础】Three.js 自定义几何体和复制几何体

通过自定义顶点数据,可以创建任意的几何体。像threejs的长方体BoxGeometry、球体SphereGeometry等几何体都是基于BufferGeometry类构建的,它表示一个没有任何形状的空几何体。
请添加图片描述

1. 自定义点模型

通过javascript 类型化数组 Float32Array创建一组xyz坐标数据用来表示几何体的顶点坐标。每3个一组为一个坐标点。
在这里插入图片描述

point.ts文件:

import * as THREE from "three";//创建一个空的几何体对象
const geometry = new THREE.BufferGeometry();//类型化数组创建顶点数据
const vertices = new Float32Array([0,0,0, //顶点1坐标20,0,0, //顶点2坐标20,20,0, //顶点3坐标0,20,0, //顶点4坐标10,30,30, //顶点5坐标10,40,15, //顶点6坐标
]);// 创建属性缓冲区对象: 3个为一组,表示一个顶点的xyz坐标
const attribute = new THREE.BufferAttribute(vertices, 3);
geometry.attributes.position = attribute; // 设置几何体attributes属性的位置属性// 点材质
const material = new THREE.PointsMaterial({color: 0xffff00,size: 2.0, //点对象像素尺寸
});
const points = new THREE.Points(geometry, material); // 点对象
export {points}

主文件:

<template><div class="wrapper"><div ref="threeRef"></div></div>
</template>
<script setup lang="ts">
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { points} from "./components/points";
import { onMounted, ref } from "vue";
const threeRef = ref();onMounted(() => {// 场景const scene = new THREE.Scene();// 添加点进入场景scene.add(points);// 相机const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000);camera.position.set(50, 50, 50); // 相机位置// 渲染器const renderer = new THREE.WebGLRenderer({antialias: true, // 设置锯齿属性,为了获得更好的图像质量});// 定义threejs输出画布的尺寸(单位:像素px)renderer.setSize(window.innerWidth, window.innerHeight);// 为了适应不同的硬件设备屏幕,设置设备像素比renderer.setPixelRatio(window.devicePixelRatio);// 插入到任意HTML元素中threeRef.value.append(renderer.domElement);renderer.render(scene, camera);// AxesHelper:辅助观察的坐标系const axesHelper = new THREE.AxesHelper(50);scene.add(axesHelper);// 可拖拽查看模型const controls = new OrbitControls(camera, renderer.domElement);controls.addEventListener("change", function () {renderer.render(scene, camera); //执行渲染操作});window.onresize = function () {// 更新相机纵横比camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();// 更新渲染器的大小renderer.setSize(window.innerWidth, window.innerHeight);};
});
</script>
<style scoped></style>

2. 自定义线模型

new THREE.Line( geometry, material ); 创建一条连续的线
在这里插入图片描述

new THREE.LineLoop( geometry, material ); 创建环线
在这里插入图片描述

new THREE.LineSegments( geometry, material ); 创建线段
在这里插入图片描述
(为了观察由哪些点生成的线,保留了点模型)

//创建一个空的几何体对象
const geometry = new THREE.BufferGeometry();//类型化数组创建顶点数据
const vertices = new Float32Array([0,0,0, //顶点1坐标20,0,0, //顶点2坐标20,20,0, //顶点3坐标0,20,0, //顶点4坐标10,30,30, //顶点5坐标10,40,15, //顶点6坐标
]);// 创建属性缓冲区对象: 3个为一组,表示一个顶点的xyz坐标
const attribute = new THREE.BufferAttribute(vertices, 3);
geometry.attributes.position = attribute; // 设置几何体attributes属性的位置属性// 点材质
const material = new THREE.PointsMaterial({color: 0xffff00,size: 2.0, //点对象像素尺寸
});
// 线材质
const material1 = new THREE.LineBasicMaterial({color: 0xff0000, //线条颜色
});
const points = new THREE.Points(geometry, material); // 点对象
const lines = new THREE.Line(geometry, material1); // 线对象
export {points,lines } // 在主文件中引入,并添加到场景中即可

4. 网格模型(三角形概念)

网格模型Mesh其实就一个一个三角形(面)拼接构成。使用网格模型Mesh渲染几何体geometry,就是几何体所有顶点坐标三个为一组,构成一个三角形,多组顶点构成多个三角形,就可以用来模拟表示物体的表面。

可见性:
三个顶点的顺序是【逆时针】方向,该面视为【正面】
三个顶点的顺序是【顺时针】方向,该面视为【反面】,默认不可见
在这里插入图片描述

import * as THREE from "three";//创建一个空的几何体对象
const geometry = new THREE.BufferGeometry();
//顶点数据
const vertices = new Float32Array([0, 0, 0, //顶点1坐标50, 0, 0, //顶点2坐标50,50, 0, //顶点3坐标
]);
// 创建属性缓冲区对象: 3个为一组,表示一个顶点的xyz坐标
const attribute = new THREE.BufferAttribute(vertices, 3);
geometry.attributes.position = attribute; // 设置几何体attributes属性的位置属性// 网格模型:
const material = new THREE.MeshBasicMaterial({color: 0xffff00, //材质颜色//   side: THREE.BackSide,// 仅有反面可见side: THREE.DoubleSide, //两面可见transparent: true, // 开启透明opacity: 0.5, //透明度
});
const flat = new THREE.Mesh(geometry, material); // 网格对象
export { flat };

4. 自定义矩形平面

一个矩形平面,可以至少通过两个三角形拼接而成,而且两个三角形是紧密贴合的,所以会存在两个相同的坐标点。
注意:为了让两个三角形的正反面显示一致,每一个三角形顶点的的顺序应该保持一致!!
在这里插入图片描述
在这里插入图片描述

import * as THREE from "three";//创建一个空的几何体对象
const geometry = new THREE.BufferGeometry();
//顶点数据
const 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坐标
]);// 创建属性缓冲区对象: 3个为一组,表示一个顶点的xyz坐标
const attribute = new THREE.BufferAttribute(vertices, 3);
geometry.attributes.position = attribute; // 设置几何体attributes属性的位置属性// 网格模型:
const material = new THREE.MeshBasicMaterial({color: 0xffff00, //材质颜色//   side: THREE.BackSide,// 仅有反面可见side: THREE.DoubleSide, //两面可见transparent: true, // 开启透明opacity: 0.5, //透明度
});
const flat = new THREE.Mesh(geometry, material); // 网格对象
export { flat };

也可以使用几何体顶点索引数据geometry.index来实现
在这里插入图片描述

import * as THREE from "three";//创建一个空的几何体对象
const geometry = new THREE.BufferGeometry();
//顶点数据
const vertices = new Float32Array([0, 0, 0, //顶点1坐标80, 0, 0, //顶点2坐标80, 80, 0, //顶点3坐标0, 80, 0, //顶点6坐标
]);// Uint16Array类型数组创建顶点索引数据
const indexes = new Uint16Array([// 下面索引值对应顶点位置数据中的顶点坐标0, 1, 2, 0, 2, 3,
]);
// 索引数据赋值给几何体的index属性
geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组// 创建属性缓冲区对象: 3个为一组,表示一个顶点的xyz坐标
const attribute = new THREE.BufferAttribute(vertices, 3);
geometry.attributes.position = attribute; // 设置几何体attributes属性的位置属性// 网格模型
const material = new THREE.MeshBasicMaterial({color: 0xffff00, //材质颜色//   side: THREE.BackSide,// 仅有反面可见side: THREE.DoubleSide, //两面可见transparent: true, // 开启透明opacity: 0.5, //透明度
});
const flat = new THREE.Mesh(geometry, material); // 网格对象
export { flat };

如果将材质更换成其他受光照影响的材质,比如MeshLambertMaterial,则无法正常显示平面,因为受光照影响的材质,需要给几何体设置顶点法线

// 每个顶点的法线数据和顶点位置数据一一对应
const 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);
// 网格模型:
const material2 = new THREE.MeshLambertMaterial({color: 0xffff00, //材质颜色//   side: THREE.BackSide,// 仅有反面可见side: THREE.DoubleSide, //两面可见transparent: true, // 开启透明opacity: 0.5, //透明度
});

在场景中添加光源:

  //环境光const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);scene.add(ambientLight);// 平行光const directionalLight = new THREE.DirectionalLight(0xffffff, 1);// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算directionalLight.position.set(10, 15, 25);// 方向光指向对象网格模型directionalLight.target = flat;

5. 内置原始几何体

请添加图片描述

import * as THREE from "three";
// 立方体
const geometry1 = new THREE.BoxGeometry(8, 8, 8);
// 球体
const geometry2 = new THREE.SphereGeometry(10);const material1 = new THREE.MeshLambertMaterial({color: 0x00ffff,wireframe: true, //线条模式渲染mesh对应的三角形数据
});
const material2 = new THREE.MeshLambertMaterial({color: 0xffffff,wireframe: true, //线条模式渲染mesh对应的三角形数据
});
const box = new THREE.Mesh(geometry1, material1);
const sphere = new THREE.Mesh(geometry2, material2);
// 位置平移
sphere.translateX(-15);
box.translateX(-15);// 克隆一个box对象
const box2 = box.clone();
// 克隆几何体材质,并重新设置的材质和几何体属性
box2.material = box.material.clone();
box2.material.color.set(0xff0000);
box2.translateY(15);
// 缩小尺寸
box2.scale.set(0.5, 0.5, 0.5);
export {  sphere, box, box2 };

https://threejs.org/docs/index.html?q=geo#api/zh/geometries/BoxGeometry

添加循环动画:

  // 渲染循环function render() {box.rotateY(0.01); // 旋转动画sphere.rotateY(-0.01);// 同步mesh2和mesh的姿态角度一样,不管mesh姿态角度怎么变化,mesh2始终保持同步box2.rotation.copy(box.rotation);renderer.render(scene, camera);requestAnimationFrame(render);}render();

🔍【基础】Three.js的零基础入门篇(附案例代码)
🔍【基础】Three.js中添加操作面板,GUI可视化调试(附案例代码)
🔍【基础】Three.js加载纹理贴图、加载外部gltf格式文件

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Python读取excel数据
  • fastadmin 文件上传七牛云
  • PCL-半径滤波
  • 基于深度学习的创新设计的生成AI
  • vue+ThreeJS:从0 到1 搭建开发环境
  • 一些深度学习相关指令
  • 【C-实践】文件服务器(1.0)
  • 【代码随想录训练营第42期 Day53打卡 - 图论Part4 - 卡码网 110. 字符串接龙 105. 有向图的完全可达性
  • 10分钟教你使用docker在本地部署Wordpress
  • 【C++进阶】hash表的封装
  • 芯旺微,车规级32位MCU KF32A芯片简介
  • MATLAB中sim函数的用法
  • JavaWeb后端开发总结(3)
  • 微知-BIOS中的XHCI模式是什么意思?(usb3.0的扩展控制器影响usb3.0速率等选项)
  • Android之同一个Thread线程里只能有一个Looper?(ThreadLocal)
  • 时间复杂度分析经典问题——最大子序列和
  • 2019年如何成为全栈工程师?
  • JS专题之继承
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • Vue 重置组件到初始状态
  • Windows Containers 大冒险: 容器网络
  • 反思总结然后整装待发
  • 给Prometheus造假数据的方法
  • 关于for循环的简单归纳
  • 聊聊flink的BlobWriter
  • 如何实现 font-size 的响应式
  • 使用parted解决大于2T的磁盘分区
  • 400多位云计算专家和开发者,加入了同一个组织 ...
  • const的用法,特别是用在函数前面与后面的区别
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • ​马来语翻译中文去哪比较好?
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • # 消息中间件 RocketMQ 高级功能和源码分析(七)
  • (2)从源码角度聊聊Jetpack Navigator的工作流程
  • (C++)八皇后问题
  • (翻译)terry crowley: 写给程序员
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (附源码)计算机毕业设计高校学生选课系统
  • (三)终结任务
  • (三十五)大数据实战——Superset可视化平台搭建
  • (四)鸿鹄云架构一服务注册中心
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (转)h264中avc和flv数据的解析
  • .gitignore
  • .net 流——流的类型体系简单介绍
  • .NET8使用VS2022打包Docker镜像
  • @Transactional 详解
  • @Value读取properties中文乱码解决方案
  • @Value获取值和@ConfigurationProperties获取值用法及比较(springboot)
  • [AI 大模型] Meta LLaMA-2
  • [AIGC] 使用Curl进行网络请求的常见用法
  • [BZOJ 1040] 骑士
  • [BZOJ2850]巧克力王国