Three.js 中三角形到四边形的顶点变换:一场几何的华丽变身

**

在 3D 图形的世界里,三角形就像是乐高积木里最基础的那块小方块 ------ 简单、可靠,几乎所有复杂模型都能由它堆砌而成。但有时候,我们需要更 "大气" 的形状来完成设计,比如四边形。今天我们就来看看,在 Three.js 的魔法世界里,三角形是如何摇身一变成为四边形的,这背后又藏着哪些几何的小秘密。

从三角形说起:3D 世界的 "原子"

想象一下,你手里有一张三角形的纸,三个顶点就像是三个固定的钉子,牢牢地把这张纸钉在空间中。在 Three.js 里,这三个顶点就是我们定义三角形的关键。让我们用代码来创建一个最简单的三角形:

javascript 复制代码
// 定义三角形的三个顶点坐标
const triangleVertices = new Float32Array([
  0, 1, 0,   // 顶部顶点,像山峰的顶端
  -1, -1, 0, // 左下顶点,脚踏实地
  1, -1, 0   // 右下顶点,与左顶点遥遥相对
]);
// 创建几何体并设置顶点
const triangleGeometry = new THREE.BufferGeometry();
triangleGeometry.setAttribute('position', new THREE.BufferAttribute(triangleVertices, 3));

这段代码就像是在 3D 空间里钉下了三个点,然后用线把它们连起来,形成了一个稳定的三角形。这里的每个顶点都有三个数字来描述它的位置 ------ 分别对应 X 轴、Y 轴和 Z 轴,就像是空间中的经纬度加上海拔高度。

为什么三角形这么重要?因为三个点确定一个平面,就像相机的三脚架永远不会晃动一样,三角形在 3D 世界里也是最稳定的结构。但当我们需要更宽敞的 "舞台" 时,四边形就该登场了。

四边形的诞生:多一个顶点的自由

四边形比三角形多了一个顶点,这可不是简单地多画一条线那么简单。如果说三角形是被三个钉子固定的纸,那四边形就像是被四个钉子固定的布 ------ 它有了更多的褶皱和伸展的可能,这也意味着我们需要更聪明的方法来控制它的形状。

要把三角形变成四边形,最直接的办法就是 "加一个点"。但这个点加在哪里,怎么加,可是门大学问。我们不能随便找个地方戳个钉子,那样可能会让整个形状变得扭曲怪异。

让我们先创建一个四边形的基础结构:

javascript 复制代码
// 四边形的四个顶点坐标
const quadVertices = new Float32Array([
  -1, 1, 0,   // 左上顶点
  1, 1, 0,    // 右上顶点
  1, -1, 0,   // 右下顶点
  -1, -1, 0   // 左下顶点
]);
// 创建四边形几何体
const quadGeometry = new THREE.BufferGeometry();
quadGeometry.setAttribute('position', new THREE.BufferAttribute(quadVertices, 3));

看,这就是一个标准的四边形,四个顶点像站岗的士兵一样,分别守在左上、右上、右下、左下四个位置,形成了一个规则的矩形。但如果我们想从之前的三角形变换过来,事情就没这么简单了。

顶点变换的核心:坐标的舞蹈

三角形有三个顶点,四边形有四个顶点,这意味着我们需要 "创造" 出一个新的顶点。这个新顶点从哪里来呢?其实它就藏在三角形的某个位置,等待我们把它 "拉" 出来。

想象一下,三角形的三个顶点就像三个好朋友,分别站在 (0,1,0)、(-1,-1,0) 和 (1,-1,0) 这三个位置。现在我们要邀请第四个朋友加入,让他们四个站成一个四边形。最自然的做法,就是在三角形的一条边上找一个点,把它 "拽" 出去,形成一个新的顶点。

让我们用代码来模拟这个过程。假设我们有一个三角形的顶点数组,现在要通过计算得到第四个顶点:

arduino 复制代码
// 原始三角形顶点
const triangleVerts = [
  new THREE.Vector3(0, 1, 0),   // 顶部
  new THREE.Vector3(-1, -1, 0), // 左下
  new THREE.Vector3(1, -1, 0)   // 右下
];
// 我们在左下和右下顶点之间"插入"一个新顶点
// 先算出左下到右下的中点
const midPoint = new THREE.Vector3();
midPoint.x = (triangleVerts[1].x + triangleVerts[2].x) / 2;
midPoint.y = (triangleVerts[1].y + triangleVerts[2].y) / 2;
midPoint.z = 0; // z轴保持不变
// 把这个中点向上"拉"一点,形成新的顶点
const newVertex = new THREE.Vector3(
  midPoint.x,
  midPoint.y + 0.5, // 向上移动0.5单位
  midPoint.z
);
// 现在我们有了四个顶点,可以组成四边形了
const quadVerts = [
  triangleVerts[0],   // 顶部
  triangleVerts[1],   // 左下
  newVertex,          // 新顶点
  triangleVerts[2]    // 右下
];

这里的关键就像是在折纸 ------ 我们找到三角形底边的中点,然后把它向上折起,原本的一条边就变成了两条边,三角形也就变成了一个四边形。这个过程中,每个顶点的坐标都在按照我们的意愿进行调整,就像指挥家指挥着音符的跳动。

底层的几何魔法:向量与空间变换

你可能会好奇,为什么移动一个点就能改变整个形状?这就要从 3D 图形的底层原理说起了。在计算机的世界里,每个顶点都是一个 "向量"------ 既有大小又有方向的数学精灵。当我们改变顶点的坐标时,其实是在改变这些向量的方向或长度。

比如,在上面的例子中,新顶点的 x 坐标和中点一样,这意味着它在水平方向上处于左下和右下顶点的正中间;而 y 坐标比中点高,这就像是把这个点向上 "拉" 了一把,让原本平坦的底边凸起,形成了一个新的角。

Three.js 为我们提供了很多方便的方法来操作这些向量。比如,我们可以用add方法来计算两个点的和,用multiplyScalar来缩放一个点的位置:

ini 复制代码
// 另一种创建新顶点的方法:向量运算
const vectorFromLeftToRight = new THREE.Vector3();
vectorFromLeftToRight.subVectors(triangleVerts[2], triangleVerts[1]); // 右下减左下,得到方向向量
// 取一半长度,就是中点到左下的向量
const halfVector = vectorFromLeftToRight.clone().multiplyScalar(0.5);
// 从左下顶点出发,加上这个一半向量,再向上移动
const newVertex2 = triangleVerts[1].clone().add(halfVector).add(new THREE.Vector3(0, 0.5, 0));

这段代码做的事情和之前差不多,但更能体现向量的思想 ------ 我们不是直接计算坐标,而是通过向量的加减来 "移动" 点的位置。这就像是告诉计算机:"从左下顶点出发,向右走一半的距离,再向上走 0.5 单位,那里就是新顶点的位置。"

从三角形到四边形:拓扑的奥秘

除了顶点的位置,形状的 "拓扑结构" 也很重要。拓扑就像是图形的 "连接方式"------ 哪些顶点连在一起,形成什么样的面。在 Three.js 中,我们需要明确告诉计算机这些连接关系。

对于三角形,我们只需要说 "三个顶点连在一起形成一个面";而对于四边形,我们需要定义两个三角形来组成它(因为 GPU 通常只认三角形):

arduino 复制代码
// 定义四边形的面(由两个三角形组成)
const indices = [
  0, 1, 2,  // 第一个三角形:顶部、左下、新顶点
  0, 2, 3   // 第二个三角形:顶部、新顶点、右下
];
// 创建索引缓冲区
quadGeometry.setIndex(new THREE.Uint16BufferAttribute(indices, 1));

这就像是告诉计算机:"你看,这个四边形其实是由两个小三角形拼起来的,你只要分别画出这两个三角形,看起来就像是一个四边形了。" 这种把复杂形状分解成三角形的过程,在 3D 图形学中叫做 "三角剖分",是计算机处理复杂图形的基本技巧。

让形状动起来:动画中的顶点变换

顶点变换不仅仅用于创建静态形状,更重要的是在动画中让物体 "活" 起来。比如,我们可以让一个三角形逐渐变成四边形,就像花朵慢慢绽放:

ini 复制代码
// 动画函数:让三角形逐渐变成四边形
function animate() {
  requestAnimationFrame(animate);
  
  // 计算动画进度(0到1之间)
  const progress = (Math.sin(Date.now() * 0.001) + 1) / 2;
  
  // 根据进度更新新顶点的位置
  const currentY = -1 + progress * 0.5; // 从-1逐渐升到-0.5
  quadVerts[2].y = currentY;
  
  // 更新几何体的顶点数据
  quadGeometry.attributes.position.needsUpdate = true;
  
  renderer.render(scene, camera);
}

这段代码就像是给形状装上了 "关节",通过不断改变新顶点的 y 坐标,让它从底边慢慢升起,三角形也就逐渐变成了四边形。这里的进度计算用了正弦函数,让变化看起来更平滑自然,就像呼吸一样有节奏。

总结:几何的魅力在于创造

从三角形到四边形的顶点变换,看似简单,却包含了 3D 图形学的许多基本原理:顶点坐标的表示、向量的运算、拓扑结构的定义,以及动画中的插值计算。就像用积木搭房子,我们通过移动一个个小小的顶点,就能创造出千变万化的形状。

下次当你在 Three.js 中创建模型时,不妨多留意这些隐藏在代码背后的几何奥秘。也许有一天,你会发现自己能用这些简单的原理,创造出令人惊叹的 3D 世界 ------ 毕竟,再复杂的模型,追根溯源,都只是一个个顶点在空间中的优雅舞蹈。

记住,在 3D 的世界里,没有绝对的固定形状,只有无限的可能。只要你愿意,三角形可以变成四边形,四边形可以变成更复杂的多边形,而这一切,都从理解每个顶点的小小移动开始。

相关推荐
G_G#5 分钟前
纯前端js插件实现同一浏览器控制只允许打开一个标签,处理session变更问题
前端·javascript·浏览器标签页通信·只允许一个标签页
@大迁世界21 分钟前
TypeScript 的本质并非类型,而是信任
开发语言·前端·javascript·typescript·ecmascript
GIS之路30 分钟前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug33 分钟前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu1213835 分钟前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中1 小时前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路1 小时前
GDAL 实现矢量合并
前端
hxjhnct1 小时前
React useContext的缺陷
前端·react.js·前端框架
冰暮流星1 小时前
javascript逻辑运算符
开发语言·javascript·ecmascript
前端 贾公子1 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端