@neutrinoparticles/js-v1.1-pixi8 1.0.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/CHANGELOG.md +9 -0
- package/README.md +231 -0
- package/dist/AplicationPlugin.d.ts +9 -0
- package/dist/Context.d.ts +92 -0
- package/dist/DataTextureManager.d.ts +32 -0
- package/dist/Effect.d.ts +104 -0
- package/dist/EffectModel.d.ts +20 -0
- package/dist/EffectModelLoader.d.ts +13 -0
- package/dist/EffectPipe.d.ts +25 -0
- package/dist/NeutrinoRenderer.d.ts +31 -0
- package/dist/PerspectiveProjection.d.ts +70 -0
- package/dist/TexturesLoader.d.ts +17 -0
- package/dist/gl1/DataTextureManagerGL1.d.ts +23 -0
- package/dist/gl1/MetaTextureManager.d.ts +9 -0
- package/dist/index.d.ts +22 -0
- package/dist/neutrinoparticles.js-v1.1-pixi8.cjs.js +1214 -0
- package/dist/neutrinoparticles.js-v1.1-pixi8.cjs.js.map +1 -0
- package/dist/neutrinoparticles.js-v1.1-pixi8.d.ts +482 -0
- package/dist/neutrinoparticles.js-v1.1-pixi8.es.js +2211 -0
- package/dist/neutrinoparticles.js-v1.1-pixi8.es.js.map +1 -0
- package/dist/neutrinoparticles.js-v1.1-pixi8.umd.js +1214 -0
- package/dist/neutrinoparticles.js-v1.1-pixi8.umd.js.map +1 -0
- package/dist/types.d.ts +59 -0
- package/package.json +56 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## CurrentVersion
|
|
4
|
+
|
|
5
|
+
- Initial PIXI v8 integration for the JS v1.1 export format (GPU geometry construction, data-texture renderer).
|
|
6
|
+
- Added 3D perspective projection support (`PerspectiveProjection` passed via the `projection` effect option) with the same behavior and API as the JS v1.0 runtimes: particles with 3D motion scale with depth toward the screen center and are discarded behind the camera.
|
|
7
|
+
- Added automatic WebGL1 rendering support on compatible devices. WebGL2 remains the primary path.
|
|
8
|
+
- Auto-unpause an effect on its first render when it is rendered before its first update (`Pause.BEFORE_UPDATE_OR_RENDER`), matching the pixi7/phaser adapters; previously such an effect stayed paused and produced an empty first frame.
|
|
9
|
+
- Fixed strip texture seams: a ribbon whose atlas texture repeats along its length no longer shows a muddy "chewed" column at tile junctions when the texture has mipmaps (WebGL2).
|
package/README.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# @neutrinoparticles/js-v1.1-pixi8
|
|
2
|
+
|
|
3
|
+
PIXI.js v8 integration for [NeutrinoParticles](https://neutrinoparticles.com/) real-time particle effects (format **v1.1**).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @neutrinoparticles/js-v1.1-pixi8
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The core runtime (`@neutrinoparticles/js-v1.1`) is installed automatically as a dependency.
|
|
12
|
+
|
|
13
|
+
**Peer dependency:** PIXI.js v8
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
The v1.1 renderer reconstructs particle geometry on the GPU. It works on:
|
|
18
|
+
|
|
19
|
+
- **WebGL2** (the PIXI v8 default) — the primary path;
|
|
20
|
+
- **WebGL1** — supported automatically on contexts that provide
|
|
21
|
+
`OES_texture_float`, at least 2 vertex texture image units, `highp` float
|
|
22
|
+
in fragment shaders, and pass a one-time vertex-float-texture smoke test
|
|
23
|
+
at startup. The renderer detects the context version and picks the path
|
|
24
|
+
by itself — no configuration needed.
|
|
25
|
+
|
|
26
|
+
On a WebGL1 context missing those capabilities, creating the plugin context
|
|
27
|
+
throws an `Error` naming the missing capability (for example
|
|
28
|
+
`NeutrinoParticles (js-v1.1): WebGL1 context lacks OES_texture_float; WebGL2
|
|
29
|
+
or WebGL1 with vertex float textures is required.`).
|
|
30
|
+
|
|
31
|
+
### WebGL2 vs WebGL1: which to use
|
|
32
|
+
|
|
33
|
+
**Prefer WebGL2 whenever it is available** — it is the faster and leaner
|
|
34
|
+
path. WebGL1 is a compatibility fallback for devices and embeds that cannot
|
|
35
|
+
create a WebGL2 context. Rough comparison of the same effect on the two
|
|
36
|
+
paths:
|
|
37
|
+
|
|
38
|
+
- **Rendering speed:** identical at typical particle counts (up to ~20k
|
|
39
|
+
live particles the difference is not measurable); on very heavy effects
|
|
40
|
+
(~100k live particles) WebGL1 costs roughly 10% more render time per
|
|
41
|
+
frame — the vertex shader does almost twice as many texture reads and
|
|
42
|
+
extra math to unpack data that WebGL2 reads directly.
|
|
43
|
+
- **GPU memory:** WebGL1 uses about 25% more per effect (an extra byte
|
|
44
|
+
texture carries the data WebGL1 shaders cannot decode from the float
|
|
45
|
+
texture).
|
|
46
|
+
- **Features/visuals:** identical — both paths render the same effects with
|
|
47
|
+
full parity (quads and ribbons).
|
|
48
|
+
|
|
49
|
+
In practice: keep PIXI's default (`preferWebGLVersion: 2`) so WebGL1
|
|
50
|
+
engages automatically only where WebGL2 truly is not available — set
|
|
51
|
+
`preferWebGLVersion: 1` in `app.init` only when you deliberately need to
|
|
52
|
+
test or target the legacy path.
|
|
53
|
+
|
|
54
|
+
## Export Target in Editor
|
|
55
|
+
|
|
56
|
+
In the NeutrinoParticles Editor, set the export target to **JavaScript v1.1**.
|
|
57
|
+
|
|
58
|
+
After export you get a `.js` file (e.g. `my_effect.js`) containing the effect model.
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
### HTML + Dynamic loading
|
|
63
|
+
|
|
64
|
+
In the editor's project settings, select **For XHR Request** export format, then
|
|
65
|
+
load the effect at runtime via `PIXI.Assets`. Pass `app.neutrino.loadData` so the
|
|
66
|
+
loader parses the file as a NeutrinoParticles effect.
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<script src="path/to/pixi.js"></script>
|
|
70
|
+
<script src="path/to/@neutrinoparticles/js-v1.1/dist/neutrinoparticles.js-v1.1.umd.js"></script>
|
|
71
|
+
<script src="path/to/@neutrinoparticles/js-v1.1-pixi8/dist/neutrinoparticles.js-v1.1-pixi8.umd.js"></script>
|
|
72
|
+
<script>
|
|
73
|
+
|
|
74
|
+
(async () => {
|
|
75
|
+
const app = new PIXI.Application();
|
|
76
|
+
|
|
77
|
+
await app.init({
|
|
78
|
+
width: 800,
|
|
79
|
+
height: 600,
|
|
80
|
+
neutrino: { // options for PIXINeutrino.Context
|
|
81
|
+
texturesBasePath: 'textures/' // Prefix for loading textures. Slash at the end!
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
document.body.appendChild(app.canvas);
|
|
86
|
+
|
|
87
|
+
// Generate turbulence if your effects use it
|
|
88
|
+
// app.neutrino.generateNoise();
|
|
89
|
+
|
|
90
|
+
PIXI.Assets.add({
|
|
91
|
+
alias: 'effectModel',
|
|
92
|
+
src: 'export_js/my_effect.js',
|
|
93
|
+
data: app.neutrino.loadData
|
|
94
|
+
});
|
|
95
|
+
const effectModel = await PIXI.Assets.load('effectModel');
|
|
96
|
+
|
|
97
|
+
const effect = new PIXINeutrino.Effect(effectModel, {
|
|
98
|
+
position: [400, 300, 0]
|
|
99
|
+
});
|
|
100
|
+
app.stage.addChild(effect);
|
|
101
|
+
|
|
102
|
+
app.ticker.add((time) => {
|
|
103
|
+
const sec = time.deltaMS / 1000;
|
|
104
|
+
effect.update(sec > 1.0 ? 1.0 : sec);
|
|
105
|
+
});
|
|
106
|
+
})();
|
|
107
|
+
|
|
108
|
+
</script>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### ES6 + Bundler
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
import * as PIXI from 'pixi.js'
|
|
115
|
+
import * as PIXINeutrino from '@neutrinoparticles/js-v1.1-pixi8'
|
|
116
|
+
|
|
117
|
+
const app = new PIXI.Application();
|
|
118
|
+
await app.init({
|
|
119
|
+
width: 800,
|
|
120
|
+
height: 600,
|
|
121
|
+
neutrino: { texturesBasePath: 'textures/' }
|
|
122
|
+
});
|
|
123
|
+
document.body.appendChild(app.canvas);
|
|
124
|
+
|
|
125
|
+
PIXI.Assets.add({ alias: 'effectModel', src: 'export_js/my_effect.js', data: app.neutrino.loadData });
|
|
126
|
+
const effectModel = await PIXI.Assets.load('effectModel');
|
|
127
|
+
|
|
128
|
+
const effect = new PIXINeutrino.Effect(effectModel, { position: [400, 300, 0] });
|
|
129
|
+
app.stage.addChild(effect);
|
|
130
|
+
|
|
131
|
+
app.ticker.add((time) => {
|
|
132
|
+
const sec = time.deltaMS / 1000;
|
|
133
|
+
effect.update(sec > 1.0 ? 1.0 : sec);
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 3D Perspective Projection
|
|
138
|
+
|
|
139
|
+
Effects can place particles in 3D (Z position/velocity set up in the editor). By
|
|
140
|
+
default the renderer is orthographic: Z is ignored. Pass a `PerspectiveProjection`
|
|
141
|
+
to make particles scale with depth (same behavior and API as the JS v1.0 runtimes):
|
|
142
|
+
particles farther away shrink toward the screen center, particles behind the
|
|
143
|
+
camera are discarded.
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
const projection = new PIXINeutrino.PerspectiveProjection(60.0); // horizontal FOV, degrees
|
|
147
|
+
|
|
148
|
+
const effect = new PIXINeutrino.Effect(effectModel, {
|
|
149
|
+
position: [400, 300, 0],
|
|
150
|
+
projection // can be shared between effects
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
For the angle use the same value as in the NeutrinoParticles Editor project
|
|
155
|
+
(Project Settings > Preview > Perspective) to match the editor preview. The
|
|
156
|
+
projection has no camera rotation — only depth scaling around the screen center.
|
|
157
|
+
|
|
158
|
+
## Instant Position Change (Teleporting)
|
|
159
|
+
|
|
160
|
+
Moving the effect via `position` creates a smooth trail of particles. To instantly teleport the effect without a trail:
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
effect.resetPosition([newX, newY, 0]);
|
|
164
|
+
|
|
165
|
+
// With new rotation (radians)
|
|
166
|
+
effect.resetPosition([newX, newY, 0], newRotationRadians);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Restart
|
|
170
|
+
|
|
171
|
+
Restart destroys all existing particles and starts the effect from scratch:
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
effect.restart([newX, newY, 0]);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Pause
|
|
178
|
+
|
|
179
|
+
**Full pause** — all particles freeze, nothing is generated:
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
effect.pause();
|
|
183
|
+
effect.unpause();
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Generators pause** — existing particles continue to live, but no new particles are created:
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
effect.pauseGenerators();
|
|
190
|
+
effect.unpauseGenerators();
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Set the initial pause state in the constructor:
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
const effect = new PIXINeutrino.Effect(effectModel, {
|
|
197
|
+
position: [400, 300, 0],
|
|
198
|
+
pause: PIXINeutrino.Pause.YES // starts paused
|
|
199
|
+
});
|
|
200
|
+
// ...later:
|
|
201
|
+
effect.unpause();
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Emitter Properties
|
|
205
|
+
|
|
206
|
+
Control exposed emitter properties at runtime. Properties are defined in Emitter Guide or Emitter Scheme in the Editor.
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
effect.setPropertyInAllEmitters('MyParticlesPerSecond', 100);
|
|
210
|
+
effect.setPropertyInAllEmitters('MyColor', [1.0, 0.5, 0.2]);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Number of Particles
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
const numParticles = effect.getNumParticles();
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Common Issues
|
|
220
|
+
|
|
221
|
+
- **`a WebGL2 renderer is required` error:** The v1.1 renderer needs WebGL2. PIXI v8 uses WebGL2 by default; make sure you are not forcing a WebGL1 renderer.
|
|
222
|
+
- **No particles visible:** Check that the export target in the editor is set to JavaScript v1.1. Verify `texturesBasePath` points to the correct textures directory.
|
|
223
|
+
- **Turbulence not working:** Call `app.neutrino.generateNoise()` before creating effects that use noise/turbulence.
|
|
224
|
+
|
|
225
|
+
## Documentation
|
|
226
|
+
|
|
227
|
+
Full documentation at [neutrinoparticles.com](https://neutrinoparticles.com/en/docs/199).
|
|
228
|
+
|
|
229
|
+
## License
|
|
230
|
+
|
|
231
|
+
Copyright (c) Yurii Miroshnyk. All rights reserved.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Application } from "pixi.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates the shared {@link Context} and assigns it to app.neutrino on init.
|
|
4
|
+
*/
|
|
5
|
+
export declare class ApplicationPlugin {
|
|
6
|
+
static get extension(): any;
|
|
7
|
+
static init(this: Application, options: any): void;
|
|
8
|
+
static destroy(this: Application): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Renderer } from 'pixi.js';
|
|
2
|
+
import { NeutrinoContext } from './types';
|
|
3
|
+
export interface ContextOptions {
|
|
4
|
+
texturesBasePath?: string;
|
|
5
|
+
trimmedExtensionsLookupFirst?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface ContextLoadData {
|
|
8
|
+
__neutrinoContext__: Context;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Shared GL state for the PIXI v8 NeutrinoParticles integration: the shader
|
|
12
|
+
* program (WebGL2 data-texture path, or the WebGL1 meta-texture path — see
|
|
13
|
+
* docs/tdd/TDD_js-v1.1-webgl1.md), a static quad index buffer (+ VAO on
|
|
14
|
+
* WebGL2 / aId attribute stream on WebGL1), and all uniform locations.
|
|
15
|
+
* Created once per application and reused by every {@link Effect}.
|
|
16
|
+
*/
|
|
17
|
+
export declare class Context {
|
|
18
|
+
readonly neutrino: NeutrinoContext;
|
|
19
|
+
readonly renderer: Renderer;
|
|
20
|
+
readonly gl: WebGL2RenderingContext;
|
|
21
|
+
readonly options: ContextOptions;
|
|
22
|
+
readonly loadData: ContextLoadData;
|
|
23
|
+
private _shaderProgram;
|
|
24
|
+
private _indexBuffer;
|
|
25
|
+
private _dummyVB;
|
|
26
|
+
private _indexBufferCapacity;
|
|
27
|
+
private _vao;
|
|
28
|
+
private _isWebGL1;
|
|
29
|
+
private _maxBatchTextures;
|
|
30
|
+
private _hasElementIndexUint;
|
|
31
|
+
private _vaoExt;
|
|
32
|
+
private _aIdBuffer;
|
|
33
|
+
private _aIdLocation;
|
|
34
|
+
static readonly MAX_BATCH_TEXTURES = 8;
|
|
35
|
+
private _uDataTexture;
|
|
36
|
+
private _uDataTextureWidth;
|
|
37
|
+
private _uMetaTexture;
|
|
38
|
+
private _uDataTexSize;
|
|
39
|
+
private _uCameraRight;
|
|
40
|
+
private _uCameraUp;
|
|
41
|
+
private _uCameraDir;
|
|
42
|
+
private _uViewProjMatrix;
|
|
43
|
+
private _uModelMatrix;
|
|
44
|
+
private _uViewportAspect;
|
|
45
|
+
private _uWorldAlpha;
|
|
46
|
+
private _uTextures;
|
|
47
|
+
private _uTexRemaps;
|
|
48
|
+
constructor(renderer: Renderer, options?: ContextOptions);
|
|
49
|
+
private _noiseInitialized;
|
|
50
|
+
initializeNoise(path: string, success: () => void, fail: () => void): void;
|
|
51
|
+
generateNoise(): void;
|
|
52
|
+
get shaderProgram(): WebGLProgram;
|
|
53
|
+
get isWebGL1(): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Textures usable in one batch. 8 on WebGL2; on WebGL1 reduced when the
|
|
56
|
+
* combined texture-unit budget is tight (the vertex stage takes 2 units).
|
|
57
|
+
* A lower cap only produces more batches, never wrong output.
|
|
58
|
+
*/
|
|
59
|
+
get maxBatchTextures(): number;
|
|
60
|
+
get uDataTexture(): WebGLUniformLocation | null;
|
|
61
|
+
get uDataTextureWidth(): WebGLUniformLocation | null;
|
|
62
|
+
get uMetaTexture(): WebGLUniformLocation | null;
|
|
63
|
+
get uDataTexSize(): WebGLUniformLocation | null;
|
|
64
|
+
get uCameraRight(): WebGLUniformLocation | null;
|
|
65
|
+
get uCameraUp(): WebGLUniformLocation | null;
|
|
66
|
+
get uCameraDir(): WebGLUniformLocation | null;
|
|
67
|
+
get uViewProjMatrix(): WebGLUniformLocation | null;
|
|
68
|
+
get uModelMatrix(): WebGLUniformLocation | null;
|
|
69
|
+
get uViewportAspect(): WebGLUniformLocation | null;
|
|
70
|
+
get uWorldAlpha(): WebGLUniformLocation | null;
|
|
71
|
+
get uTextures(): (WebGLUniformLocation | null)[];
|
|
72
|
+
get uTexRemaps(): (WebGLUniformLocation | null)[];
|
|
73
|
+
ensureIndexBuffer(maxParticles: number): void;
|
|
74
|
+
get vao(): WebGLVertexArrayObject;
|
|
75
|
+
get indexBuffer(): WebGLBuffer;
|
|
76
|
+
get aIdBuffer(): WebGLBuffer;
|
|
77
|
+
get aIdLocation(): number;
|
|
78
|
+
get indexType(): number;
|
|
79
|
+
/** Unbind any VAO (incl. OES on WebGL1) before raw attribute setup. */
|
|
80
|
+
unbindVao(): void;
|
|
81
|
+
destroy(): void;
|
|
82
|
+
private _probeWebGL1Capabilities;
|
|
83
|
+
/**
|
|
84
|
+
* Compile/link alone does not prove vertex texture fetch works on a
|
|
85
|
+
* driver — some fail only at draw time. One-time 1×1 smoke draw: a point
|
|
86
|
+
* whose color is produced by sampling a float and a byte texture in the
|
|
87
|
+
* vertex shader, rendered into a 1×1 RGBA8 FBO and read back.
|
|
88
|
+
*/
|
|
89
|
+
private _smokeTestVertexTextureFetch;
|
|
90
|
+
private _initShader;
|
|
91
|
+
private _compileShader;
|
|
92
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages a small ring of RGBA32F WebGL textures that hold the runtime's flat
|
|
3
|
+
* particle data buffer. Each frame the current texture is re-uploaded (zero-copy
|
|
4
|
+
* from the runtime-owned Uint32Array via a Float32 view) and the ring advances,
|
|
5
|
+
* which avoids GPU pipeline stalls from re-uploading into a texture still in use.
|
|
6
|
+
*
|
|
7
|
+
* Unlike the pixi7 adapter this owns raw GL textures directly (no PIXI texture
|
|
8
|
+
* system), so the exact same class works for both the PIXI v8 and Phaser
|
|
9
|
+
* integrations, which both do their own raw WebGL2 draw.
|
|
10
|
+
*/
|
|
11
|
+
export declare class DataTextureManager {
|
|
12
|
+
readonly textureWidth: number;
|
|
13
|
+
readonly textureHeight: number;
|
|
14
|
+
private readonly _gl;
|
|
15
|
+
private readonly _floatView;
|
|
16
|
+
private _textures;
|
|
17
|
+
private _currentIndex;
|
|
18
|
+
/**
|
|
19
|
+
* @param gl - WebGL2 context (from the host renderer)
|
|
20
|
+
* @param data - Uint32Array from the runtime. A Float32Array view over the
|
|
21
|
+
* same buffer is uploaded as RGBA32F — bit patterns (incl. NaN/Inf) pass
|
|
22
|
+
* through unchanged.
|
|
23
|
+
* @param textureWidth - from runtime (system.dataTextureWidth)
|
|
24
|
+
* @param textureHeight - from runtime (system.dataTextureHeight)
|
|
25
|
+
*/
|
|
26
|
+
constructor(gl: WebGL2RenderingContext, data: Uint32Array, textureWidth: number, textureHeight: number);
|
|
27
|
+
get currentTexture(): WebGLTexture;
|
|
28
|
+
/** Bind the current texture to a unit and upload the latest particle data. */
|
|
29
|
+
uploadAndBind(unit: number): void;
|
|
30
|
+
advance(): void;
|
|
31
|
+
destroy(): void;
|
|
32
|
+
}
|
package/dist/Effect.d.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Bounds, Container, Instruction, ViewContainer } from 'pixi.js';
|
|
2
|
+
import { EffectModel } from './EffectModel';
|
|
3
|
+
import { Context } from './Context';
|
|
4
|
+
import { DataTextureManager } from './DataTextureManager';
|
|
5
|
+
import { DataTextureManagerGL1 } from './gl1/DataTextureManagerGL1';
|
|
6
|
+
import { PerspectiveProjection } from './PerspectiveProjection';
|
|
7
|
+
import { NeutrinoSystem, Vec2, Vec3 } from './types';
|
|
8
|
+
export declare enum Pause {
|
|
9
|
+
NO = 0,
|
|
10
|
+
BEFORE_UPDATE_OR_RENDER = 1,
|
|
11
|
+
YES = 2
|
|
12
|
+
}
|
|
13
|
+
export interface EffectOptions {
|
|
14
|
+
position?: Vec3;
|
|
15
|
+
rotation?: number;
|
|
16
|
+
scale?: Vec3;
|
|
17
|
+
pause?: Pause;
|
|
18
|
+
generatorsPaused?: boolean;
|
|
19
|
+
baseParent?: Container;
|
|
20
|
+
projection?: PerspectiveProjection;
|
|
21
|
+
autoInit?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface RenderMatrix {
|
|
24
|
+
a: number;
|
|
25
|
+
b: number;
|
|
26
|
+
c: number;
|
|
27
|
+
d: number;
|
|
28
|
+
tx: number;
|
|
29
|
+
ty: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A NeutrinoParticles effect instance on a PIXI v8 scene.
|
|
33
|
+
*
|
|
34
|
+
* Extends ViewContainer and plugs into the v8 render graph as a custom render
|
|
35
|
+
* pipe ('neutrino'). Simulation runs on the CPU (neutrinoparticles.js v1.1);
|
|
36
|
+
* geometry is constructed on the GPU from a data texture by {@link NeutrinoRenderer}.
|
|
37
|
+
*/
|
|
38
|
+
export declare class Effect extends ViewContainer implements Instruction {
|
|
39
|
+
readonly renderPipeId: string;
|
|
40
|
+
batched: boolean;
|
|
41
|
+
readonly ctx: Context;
|
|
42
|
+
readonly effectModel: EffectModel;
|
|
43
|
+
effect?: NeutrinoSystem;
|
|
44
|
+
readonly baseParent?: Container;
|
|
45
|
+
readonly projection?: PerspectiveProjection;
|
|
46
|
+
positionZ: number;
|
|
47
|
+
scaleZ: number;
|
|
48
|
+
/** World transform actually fed to the renderer's model matrix (2x3). */
|
|
49
|
+
worldRenderMatrix: RenderMatrix;
|
|
50
|
+
private _worldPosition;
|
|
51
|
+
private _worldRotationDegree;
|
|
52
|
+
private _worldScale;
|
|
53
|
+
private _dataTextureManager?;
|
|
54
|
+
private _unpauseOnUpdateRender;
|
|
55
|
+
private _startupOptions;
|
|
56
|
+
private _inited;
|
|
57
|
+
private _ready;
|
|
58
|
+
constructor(effectModel: EffectModel, options?: EffectOptions);
|
|
59
|
+
get bounds(): Bounds;
|
|
60
|
+
protected updateBounds(): void;
|
|
61
|
+
init(): void;
|
|
62
|
+
ready(): boolean;
|
|
63
|
+
update(seconds: number): void;
|
|
64
|
+
restart(position?: Vec3, rotation?: number): void;
|
|
65
|
+
resetPosition(position?: Vec3, rotation?: number): void;
|
|
66
|
+
pause(): void;
|
|
67
|
+
unpause(): void;
|
|
68
|
+
pauseGenerators(): void;
|
|
69
|
+
unpauseGenerators(): void;
|
|
70
|
+
setPropertyInAllEmitters(name: string, value: Vec3 | Vec2 | number): void;
|
|
71
|
+
getNumParticles(): number;
|
|
72
|
+
/** @internal — called by EffectPipe during the render pass. */
|
|
73
|
+
_dtm(): DataTextureManager | DataTextureManagerGL1 | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* @internal — called by EffectPipe before constructing the frame.
|
|
76
|
+
* Auto-unpauses an effect whose first interaction is a render rather than an
|
|
77
|
+
* update (Pause.BEFORE_UPDATE_OR_RENDER), then refreshes the world transform
|
|
78
|
+
* from the live scene graph so a parent transform change since the last
|
|
79
|
+
* update() is reflected this frame (mirrors pixi7, which reads
|
|
80
|
+
* baseParent.worldTransform live in its render plugin).
|
|
81
|
+
*/
|
|
82
|
+
_prepareRender(): void;
|
|
83
|
+
/**
|
|
84
|
+
* @internal — resolved world alpha fed to the renderer (uWorldAlpha).
|
|
85
|
+
* groupAlpha only accumulates alpha WITHIN the effect's render group; the
|
|
86
|
+
* cross-group factor lives on parentRenderGroup.worldAlpha, so multiply both
|
|
87
|
+
* to honour transparency set on a render-group ancestor.
|
|
88
|
+
*/
|
|
89
|
+
get worldAlpha(): number;
|
|
90
|
+
/**
|
|
91
|
+
* @internal — called by EffectPipe. True when the effect is fully
|
|
92
|
+
* transparent, in which case the draw is skipped entirely (mirrors the phaser
|
|
93
|
+
* adapter and PIXI's scene-graph cull of a zero-alpha container). Partial
|
|
94
|
+
* alpha is applied in the shader via uWorldAlpha (see {@link worldAlpha}).
|
|
95
|
+
*/
|
|
96
|
+
_isInvisible(): boolean;
|
|
97
|
+
destroy(options?: any): void;
|
|
98
|
+
private _onEffectReady;
|
|
99
|
+
private _scaledPosition;
|
|
100
|
+
private _getRenderGroupContainer;
|
|
101
|
+
private _updateWorldTransform;
|
|
102
|
+
private _calcWorldRotation;
|
|
103
|
+
private _checkUnpauseOnUpdateRender;
|
|
104
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EventEmitter, Texture } from "pixi.js";
|
|
2
|
+
import { Context } from "./Context";
|
|
3
|
+
import { AbstractTexturesLoader } from "./TexturesLoader";
|
|
4
|
+
import { NeutrinoEffectModel, NeutrinoSubRect } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Wraps a neutrinoparticles.js v1.1 effect model and loads its textures via the
|
|
7
|
+
* PIXI v8 asset cache. Computes atlas UV remaps (as plain {x,y,width,height}
|
|
8
|
+
* objects — the v1.1 renderer reads them directly, no SubRect wrapper).
|
|
9
|
+
*/
|
|
10
|
+
export declare class EffectModel extends EventEmitter {
|
|
11
|
+
readonly ctx: Context;
|
|
12
|
+
readonly effectModel: NeutrinoEffectModel;
|
|
13
|
+
texturesRemap: Array<NeutrinoSubRect | null>;
|
|
14
|
+
readonly textures: Array<Texture>;
|
|
15
|
+
private _numTexturesToLoadLeft;
|
|
16
|
+
constructor(context: Context, neutrinoModel: string | NeutrinoEffectModel, texturesLoader: AbstractTexturesLoader);
|
|
17
|
+
ready(): boolean;
|
|
18
|
+
private _onTextureLoaded;
|
|
19
|
+
private _initTexturesRemapIfNeeded;
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ExtensionType, Loader, LoaderParserPriority, ResolvedAsset } from 'pixi.js';
|
|
2
|
+
import { EffectModel } from './EffectModel';
|
|
3
|
+
export declare const effectModelLoader: {
|
|
4
|
+
extension: {
|
|
5
|
+
type: ExtensionType;
|
|
6
|
+
priority: LoaderParserPriority;
|
|
7
|
+
};
|
|
8
|
+
test(_url: string, loadAsset: ResolvedAsset, _loader: Loader): any;
|
|
9
|
+
load(url: string, _loadAsset: ResolvedAsset, _loader: Loader): Promise<string>;
|
|
10
|
+
testParse(this: Loader, _asset: any, options: ResolvedAsset): Promise<any>;
|
|
11
|
+
parse(asset: string, options: ResolvedAsset, loader: Loader): Promise<unknown>;
|
|
12
|
+
unload(_effectModel: EffectModel): void;
|
|
13
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ExtensionType, InstructionSet, RenderPipe, WebGLRenderer } from "pixi.js";
|
|
2
|
+
import { Effect } from "./Effect";
|
|
3
|
+
/**
|
|
4
|
+
* PIXI v8 render pipe for NeutrinoParticles effects.
|
|
5
|
+
*
|
|
6
|
+
* Each effect is its own instruction (Effect.batched = false). The actual draw
|
|
7
|
+
* happens in {@link execute}, which runs inside the v8 render pass where PIXI
|
|
8
|
+
* owns the GL state — there we construct the frame's geometry and issue the raw
|
|
9
|
+
* WebGL2 data-texture draw via {@link NeutrinoRenderer}.
|
|
10
|
+
*/
|
|
11
|
+
export declare class EffectPipe implements RenderPipe<Effect> {
|
|
12
|
+
static extension: {
|
|
13
|
+
readonly type: readonly [ExtensionType.WebGLPipes];
|
|
14
|
+
readonly name: "neutrino";
|
|
15
|
+
};
|
|
16
|
+
readonly renderer: WebGLRenderer;
|
|
17
|
+
private readonly _neutrinoRenderer;
|
|
18
|
+
constructor(renderer: WebGLRenderer);
|
|
19
|
+
validateRenderable(_effect: Effect): boolean;
|
|
20
|
+
addRenderable(effect: Effect, instructionSet: InstructionSet): void;
|
|
21
|
+
updateRenderable(_effect: Effect): void;
|
|
22
|
+
destroyRenderable(_effect: Effect): void;
|
|
23
|
+
execute(effect: Effect): void;
|
|
24
|
+
destroy(): void;
|
|
25
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { WebGLRenderer } from "pixi.js";
|
|
2
|
+
import { Context } from "./Context";
|
|
3
|
+
import { Effect } from "./Effect";
|
|
4
|
+
import { DataTextureManager } from "./DataTextureManager";
|
|
5
|
+
import { DataTextureManagerGL1 } from "./gl1/DataTextureManagerGL1";
|
|
6
|
+
/**
|
|
7
|
+
* Raw WebGL2 data-texture renderer for the PIXI v8 integration.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors the pixi7 RendererPlugin: builds draw batches (grouped by blend mode,
|
|
10
|
+
* up to 8 textures each), patches the per-particle texture-slot byte into the
|
|
11
|
+
* runtime data buffer, uploads the data texture, sets camera/projection/model
|
|
12
|
+
* uniforms, and issues one drawElements per batch. Particle textures are bound
|
|
13
|
+
* by their raw WebGL handle (resolved from PIXI via the texture system).
|
|
14
|
+
*/
|
|
15
|
+
export declare class NeutrinoRenderer {
|
|
16
|
+
private _orthoMatrix;
|
|
17
|
+
private _perspMatrix;
|
|
18
|
+
private _vpMatrix;
|
|
19
|
+
private _modelMatrix;
|
|
20
|
+
private _projFrame;
|
|
21
|
+
private _texSlotMap;
|
|
22
|
+
private _batchPool;
|
|
23
|
+
private _batchCount;
|
|
24
|
+
constructor();
|
|
25
|
+
renderEffect(renderer: WebGLRenderer, ctx: Context, effect: Effect, dtm: DataTextureManager | DataTextureManagerGL1, instructions: any[], numParticles: number): void;
|
|
26
|
+
private _resolveBlend;
|
|
27
|
+
private _applyBlendMode;
|
|
28
|
+
private _fillProjMatrix;
|
|
29
|
+
private _mulMatrix;
|
|
30
|
+
private _fillModelMatrix;
|
|
31
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The class implements perspective projection transformation.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* // Create effect instance using loaded model
|
|
6
|
+
* let effect = new PIXINeutrino.Effect(resources.effectModel, {
|
|
7
|
+
* position: [400, 300, 0],
|
|
8
|
+
* projection: new PIXINeutrino.PerspectiveProjection(60.0)
|
|
9
|
+
* });
|
|
10
|
+
*
|
|
11
|
+
* @param {number} [horizontalAngle] Horizontal angle of the perspective projection in degrees.
|
|
12
|
+
*/
|
|
13
|
+
import { Rectangle } from "pixi.js";
|
|
14
|
+
import { Vec2, Vec3 } from "./types";
|
|
15
|
+
export declare class PerspectiveProjection {
|
|
16
|
+
private _angleTan;
|
|
17
|
+
private _screenWidth;
|
|
18
|
+
private _screenPosX;
|
|
19
|
+
private _screenPosY;
|
|
20
|
+
private _z;
|
|
21
|
+
private _near;
|
|
22
|
+
set horizontalAngle(value: number);
|
|
23
|
+
constructor(horizontalAngle: number);
|
|
24
|
+
/**
|
|
25
|
+
* Changes horizontal angle of the projection.
|
|
26
|
+
*
|
|
27
|
+
* @param {number} value Angle in degrees.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Sets rendering frame for the projection.
|
|
31
|
+
*
|
|
32
|
+
* This method shouldn't be called manually when the class is used with effects. It is called
|
|
33
|
+
* on every render call for each effect automatically.
|
|
34
|
+
* @param {PIXI.Rectangle} frame Rendering frame.
|
|
35
|
+
*/
|
|
36
|
+
setScreenFrame(frame: Rectangle): void;
|
|
37
|
+
/**
|
|
38
|
+
* Transforms 3D point accordingly to the projection.
|
|
39
|
+
*
|
|
40
|
+
* Basically, point's position X and Y components are simply scaled dependently on Z position. The method
|
|
41
|
+
* is used in WebGL and Canvas rendering.
|
|
42
|
+
*
|
|
43
|
+
* @param {Array} out [x, y] Transformed position.
|
|
44
|
+
* @param {Array} pos [x, y, z] Untransformed input vertex position.
|
|
45
|
+
* @returns false, if a particle is on the back side of the camera and should be discarded. Otherwise - true.
|
|
46
|
+
*/
|
|
47
|
+
transformPosition(out: Vec2, pos: Vec3): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Transforms 2D size of a particle accordingly to the projection.
|
|
50
|
+
*
|
|
51
|
+
* Basically, size is simply scaled dependently on Z position of a particle. The method is used
|
|
52
|
+
* only in Canvas rendering.
|
|
53
|
+
*
|
|
54
|
+
* @param {Array} outSize [width, height] Transformed size.
|
|
55
|
+
* @param {Array} pos [x, y, z] Untransformed particle position.
|
|
56
|
+
* @param {Array} size [width, height] Untransformed size.
|
|
57
|
+
*/
|
|
58
|
+
transformSize(outSize: Vec2, pos: Vec3, size: Vec2): void;
|
|
59
|
+
_getScale(pos: Vec3): number;
|
|
60
|
+
/**
|
|
61
|
+
* Writes the projection as a 4x4 column-major matrix operating in screen
|
|
62
|
+
* space, for the GPU render path. Homogeneous equivalent of
|
|
63
|
+
* transformPosition(): clip.xy = p.xy - center * (p.z / z),
|
|
64
|
+
* clip.w = 1 - p.z / z; the z row is zeroed (no depth on this path).
|
|
65
|
+
* setScreenFrame() must have been called before.
|
|
66
|
+
*
|
|
67
|
+
* @param {Float32Array} out 16-element column-major output matrix.
|
|
68
|
+
*/
|
|
69
|
+
writeMatrix(out: Float32Array): void;
|
|
70
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Loader, Texture } from 'pixi.js';
|
|
2
|
+
/**
|
|
3
|
+
* Texture loader interface used by {@link EffectModel} to load required textures.
|
|
4
|
+
*/
|
|
5
|
+
export declare abstract class AbstractTexturesLoader {
|
|
6
|
+
constructor();
|
|
7
|
+
abstract load(texturePath: string): Promise<Texture>;
|
|
8
|
+
}
|
|
9
|
+
export declare class AssetsTexturesLoader extends AbstractTexturesLoader {
|
|
10
|
+
private loader;
|
|
11
|
+
constructor(loader: Loader);
|
|
12
|
+
load(texturePath: string): Promise<Texture>;
|
|
13
|
+
}
|
|
14
|
+
export declare class DefaultAssetsTexturesLoader extends AssetsTexturesLoader {
|
|
15
|
+
static readonly instance: DefaultAssetsTexturesLoader;
|
|
16
|
+
private constructor();
|
|
17
|
+
}
|