【threejs】使用任意矩阵创建曲面

文章介绍了如何使用Three.js库中的BufferGeometry和MeshBasicMaterial在Three.js中创建一个基于三维矩阵表示的不规则面,通过计算和分配网格、UV坐标以及颜色,实现模型的渲染并支持贴图显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用一个三维矩阵描述一个不规则的面时(类似geojson的多边形,模型单个面网格),

	[
		[
		[x,y,z],[x,y,z]
		]
	]

可以使用本方法创建平面,基本原理就是创建buffergeometry并通过index分配网格 同时修正uv让整个曲面可以展示贴图

import { BufferGeometry, Color, DoubleSide, Float32BufferAttribute, Mesh, MeshBasicMaterial } from "three";

export default function createAnyFaceByMatrix3d(points, cof) {

    const config = {
        // material
        color: "#00ffff",
        hue: 1,
        maxHsl: 1, minHsl: 0,
        useHeightColor: false
    }
    Object.assign(config, cof)

    const material = new MeshBasicMaterial({
        side: DoubleSide,
        vertexColors: config.useHeightColor,
        color: config.color,
        // transparent: true,
        // opacity: .5
        // wireframe: true
    })

    let vecs = points.flat()
    let max = 0, min = 99999999
    for (let i = 0; i < vecs.length; i++) {
        let z = vecs[i][2]
        if (max < z) max = z
        if (min > z) min = z
    }


    const vertices = []
    const uvs = []
    const normals = []//按需添加,建议不加
    const colors = []
    const indices = []
    let last_i = 0
    let last_j = 0
    let count = 0
    let length = points.length
    // let length = 2
    const color = new Color()
    for (let i = 0; i < length; i++) {
        let row = points[i]
        let len = row.length
        // let len = 2
        for (let j = 0; j < len; j++) {
            let p = points[i][j]
            vertices.push(...p)
            let hue = getHue(max, min, config.maxHsl, config.minHsl, p[2],)
            color.setHSL(hue, 1, .5)
            colors.push(color.r, color.g, color.b)
            // uv
            let u = i / (length - 1)
            let v = j / (len - 1)
            uvs.push(v, u)
            // index (顶点顺序)
            if (i > 0 && j > 0) {
                let indexs = getIndexs(last_i, last_j, count, i, j)
                indices.push(...indexs)
            }
        }
        last_i = i
        last_j = len
        count += len
    }

    const geometry = new BufferGeometry()
    geometry.setIndex(indices);
    geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3));
    // geometry.setAttribute('normal', new Float32BufferAttribute(normals, 3));
    geometry.setAttribute('color', new Float32BufferAttribute(colors, 3));
    geometry.setAttribute('uv', new Float32BufferAttribute(uvs, 2));
    const mesh = new Mesh(geometry, material)
    return mesh
}

// 分配面顶点
function getIndexs(last_i, last_j, count, i, j) {

    let last_count = count - last_j
    let a = last_count + j - 1
    let b = last_count + j
    let c = count + j - 1
    let d = count + j

    const indexs = [
        a, b, d, a, d, c
    ]

    return indexs
}
// 生成顶点颜色,按需修改
function getHue(max, min, maxHsl, minHsl, h,) {
    let hue = (h - min) / (max - min)
    hue = hue * (maxHsl - minHsl) + minHsl
    return hue
}

修改

20240326
有的矩阵不是完全填充的,使用indexARR存储已经存在的点的index优化 ,可以完成不完全矩阵的绘制



import { BufferGeometry, Color, DoubleSide, Float32BufferAttribute, Mesh, MeshBasicMaterial } from "three";

export default function createAnyFaceByMatrix3d(points, cof) {

    const config = {
        // material
        color: "#00ffff",
        hue: 1,
        maxHsl: 1, minHsl: 0,
        useHeightColor: false
    }
    Object.assign(config, cof)

    const material =
        config.material ? config.material :
            new MeshBasicMaterial({
                side: DoubleSide,
                vertexColors: config.useHeightColor,
                color: config.color,
                // transparent: true,
                // opacity: .5
                // wireframe: true
            })

    let vecs = points.flat()
    let max = 0, min = 99999999
    for (let i = 0; i < vecs.length; i++) {
        if (vecs[i] && vecs[i][2]) {
            let z = vecs[i][2]
            if (max < z) max = z
            if (min > z) min = z
        }

    }


    const vertices = []
    const uvs = []
    const normals = []//按需添加,建议不加
    const colors = []

    let indexNum = 0
    const indices = []
    const indexArray = []
    let last_i = 0
    let last_j = 0
    let count = 0
    let length = points.length
    // let length = 2
    const color = new Color()

    for (let i = 0; i < length; i++) {
        let row = points[i]
        let len = row.length
        // let len = 2
        for (let j = 0; j < len; j++) {
            let p = points[i][j]
            if (!p) continue
            vertices.push(...p)
            let hue = getHue(max, min, config.maxHsl, config.minHsl, p[2],)
            color.setHSL(hue, 1, .5)
            colors.push(color.r, color.g, color.b)
            // uv
            let u = i / (length - 1)
            let v = j / (len - 1)
            uvs.push(v, u)



            indexArray[count + j] = indexNum++//存储已存在的index序号
            // index (顶点顺序)
         
            if (i > 0 && j > 0) {
                let indexs = getIndexs(last_i, last_j, count, i, j)
                let arr = indexs.map(n => indexArray[n])//获取矩阵对应位置的index序号
                indices.push(
                    ...arr
                )
            
            }
        }
        last_i = i
        last_j = len
        count += len
    }

    const geometry = new BufferGeometry()
    geometry.setIndex(indices);
    geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3));
    // geometry.setAttribute('normal', new Float32BufferAttribute(normals, 3));
    geometry.setAttribute('color', new Float32BufferAttribute(colors, 3));
    // geometry.setAttribute('uv', new Float32BufferAttribute(uvs, 2));
    const mesh = new Mesh(geometry, material)
    return mesh
}

// 分配面顶点
function getIndexs(last_i, last_j, count, i, j) {

    let last_count = count - last_j
    let a = last_count + j - 1
    let b = last_count + j
    let c = count + j - 1
    let d = count + j

    const indexs = [
        a, b, d, a, d, c
    ]

    return indexs
}
// 生成顶点颜色,按需修改
function getHue(max, min, maxHsl, minHsl, h,) {
    let hue = (h - min) / (max - min)
    hue = hue * (maxHsl - minHsl) + minHsl
    return hue
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鸢_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值