Skip to content

Commit 6d0fdd8

Browse files
authored
ParticleRenderer support bounds and frustum culling (#1963)
* feat: calculate particleRenderer boundingBox
1 parent 11a54aa commit 6d0fdd8

21 files changed

+2309
-154
lines changed

e2e/case/particleRenderer-dream.ts

+343
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
/**
2+
* @title Particle Dream
3+
* @category Particle
4+
*/
5+
import {
6+
AssetType,
7+
BlendMode,
8+
BoxShape,
9+
Camera,
10+
Color,
11+
Engine,
12+
Entity,
13+
Logger,
14+
ParticleCurveMode,
15+
ParticleGradientMode,
16+
ParticleMaterial,
17+
ParticleRenderMode,
18+
ParticleRenderer,
19+
Texture2D,
20+
Vector3,
21+
WebGLEngine,
22+
WebGLMode
23+
} from "@galacean/engine";
24+
import { initScreenshot, updateForE2E } from "./.mockForE2E";
25+
26+
// Create engine
27+
WebGLEngine.create({
28+
canvas: "canvas",
29+
graphicDeviceOptions: { webGLMode: WebGLMode.WebGL1 }
30+
}).then((engine) => {
31+
Logger.enable();
32+
engine.canvas.resizeByClientSize();
33+
34+
const scene = engine.sceneManager.activeScene;
35+
const rootEntity = scene.createRootEntity();
36+
scene.background.solidColor = new Color(15 / 255, 38 / 255, 18 / 255, 1);
37+
38+
// Create camera
39+
const cameraEntity = rootEntity.createChild("camera_entity");
40+
cameraEntity.transform.position = new Vector3(0, 1, 3);
41+
const camera = cameraEntity.addComponent(Camera);
42+
camera.fieldOfView = 60;
43+
44+
engine.run();
45+
46+
engine.resourceManager
47+
.load([
48+
{
49+
url: "https://mdn.alipayobjects.com/huamei_b4l2if/afts/img/A*JPsCSK5LtYkAAAAAAAAAAAAADil6AQ/original",
50+
type: AssetType.Texture2D
51+
},
52+
{
53+
url: "https://mdn.alipayobjects.com/huamei_b4l2if/afts/img/A*eWTFRZPqfDMAAAAAAAAAAAAADil6AQ/original",
54+
type: AssetType.Texture2D
55+
},
56+
{
57+
url: "https://mdn.alipayobjects.com/huamei_b4l2if/afts/img/A*J8uhRoxJtYgAAAAAAAAAAAAADil6AQ/original",
58+
type: AssetType.Texture2D
59+
},
60+
{
61+
url: "https://mdn.alipayobjects.com/huamei_b4l2if/afts/img/A*Ea3qRb1yCQMAAAAAAAAAAAAADil6AQ/original",
62+
type: AssetType.Texture2D
63+
}
64+
])
65+
.then((textures) => {
66+
const fireEntity = createDebrisParticle(engine, <Texture2D>textures[0]);
67+
createGlowParticle(fireEntity, <Texture2D>textures[1]);
68+
createSparksParticle(fireEntity, <Texture2D>textures[2]);
69+
createHighlightsParticle(fireEntity, <Texture2D>textures[3]);
70+
71+
cameraEntity.addChild(fireEntity);
72+
73+
setTimeout(() => {
74+
updateForE2E(engine);
75+
initScreenshot(engine, camera);
76+
}, 2000);
77+
});
78+
});
79+
80+
function createDebrisParticle(engine: Engine, texture: Texture2D): Entity {
81+
const particleEntity = new Entity(engine, "Debris");
82+
particleEntity.transform.position.set(0, -7.5, -8);
83+
84+
const particleRenderer = particleEntity.addComponent(ParticleRenderer);
85+
86+
const material = new ParticleMaterial(engine);
87+
material.baseColor = new Color(1.0, 1.0, 1.0, 1.0);
88+
material.blendMode = BlendMode.Additive;
89+
material.baseTexture = texture;
90+
particleRenderer.setMaterial(material);
91+
particleRenderer.priority = 2;
92+
93+
particleRenderer.generator.useAutoRandomSeed = false;
94+
95+
const { main, emission, sizeOverLifetime, colorOverLifetime, velocityOverLifetime } = particleRenderer.generator;
96+
97+
// Main module
98+
main.startSpeed.constant = 0;
99+
100+
main.startSize.constantMin = 0.1;
101+
main.startSize.constantMax = 1;
102+
main.startSize.mode = ParticleCurveMode.TwoConstants;
103+
104+
main.startRotationZ.constantMin = 0;
105+
main.startRotationZ.constantMax = 360;
106+
main.startRotationZ.mode = ParticleCurveMode.TwoConstants;
107+
108+
main.startColor.constantMin.set(255 / 255, 255 / 255, 255 / 255, 1.0);
109+
main.startColor.constantMax.set(13 / 255, 255 / 255, 0 / 255, 1.0);
110+
main.startColor.mode = ParticleGradientMode.TwoConstants;
111+
112+
// Emission module
113+
emission.rateOverTime.constant = 5;
114+
115+
const boxShape = new BoxShape();
116+
boxShape.size.set(22, 1, 0);
117+
emission.shape = boxShape;
118+
119+
// Color over lifetime module
120+
colorOverLifetime.enabled = true;
121+
colorOverLifetime.color.mode = ParticleGradientMode.Gradient;
122+
123+
const gradient = colorOverLifetime.color.gradient;
124+
gradient.alphaKeys[0].alpha = 0;
125+
gradient.alphaKeys[1].alpha = 0;
126+
gradient.addAlphaKey(0.2, 1.0);
127+
gradient.addAlphaKey(0.8, 1.0);
128+
129+
// Size over lifetime module
130+
sizeOverLifetime.enabled = true;
131+
const keys = sizeOverLifetime.size.curve.keys;
132+
keys[0].value = 1;
133+
keys[1].value = 0;
134+
135+
// Velocity over lifetime module
136+
velocityOverLifetime.enabled = true;
137+
velocityOverLifetime.velocityX.constantMin = 2;
138+
velocityOverLifetime.velocityX.constantMax = 1;
139+
velocityOverLifetime.velocityX.mode = ParticleCurveMode.TwoConstants;
140+
141+
velocityOverLifetime.velocityY.constantMin = 4;
142+
velocityOverLifetime.velocityY.constantMax = 2;
143+
velocityOverLifetime.velocityY.mode = ParticleCurveMode.TwoConstants;
144+
145+
velocityOverLifetime.velocityZ.constantMin = 0;
146+
velocityOverLifetime.velocityZ.constantMax = 0;
147+
velocityOverLifetime.velocityZ.mode = ParticleCurveMode.TwoConstants;
148+
149+
return particleEntity;
150+
}
151+
152+
function createGlowParticle(fireEntity: Entity, texture: Texture2D): void {
153+
const particleEntity = fireEntity.createChild("Glow");
154+
particleEntity.transform.position.set(-1.88, 0, 0);
155+
156+
const particleRenderer = particleEntity.addComponent(ParticleRenderer);
157+
particleRenderer.renderMode = ParticleRenderMode.StretchBillboard;
158+
particleRenderer.lengthScale = 2;
159+
160+
const material = new ParticleMaterial(fireEntity.engine);
161+
material.blendMode = BlendMode.Additive;
162+
material.baseTexture = texture;
163+
particleRenderer.setMaterial(material);
164+
particleRenderer.priority = 1;
165+
166+
const generator = particleRenderer.generator;
167+
generator.useAutoRandomSeed = false;
168+
const { main, emission, velocityOverLifetime, colorOverLifetime } = generator;
169+
170+
// Main module
171+
main.startSpeed.constant = 0.0;
172+
173+
main.startSize.constantMin = 5;
174+
main.startSize.constantMax = 9;
175+
main.startSize.mode = ParticleCurveMode.TwoConstants;
176+
177+
main.startRotationZ.constantMin = 0;
178+
main.startRotationZ.constantMax = 360;
179+
main.startRotationZ.mode = ParticleCurveMode.TwoConstants;
180+
181+
main.startColor.constantMin = new Color(0 / 255, 157 / 255, 255 / 255, 64 / 255);
182+
main.startColor.constantMax = new Color(13 / 255, 255 / 255, 0 / 255, 128 / 255);
183+
main.startColor.mode = ParticleGradientMode.TwoConstants;
184+
185+
// Emission module
186+
emission.rateOverTime.constant = 10;
187+
188+
const boxShape = new BoxShape();
189+
boxShape.size.set(22, 1, 0);
190+
emission.shape = boxShape;
191+
192+
// Velocity over lifetime module
193+
velocityOverLifetime.enabled = true;
194+
velocityOverLifetime.velocityX.constantMin = 2;
195+
velocityOverLifetime.velocityX.constantMax = 1;
196+
velocityOverLifetime.velocityX.mode = ParticleCurveMode.TwoConstants;
197+
198+
velocityOverLifetime.velocityY.constantMin = 4;
199+
velocityOverLifetime.velocityY.constantMax = 2;
200+
velocityOverLifetime.velocityY.mode = ParticleCurveMode.TwoConstants;
201+
202+
velocityOverLifetime.velocityZ.constantMin = 0;
203+
velocityOverLifetime.velocityZ.constantMax = 0;
204+
velocityOverLifetime.velocityZ.mode = ParticleCurveMode.TwoConstants;
205+
206+
// Color over lifetime module
207+
colorOverLifetime.enabled = true;
208+
colorOverLifetime.color.mode = ParticleGradientMode.Gradient;
209+
210+
const gradient = colorOverLifetime.color.gradient;
211+
gradient.alphaKeys[0].alpha = 0;
212+
gradient.alphaKeys[1].alpha = 0;
213+
gradient.addAlphaKey(0.2, 1.0);
214+
}
215+
216+
function createSparksParticle(fireEntity: Entity, texture: Texture2D): void {
217+
const particleEntity = fireEntity.createChild("Sparks");
218+
particleEntity.transform.position.set(-1.54, 0, 0);
219+
220+
const particleRenderer = particleEntity.addComponent(ParticleRenderer);
221+
const material = new ParticleMaterial(fireEntity.engine);
222+
material.baseTexture = texture;
223+
particleRenderer.setMaterial(material);
224+
particleRenderer.priority = 0;
225+
226+
const { main, emission, colorOverLifetime, velocityOverLifetime } = particleRenderer.generator;
227+
particleRenderer.generator.useAutoRandomSeed = false;
228+
229+
// Main module
230+
main.startLifetime.constant = 5;
231+
main.startSpeed.constant = 0;
232+
233+
main.startSize.constantMin = 0.05;
234+
main.startSize.constantMax = 0.2;
235+
main.startSize.mode = ParticleCurveMode.TwoConstants;
236+
237+
main.startRotationZ.constantMin = 0;
238+
main.startRotationZ.constantMax = 360;
239+
main.startRotationZ.mode = ParticleCurveMode.TwoConstants;
240+
241+
main.startColor.constant = new Color(37 / 255, 133 / 255, 255 / 255, 255 / 255);
242+
243+
// Emission module
244+
emission.rateOverTime.constant = 30;
245+
246+
const boxShape = new BoxShape();
247+
boxShape.size.set(22, 1, 0);
248+
emission.shape = boxShape;
249+
250+
// Velocity over lifetime module
251+
velocityOverLifetime.enabled = true;
252+
velocityOverLifetime.velocityX.constantMin = 2;
253+
velocityOverLifetime.velocityX.constantMax = 1;
254+
velocityOverLifetime.velocityX.mode = ParticleCurveMode.TwoConstants;
255+
256+
velocityOverLifetime.velocityY.constantMin = 4;
257+
velocityOverLifetime.velocityY.constantMax = 2;
258+
velocityOverLifetime.velocityY.mode = ParticleCurveMode.TwoConstants;
259+
260+
velocityOverLifetime.velocityZ.constantMin = 0;
261+
velocityOverLifetime.velocityZ.constantMax = 0;
262+
velocityOverLifetime.velocityZ.mode = ParticleCurveMode.TwoConstants;
263+
264+
// Color over lifetime module
265+
colorOverLifetime.enabled = true;
266+
colorOverLifetime.color.mode = ParticleGradientMode.Gradient;
267+
268+
const gradient = colorOverLifetime.color.gradient;
269+
gradient.alphaKeys[0].alpha = 0;
270+
gradient.alphaKeys[1].alpha = 0;
271+
gradient.addAlphaKey(0.2, 1.0);
272+
gradient.addAlphaKey(0.8, 1.0);
273+
}
274+
275+
function createHighlightsParticle(fireEntity: Entity, texture: Texture2D): void {
276+
const particleEntity = fireEntity.createChild("Highlights");
277+
particleEntity.transform.position.set(-5.31, 0, 0);
278+
279+
const particleRenderer = particleEntity.addComponent(ParticleRenderer);
280+
281+
const material = new ParticleMaterial(fireEntity.engine);
282+
material.blendMode = BlendMode.Additive;
283+
material.baseTexture = texture;
284+
particleRenderer.setMaterial(material);
285+
particleRenderer.priority = 3;
286+
287+
const generator = particleRenderer.generator;
288+
const { main, emission, sizeOverLifetime, colorOverLifetime, velocityOverLifetime } = generator;
289+
generator.useAutoRandomSeed = false;
290+
291+
// Main module
292+
main.startSpeed.constant = 0;
293+
294+
main.startSize.constantMin = 0.1;
295+
main.startSize.constantMax = 7;
296+
main.startSize.mode = ParticleCurveMode.TwoConstants;
297+
298+
main.startRotationZ.constantMin = 0;
299+
main.startRotationZ.constantMax = 360;
300+
main.startRotationZ.mode = ParticleCurveMode.TwoConstants;
301+
302+
main.startColor.constantMin.set(105 / 255, 198 / 255, 255 / 255, 64 / 255);
303+
main.startColor.constantMax.set(13 / 255, 255 / 255, 0 / 255, 32 / 255);
304+
main.startColor.mode = ParticleGradientMode.TwoConstants;
305+
306+
// Emission module
307+
emission.rateOverTime.constant = 40;
308+
309+
const boxShape = new BoxShape();
310+
boxShape.size.set(22, 1, 0);
311+
emission.shape = boxShape;
312+
313+
// Velocity over lifetime module
314+
velocityOverLifetime.enabled = true;
315+
velocityOverLifetime.velocityX.constantMin = 3;
316+
velocityOverLifetime.velocityX.constantMax = 2;
317+
velocityOverLifetime.velocityX.mode = ParticleCurveMode.TwoConstants;
318+
319+
velocityOverLifetime.velocityY.constantMin = 4;
320+
velocityOverLifetime.velocityY.constantMax = 2;
321+
velocityOverLifetime.velocityY.mode = ParticleCurveMode.TwoConstants;
322+
323+
velocityOverLifetime.velocityZ.constantMin = 0;
324+
velocityOverLifetime.velocityZ.constantMax = 0;
325+
velocityOverLifetime.velocityZ.mode = ParticleCurveMode.TwoConstants;
326+
327+
// Color over lifetime module
328+
colorOverLifetime.enabled = true;
329+
colorOverLifetime.color.mode = ParticleGradientMode.Gradient;
330+
331+
const gradient = colorOverLifetime.color.gradient;
332+
gradient.alphaKeys[0].alpha = 0;
333+
gradient.alphaKeys[1].alpha = 0;
334+
gradient.addAlphaKey(0.2, 1.0);
335+
gradient.addAlphaKey(0.8, 1.0);
336+
337+
// Size over lifetime module
338+
sizeOverLifetime.enabled = true;
339+
const curve = sizeOverLifetime.size.curve;
340+
sizeOverLifetime.size.mode = ParticleCurveMode.Curve;
341+
curve.keys[0].value = 1;
342+
curve.keys[1].value = 0;
343+
}

e2e/config.ts

+7
Original file line numberDiff line numberDiff line change
@@ -163,5 +163,12 @@ export const E2E_CONFIG = {
163163
caseFileName: "physx-collision",
164164
threshold: 0.1
165165
}
166+
},
167+
Particle: {
168+
meshopt: {
169+
category: "Particle",
170+
caseFileName: "particleRenderer-dream",
171+
threshold: 0.3
172+
}
166173
}
167174
};
Loading

0 commit comments

Comments
 (0)