Files
EVEngine/docs/usr/modules/particles.md
T

448 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 粒子模块
**脚本入口:** `eve.Particles()`
用代码或 JSON 创建发射器,配置运动、颜色、寿命并进行更新和渲染。
## 基本用法
```squirrel
local particles = eve.Particles();
local fire = particles.newEmitterFromFile("particles/fire.json");
fire.setPosition(320, 420);
fire.start();
particles.update(dt);
particles.render(gfx);
```
## 配置热重载观察
`setAutoReload(true)`(默认开启)后,模块会在 `pollConfigs()` 或模块更新阶段
观察绑定配置文件的修改时间。`getConfigReloadObservation()` 返回最近一次明确观察
到的状态字符串:`"unbound"`(没有绑定配置文件)、
`"mtime_polling_unchanged"`(文件未改变)、`"mtime_polling_reloaded"`(已重新加载)、
`"mtime_unavailable"`(无法取得文件修改时间)或
`"mtime_polling_reload_failed"`(检测到变化但重新加载失败)。该接口只报告观察结果,
不会代替 `reloadConfig()`;读取失败时发射器仍保留原配置,调用方可据此记录诊断或重试。
## 版本化多发射器特效资产
复杂特效应保存为 `eve.particle-effect` 资产,而不是让玩法脚本逐个拼装发射器。版本 1 支持命名层、嵌入式发射器配置或外部 `config` 引用、局部偏移/旋转、禁用层、资产参数默认值和逐层参数覆盖。
```json
{
"type": "eve.particle-effect",
"version": 1,
"parameters": { "intensity": 1.0 },
"emitters": [
{
"name": "core",
"offset": [0, -6],
"emitter": {
"buffer": 128,
"preset": "fire",
"parameterBindings": [
{ "parameter": "intensity", "target": "size", "scale": 1.0 }
]
}
},
{ "name": "smoke", "config": "emitters/smoke.json" }
]
}
```
```squirrel
local impact = particles.newEffectFromFile("effects/impact.effect.json");
if (impact == null) {
print(particles.getLastEffectError() + "\n");
} else {
impact.setPosition(480, 320);
impact.setRotation(0.5);
impact.setFloatParameter("intensity", 1.4);
impact.start();
local sparks = impact.getEmitterByName("sparks"); // 仍可精调单层
}
```
`newEffectFromText()` 供编辑器预览未落盘的 JSON。组对象提供 `setPosition`、`setRotation`、`setScale`、`setLayer`、`setVisible`、`start`、`pause`、`stop`、`reset` 和命名层 `emit`;组销毁时会一起回收所拥有的发射器。未知版本、重名层和无效配置会拒绝实例化,并通过 `getLastEffectError()` 返回可展示的诊断。
## 绑定到动态骨骼
粒子仍是 2D。支持多种运行时骨骼源;每帧 `particles.update` 会自动 `syncAttach`。
| 源 | API | 说明 |
|----|-----|------|
| 3D `AnimPose` | `attachToBone` / `attachToBoneByName` | 骨骼世界坐标经 `plane`(`xy`/`xz`/`yz`)与 `scale` 投影 |
| 2D Spine | `attachToSpineBone` / `attachToSpineBoneByName` | 像素空间;`scale` 仍生效,`plane` 忽略 |
| IK `Skeleton2D` | `attachToSkeleton2D` | FABRIK 链骨位置(像素/世界单位 × `scale`) |
| IK `Skeleton3D` | `attachToSkeleton3D` | 3D 骨位置经 `plane`+`scale` 投影 |
```squirrel
local anim = eve.Animation();
// … player/sm 驱动 pose,并 pose.computeWorld(sk) …
local spark = particles.newEmitter(128);
spark.applyPreset("spark");
spark.setAttachScale(100); // 米 → 像素
spark.setAttachPlane("xy");
spark.setAttachOffset(0, 0.05, 0);
spark.setFollowBoneRotation(true);
spark.attachToBoneByName(pose, sk, "LeftHand");
spark.start();
```
Spine(2D)示例:
```squirrel
local spine = anim.newSpineSkeleton(data);
spine.updateWorldTransform();
local dust = particles.newEmitter(64);
dust.attachToSpineBoneByName(spine, "hand");
dust.start();
```
IK 2D/3D 示例:
```squirrel
local ik = eve.IK();
local sk2 = ik.newSkeleton2D();
// … createBone / solve …
local tipFx = particles.newEmitter(32);
tipFx.attachToSkeleton2D(sk2, tipBoneId);
tipFx.setFollowBoneRotation(true);
```
`detach()` 解除绑定;`getAttachKind()` 返回 `"anim"` / `"spine"` / `"ik2d"` / `"ik3d"` / `"none"`;也可手动 `syncAttach()`。
## 蒙皮表面发射(人物皮肤粒子)
从 CPU 蒙皮后的顶点采样发射位置,适合身体表面的火花、灰尘、能量层:
```squirrel
local skin = anim.newSkinFromModel(model, meshIndex, sk);
pose.computeWorld(sk);
local aura = particles.newEmitter(512);
aura.applyPreset("smoke");
aura.setSkinScale(100);
aura.setSkinPlane("xy");
aura.setSkinSource(skin, pose);
// 可选:只从某根骨附近的顶点发射
aura.setSkinBoneFilterByName(sk, "Spine", 0.2);
aura.start();
// 或瞬时爆发:
aura.emitFromSkin(80);
```
脚本侧也可主动刷新蒙皮缓存:`skin.updateSkinnedPositions(pose)`,再用 `getSkinnedPositionX/Y/Z(i)` 读取。
## 外观增强:混合模式、序列帧与生命周期曲线
发射器支持加法混合、精灵表序列帧动画、多段颜色渐变与大小/旋转曲线,均可通过 JSON 或脚本配置。
```squirrel
// 加法混合 + 序列帧(4x2 精灵表,12 帧/秒,随机起始帧 0~25%)
local burst = particles.newEmitter(256);
burst.setBlendMode("additive");
burst.setFlipbook(4, 2, 12, 0.25);
burst.setTexture(tex); // 精灵表贴图
burst.start();
// 多段颜色渐变 + 大小曲线 + 初始随机旋转
burst.clearColorGradient();
burst.addColorStop(0.0, 1.0, 0.9, 0.4, 1.0); // 白热
burst.addColorStop(0.5, 1.0, 0.3, 0.0, 0.8); // 橙红
burst.addColorStop(1.0, 0.1, 0.0, 0.0, 0.0); // 熄灭
burst.clearSizeCurve();
burst.addSizeCurvePoint(0.0, 0.3);
burst.addSizeCurvePoint(0.7, 1.0);
burst.addSizeCurvePoint(1.0, 0.1);
burst.setStartRotation(-30, 30); // 度
```
JSON 等价配置:
```json
{
"blendMode": "additive",
"flipbook": { "hframes": 4, "vframes": 2, "frameRate": 12, "frameRandomStart": 0.25 },
"startRotation": [-30, 30],
"colorOverLifetime": [
{ "t": 0.0, "r": 1.0, "g": 0.9, "b": 0.4, "a": 1.0 },
{ "t": 0.5, "r": 1.0, "g": 0.3, "b": 0.0, "a": 0.8 },
{ "t": 1.0, "r": 0.1, "g": 0.0, "b": 0.0, "a": 0.0 }
],
"sizeOverLifetime": [[0.0, 0.3], [0.7, 1.0], [1.0, 0.1]],
"rotationOverLifetime": [[0.0, 0.0], [1.0, 120.0]]
}
```
说明:
- `blendMode`:`"alpha"`(默认)/ `"additive"` / `"opaque"`。加法混合适合火焰、火花、魔法等自发光效果。
- `flipbook`:`hframes`/`vframes` 为精灵表行列数;`frameRate` 为每秒帧数(0 = 静止第一帧);`frameRandomStart`(0~1)随机化起始帧。
- `colorOverLifetime` / `sizeOverLifetime` / `rotationOverLifetime` 为按归一化寿命采样的多段渐变/曲线;不配置时回退到 `colorStart`/`colorEnd` 与 `sizes` 的两端线性插值。`rotationOverLifetime` 单位为度,叠加在初始旋转与自旋之上。
## 发射控制与受力增强
发射器支持定时爆发、预热、重力/阻尼/限速、速度曲线、继承速度与本地/世界仿真空间:
```squirrel
// 定时爆发 + 预热(一次性爆炸,开场即满)
local boom = particles.newEmitter(256);
boom.addBurst(0.0, 60); // 第 0 秒爆发 60 个
boom.addBurst(0.15, 30); // 第 0.15 秒再爆 30 个
boom.setEmitterLifetime(0.3); // 单次效果
boom.setPrewarm(0.5); // start() 时预模拟 0.5 秒
boom.start();
// 重力 + 阻尼 + 限速 + 继承发射器移动速度(角色跑动扬尘)
local dust = particles.newEmitter(128);
dust.setGravity(0, 40);
dust.setDamping(0.8);
dust.setLimitVelocity(120);
dust.setInheritVelocity(0.6);
dust.setSimulationSpace("local"); // 粒子跟随发射器(本地空间)
dust.start();
```
JSON 等价配置:
```json
{
"bursts": [ { "time": 0.0, "count": 60 }, { "time": 0.15, "count": 30 } ],
"prewarm": 0.5,
"gravity": [0, 40],
"damping": 0.8,
"limitVelocity": 120,
"velocityOverLifetime": [[0.0, 1.0], [1.0, 0.2]],
"inheritVelocity": 0.6,
"simulationSpace": "local",
"noise": { "strength": 8, "frequency": 0.05, "speed": 1.5 },
"maxDeltaTime": 0.1
}
```
说明:
- `bursts`:按发射器运行时间触发的爆发(数组元素为 `{time, count}` 或 `[time, count]`),每个爆发只触发一次。
- `prewarm`:`start()` 时按 1/60 步长预模拟,让循环效果在首帧就是满的。
- `gravity` 每步作为加速度叠加;`damping` 为每秒速度衰减比例(0~1);`limitVelocity` 为速度上限(0 = 不限);`velocityOverLifetime` 为速度倍率曲线。
- `inheritVelocity`(0~1)把发射器当前移动速度按比例附加到新粒子;`simulationSpace: "local"` 时粒子随发射器平移(默认 `"world"`)。
- `noise` 为 CPU 值噪声湍流(强度/频率/时间流速),适合烟雾、火焰的自然扰动。
- `maxDeltaTime` 限制单帧模拟步长,防止卡顿后的粒子爆炸。
## 可复现播放、固定步进与按距离发射
需要录制回放、网络同步、慢动作或稳定拖尾时,可显式控制粒子时间线:
```squirrel
local trail = particles.newEmitter(512);
trail.setRandomSeed(20260826); // 每次 start() 重放相同随机序列
trail.setAutoRandomSeed(false);
trail.setEmitterLifetime(1.5);
trail.setLooping(true); // 有限时间线循环,burst 也会重新触发
trail.setPlaybackSpeed(0.5); // 半速播放;0 = 冻结
trail.setFixedTimeStep(1.0 / 120.0, 8); // 固定步长 + 每帧最多追 8 步
trail.setEmissionRateOverDistance(0.25); // 每移动 4 个世界单位发射 1 个
trail.start();
```
JSON 等价配置:
```json
{
"randomSeed": 20260826,
"autoRandomSeed": false,
"emitterLife": 1.5,
"looping": true,
"playbackSpeed": 0.5,
"fixedTimeStep": 0.008333333,
"maxSubSteps": 8,
"emissionRateOverDistance": 0.25
}
```
- 固定种子会让寿命、速度、方向、大小、旋转、发射形状和序列帧起点等随机采样可复现;`autoRandomSeed: true`(默认)则每次 `start()` 生成新序列。
- 固定步进由 `maxSubSteps` 限制追帧工作量,超过上限的时间债务会被丢弃,避免暂停恢复后形成长时间尖峰。
- 按距离发射会沿上一位置到当前位置的线段均匀插值,世界空间拖尾不会因帧率变化形成粒子团。第一次更新只建立运动基线,不会补发创建前的路径。
## 质量等级、预算、剔除与性能统计
大规模战斗或天气效果应通过运行时预算稳定降级,而不是等粒子缓冲溢出:
```squirrel
particles.setQualityLevel(2); // 0=最低,3=最高
particles.setBudget(50000, 256); // 全局存活粒子软上限、每帧模拟发射器上限;0=不限
local heroFx = particles.newEmitter(2048);
heroFx.setPriority(100); // 高优先级先获得模拟/生成预算
heroFx.setMinimumQuality(0); // 所有质量等级都保留
heroFx.setCullingMode("always"); // 即使离屏也继续模拟
heroFx.setMaxSpawnPerFrame(256);
local ambience = particles.newEmitter(8192);
ambience.setPriority(-10);
ambience.setMinimumQuality(2);
ambience.setCullingMode("pause"); // 离屏或超出距离时冻结
ambience.setCullDistance(1800);
ambience.setMaxSpawnPerFrame(96);
```
JSON 发射器策略:
```json
{
"priority": -10,
"minimumQuality": 2,
"cullingMode": "pause",
"cullDistance": 1800,
"maxSpawnPerFrame": 96
}
```
- 发射器按 `priority` 从高到低分配每帧模拟器数量和剩余粒子空间;总粒子数是软上限,调低预算不会立即删除已经存活的粒子,但会停止超额生成,让它们自然死亡。
- `cullingMode`:`"automatic"`(默认,仅跳过离屏且为空的发射器)、`"pause"`(离屏时冻结全部模拟)、`"always"`(关键玩法效果始终模拟)。渲染阶段仍会跳过确定不可见的粒子。
- `minimumQuality` 高于当前全局质量等级时,发射器冻结且不渲染;恢复质量后继续运行,不破坏已有粒子状态。
- 每次 `update`/`render` 后可读取 `getLastSimulatedEmitters()`、`getLastCulledEmitters()`、`getLastBudgetSkippedEmitters()`、`getLastParticleCount()`、`getLastSpawnedParticles()`、`getLastDroppedSpawns()`、`getLastRenderedParticles()`、`getLastSimulationMs()` 与 `getLastRenderMs()`,用于 HUD、自动伸缩和性能回归。
## 碰撞与子发射器
```squirrel
// 世界边界反弹(雨滴落地溅射)
local rain = particles.newEmitter(512);
rain.setCollision("bounce", 2, 0.4, 0.1); // 半径 2、弹性 0.4、每次碰撞损失 10% 寿命
rain.setCollisionBounds(true, 0, 0, 960, 640);
rain.setWorldCollision(true); // 可选:查询引擎级碰撞解析器(tilemap/Box2D)
// 子发射器:出生时喷火花,死亡时冒烟
local sparks = particles.newEmitter(128);
local smoke = particles.newEmitter(128);
sparks.addSubEmitter(smoke, "death", 0.3); // 继承 30% 速度
```
JSON:`collision: {mode, radius, restitution, lifetimeLoss}`、`collisionBounds: {enabled, minX, minY, maxX, maxY}`、`worldCollision: true`。子发射器目前通过脚本 `addSubEmitter(target, trigger, inherit)` 关联(trigger 为 `"birth"` / `"death"` / `"collision"`)。
精灵朝向统一由 `setRenderMode` 控制:`"billboard"` 使用粒子自身旋转,`"axis"` 配合 `setRenderAxis(degrees)` 固定到屏幕空间轴,`"stretched"`(也接受 `"velocity"`)按速度方向拉伸。JSON 对应 `renderMode`、`renderAxis` 和 `stretch`。
透明粒子可用 `setSortMode("none" | "oldest" | "youngest" | "distance")` 选择稳定的逐发射器提交顺序,`getSortMode()` 返回规范化后的策略。`distance` 在有相机时按远到近排列。当前 GPU 常驻后端只支持 `none`;其他策略明确保留在 CPU 后端,避免宣称排序已在 GPU 上完成。
连续拖尾使用 `setRibbon(width, minSegmentLength)`,它按稳定的粒子出生顺序连接相邻控制点,跳过过短段,并沿段方向生成带宽度的纹理四边形;JSON 为 `ribbon: {width, minSegmentLength}`。Ribbon 当前明确使用 CPU 渲染后端,适合配合 `setEmissionRateOverDistance` 制作弹道、刀光和移动轨迹。
`setSoftParticles(true, depth, fadeDistance)` 让常驻粒子采样当前 G-buffer 的线性场景深度,在与几何相交或被遮挡时平滑衰减 alpha;JSON 为 `softParticles: {enabled, depth, fadeDistance}`,深度值均为 `[0,1]` 线性深度。`isSoftParticlesActive()` 只有在 GPU 常驻渲染器已激活且当前帧确实产生场景深度时才返回 true;纯 2D 帧不会伪造深度,而是保持普通粒子外观。
粒子材质默认是 `unlit`,不受场景灯光影响。`setMaterialMode("lit")` 会让粒子接收现有 2D 环境光和点光/方向光;配合 `setNormalTexture(normalTex)` 时使用切线空间法线贴图,否则使用无贴图的逐粒子中心光照。JSON 可写为:
```json
{
"material": {
"mode": "lit",
"normalTexture": "particles/smoke-normal.png"
}
}
```
Lit/法线贴图目前明确使用 CPU 粒子模拟加 GPU 2D lit 绘制;即使请求了 `gpuSimulation`,也会安全回退,不会静默忽略灯光。切回 `unlit` 后可重新满足 GPU 常驻条件。
`setMaterialMode("distortion")` 把粒子纹理解释为屏幕空间位移场:R/G 的 0.5 表示零偏移,0/1 表示负/正方向,A 控制羽化覆盖;`setDistortionStrength(pixels)`(`getDistortionStrength()` 可读回)设置最大折射像素数。它采样同一帧已解析的 3D 场景颜色,因此纯 2D 帧或离屏 Canvas 不会伪造背景。JSON 示例:`material: {mode: "distortion", distortionStrength: 12}`。Distortion 当前使用 CPU 粒子模拟和专用 GPU 合成管线。
运行时诊断可读取 `getSimulationBackend()`(`"cpu"` / `"gpu"`)和 `getGpuFallbackReason()`。后者在 GPU 已激活时为空;可返回 `disabled`、`backend_unavailable`、`pending_activation`,或具体功能原因:`canvas`、`custom_shader`、`collision`、`force_fields`、`sub_emitters`、`particle_lights`、`curves`、`sorting`、`ribbon`、`lit_material`、`distortion_material`。`isGpuFeatureSetSupported()` 只检查当前功能组合,不把机器是否支持 Vulkan resident 后端混在一起。
玩法和效果资产可通过命名浮点参数实时驱动 emitter,无需重建或覆盖基础配置:
```squirrel
fire.setFloatParameter("intensity", 1.5);
fire.bindFloatParameter("intensity", "emission", 1.0, 0.0);
fire.bindFloatParameter("intensity", "speed", 0.5, 0.25);
fire.bindFloatParameter("intensity", "size", 0.35, 0.65);
```
支持的 target 是 `emission`、`speed`、`size`、`playback`,解析公式为 `max(0, value * scale + offset)`;参数缺失或未绑定时倍率为 1。JSON 使用 `parameters` 对象和 `parameterBindings` 数组。这些值在 CPU 与 GPU resident 的生成输入上保持一致,适合武器充能、天气强度、角色状态与关卡脚本驱动。
健壮性:`overflowMode`(`"drop"` 默认 / `"pause"` 暂停发射直到有空位 / `"warn"` 日志提示);`setMaxDeltaTime` 限制单帧步长;带相机的发射器在屏幕外且无存活粒子时会跳过模拟。
## 力场、自定义 Shader 与粒子灯光
```squirrel
// 径向力场:黑洞(吸引)/ 斥力场;strength > 0 吸引,< 0 排斥
local vortex = particles.newEmitter(512);
vortex.addForceField(400, 300, 180, 90, 1.5); // 中心 (400,300),半径 180,强度 90,衰减指数 1.5
// 自定义粒子 Shader(仅作用于带贴图的粒子;需要先创建 Shader)
local glow = particles.newEmitter(256);
glow.setShader(myShader);
// 粒子灯光:跟随存活粒子的 2D 点光源(每个发射器最多 8 盏,引擎单画布每帧最多 8 盏)
local torch = particles.newEmitter(128);
torch.setLights(true, 120, 1.2, 1.0, 0.6, 0.2, 4);
```
JSON:`forceFields: [{x, y, radius, strength, falloff}]`;`lights: {enabled, max, radius, intensity, color: [r,g,b]}`。粒子灯光由 `ParticleLightSystem`(随 `particles.update` 自动调用)维护一盏 `Light2D` 池,位置与最前面的存活粒子同步。
## GPU 加速模拟
`setGpuSimulation(true)` 或 JSON `"gpuSimulation": true` 会请求常驻 GPU 后端。首次可提交帧把当前新生粒子上传到后端拥有的多帧 SSBO;之后更新、死亡剔除、存活压缩和 `VkDrawIndirectCommand` 都在同一帧命令缓冲内完成。渲染直接读取压缩后的 SSBO,不逐帧回读粒子状态,也不为每个发射器单独提交或等待队列。CPU 只维护确定性的发射调度、预算和寿命数量估计。
```squirrel
local embers = particles.newEmitter(20000); // 上万粒子场景
embers.setGpuSimulation(true);
embers.setGravity(0, 30);
embers.start();
```
调用 `isGpuSimulationActive()` 可区分“资产请求 GPU”与“本帧已经迁移到 GPU”。`particles.getLastGpuResidentEmitters()` 和 `particles.getLastGpuResidentParticles()` 可用于性能 HUD 和自动质量伸缩。后者是 CPU 侧精确寿命估计;后端的存活、生成、死亡、丢弃和间接实例计数采用帧槽延迟读数,不会阻塞当前帧。
当前常驻 GPU 后端覆盖基础点/线/矩形/椭圆发射、重力、线性/径向/切向加速度、阻尼、限速、噪声、本地/世界空间、旋转、尺寸和起止颜色、flipbook、拉伸与常用混合模式。需要玩法回调或逐粒子 CPU 状态的功能会自动保留在确定性 CPU 后端,包括碰撞、力场、子发射器、粒子灯光、自定义 shader/canvas,以及自定义速度/尺寸/旋转曲线和多段颜色渐变。没有可用图形后端时也安全回退 CPU。
着色器源位于 `graphics/shaders/particle_resident.*`;修改后运行 `python scripts/compile_particle_gpu_shaders.py` 更新随引擎编译的 SPIR-V 与 include 文件。
## 对象关系与调用时机
`Particles` 管理 Emitter 及配置、模拟、渲染系统;Emitter 持有容量、发射配置与运行状态。模块 update 统一推进所有 emitter(含骨骼绑定同步与蒙皮表面采样),render 按 layer 提交。
帧序建议:动画 `computeWorld` → `particles.update(dt)` → `particles.render(gfx)`。
## 目标导向指南
### 从 JSON 创建火焰
配置 buffer、发射率、寿命、速度、颜色和 `autoReload`,调用 `newEmitterFromFile()`;设置位置后 `start()`。模块统一 `update(dt)` 和 `render(gfx)`,无需逐粒子操作。
### 制作一次性爆炸
创建容量足够的 emitter,设置有限 emitter life 和较高瞬时发射率,停止循环;播放结束后检查 active 状态并回收。预览时用 preset 起步,再逐项覆盖参数。
### 角色手上的拖尾 / 皮肤光晕
动画更新并 `computeWorld` 后,用 `attachToBoneByName` 绑定肢体,或用 `setSkinSource` 从蒙皮表面发射;`setAttachScale` / `setSkinScale` 把模型单位映射到像素空间。
## 常见问题
- buffer 太小导致高发射率粒子被覆盖。
- 只 render 不 update,粒子静止。
- 无限 emitter 离开场景后未 stop/回收。
- 骨骼绑定后位置不对:检查是否先更新姿态(`pose.computeWorld(sk)` / `spine.updateWorldTransform()` / IK `forwardKinematics`/`solve`),以及 `plane`/`scale` 是否匹配相机投影。
- 蒙皮表面无粒子:确认 `setSkinSource` 与 `hasBones` 网格,且过滤器未把候选顶点剔光。
## API 快查
下列方法名来自当前 Squirrel 绑定;同一模块创建的辅助对象(例如 `World`、`Body`、`Source`)的方法也列在这里。
- `addBurst()`、`addColorStop()`、`addForceField()`、`addRotationCurvePoint()`、`addSizeCurvePoint()`、`addSubEmitter()`、`addVelocityCurvePoint()`、`applyConfig()`、`applyPreset()`、`attachToBone()`、`attachToBoneByName()`、`attachToSkeleton2D()`、`attachToSkeleton3D()`、`attachToSpineBone()`、`attachToSpineBoneByName()`、`bindFloatParameter()`、`clearBursts()`、`clearColorGradient()`、`clearFloatParameterBindings()`、`clearFloatParameters()`、`clearForceFields()`、`clearRotationCurve()`、`clearSizeCurve()`、`clearSkinSource()`、`clearSubEmitters()`、`clearVelocityCurve()`、`detach()`、`emit()`、`emitFromSkin()`、`getAttachBone()`、`getAttachKind()`、`getAutoRandomSeed()`、`getAutoReload()`、`getBlendMode()`、`getBufferSize()`、`getConfigPath()`、`getCount()`、`getDirection()`、`getEmissionRateOverDistance()`、`getFixedTimeStep()`、`getGpuSimulation()`、`getLightsEnabled()`、`getLooping()`、`getPlaybackSpeed()`、`getPrewarmSeconds()`、`getRandomSeed()`、`getShader()`
- `getEmissionAreaType()`、`getEmissionAreaX()`、`getEmissionAreaY()`、`getEmissionRate()`、`getEmitterCount()`、`getEmitterLifetime()`、`getEmitterName()`、`getEmitter()`、`getEmitterByName()`、`getFloatParameter()`、`getGpuFallbackReason()`、`getLastEffectError()`、`getLayer()`、`getName()`、`getPriority()`、`getMinimumQuality()`、`getCullingMode()`、`getCullDistance()`、`getMaxSpawnPerFrame()`、`getMaterialMode()`、`getDistortionStrength()`、`getNormalTexture()`、`getResolvedParameterScale()`、`getRotation()`、`getScale()`、`getSimulationBackend()`、`getSourcePath()`、`getVersion()`
- `getMaxParticles()`、`getMaxSimulatedEmitters()`、`getQualityLevel()`、`getLastSimulatedEmitters()`、`getLastCulledEmitters()`、`getLastBudgetSkippedEmitters()`、`getLastParticleCount()`、`getLastSpawnedParticles()`、`getLastDroppedSpawns()`、`getLastRenderedParticles()`、`getLastSimulationMs()`、`getLastRenderMs()`
- `getParticleHeight()`、`getParticleLifetimeMax()`、`getParticleLifetimeMin()`、`getParticleWidth()`、`getSizeVariation()`、`getSpread()`、`getX()`、`getY()`
- `hasFloatParameter()`、`hasSkinSource()`、`isActive()`、`isAttached()`、`isGpuFeatureSetSupported()`、`isPaused()`、`isStopped()`、`isVisible()`、`loadConfig()`、`moveTo()`、`newEffectFromFile()`、`newEffectFromText()`、`newEmitter()`、`newEmitterFromFile()`
- `pause()`、`pollConfigs()`、`reloadConfig()`、`render()`、`reset()`、`setAttachOffset()`、`setAttachPlane()`、`setAttachScale()`、`setAutoReload()`、`setCamera()`、`setCanvas()`、`getConfigReloadObservation()`
- `setAutoRandomSeed()`、`setBlendMode()`、`setBudget()`、`setCollision()`、`setCollisionBounds()`、`setColorEnd()`、`setColorStart()`、`setCullingMode()`、`setCullDistance()`、`setDamping()`、`setDirection()`、`setDistortionStrength()`、`setEmissionArea()`、`setEmissionRate()`、`setEmissionRateOverDistance()`、`setEmitterLife()`、`setEmitterLifetime()`、`setEmitterTime()`、`setFixedTimeStep()`、`setFlipbook()`、`setFloatParameter()`、`setGpuSimulation()`、`setGravity()`、`setInheritVelocity()`、`setLights()`、`setLimitVelocity()`、`setLooping()`、`setMaterialMode()`、`setMaxDeltaTime()`、`setMaxSpawnPerFrame()`、`setMinimumQuality()`、`setNoise()`、`setNormalTexture()`、`setOverflowMode()`、`setPlaybackSpeed()`、`setPrewarm()`、`setPriority()`、`setQualityLevel()`、`setRandomSeed()`、`setRenderMode()`、`setShader()`、`setSimulationSpace()`、`setWorldCollision()`
- `setFollowBoneRotation()`、`setLayer()`、`setLinearAcceleration()`、`setParticleLife()`、`setParticleLifetime()`、`setParticleSize()`、`setPosition()`、`setRadialAcceleration()`、`setRotation()`、`setScale()`、`setSizeVariation()`
- `setSizes()`、`setSkinBoneFilter()`、`setSkinBoneFilterByName()`、`setSkinPlane()`、`setSkinScale()`、`setSkinSource()`、`setSpeed()`、`setSpin()`、`setSpread()`、`setStartRotation()`、`setTangentialAcceleration()`、`setTexture()`、`setVisible()`、`start()`
- `stop()`、`syncAttach()`、`update()`
## 使用要点
- 模块对象和它创建的资源对象应保存在全局或实体状态中,不要在每帧重复创建。
- 带 `update(dt)` 的系统应在 `eve_update` 调用;绘制方法应在 `eve_render` 调用。
- 参数约束、默认值和返回类型以对应模块头文件及 `addFunc` 绑定为准;本文 API 快查与当前源码同步生成。
**源码:** [`src/modules/particles/`](../../../src/modules/particles/)
**相关测试:** [`test/particles.cpp`](../../../test/particles.cpp)、[`test/particles_effect_asset.cpp`](../../../test/particles_effect_asset.cpp)、[`test/particles_reference_effects.cpp`](../../../test/particles_reference_effects.cpp)、[`test/particles_attach_skin.cpp`](../../../test/particles_attach_skin.cpp)、[`test/particles_dynamic_bones.cpp`](../../../test/particles_dynamic_bones.cpp)、[`test/particles_attach_more.cpp`](../../../test/particles_attach_more.cpp)、[`test/particles_attach_extra.cpp`](../../../test/particles_attach_extra.cpp)。