babylon.quarks 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/babylon.quarks.cjs +2 -0
- package/dist/babylon.quarks.cjs.map +1 -0
- package/dist/babylon.quarks.esm.js +2 -0
- package/dist/babylon.quarks.esm.js.map +1 -0
- package/dist/types/BatchedParticleRenderer.d.ts +2 -0
- package/dist/types/BatchedRenderer.d.ts +40 -0
- package/dist/types/MeshSurfaceEmitter.d.ts +19 -0
- package/dist/types/ParticleEmitter.d.ts +16 -0
- package/dist/types/ParticleSystem.d.ts +226 -0
- package/dist/types/QuarksLoader.d.ts +28 -0
- package/dist/types/QuarksPrefab.d.ts +48 -0
- package/dist/types/QuarksUtil.d.ts +14 -0
- package/dist/types/SpriteBatch.d.ts +32 -0
- package/dist/types/TrailBatch.d.ts +27 -0
- package/dist/types/VFXBatch.d.ts +51 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/materials/ParticleMaterials.d.ts +12 -0
- package/dist/types/materials/index.d.ts +1 -0
- package/dist/types/shaders/chunks/index.d.ts +1 -0
- package/dist/types/shaders/chunks/register-shader-chunks.d.ts +3 -0
- package/dist/types/shaders/chunks/soft_fragment.glsl.d.ts +2 -0
- package/dist/types/shaders/chunks/soft_pars_fragment.glsl.d.ts +2 -0
- package/dist/types/shaders/chunks/soft_pars_vertex.glsl.d.ts +2 -0
- package/dist/types/shaders/chunks/soft_vertex.glsl.d.ts +2 -0
- package/dist/types/shaders/chunks/tile_fragment.glsl.d.ts +2 -0
- package/dist/types/shaders/chunks/tile_pars_fragment.glsl.d.ts +2 -0
- package/dist/types/shaders/chunks/tile_pars_vertex.glsl.d.ts +2 -0
- package/dist/types/shaders/chunks/tile_vertex.glsl.d.ts +2 -0
- package/dist/types/shaders/index.d.ts +9 -0
- package/dist/types/shaders/local_particle_physics_vert.glsl.d.ts +2 -0
- package/dist/types/shaders/local_particle_vert.glsl.d.ts +2 -0
- package/dist/types/shaders/particle_frag.glsl.d.ts +2 -0
- package/dist/types/shaders/particle_physics_frag.glsl.d.ts +2 -0
- package/dist/types/shaders/particle_vert.glsl.d.ts +2 -0
- package/dist/types/shaders/stretched_bb_particle_vert.glsl.d.ts +2 -0
- package/dist/types/shaders/trail_frag.glsl.d.ts +2 -0
- package/dist/types/shaders/trail_vert.glsl.d.ts +2 -0
- package/package.json +58 -0
- package/src/BatchedParticleRenderer.ts +3 -0
- package/src/BatchedRenderer.ts +135 -0
- package/src/MeshSurfaceEmitter.ts +137 -0
- package/src/ParticleEmitter.ts +86 -0
- package/src/ParticleSystem.ts +1162 -0
- package/src/QuarksLoader.ts +503 -0
- package/src/QuarksPrefab.ts +307 -0
- package/src/QuarksUtil.ts +66 -0
- package/src/SpriteBatch.ts +391 -0
- package/src/TrailBatch.ts +345 -0
- package/src/VFXBatch.ts +102 -0
- package/src/index.ts +54 -0
- package/src/materials/ParticleMaterials.ts +23 -0
- package/src/materials/index.ts +1 -0
- package/src/shaders/chunks/index.ts +1 -0
- package/src/shaders/chunks/register-shader-chunks.ts +32 -0
- package/src/shaders/chunks/soft_fragment.glsl.ts +13 -0
- package/src/shaders/chunks/soft_pars_fragment.glsl.ts +20 -0
- package/src/shaders/chunks/soft_pars_vertex.glsl.ts +6 -0
- package/src/shaders/chunks/soft_vertex.glsl.ts +6 -0
- package/src/shaders/chunks/tile_fragment.glsl.ts +9 -0
- package/src/shaders/chunks/tile_pars_fragment.glsl.ts +9 -0
- package/src/shaders/chunks/tile_pars_vertex.glsl.ts +28 -0
- package/src/shaders/chunks/tile_vertex.glsl.ts +18 -0
- package/src/shaders/index.ts +9 -0
- package/src/shaders/local_particle_physics_vert.glsl.ts +66 -0
- package/src/shaders/local_particle_vert.glsl.ts +50 -0
- package/src/shaders/particle_frag.glsl.ts +61 -0
- package/src/shaders/particle_physics_frag.glsl.ts +67 -0
- package/src/shaders/particle_vert.glsl.ts +85 -0
- package/src/shaders/stretched_bb_particle_vert.glsl.ts +74 -0
- package/src/shaders/trail_frag.glsl.ts +21 -0
- package/src/shaders/trail_vert.glsl.ts +58 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import {Mesh} from '@babylonjs/core/Meshes/mesh';
|
|
2
|
+
import {VertexBuffer} from '@babylonjs/core/Buffers/buffer';
|
|
3
|
+
import {Effect} from '@babylonjs/core/Materials/effect';
|
|
4
|
+
import {ShaderMaterial} from '@babylonjs/core/Materials/shaderMaterial';
|
|
5
|
+
import {Scene} from '@babylonjs/core/scene';
|
|
6
|
+
import {BoundingInfo} from '@babylonjs/core/Culling/boundingInfo';
|
|
7
|
+
import {Vector3 as BVector3} from '@babylonjs/core/Maths/math.vector';
|
|
8
|
+
import {Vector2 as BVector2} from '@babylonjs/core/Maths/math.vector';
|
|
9
|
+
import {Constants} from '@babylonjs/core/Engines/constants';
|
|
10
|
+
import {Matrix4, Quaternion, RecordState, TrailParticle, Vector3} from 'quarks.core';
|
|
11
|
+
import {VFXBatch, RenderMode} from './VFXBatch';
|
|
12
|
+
import {VFXBatchSettings} from './BatchedRenderer';
|
|
13
|
+
import trail_vert from './shaders/trail_vert.glsl';
|
|
14
|
+
import trail_frag from './shaders/trail_frag.glsl';
|
|
15
|
+
|
|
16
|
+
export class TrailBatch extends VFXBatch {
|
|
17
|
+
private positionBuffer!: Float32Array;
|
|
18
|
+
private previousBuffer!: Float32Array;
|
|
19
|
+
private nextBuffer!: Float32Array;
|
|
20
|
+
private uvBuffer!: Float32Array;
|
|
21
|
+
private sideBuffer!: Float32Array;
|
|
22
|
+
private widthBuffer!: Float32Array;
|
|
23
|
+
private colorBuffer!: Float32Array;
|
|
24
|
+
private indexBuffer!: Uint32Array;
|
|
25
|
+
private previousVB!: VertexBuffer;
|
|
26
|
+
private nextVB!: VertexBuffer;
|
|
27
|
+
private sideVB!: VertexBuffer;
|
|
28
|
+
private widthVB!: VertexBuffer;
|
|
29
|
+
|
|
30
|
+
constructor(settings: VFXBatchSettings, scene: Scene) {
|
|
31
|
+
super(settings, scene);
|
|
32
|
+
this.maxParticles = 10000;
|
|
33
|
+
this.setupBuffers();
|
|
34
|
+
this.rebuildMaterial();
|
|
35
|
+
this.mesh.setEnabled(false);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setupBuffers(): void {
|
|
39
|
+
this.mesh.dispose();
|
|
40
|
+
this.mesh = new Mesh('trailBatch', this.scene);
|
|
41
|
+
this.mesh.alwaysSelectAsActiveMesh = true;
|
|
42
|
+
|
|
43
|
+
this.positionBuffer = new Float32Array(this.maxParticles * 6);
|
|
44
|
+
this.previousBuffer = new Float32Array(this.maxParticles * 6);
|
|
45
|
+
this.nextBuffer = new Float32Array(this.maxParticles * 6);
|
|
46
|
+
this.uvBuffer = new Float32Array(this.maxParticles * 4);
|
|
47
|
+
this.sideBuffer = new Float32Array(this.maxParticles * 2);
|
|
48
|
+
this.widthBuffer = new Float32Array(this.maxParticles * 2);
|
|
49
|
+
this.colorBuffer = new Float32Array(this.maxParticles * 8);
|
|
50
|
+
this.indexBuffer = new Uint32Array(this.maxParticles * 6);
|
|
51
|
+
|
|
52
|
+
// Initialize with full-capacity buffers (updatable) and a dummy triangle
|
|
53
|
+
this.positionBuffer[0] = 0; this.positionBuffer[1] = 0; this.positionBuffer[2] = 0;
|
|
54
|
+
this.positionBuffer[3] = 1; this.positionBuffer[4] = 0; this.positionBuffer[5] = 0;
|
|
55
|
+
this.positionBuffer[6] = 0; this.positionBuffer[7] = 1; this.positionBuffer[8] = 0;
|
|
56
|
+
this.positionBuffer[9] = 1; this.positionBuffer[10] = 1; this.positionBuffer[11] = 0;
|
|
57
|
+
this.indexBuffer[0] = 0; this.indexBuffer[1] = 1; this.indexBuffer[2] = 2;
|
|
58
|
+
this.indexBuffer[3] = 1; this.indexBuffer[4] = 3; this.indexBuffer[5] = 2;
|
|
59
|
+
|
|
60
|
+
// Set standard vertex data with full buffer capacity (updatable)
|
|
61
|
+
this.mesh.setVerticesData(VertexBuffer.PositionKind, this.positionBuffer, true);
|
|
62
|
+
this.mesh.setVerticesData(VertexBuffer.UVKind, this.uvBuffer, true);
|
|
63
|
+
this.mesh.setVerticesData(VertexBuffer.ColorKind, this.colorBuffer, true, 4);
|
|
64
|
+
this.mesh.setIndices(Array.from(this.indexBuffer.subarray(0, 6)), null, true);
|
|
65
|
+
const engine = this.scene.getEngine();
|
|
66
|
+
this.previousVB = new VertexBuffer(engine, this.previousBuffer, 'previous', true, false, 3, false);
|
|
67
|
+
this.nextVB = new VertexBuffer(engine, this.nextBuffer, 'next', true, false, 3, false);
|
|
68
|
+
this.sideVB = new VertexBuffer(engine, this.sideBuffer, 'side', true, false, 1, false);
|
|
69
|
+
this.widthVB = new VertexBuffer(engine, this.widthBuffer, 'width', true, false, 1, false);
|
|
70
|
+
this.mesh.setVerticesBuffer(this.previousVB);
|
|
71
|
+
this.mesh.setVerticesBuffer(this.nextVB);
|
|
72
|
+
this.mesh.setVerticesBuffer(this.sideVB);
|
|
73
|
+
this.mesh.setVerticesBuffer(this.widthVB);
|
|
74
|
+
|
|
75
|
+
// Disable bounding info recomputation
|
|
76
|
+
this.mesh.doNotSyncBoundingInfo = true;
|
|
77
|
+
const min = new BVector3(-10000, -10000, -10000);
|
|
78
|
+
const max = new BVector3(10000, 10000, 10000);
|
|
79
|
+
this.mesh.setBoundingInfo(new BoundingInfo(min, max));
|
|
80
|
+
if (this.mesh.subMeshes) {
|
|
81
|
+
for (const sub of this.mesh.subMeshes) {
|
|
82
|
+
(sub as any)._boundingInfo = this.mesh.getBoundingInfo();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
expandBuffers(target: number): void {
|
|
89
|
+
while (target >= this.maxParticles) {
|
|
90
|
+
this.maxParticles *= 2;
|
|
91
|
+
}
|
|
92
|
+
this.setupBuffers();
|
|
93
|
+
this.rebuildMaterial();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
rebuildMaterial(): void {
|
|
97
|
+
const shaderName = `quarksTrail_${Date.now()}`;
|
|
98
|
+
const defines: string[] = [];
|
|
99
|
+
|
|
100
|
+
if (this.settings.texture) {
|
|
101
|
+
defines.push('USE_MAP');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
Effect.ShadersStore[shaderName + 'VertexShader'] = trail_vert;
|
|
105
|
+
Effect.ShadersStore[shaderName + 'FragmentShader'] = trail_frag;
|
|
106
|
+
|
|
107
|
+
const attributes = ['position', 'previous', 'next', 'side', 'width', 'uv', 'color'];
|
|
108
|
+
const uniforms = ['world', 'view', 'projection', 'worldViewProjection', 'lineWidth', 'resolution', 'sizeAttenuation'];
|
|
109
|
+
const samplers: string[] = [];
|
|
110
|
+
|
|
111
|
+
if (this.settings.texture) {
|
|
112
|
+
samplers.push('map');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const mat = new ShaderMaterial(shaderName, this.scene,
|
|
116
|
+
{vertex: shaderName, fragment: shaderName},
|
|
117
|
+
{
|
|
118
|
+
attributes,
|
|
119
|
+
uniforms,
|
|
120
|
+
samplers,
|
|
121
|
+
defines,
|
|
122
|
+
needAlphaBlending: this.settings.materialTransparent,
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
if (this.settings.texture) {
|
|
127
|
+
mat.setTexture('map', this.settings.texture);
|
|
128
|
+
}
|
|
129
|
+
const engine = this.scene.getEngine();
|
|
130
|
+
mat.setFloat('lineWidth', 1);
|
|
131
|
+
mat.setVector2('resolution', new BVector2(engine.getRenderWidth(), engine.getRenderHeight()));
|
|
132
|
+
mat.setFloat('sizeAttenuation', 1);
|
|
133
|
+
mat.onBindObservable.add(() => {
|
|
134
|
+
const renderEngine = this.scene.getEngine();
|
|
135
|
+
mat.setVector2('resolution', new BVector2(renderEngine.getRenderWidth(), renderEngine.getRenderHeight()));
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
mat.backFaceCulling = false;
|
|
139
|
+
|
|
140
|
+
if (this.settings.materialTransparent) {
|
|
141
|
+
mat.alphaMode = this.settings.materialBlendMode;
|
|
142
|
+
} else {
|
|
143
|
+
mat.alphaMode = Constants.ALPHA_DISABLE;
|
|
144
|
+
}
|
|
145
|
+
mat.needDepthPrePass = this.settings.materialDepthWrite;
|
|
146
|
+
mat.forceDepthWrite = this.settings.materialDepthWrite;
|
|
147
|
+
mat.disableDepthWrite = !this.settings.materialDepthWrite;
|
|
148
|
+
|
|
149
|
+
this.mesh.material = mat;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private vector_ = new Vector3();
|
|
153
|
+
private vector2_ = new Vector3();
|
|
154
|
+
private vector3_ = new Vector3();
|
|
155
|
+
private quaternion_ = new Quaternion();
|
|
156
|
+
|
|
157
|
+
update(): void {
|
|
158
|
+
let index = 0;
|
|
159
|
+
let triangles = 0;
|
|
160
|
+
|
|
161
|
+
let particleCount = 0;
|
|
162
|
+
const visibleSystems = this.getVisibleSystems();
|
|
163
|
+
for (const system of visibleSystems) {
|
|
164
|
+
for (let j = 0; j < system.particleNum; j++) {
|
|
165
|
+
particleCount += (system.particles[j] as TrailParticle).previous.length * 2;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (particleCount > this.maxParticles) {
|
|
169
|
+
this.expandBuffers(particleCount);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
for (const system of visibleSystems) {
|
|
173
|
+
// Ensure world matrix is up to date
|
|
174
|
+
if ((system.emitter as any).computeWorldMatrix) {
|
|
175
|
+
(system.emitter as any).computeWorldMatrix(true);
|
|
176
|
+
}
|
|
177
|
+
const rotation = this.quaternion_;
|
|
178
|
+
const translation = this.vector2_;
|
|
179
|
+
const scale = this.vector3_;
|
|
180
|
+
system.emitter.matrixWorld.decompose(translation, rotation, scale);
|
|
181
|
+
|
|
182
|
+
const particles = system.particles;
|
|
183
|
+
const particleNum = system.particleNum;
|
|
184
|
+
const uTileCount = this.settings.uTileCount;
|
|
185
|
+
const vTileCount = this.settings.vTileCount;
|
|
186
|
+
const tileWidth = 1 / uTileCount;
|
|
187
|
+
const tileHeight = 1 / vTileCount;
|
|
188
|
+
|
|
189
|
+
for (let j = 0; j < particleNum; j++) {
|
|
190
|
+
const particle = particles[j] as TrailParticle;
|
|
191
|
+
const col = particle.uvTile % vTileCount;
|
|
192
|
+
const row = Math.floor(particle.uvTile / vTileCount + 0.001);
|
|
193
|
+
|
|
194
|
+
const iter = particle.previous.values();
|
|
195
|
+
let curIter = iter.next();
|
|
196
|
+
let previous: RecordState = curIter.value as RecordState;
|
|
197
|
+
let current: RecordState = previous;
|
|
198
|
+
if (!curIter.done) curIter = iter.next();
|
|
199
|
+
let next: RecordState;
|
|
200
|
+
if (curIter.value !== undefined) {
|
|
201
|
+
next = curIter.value as RecordState;
|
|
202
|
+
} else {
|
|
203
|
+
next = current;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
for (let i = 0; i < particle.previous.length; i++, index += 2) {
|
|
207
|
+
let pos: Vector3;
|
|
208
|
+
if (system.worldSpace) {
|
|
209
|
+
pos = current.position;
|
|
210
|
+
} else {
|
|
211
|
+
if (particle.parentMatrix) {
|
|
212
|
+
this.vector_.copy(current.position).applyMatrix4(particle.parentMatrix as unknown as Matrix4);
|
|
213
|
+
} else {
|
|
214
|
+
this.vector_.copy(current.position).applyMatrix4(system.emitter.matrixWorld);
|
|
215
|
+
}
|
|
216
|
+
pos = this.vector_;
|
|
217
|
+
}
|
|
218
|
+
const pi = index * 3;
|
|
219
|
+
this.positionBuffer[pi] = pos.x;
|
|
220
|
+
this.positionBuffer[pi + 1] = pos.y;
|
|
221
|
+
this.positionBuffer[pi + 2] = pos.z;
|
|
222
|
+
this.positionBuffer[pi + 3] = pos.x;
|
|
223
|
+
this.positionBuffer[pi + 4] = pos.y;
|
|
224
|
+
this.positionBuffer[pi + 5] = pos.z;
|
|
225
|
+
|
|
226
|
+
let prevPos: Vector3;
|
|
227
|
+
if (system.worldSpace) {
|
|
228
|
+
prevPos = previous.position;
|
|
229
|
+
} else {
|
|
230
|
+
if (particle.parentMatrix) {
|
|
231
|
+
this.vector_.copy(previous.position).applyMatrix4(particle.parentMatrix as unknown as Matrix4);
|
|
232
|
+
} else {
|
|
233
|
+
this.vector_.copy(previous.position).applyMatrix4(system.emitter.matrixWorld);
|
|
234
|
+
}
|
|
235
|
+
prevPos = this.vector_;
|
|
236
|
+
}
|
|
237
|
+
this.previousBuffer[pi] = prevPos.x;
|
|
238
|
+
this.previousBuffer[pi + 1] = prevPos.y;
|
|
239
|
+
this.previousBuffer[pi + 2] = prevPos.z;
|
|
240
|
+
this.previousBuffer[pi + 3] = prevPos.x;
|
|
241
|
+
this.previousBuffer[pi + 4] = prevPos.y;
|
|
242
|
+
this.previousBuffer[pi + 5] = prevPos.z;
|
|
243
|
+
|
|
244
|
+
let nextPos: Vector3;
|
|
245
|
+
if (system.worldSpace) {
|
|
246
|
+
nextPos = next.position;
|
|
247
|
+
} else {
|
|
248
|
+
if (particle.parentMatrix) {
|
|
249
|
+
this.vector_.copy(next.position).applyMatrix4(particle.parentMatrix as unknown as Matrix4);
|
|
250
|
+
} else {
|
|
251
|
+
this.vector_.copy(next.position).applyMatrix4(system.emitter.matrixWorld);
|
|
252
|
+
}
|
|
253
|
+
nextPos = this.vector_;
|
|
254
|
+
}
|
|
255
|
+
this.nextBuffer[pi] = nextPos.x;
|
|
256
|
+
this.nextBuffer[pi + 1] = nextPos.y;
|
|
257
|
+
this.nextBuffer[pi + 2] = nextPos.z;
|
|
258
|
+
this.nextBuffer[pi + 3] = nextPos.x;
|
|
259
|
+
this.nextBuffer[pi + 4] = nextPos.y;
|
|
260
|
+
this.nextBuffer[pi + 5] = nextPos.z;
|
|
261
|
+
|
|
262
|
+
this.sideBuffer[index] = 1;
|
|
263
|
+
this.sideBuffer[index + 1] = -1;
|
|
264
|
+
|
|
265
|
+
if (system.worldSpace || particle.parentMatrix) {
|
|
266
|
+
this.widthBuffer[index] = current.size;
|
|
267
|
+
this.widthBuffer[index + 1] = current.size;
|
|
268
|
+
} else {
|
|
269
|
+
const objectScale = (Math.abs(scale.x) + Math.abs(scale.y) + Math.abs(scale.z)) / 3;
|
|
270
|
+
this.widthBuffer[index] = current.size * objectScale;
|
|
271
|
+
this.widthBuffer[index + 1] = current.size * objectScale;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const ui = index * 2;
|
|
275
|
+
this.uvBuffer[ui] = (i / particle.previous.length + col) * tileWidth;
|
|
276
|
+
this.uvBuffer[ui + 1] = (vTileCount - row - 1) * tileHeight;
|
|
277
|
+
this.uvBuffer[ui + 2] = (i / particle.previous.length + col) * tileWidth;
|
|
278
|
+
this.uvBuffer[ui + 3] = (vTileCount - row) * tileHeight;
|
|
279
|
+
|
|
280
|
+
const cci = index * 4;
|
|
281
|
+
this.colorBuffer[cci] = current.color.x;
|
|
282
|
+
this.colorBuffer[cci + 1] = current.color.y;
|
|
283
|
+
this.colorBuffer[cci + 2] = current.color.z;
|
|
284
|
+
this.colorBuffer[cci + 3] = current.color.w;
|
|
285
|
+
this.colorBuffer[cci + 4] = current.color.x;
|
|
286
|
+
this.colorBuffer[cci + 5] = current.color.y;
|
|
287
|
+
this.colorBuffer[cci + 6] = current.color.z;
|
|
288
|
+
this.colorBuffer[cci + 7] = current.color.w;
|
|
289
|
+
|
|
290
|
+
if (i + 1 < particle.previous.length) {
|
|
291
|
+
this.indexBuffer[triangles * 3] = index;
|
|
292
|
+
this.indexBuffer[triangles * 3 + 1] = index + 1;
|
|
293
|
+
this.indexBuffer[triangles * 3 + 2] = index + 2;
|
|
294
|
+
triangles++;
|
|
295
|
+
this.indexBuffer[triangles * 3] = index + 2;
|
|
296
|
+
this.indexBuffer[triangles * 3 + 1] = index + 1;
|
|
297
|
+
this.indexBuffer[triangles * 3 + 2] = index + 3;
|
|
298
|
+
triangles++;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
previous = current;
|
|
302
|
+
current = next;
|
|
303
|
+
if (!curIter.done) {
|
|
304
|
+
curIter = iter.next();
|
|
305
|
+
if (curIter.value !== undefined) {
|
|
306
|
+
next = curIter.value as RecordState;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (index > 0 && triangles > 0) {
|
|
314
|
+
this.mesh.updateVerticesData(VertexBuffer.PositionKind, this.positionBuffer);
|
|
315
|
+
this.mesh.updateVerticesData(VertexBuffer.UVKind, this.uvBuffer);
|
|
316
|
+
this.mesh.updateIndices(Array.from(this.indexBuffer.subarray(0, triangles * 3)));
|
|
317
|
+
this.previousVB.update(this.previousBuffer);
|
|
318
|
+
this.nextVB.update(this.nextBuffer);
|
|
319
|
+
this.sideVB.update(this.sideBuffer);
|
|
320
|
+
this.widthVB.update(this.widthBuffer);
|
|
321
|
+
|
|
322
|
+
const colorVB = this.mesh.getVertexBuffer(VertexBuffer.ColorKind);
|
|
323
|
+
if (colorVB) colorVB.update(this.colorBuffer);
|
|
324
|
+
|
|
325
|
+
this.mesh.setEnabled(true);
|
|
326
|
+
if (this.mesh.subMeshes && this.mesh.subMeshes.length > 0) {
|
|
327
|
+
const meshBoundingInfo = this.mesh.getBoundingInfo();
|
|
328
|
+
for (const subMesh of this.mesh.subMeshes) {
|
|
329
|
+
(subMesh as any)._boundingInfo = meshBoundingInfo;
|
|
330
|
+
}
|
|
331
|
+
this.mesh.subMeshes[0].indexCount = triangles * 3;
|
|
332
|
+
this.mesh.subMeshes[0].verticesCount = index;
|
|
333
|
+
}
|
|
334
|
+
} else {
|
|
335
|
+
this.mesh.setEnabled(false);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
dispose(): void {
|
|
340
|
+
if (this.mesh.material) {
|
|
341
|
+
this.mesh.material.dispose();
|
|
342
|
+
}
|
|
343
|
+
super.dispose();
|
|
344
|
+
}
|
|
345
|
+
}
|
package/src/VFXBatch.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {Mesh} from '@babylonjs/core/Meshes/mesh';
|
|
2
|
+
import {Scene} from '@babylonjs/core/scene';
|
|
3
|
+
import {BaseTexture} from '@babylonjs/core/Materials/Textures/baseTexture';
|
|
4
|
+
import {ShaderMaterial} from '@babylonjs/core/Materials/shaderMaterial';
|
|
5
|
+
import {IParticleSystem} from 'quarks.core';
|
|
6
|
+
import {VFXBatchSettings} from './BatchedRenderer';
|
|
7
|
+
|
|
8
|
+
export enum RenderMode {
|
|
9
|
+
BillBoard = 0,
|
|
10
|
+
StretchedBillBoard = 1,
|
|
11
|
+
Mesh = 2,
|
|
12
|
+
Trail = 3,
|
|
13
|
+
HorizontalBillBoard = 4,
|
|
14
|
+
VerticalBillBoard = 5,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface StoredBatchSettings {
|
|
18
|
+
instancingGeometry: Float32Array;
|
|
19
|
+
instancingIndices: Uint32Array | Uint16Array;
|
|
20
|
+
instancingUVs?: Float32Array;
|
|
21
|
+
instancingNormals?: Float32Array;
|
|
22
|
+
renderMode: RenderMode;
|
|
23
|
+
renderOrder: number;
|
|
24
|
+
uTileCount: number;
|
|
25
|
+
vTileCount: number;
|
|
26
|
+
blendTiles: boolean;
|
|
27
|
+
softParticles: boolean;
|
|
28
|
+
softNearFade: number;
|
|
29
|
+
softFarFade: number;
|
|
30
|
+
materialBlendMode: number;
|
|
31
|
+
materialTransparent: boolean;
|
|
32
|
+
materialDepthTest: boolean;
|
|
33
|
+
materialDepthWrite: boolean;
|
|
34
|
+
materialAlphaTest: number;
|
|
35
|
+
texture: any;
|
|
36
|
+
layerMask: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export abstract class VFXBatch {
|
|
40
|
+
mesh: Mesh;
|
|
41
|
+
systems: Set<IParticleSystem>;
|
|
42
|
+
settings: StoredBatchSettings;
|
|
43
|
+
protected maxParticles: number;
|
|
44
|
+
protected scene: Scene;
|
|
45
|
+
|
|
46
|
+
protected constructor(settings: VFXBatchSettings, scene: Scene) {
|
|
47
|
+
this.scene = scene;
|
|
48
|
+
this.maxParticles = 1000;
|
|
49
|
+
this.systems = new Set<IParticleSystem>();
|
|
50
|
+
this.settings = {
|
|
51
|
+
instancingGeometry: settings.instancingGeometry,
|
|
52
|
+
instancingIndices: settings.instancingIndices,
|
|
53
|
+
instancingUVs: settings.instancingUVs,
|
|
54
|
+
instancingNormals: settings.instancingNormals,
|
|
55
|
+
renderMode: settings.renderMode,
|
|
56
|
+
renderOrder: settings.renderOrder,
|
|
57
|
+
uTileCount: settings.uTileCount,
|
|
58
|
+
vTileCount: settings.vTileCount,
|
|
59
|
+
blendTiles: settings.blendTiles,
|
|
60
|
+
softParticles: settings.softParticles,
|
|
61
|
+
softNearFade: settings.softNearFade,
|
|
62
|
+
softFarFade: settings.softFarFade,
|
|
63
|
+
materialBlendMode: settings.materialBlendMode,
|
|
64
|
+
materialTransparent: settings.materialTransparent,
|
|
65
|
+
materialDepthTest: settings.materialDepthTest,
|
|
66
|
+
materialDepthWrite: settings.materialDepthWrite,
|
|
67
|
+
materialAlphaTest: settings.materialAlphaTest,
|
|
68
|
+
texture: settings.texture,
|
|
69
|
+
layerMask: settings.layerMask,
|
|
70
|
+
};
|
|
71
|
+
this.mesh = new Mesh('vfxBatch', scene);
|
|
72
|
+
this.mesh.alwaysSelectAsActiveMesh = true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
addSystem(system: IParticleSystem) {
|
|
76
|
+
this.systems.add(system);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
removeSystem(system: IParticleSystem) {
|
|
80
|
+
this.systems.delete(system);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
getVisibleSystems(): IParticleSystem[] {
|
|
84
|
+
return Array.from(this.systems).filter((system) => system.emitter.visible);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
applyDepthTexture(depthTexture: BaseTexture | null): void {
|
|
88
|
+
const material = this.mesh.material;
|
|
89
|
+
if (material && material instanceof ShaderMaterial) {
|
|
90
|
+
material.setTexture('depthTexture', depthTexture);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
abstract setupBuffers(): void;
|
|
95
|
+
abstract expandBuffers(target: number): void;
|
|
96
|
+
abstract rebuildMaterial(): void;
|
|
97
|
+
abstract update(): void;
|
|
98
|
+
|
|
99
|
+
dispose(): void {
|
|
100
|
+
this.mesh.dispose();
|
|
101
|
+
}
|
|
102
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {loadPlugin} from 'quarks.core';
|
|
2
|
+
import {MeshSurfaceEmitterPlugin} from './MeshSurfaceEmitter';
|
|
3
|
+
import {registerShaderChunks} from './shaders';
|
|
4
|
+
|
|
5
|
+
export {BatchedRenderer} from './BatchedRenderer';
|
|
6
|
+
export type {VFXBatchSettings} from './BatchedRenderer';
|
|
7
|
+
export {BatchedParticleRenderer} from './BatchedParticleRenderer';
|
|
8
|
+
export {VFXBatch, RenderMode} from './VFXBatch';
|
|
9
|
+
export type {StoredBatchSettings} from './VFXBatch';
|
|
10
|
+
export {SpriteBatch} from './SpriteBatch';
|
|
11
|
+
export {TrailBatch} from './TrailBatch';
|
|
12
|
+
export {ParticleSystem} from './ParticleSystem';
|
|
13
|
+
export type {ParticleSystemParameters, BurstParameters} from './ParticleSystem';
|
|
14
|
+
export {ParticleEmitter} from './ParticleEmitter';
|
|
15
|
+
export {QuarksUtil} from './QuarksUtil';
|
|
16
|
+
export {QuarksLoader} from './QuarksLoader';
|
|
17
|
+
export type {QuarksLoaderOptions} from './QuarksLoader';
|
|
18
|
+
export {QuarksPrefab} from './QuarksPrefab';
|
|
19
|
+
export {MeshSurfaceEmitter, MeshSurfaceEmitterPlugin} from './MeshSurfaceEmitter';
|
|
20
|
+
export * from './shaders/';
|
|
21
|
+
export * from './materials/';
|
|
22
|
+
export * from 'quarks.core';
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
// Re-export quarks.core types (interfaces - type-only)
|
|
26
|
+
export type {
|
|
27
|
+
IParticleSystem,
|
|
28
|
+
IParticle,
|
|
29
|
+
Particle,
|
|
30
|
+
EmissionState,
|
|
31
|
+
RendererEmitterSettings,
|
|
32
|
+
TrailSettings,
|
|
33
|
+
StretchedBillBoardSettings,
|
|
34
|
+
BillBoardSettings,
|
|
35
|
+
MeshSettings,
|
|
36
|
+
IEmitter,
|
|
37
|
+
ParticleSystemEvent,
|
|
38
|
+
ParticleSystemEventType,
|
|
39
|
+
SerializationOptions,
|
|
40
|
+
Behavior,
|
|
41
|
+
EmitterShape,
|
|
42
|
+
ValueGenerator,
|
|
43
|
+
FunctionValueGenerator,
|
|
44
|
+
ColorGenerator,
|
|
45
|
+
FunctionColorGenerator,
|
|
46
|
+
RotationGenerator,
|
|
47
|
+
Vector3Generator,
|
|
48
|
+
} from 'quarks.core';
|
|
49
|
+
|
|
50
|
+
registerShaderChunks();
|
|
51
|
+
loadPlugin(MeshSurfaceEmitterPlugin);
|
|
52
|
+
// remove this line if you have pro license
|
|
53
|
+
console.log('%c Particle system powered by babylon.quarks. https://quarks.art/', 'font-size: 14px; font-weight: bold;');
|
|
54
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {Scene} from '@babylonjs/core/scene';
|
|
2
|
+
import {PBRMaterial} from '@babylonjs/core/Materials/PBR/pbrMaterial';
|
|
3
|
+
import {StandardMaterial} from '@babylonjs/core/Materials/standardMaterial';
|
|
4
|
+
|
|
5
|
+
export type BabylonParticleMaterialParameters = Record<string, any>;
|
|
6
|
+
|
|
7
|
+
export class ParticleMeshStandardMaterial extends StandardMaterial {
|
|
8
|
+
readonly isParticleMeshStandardMaterial = true;
|
|
9
|
+
|
|
10
|
+
constructor(name: string, scene?: Scene, parameters: BabylonParticleMaterialParameters = {}) {
|
|
11
|
+
super(name, scene);
|
|
12
|
+
Object.assign(this, parameters);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class ParticleMeshPhysicsMaterial extends PBRMaterial {
|
|
17
|
+
readonly isParticleMeshPhysicsMaterial = true;
|
|
18
|
+
|
|
19
|
+
constructor(name: string, scene?: Scene, parameters: BabylonParticleMaterialParameters = {}) {
|
|
20
|
+
super(name, scene);
|
|
21
|
+
Object.assign(this, parameters);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ParticleMaterials';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './register-shader-chunks';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import softFragment from './soft_fragment.glsl';
|
|
2
|
+
import softParsFragment from './soft_pars_fragment.glsl';
|
|
3
|
+
import softParsVertex from './soft_pars_vertex.glsl';
|
|
4
|
+
import softVertex from './soft_vertex.glsl';
|
|
5
|
+
import tileFragment from './tile_fragment.glsl';
|
|
6
|
+
import tileParsFragment from './tile_pars_fragment.glsl';
|
|
7
|
+
import tileParsVertex from './tile_pars_vertex.glsl';
|
|
8
|
+
import tileVertex from './tile_vertex.glsl';
|
|
9
|
+
|
|
10
|
+
const shaderChunks: Record<string, string> = {};
|
|
11
|
+
let registered = false;
|
|
12
|
+
|
|
13
|
+
export function registerShaderChunks(): void {
|
|
14
|
+
if (registered) return;
|
|
15
|
+
shaderChunks.tile_pars_vertex = tileParsVertex;
|
|
16
|
+
shaderChunks.tile_vertex = tileVertex;
|
|
17
|
+
shaderChunks.tile_pars_fragment = tileParsFragment;
|
|
18
|
+
shaderChunks.tile_fragment = tileFragment;
|
|
19
|
+
shaderChunks.soft_pars_vertex = softParsVertex;
|
|
20
|
+
shaderChunks.soft_vertex = softVertex;
|
|
21
|
+
shaderChunks.soft_pars_fragment = softParsFragment;
|
|
22
|
+
shaderChunks.soft_fragment = softFragment;
|
|
23
|
+
registered = true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getShaderChunk(chunkName: string): string | undefined {
|
|
27
|
+
return shaderChunks[chunkName];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getRegisteredShaderChunks(): Readonly<Record<string, string>> {
|
|
31
|
+
return shaderChunks;
|
|
32
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default /* glsl */ `
|
|
2
|
+
#ifdef SOFT_PARTICLES
|
|
3
|
+
|
|
4
|
+
vec2 p2 = projPosition.xy / projPosition.w;
|
|
5
|
+
p2 = 0.5 * p2 + 0.5;
|
|
6
|
+
|
|
7
|
+
float readDepth = texture2D(depthTexture, p2.xy).r;
|
|
8
|
+
float viewDepth = linearize_depth(readDepth);
|
|
9
|
+
float softParticlesFade = saturate(SOFT_INV_FADE_DISTANCE * ((viewDepth - SOFT_NEAR_FADE) - linearDepth));
|
|
10
|
+
|
|
11
|
+
gl_FragColor *= softParticlesFade;
|
|
12
|
+
#endif
|
|
13
|
+
`;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export default /* glsl */ `
|
|
2
|
+
#ifdef SOFT_PARTICLES
|
|
3
|
+
uniform sampler2D depthTexture;
|
|
4
|
+
uniform vec4 projParams;
|
|
5
|
+
uniform vec2 softParams;
|
|
6
|
+
|
|
7
|
+
varying vec4 projPosition;
|
|
8
|
+
varying float linearDepth;
|
|
9
|
+
|
|
10
|
+
#define SOFT_NEAR_FADE softParams.x
|
|
11
|
+
#define SOFT_INV_FADE_DISTANCE softParams.y
|
|
12
|
+
|
|
13
|
+
#define zNear projParams.x
|
|
14
|
+
#define zFar projParams.y
|
|
15
|
+
|
|
16
|
+
float linearize_depth(float d) {
|
|
17
|
+
return (zFar * zNear) / (zFar - d * (zFar - zNear));
|
|
18
|
+
}
|
|
19
|
+
#endif
|
|
20
|
+
`;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export default /* glsl */ `
|
|
2
|
+
#ifdef UV_TILE
|
|
3
|
+
attribute float uvTile;
|
|
4
|
+
uniform vec2 tileCount;
|
|
5
|
+
|
|
6
|
+
mat3 makeTileTransform(float tileIndex) {
|
|
7
|
+
float col = mod(tileIndex, tileCount.x);
|
|
8
|
+
float row = (tileCount.y - floor(tileIndex / tileCount.x) - 1.0);
|
|
9
|
+
return mat3(
|
|
10
|
+
1.0 / tileCount.x, 0.0, 0.0,
|
|
11
|
+
0.0, 1.0 / tileCount.y, 0.0,
|
|
12
|
+
col / tileCount.x, row / tileCount.y, 1.0
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
#else
|
|
16
|
+
mat3 makeTileTransform(float tileIndex) {
|
|
17
|
+
return mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
|
|
18
|
+
}
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
#if defined(USE_UV)
|
|
22
|
+
varying vec2 vUv;
|
|
23
|
+
#ifdef TILE_BLEND
|
|
24
|
+
varying vec2 vUvNext;
|
|
25
|
+
varying float vUvBlend;
|
|
26
|
+
#endif
|
|
27
|
+
#endif
|
|
28
|
+
`;
|