news 2026/10/17 2:36:19

PointMesh:一个顶点渲染万粒粒子

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PointMesh:一个顶点渲染万粒粒子

PointMesh:一个顶点渲染万粒粒子

【免费下载链接】godot-docsGodot Engine official documentation项目地址: https://gitcode.com/GitHub_Trending/go/godot-docs

写粒子系统时,你有没有算过账:几千个粒子,每个还是球体网格,顶点数直接爆炸?Godot 里的 PointMesh 把每个粒子压到 1 个顶点、0 个三角形,代价是——忘记设点大小,一个都看不见。读完这篇,你能用几行代码搭出自己的廉价粒子、点云和海量小图标。

一、它到底解决谁的什么问题

先说结论:它解决"数量大、单个不需要几何细节"的渲染开销问题。

想象你要画 5000 粒灰尘。用默认的球体粒子,每个粒子自带上万顶点,总量轻松破亿。而人眼在这个距离上看到的只是一团模糊的光点,那些三角面全白算了。PointMesh 的思路是:既然看到的只是一个"色块",那就只提交一个顶点。GPU 把这个顶点投影到屏幕上,再画一个固定像素大小的矩形盖上去。5000 粒灰尘,5000 个顶点,几何开销直接低三个数量级。

没有它的话,你要么忍受掉帧,要么自己写 instancing 拼凑——它把这个方案做成了引擎内置的 PointMesh。

二、最短路径先跑通

结论先行:点必须配一个"声明了点大小"的材质,否则屏幕上什么都没有。这是 PointMesh 最反直觉的一点。

最小可运行示例(GDScript 动态搭建;C# 里属性名对应为UsePointSize/PointSize,写法一致):

var dot := MeshInstance3D.new() var pm := PointMesh.new() var mat := StandardMaterial3D.new() mat.use_point_size = true # 不加这行,点基本不可见 mat.point_size = 8.0 # 点的直径,单位像素 pm.material = mat dot.mesh = pm add_child(dot)

跑起来后你会看到一个 8 像素的正方形点。先别嫌弃它方——形状的事第五节再处理。现在记住这条路径:PointMesh + use_point_size + point_size,三件套缺一不可。

三、拆开看:内部如何把事做对

按"数据→变换→呈现"三层拆,机制其实很薄。

数据层:一张只含一个顶点的点表面。Mesh的图元类型枚举里有PRIMITIVE_POINTS = 0,官方解释是"一个顶点等于一个点"(见 class_mesh.rst)。PointMesh 的表面就是这么一条点图元表面,继承自 PrimitiveMesh,没有法线、没有 UV——因为一个点既不需要光照方向,也不需要贴图坐标。

变换层:几乎无事可做。三角形网格要算蒙皮、光照、背面剔除,而点只有一个"在哪"的信息。它天然正对屏幕,等价于隐式广告牌,连billboard_mode的旋转都省了。

呈现层:像盖章一样画方块。类比一下:普通网格是"在纸上铺一整面墙",点渲染是"拿一枚固定尺寸的印章盖一下"。印章多大,由材质里的point_size(像素)或着色器里的POINT_SIZE决定。这也解释了它的核心特性:点不随距离变小,10 米外的点和 1 米外的点一样大。

四、可调参数全景

真正要调的就这么几个(默认值与单位来自 class_basematerial3d.rst 与 spatial_shader.rst):

参数类型默认值单位何时改
use_point_sizeboolfalse—任何想控制点大小的场景(总开关)
point_sizefloat1.0像素点太小看不清,或太大过曝
POINT_SIZEshader 内置(inout float)未设置像素想让大小随距离/生命周期动态变化
POINT_COORDshader 内置(只读vec2)—0~1 归一化想把方点裁成圆点或做径向渐变
materialMaterialnull—改颜色、透明度、贴图
custom_aabbAABB零包围盒世界单位着色器偏移顶点后出现意外剔除

展开讲三个关键的。

use_point_size是开关不是滑块。它对应BaseMaterial3D.Flags枚举里的FLAG_USE_POINT_SIZE = 3,不打开时point_size写了也白写。官方注释特意强调:该选项只对"基于点而非三角形"的几何生效。

point_size恒定以像素计。1 像素是默认值,多数屏幕上几乎看不见;8~16 像素是粒子常用区间。

POINT_SIZE是动态版。顶点阶段写入,片段阶段的POINT_COORD返回当前像素在点矩形内的归一化坐标,两者配合能做形状裁剪和渐变——这是"盖章"比喻里唯一能让印章变形的口子。

五、三条落地路线

由浅入深,三条路线层层递进。

路线 1:粒子本体(最浅)。适合:粒子量大、视觉要求就是"彩色斑点"的场景,比如火花、尘埃、魔法粉尘。做法:把 PointMesh 赋给粒子节点的绘制通道即可,粒子运动逻辑全部交给ParticleProcessMaterial:

var dust := CPUParticles3D.new() var pm := PointMesh.new() var mat := StandardMaterial3D.new() mat.use_point_size = true mat.point_size = 4.0 pm.material = mat dust.draw_pass_1 = pm # 网格交给绘制通道

路线 2:MultiMesh 点云(进阶)。适合:星图、采样数据可视化、大量地图标记。一个 PointMesh 资源被成千上万个实例共享,只有变换矩阵不同,GPU 侧实例化开销远低于逐个提交:

var mm := MultiMesh.new() mm.transform_count = 5000 mm.mesh = point_mesh # 共享同一份点网格 for i in range(5000): mm.set_instance_transform(i, rand_in_sphere(20.0))

路线 3:着色器动态点(最深)。适合:点大小要随深度或生命周期变化,或者非要圆点不可。用ShaderMaterial,顶点阶段写POINT_SIZE,片段阶段用POINT_COORD裁剪(GLSL 老用户可直接把gl_PointSize换成POINT_SIZE):

shader_type spatial; void vertex() { POINT_SIZE = 12.0; // 想按距离缩放,在此自行换算 } void fragment() { if (length(POINT_COORD - vec2(0.5)) > 0.5) discard; // 方点裁成圆点 ALBEDO = vec3(1.0, 0.85, 0.3); }

三条路线可叠加:MultiMesh 是载体,着色器是皮肤。

六、这些开关会"假装生效"

官方在 class_pointmesh.rst 的 Note 里点名了一组"看起来能设、实则被忽略"的属性。逐条翻译:

  • 你以为:打开billboard_mode让点跟随相机转向。实际上:点本来就恒定正对屏幕,这个属性直接被忽略——它存在的意义对点而言是零。
  • 你以为:设个grow让粒子膨胀一点。实际上:grow靠法线方向沿表面推顶点,点没有表面也没有法线,推无可推。
  • 你以为:用cull_mode = CULL_FRONT反向剔除来藏点。实际上:点没有正反面,剔除逻辑根本不参与。

背后是同一句话:这些开关全是"三角形时代的工具",对点图元没有作用对象。所以看到点不响应某个材质属性,先怀疑是不是撞上了这条边界,别在参数上空耗。

七、和它的近亲怎么选

  • vs QuadMesh:一块真正的四边形,有法线、有 UV、能吃光照和贴图,配合billboard_mode是传统广告牌。你要纹理细节和光照,选 QuadMesh;只要一个纯色斑点,选 PointMesh。
  • vs RibbonTrailMesh / TubeTrailMesh:两者沿路径生成带宽度的拖尾,点图元做不出连续轨迹。要拖尾用它们,粒子本体用 PointMesh,两者常在同一系统里搭配。
  • vs Sprite3D:Sprite3D 是"一个节点一个广告牌",摆 3 个还行,摆 3000 个节点树就完了。海量小图标一律走MultiMeshInstance3D+ PointMesh,别用 Sprite3D 硬堆。

一句话决策:几何细节需求为零 → PointMesh;要看见贴图 → QuadMesh;要拖尾 → Ribbon/Tube。

八、何时该用它、何时该放手

该用的信号:

  • 粒子或标记数量在数千以上,且单个不需要独立几何;
  • 移动端或低端设备,帧预算紧张;
  • 需要展示采样数据(点云)、星图、密集小图标。

该放手的边界:

  • 需要透视缩放——点不随距离变小,想要"远小近大"就得用 QuadMesh +billboard_mode;
  • 需要进 CSG 布尔运算——CSGMesh3D 的类型提示把PointMesh、PlaneMesh、RibbonTrailMesh明确排除在外,因为它们是非流形(non-manifold)图元,布尔算法处理不了;
  • 需要光照与阴影——没有法线,灯光无从下手;
  • 点的物理尺寸要超过一二十像素——GPU 对点尺寸本身有上限,大方块请回到四边形。

结语

回到开头那笔账:当粒子多到算不过来的时候,答案往往不是"优化三角形",而是"根本没有三角形"。把网格换成 PointMesh、挂上点大小、再决定要不要着色器——这三步走通后,下一步自然就是进 3D 粒子系统教程 里玩ParticleProcessMaterial的曲线和噪声了。点已经亮了,剩下的是让它动出花样。

【免费下载链接】godot-docsGodot Engine official documentation项目地址: https://gitcode.com/GitHub_Trending/go/godot-docs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 2:35:44

资深工程师如何将业务经验转化为可落地的Agent能力

1. 这不是“让程序员学AI”,而是把十年代码经验锻造成业务引擎“研发团队会用 AI 之后:怎样把编程经验变成业务 Agent 能力”——这个标题里藏着一个被严重低估的现实转折点。它不讲怎么调大模型API,不教Prompt Engineering入门,更…

作者头像 李华
网站建设 2026/10/17 2:33:39

Langfuse + RAGAS 生产级可观测与评测方案

Langfuse RAGAS 生产级可观测与评测方案 一、核心目标与设计原则 核心目标 构建一套非侵入、自动化、可追溯、可闭环的生产级RAG/Agent质量基建,解决「离线评测与线上脱节、问题定位难、优化无依据、质量不可控」的行业痛点,实现从「被动排查问题」到「…

作者头像 李华
网站建设 2026/10/17 2:32:52

Trae+SQLazy 实践 SQL 国产化移植:Oracle => 达梦

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/17 2:32:49

直播连麦低延迟方案(进阶篇):原理、方案与优化

本文深入探讨直播连麦低延迟方案(进阶篇),涵盖背景分析、原理剖析、实战步骤、配置示例、优化建议和避坑指南。随着业务规模增长,直播连麦低延迟方案(进阶篇)的重要性日益凸显。无论你是刚入门还是资深工程…

作者头像 李华
网站建设 2026/10/17 2:32:47

视频水印与版权保护(进阶篇)最佳实践与踩坑记录

本文深入探讨视频水印与版权保护(进阶篇),涵盖背景分析、原理剖析、实战步骤、配置示例、优化建议和避坑指南。随着业务规模增长,视频水印与版权保护(进阶篇)的重要性日益凸显。无论你是刚入门还是资深工程…

作者头像 李华