You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Three.js实现顶面可倾斜的任意多边形棱柱(含凹凸多边形)

实现支持任意凹凸多边形的可倾斜棱柱模型

问题分析

需要构建一个棱柱模型,核心需求包括:

  • 底面为任意凹凸多边形
  • 顶面可自由倾斜(后续需支持底面独立设置倾斜角度)
  • 两种尝试的方案存在缺陷:
    1. 拉伸ShapeGeometry后通过法向量识别顶面修改顶点:法向量识别易受凹凸多边形拓扑影响,修改顶点易破坏几何体拓扑,导致渲染异常
    2. 复制底面平移旋转生成顶面+拼接侧面:手动合并几何体易出现顶点索引冲突、法向量错误,且简单平移旋转无法精准匹配任意倾斜平面的需求

最优实现思路:自定义BufferGeometry构建

直接手动生成几何体的顶点、面索引,完全控制拓扑结构,适配任意凹凸多边形和倾斜平面需求,步骤如下:

核心步骤

  1. 定义基础顶点:输入底面的二维顶点数组,转换为三维坐标(初始可设z=0,后续扩展底面倾斜时可替换为平面投影)
  2. 计算顶面顶点:通过平面方程(THREE.Plane)计算每个底面顶点在目标倾斜顶面上的投影点,确保顶面严格贴合倾斜平面
  3. 三角化多边形:用THREE.ShapeUtils.triangulateShape对凹凸多边形进行三角化,生成底面和顶面的三角面索引
  4. 生成侧面:遍历相邻顶点对,连接底面与顶面的对应顶点,将四边形侧面拆分为两个三角面
  5. 整合几何体:将顶点、索引存入BufferGeometry,自动计算法向量保证光照正常

代码示例(Three.js)

import * as THREE from 'three';
import { BufferGeometryUtils } from 'three/addons/utils/BufferGeometryUtils.js';

function createTiltedPrism(baseVertices, topPlane, basePlane = new THREE.Plane(new THREE.Vector3(0,0,1), 0)) {
    // baseVertices: 二维数组,示例:[[0,0], [2,0], [3,1], [1,2], [0,1]]
    // topPlane: THREE.Plane实例,定义顶面倾斜状态
    // basePlane: THREE.Plane实例,定义底面倾斜状态(默认z=0平面)

    const vertices = [];
    const indices = [];
    const vertexCount = baseVertices.length;

    // 生成底面顶点:投影到底面平面
    const base3D = baseVertices.map(([x,y]) => {
        const ray = new THREE.Ray(new THREE.Vector3(x, y, 0), basePlane.normal);
        const point = new THREE.Vector3();
        ray.intersectPlane(basePlane, point);
        return point;
    });
    base3D.forEach(v => vertices.push(v.x, v.y, v.z));

    // 生成顶面顶点:投影到顶面平面
    const top3D = base3D.map(v => {
        const ray = new THREE.Ray(v, topPlane.normal);
        const point = new THREE.Vector3();
        ray.intersectPlane(topPlane, point);
        return point;
    });
    top3D.forEach(v => vertices.push(v.x, v.y, v.z));

    // 三角化底面,生成面索引
    const baseTriangles = THREE.ShapeUtils.triangulateShape(baseVertices, []);
    baseTriangles.forEach(tri => indices.push(tri[0], tri[1], tri[2]));

    // 三角化顶面,索引偏移底面顶点数
    const topIndexOffset = vertexCount;
    baseTriangles.forEach(tri => {
        indices.push(
            topIndexOffset + tri[0],
            topIndexOffset + tri[1],
            topIndexOffset + tri[2]
        );
    });

    // 生成侧面三角面
    for (let i = 0; i < vertexCount; i++) {
        const nextI = (i + 1) % vertexCount;
        // 四边形拆分为两个三角形
        indices.push(
            i, nextI, topIndexOffset + nextI,
            i, topIndexOffset + nextI, topIndexOffset + i
        );
    }

    // 创建BufferGeometry并计算法向量
    const geometry = new THREE.BufferGeometry();
    geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
    geometry.setIndex(indices);
    geometry.computeVertexNormals();

    return geometry;
}

// 使用示例
const baseVertices = [[0,0], [2,0], [3,1], [1,2], [0,1]]; // 凹凸多边形
// 顶面:法向量(0.2, 0.3, 1),平面方程0.2x + 0.3y + z = 2
const topPlane = new THREE.Plane(new THREE.Vector3(0.2, 0.3, 1).normalize(), -2);
// 底面:默认z=0平面,可自定义倾斜,比如new THREE.Plane(new THREE.Vector3(0.1, 0, 1).normalize(), 0)
const prismGeometry = createTiltedPrism(baseVertices, topPlane);
const material = new THREE.MeshStandardMaterial({ color: 0x42a5f5 });
const prism = new THREE.Mesh(prismGeometry, material);
scene.add(prism);

方案优势

  • 完全适配任意凹凸多边形:依赖Three.js内置的多边形三角化工具,无需额外处理凹凸逻辑
  • 精准控制倾斜平面:通过THREE.Plane定义顶面/底面,支持任意方向的倾斜,避免平移旋转的局限性
  • 拓扑结构稳定:手动生成索引,不会出现法向量识别错误或顶点冲突问题,渲染效果可靠
  • 扩展性强:通过basePlane参数直接支持底面独立倾斜,无需大幅修改核心逻辑

内容的提问来源于stack exchange,提问作者Sumadithya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 14:35:22