Threejs中的任何一个几何体都是由若干个索引点构成的,然后这些索引点其实构成的都是三个坐标的三角形。
使用顶点坐标构建几何体
1.我们需要一个支持几何体属性的物料
//创建几何体(三角形)
const geometry = new THREE.BufferGeometry();
2.构造一个顶点坐标组
const vertices = new Float32Array([
-1.0, -1.0, 0.0, //1
1.0, 1.0, 0.0, //2
1.0, -1.0, 0.0, //3
1.0, 1.0, 0.0, //4
-1.0, 1.0, 0.0, //5
-1.0, -1.0, 0.0, //6
]);
这里使用的每三个值一个的坐标, 对应的是threejs画布上的坐标,但是感觉四个值就可以完成一个正方形,为什么是六个点呢?
这是因为在threejs的世界之中,所有的内容都是由三角形狗造成的,所以我们需要绘制两个三角形,拼凑成一个正方形
三个一组 每三个数对应一个顶点坐标,这里使用到了Float32Array
其实就是用这个存点的
3.将参数融合 通过BufferAttribute方法构建几何体
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
new THREE.BufferAttribute(vertices, 3) 这个方法可以创建一个新的BufferAttribute对象,它用于存储顶点的数据。vertices
是一个包含顶点坐标的数组,而 3
表示每个顶点有三个分量(x、y、z坐标)。
什么是BufferAttribute对象呢????
BufferAttribute
是 Three.js 中用于存储顶点数据的对象之一。它是 Three.js 中对底层 WebGL 缓冲区的一个抽象,用于高效地存储和管理大量顶点数据。
在 3D 图形中,一个模型的几何信息通常包括顶点坐标、法线、颜色等数据。BufferAttribute
主要用于存储这些顶点相关的数据。它可以包含诸如顶点坐标、颜色、法线等信息,并将这些信息存储在一个 WebGL 缓冲区中,以便在 GPU 上进行高效的渲染。
4.一个自己构建的几何体就做好了
正面:
背面:
当然,我们也可以简答的使用四个点来绘制一个正方形,使用我们的索引绘制
使用索引绘制几何体
1. 构造几何体
//创建几何体
const geometry = new THREE.BufferGeometry();
2. 使用索引制作数组
//使用索引绘制
const vertices = new Float32Array([
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
-1.0, 1.0, 0,
]);
3.创建顶点属性
//创建顶点属性
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
4.创建索引
这里比较重要,这里的意思是取坐标构建三角形 三个为一组,0 1 2 代表 拿数组之中的 第0个 1个 2个 构建第一个三角形 第二个同上, 所以一共构建两个三角形。
//创建索引
const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
5.创建索引属性
//创建索引属性
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
6.构建完成
// 创建材质
const material = new THREE.MeshBasicMaterial({
color: 0xff0000,
// wireframe: true,
side: THREE.DoubleSide,
});
这里的side 是让threejs的渲染器 双面渲染 而不是渲染一面,添上线框属性可以暂时规避这个问题。
所有代码
//导入 threejs
import * as THREE from "three";
//导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
//导入lil.gui
// import * as dat from "dat.gui"; // 旧
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(
45, // 视角
window.innerWidth / window.innerHeight, // 宽高比 窗口的宽高进行设置的
0.1, // 近平面 相机最近最近能看到的物体
1000 // 远平面 相机最远能看到的物体
);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器的大小 (窗口大小)
renderer.setSize(window.innerWidth, window.innerHeight);
// 将渲染器的dom元素添加到body中
document.body.appendChild(renderer.domElement);
//创建几何体
const geometry = new THREE.BufferGeometry();
// // //创建顶点数据 顶点是由顺序的 每三个为一个顶点,逆时针为正面
// const vertices = new Float32Array([
// -1.0, -1.0, 0.0, //1
// 1.0, 1.0, 0.0, //2
// 1.0, -1.0, 0.0, //3
// 1.0, 1.0, 0.0, //4
// -1.0, 1.0, 0.0, //5
// -1.0, -1.0, 0.0, //6
// ]);
// // //下面这个代码什么意思
// // //创建顶点属性
// geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
//使用索引绘制
const vertices = new Float32Array([
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
-1.0, 1.0, 0,
]);
// console.log(geometry)
//创建顶点属性
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
//创建索引
const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
//创建索引属性
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
// 创建材质
const material = new THREE.MeshBasicMaterial({
color: 0xff0000,
wireframe: true,
// side: THREE.DoubleSide,
});
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);
// 设置立方体的旋转 绕着x旋转
// cube.rotation.x = Math.PI / 4;
//将网格体添加到场景中
// scene.add(parentCube);
// 设置相机的位置
camera.position.z = 5;
// 为了看到z轴
camera.position.y = 2;
// 设置x轴
camera.position.x = 2;
//设置相机的焦点 (相机看向哪个点)
camera.lookAt(0, 0, 0);
//添加世界坐标辅助器 (红色x轴,绿色y轴,蓝色z轴)一个线段 参数为 线段长度
const axesHelper = new THREE.AxesHelper(5);
//添加到场景之中
scene.add(axesHelper);
// 添加轨道控制器 (修改侦听位置) 一般监听画布的事件 不监听document.body
const controls = new OrbitControls(camera, renderer.domElement);
// 这里传递阻塞掉了 会导致无法点击
// const controls = new OrbitControls(camera, document.body);
// 设置带阻尼的旋转
controls.enableDamping = true;
// 设置阻尼系数
controls.dampingFactor = 0.01;
// 自动旋转
controls.autoRotate = false;
//渲染函数
function animate() {
controls.update();
//请求动画帧
requestAnimationFrame(animate);
//旋转网格体
// cube.rotation.x += 0.01;
// cube.rotation.y += 0.01;
//渲染
renderer.render(scene, camera);
}
animate();
//渲染
// 监听窗口的变化 重新设置渲染器的大小 画布自适应窗口
window.addEventListener("resize", () => {
// 重新设置渲染器的大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 重新设置相机的宽高比
camera.aspect = window.innerWidth / window.innerHeight;
// 重新计算相机的投影矩阵
camera.updateProjectionMatrix();
});
//1.gui控制按钮
let eventObj = {
Fullscreen: function () {
document.body.requestFullscreen();
},
exitFullscreen: function () {
document.exitFullscreen();
},
};
//创建gui实例
const gui = new GUI();
//添加按钮 第一个参数为对象实例 第二个参数为对象中属性名称
gui.add(eventObj, "Fullscreen").name("全屏");
//退出按钮
gui.add(eventObj, "exitFullscreen").name("退出全屏");
//2.gui控制立方体的位置
// gui.add(cube.position, "x", -5, 5).name("立方体x轴位置");