最近在研究自定义建模,有一个多断柱模型比较有意思,分享下,就是利用几组点串,比如上中下,然后每组点又不一样多,点续还不一样,(比如第一个环的第一个点在左边,第二个环在右边),然后进行插值,连接三角网

主函数:

export function createMultiRingPrismMesh(rings: Vector3[][],material?: Material,
) {if (!material) {const texture = new TextureLoader().load(green)material = new MeshStandardMaterial({map:texture,color: 0x3399ff,side: DoubleSide,wireframe: false,})}if (rings.length < 2) {throw new Error('至少需要两个环来构建几何体')}// 将所有环插值为统一点数const targetCount = Math.max(...rings.map((r) => r.length))const processedRings = rings.map((ring) => {const center = computeCenter(ring)const angles = computeAngles(ring, center)const { ring: sortedRing, angles: sortedAngles } = sortRingByAngle(ring,angles,)return interpolateRingByAngles(sortedRing, sortedAngles, targetCount)})const vertices = []const uvs = []const indices = []const ringCount = processedRings.lengthconst count = targetCount// 顶点和UVprocessedRings.forEach((ring, ringIndex) => {ring.forEach((p, i) => {vertices.push(p.x, p.y, p.z)// UV 映射:U 是角度,V 是高度归一化// const angle = (i / count) * Math.PI * 2uvs.push(i / count, ringIndex / (ringCount - 1)) // U: 角度比例, V: 层级比例})})// 侧面三角形索引for (let i = 0; i < ringCount - 1; i++) {const offset = i * countfor (let j = 0; j < count; j++) {const curr = offset + jconst next = offset + ((j + 1) % count)const currTop = curr + countconst nextTop = next + countindices.push(curr, next, currTop)indices.push(next, nextTop, currTop)}}// 封底(第一个环)const bottomCenter = computeCenter(processedRings[0])const bottomCenterIndex = vertices.length / 3vertices.push(bottomCenter.x, bottomCenter.y, bottomCenter.z)uvs.push(0.5, 0.5)for (let i = 0; i < count; i++) {const next = (i + 1) % countindices.push(bottomCenterIndex, next, i)}// 封顶(最后一个环)const topCenter = computeCenter(processedRings[ringCount - 1])const topCenterIndex = vertices.length / 3const topOffset = (ringCount - 1) * countvertices.push(topCenter.x, topCenter.y, topCenter.z)uvs.push(0.5, 0.5)for (let i = 0; i < count; i++) {const next = (i + 1) % countindices.push(topCenterIndex, topOffset + i, topOffset + next)}const geometry = new BufferGeometry()geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3))geometry.setAttribute('uv', new Float32BufferAttribute(uvs, 2))geometry.setIndex(indices)geometry.computeVertexNormals()return new Mesh(geometry, material)
}

 辅助函数

/*** 计算环中心点(平均点)* @param {Vector3[]} ring* @returns {Vector3}*/
function computeCenter(ring: Vector3[]) {const center = new Vector3(0, 0, 0)ring.forEach((p) => center.add(p))center.multiplyScalar(1 / ring.length)return center
}
/*** 计算环中每点相对于中心的角度(0~2π)* 这里按 XZ 平面计算角度* @param {Vector3[]} ring* @param {Vector3} center* @returns {number[]} 角度数组,与ring点一一对应*/
function computeAngles(ring: Vector3[], center: Vector3) {return ring.map((p) => {const dx = p.x - center.xconst dz = p.z - center.zlet angle = Math.atan2(dz, dx)if (angle < 0) angle += Math.PI * 2return angle})
}function interpolateRingByAngles(ring: Vector3[],angles: number[],targetCount: number,
) {const result = []const len = ring.length// 角度归一化到 [0, 2PI)const TWO_PI = Math.PI * 2for (let i = 0; i < targetCount; i++) {const t = (i / targetCount) * TWO_PI// 找到 t 在 angles 中所在区间 [angles[j], angles[j+1]]// 注意最后一个区间是 [angles[len-1], angles[0] + 2PI]let j = 0for (; j < len; j++) {const a0 = angles[j]const a1 = angles[(j + 1) % len] + (j === len - 1 ? TWO_PI : 0)if (t >= a0 && t <= a1) {// 找到区间const p0 = ring[j]const p1 = ring[(j + 1) % len]const localT = (t - a0) / (a1 - a0)const interpolated = new Vector3().lerpVectors(p0, p1, localT)result.push(interpolated)break}}// 保险 fallback,如果没找到区间,返回第一个点if (j === len) {result.push(ring[0].clone())}}return result
}// 对角度和点排序(保证升序)
function sortRingByAngle(ring: Vector3[], angles: number[]) {const pairs = ring.map((p, i) => ({ p, angle: angles[i] }))pairs.sort((a, b) => a.angle - b.angle)return {ring: pairs.map((pair) => pair.p),angles: pairs.map((pair) => pair.angle),}
}

使用

createMultiRingPrismMesh([points,points2,points3])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/917039.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/917039.shtml
英文地址,请注明出处:http://en.pswp.cn/news/917039.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Language Models are Few-Shot Learners: 开箱即用的GPT-3(四)

Result续 Winograd-Style Tasks Winograd-Style Tasks 是自然语言处理中的一类经典任务。它源于 Winograd Schema Challenge(WSC),主要涉及确定代词指的是哪个单词,旨在评估模型的常识推理和自然语言理解能力。 这个任务中的具体通常包含高度歧义的代词,但从语义角度看…

BGP高级特性之认证

一、概述BGP使用TCP作为传输协议&#xff0c;只要TCP数据包的源地址、目的地址、源端口、目的端 口和TCP序号是正确的&#xff0c;BGP就会认为这个数据包有效&#xff0c;但数据包的大部分参数对于攻击 者来说是不难获得的。为了保证BGP免受攻击&#xff0c;可以在BGP邻居之间使…

商旅平台怎么选?如何规避商旅流程中的违规风险?

在中大型企业的商旅管理中&#xff0c;一个典型的管理“黑洞”——流程漏洞与超标正持续吞噬企业成本与管理效能&#xff1a;差标混乱、审批脱节让超规订单频频闯关&#xff0c;不仅让企业商旅成本超支&#xff0c;还可能引发税务稽查风险。隐性的合规风险&#xff0c;比如虚假…

Anaconda的常用命令

Anaconda 是一个用于科学计算、数据分析和机器学习的 Python 发行版&#xff0c;包含了大量的预安装包。它配有 conda 命令行工具&#xff0c;方便用户管理包和环境。以下是一些常用的 conda 命令和 Anaconda 的常见操作命令&#xff0c;帮助你高效管理环境和包。1. 环境管理创…

JVM之【Java虚拟机概述】

目录 对JVM的理解 JVM的架构组成 类加载系统 执行引擎 运行时数据区 垃圾收集系统 本地方法库 对JVM的理解 JVM保证了Java程序的执行&#xff0c;同时也是Java语言具有跨平台性的根本原因&#xff1b;Java源代码通过javac等前端编译器生成的字节码计算机并不能识别&…

RabbitMQ+内网穿透远程访问教程:实现异地AMQP通信+Web管理

RabbitMQ是一个开源的消息队列中间件&#xff0c;基于Erlang开发&#xff0c;遵循AMQP&#xff08;Advanced Message Queuing Protocol&#xff0c;高级消息队列协议&#xff09;标准&#xff0c;主要用于实现异步通信、消息解耦和系统间数据传输。它的核心作用是在分布式系统中…

go 语言 timer 与 ticker理论和实例大全

目录 1. 时间之门的钥匙:Timer与Ticker的本质 2. Timer:精准的单次计时 2.1 Timer的基础用法 2.2 停止与重置Timer 2.3 Timer的高级技巧:优雅处理并发 3. Ticker:时间的节拍器 3.1 Ticker的基本用法 3.2 Ticker的高级应用:动态调整周期 4. Timer与Ticker的结合:打…

MySQL 45讲 16-17

全字段排序 explain 中的 using fiesort ,扫描 数据,取出符合判断条件的 数据,到sort buffer中,然后对排序字段采用快速排序进行 排序后直接将 所需字段进行返回 如果 字段长度所占内存大于所分配 的sort buffer ,需要借助 临时文件 进行 数据的存放排序,此时会采用 归并排序,将…

QT项目 -仿QQ音乐的音乐播放器(第四节)

一、RecBox中btUp和btDown按钮clicked处理 选中左右键&#xff08;btUp和btDown按钮&#xff09;然后右击转到槽->click() void RecBox::on_btUp_clicked() {}void RecBox::on_btDown_clicked() {} 二、imageList中图片分组 // recbox.h 中新增 int currentIndex; // 标记…

DeepSeek SEO关键词优化提升流量增长

内容概要DeepSeek SEO关键词优化致力于通过科学的方法&#xff0c;显著提升网站在搜索引擎中的可见度与自然流量。其核心在于深入理解并精准匹配用户的真实搜索意图&#xff0c;而非仅仅堆砌词汇。具体来说&#xff0c;该策略运用深度意图导向策略&#xff0c;确保内容与用户需…

# Ubuntu 系统设置 USB PnP 音频设备为默认设备的完整教程

Ubuntu 系统设置 USB PnP 音频设备为默认设备的完整教程 在使用 Ubuntu 系统时&#xff0c;尤其是在嵌入式设备如 NVIDIA Jetson 系列上&#xff0c;我们经常需要将 USB PnP 音频设备设置为默认设备。本文将详细介绍如何通过命令行配置&#xff0c;使 USB PnP 音频设备在系统重…

Hadoop JMX 配置的完整文档

一、JMX 基础概念与 Hadoop 支持 1、JMX 作用。 Java Management Extensions&#xff08;JMX&#xff09;提供标准 API 监控 JVM 应用运行时状态&#xff08;内存、线程、GC&#xff09;及 Hadoop 组件指标&#xff08;HDFS 容量、RPC 性能、节点状态&#xff09; 2、Hadoop 组…

arm架构系统打包qt程序--麒麟操作系统为例

检查系统架构 uname -a如果显示是aarch644或arm64&#xff0c;说明你使用的是ARM架构&#xff0c;&#xff0c;需要下载ARM版本。 下载对应架构的linuxdeployqt 编写脚本 vim deploy.sh#!/bin/bash APP_NAME"sunny450_silc"# 确保deploy目录存在 mkdir -p deploy# 复…

Kong API Gateway深度解析:插件系统与微服务架构的技术基石

在微服务&#xff08;microservices&#xff09;架构主导的今天&#xff0c;API网关&#xff08;API Gateway&#xff09;作为服务入口的“交通枢纽”&#xff0c;承担着流量调度、安全防护、可观测性&#xff08;observability&#xff09;等核心职责。Kong作为开源API网关领域…

Linux应用开发基础知识——Makefile初级教程(九)

目录 一、Makefile是啥&#xff1f; 1.1、了解几种文件&#xff08;.o 文件和.c文件 &#xff09; 1.2、关于Makefile的写法 1.3、简单使用Makefile基本指令 1.4、引入伪目标 1.5、Makefile的优点 1.6、Makefile的使用 二、Makefile创建和使用变量 2.1、创建变量的目的…

面试问题收集——卷积神经网络

博主会经常分享自己在人工智能阶段的学习笔记&#xff0c;欢迎大家访问我滴个人博客&#xff01;&#xff08;养成系Blog&#xff01;&#xff09; 小牛壮士滴Blog~ - 低头赶路 敬事如仪https://kukudelin.top/ 01-卷积基础知识 问&#xff1a;简述卷积基本操作&#xff0c;…

Kubernetes 全面解析:从基础设施变革到核心架构详解

引言在容器化技术席卷全球的今天&#xff0c;Kubernetes&#xff08;简称 K8s&#xff09;已成为容器编排领域的事实标准。无论是互联网企业还是传统行业&#xff0c;都在通过 Kubernetes 实现应用的高效部署、弹性扩展和自动化运维。但对于初学者而言&#xff0c;Kubernetes 的…

哈希相关的模拟实现

哈希相关的模拟实现哈希表的模拟实现闭散列除留取余法查找、插入和删除闭散列参考程序开散列除留取余法&#xff08;数组链表&#xff09;迭代器查找和删除插入开散列参考程序unordered_map和unordered_set的模拟实现unordered_mapunordered_set建议先看 哈希的概念及其应用-CS…

Vue3+Vite项目如何简单使用tsx

安装必要的依赖npm install vitejs/plugin-vue-jsx -D在 vite.config.ts 中添加以下内容import vueJsx from vitejs/plugin-vue-jsx export default {plugins: [vueJsx()] }在Vue页面使用<script lang"ts"> import { defineComponent } from vue export defaul…

05百融云策略引擎项目交付-laravel实战完整交付定义常量分文件配置-独立建立lib类处理-成功导出pdf-优雅草卓伊凡

05百融云策略引擎项目交付-laravel实战完整交付定义常量分文件配置-独立建立lib类处理-成功导出pdf-优雅草卓伊凡引言此前只是把关于如何把查询内容导出pdf库的代码实现了&#xff0c;但是我们并没有完成整个项目&#xff0c;这最后一个步骤就是安装composer再安装tcpdf库&…