@woosh/meep-engine 2.29.0 → 2.30.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.
Files changed (27) hide show
  1. package/core/process/worker/WorkerBuilder.js +5 -1
  2. package/engine/Engine.d.ts +5 -1
  3. package/engine/Engine.js +35 -17
  4. package/engine/EngineHarness.js +9 -1
  5. package/engine/asset/loaders/image/codec/CodecWithFallback.js +1 -1
  6. package/engine/asset/loaders/image/png/PNGReader.js +19 -21
  7. package/engine/ecs/EntityManager.js +10 -0
  8. package/engine/graphics/ecs/camera/topdown/ComputeCameraFacingVector.js +21 -0
  9. package/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +10 -14
  10. package/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +4 -24
  11. package/engine/graphics/particles/particular/engine/ParticularEngine.js +1 -0
  12. package/engine/graphics/particles/particular/engine/emitter/PARTICLE_ATTRIBUTES.js +3 -0
  13. package/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +27 -15
  14. package/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +30 -10
  15. package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +4 -6
  16. package/engine/graphics/particles/particular/engine/parameter/ParameterTrackSet.js +6 -3
  17. package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +271 -1
  18. package/engine/graphics/particles/particular/engine/renderers/billboard/prototypeBillboardRenderer.js +164 -0
  19. package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +10 -555
  20. package/engine/graphics/particles/particular/engine/simulator/AbstractSimulationStep.js +6 -0
  21. package/engine/graphics/particles/particular/engine/simulator/SimulationStepFixedPhysics.js +16 -1
  22. package/engine/graphics/particles/particular/engine/simulator/update_parameters.js +41 -0
  23. package/engine/graphics/render/buffer/FrameBufferManager.js +2 -0
  24. package/engine/graphics/render/visibility/IncrementalDeltaSet.js +5 -0
  25. package/engine/graphics/render/visibility/VisibilityComputer.js +6 -6
  26. package/engine/graphics/render/visibility/VisibilityFilter.js +10 -0
  27. package/package.json +1 -1
@@ -1,3 +1,273 @@
1
- export class ParticleBillboardMaterial {
1
+ import { AddEquation, CustomBlending, Matrix4, OneFactor, OneMinusSrcAlphaFactor, ShaderMaterial } from "three";
2
+ import { Vector2 as ThreeVector2 } from "three/src/math/Vector2.js";
3
+ import { ParticleSpecification } from "../../../group/ParticleSpecification.js";
4
+ import { ParticleAttribute } from "../../../group/ParticleAttribute.js";
5
+ import { ParticleAttributeType, ParticleDataType } from "../../../group/ParticleGroup.js";
2
6
 
7
+ export const BILLBOARD_PARTICLE_SPECIFICATION = new ParticleSpecification();
8
+
9
+ BILLBOARD_PARTICLE_SPECIFICATION.add(new ParticleAttribute('position', ParticleAttributeType.Vector3, ParticleDataType.Float32));
10
+ BILLBOARD_PARTICLE_SPECIFICATION.add(new ParticleAttribute('atlasPatch', ParticleAttributeType.Vector4, ParticleDataType.Float32));
11
+ BILLBOARD_PARTICLE_SPECIFICATION.add(new ParticleAttribute('size', ParticleAttributeType.Scalar, ParticleDataType.Float32));
12
+ BILLBOARD_PARTICLE_SPECIFICATION.add(new ParticleAttribute('velocity', ParticleAttributeType.Vector3, ParticleDataType.Float32));
13
+ BILLBOARD_PARTICLE_SPECIFICATION.add(new ParticleAttribute('rotation', ParticleAttributeType.Scalar, ParticleDataType.Float32));
14
+ BILLBOARD_PARTICLE_SPECIFICATION.add(new ParticleAttribute('color', ParticleAttributeType.Vector4, ParticleDataType.Float32));
15
+ BILLBOARD_PARTICLE_SPECIFICATION.add(new ParticleAttribute('blending', ParticleAttributeType.Scalar, ParticleDataType.Uint8));
16
+
17
+ export const BILLBOARD_PARTICLE_ATTRIBUTE_POSITION = 0;
18
+ export const BILLBOARD_PARTICLE_ATTRIBUTE_UV = 1;
19
+ export const BILLBOARD_PARTICLE_ATTRIBUTE_SIZE = 2;
20
+ export const BILLBOARD_PARTICLE_ATTRIBUTE_VELOCITY = 3;
21
+ export const BILLBOARD_PARTICLE_ATTRIBUTE_COLOR = 5;
22
+ export const BILLBOARD_PARTICLE_ATTRIBUTE_BLEND = 6;
23
+
24
+ const DEPTH_ERROR_MARGIN = 0.0001;
25
+
26
+ function make_vertex_shader() {
27
+ return `
28
+ uniform float cameraNear;
29
+ uniform float cameraFar;
30
+ uniform vec2 resolution;
31
+
32
+ attribute float size;
33
+ attribute vec4 color;
34
+ attribute vec4 atlasPatch;
35
+ attribute float rotation;
36
+ attribute vec3 velocity;
37
+ attribute float blending;
38
+
39
+ varying vec4 vPatch;
40
+ varying float vSize;
41
+ varying float vFadeDistance;
42
+ varying vec4 vColor;
43
+ varying vec2 vRotationMultiplier;
44
+ varying float vBlending;
45
+
46
+ void main() {
47
+
48
+ vColor = color;
49
+ vSize = size;
50
+ vPatch = atlasPatch;
51
+ vBlending = blending;
52
+
53
+ mat4 modelViewProjectionMatrix = projectionMatrix * modelViewMatrix;
54
+
55
+ vec4 position4 = vec4( position, 1.0 );
56
+
57
+ gl_Position = modelViewProjectionMatrix * position4;
58
+
59
+ float rotationGlobal = rotation;
60
+
61
+ //
62
+ #ifdef ALIGN_DIRECTION_ENABLED
63
+ if(velocity != vec3(0.0)){
64
+
65
+ vec4 vecNext = modelViewProjectionMatrix * (position4 + vec4(velocity,0.0) );
66
+
67
+ vec2 p_2 = gl_Position.xy / gl_Position.w;
68
+ vec2 vecNext_2 = vecNext.xy / vecNext.w;
69
+
70
+ vec2 direction = vecNext_2 - p_2;
71
+
72
+ float upAngle = atan(direction.y, direction.x) - 1.57079632679;
73
+
74
+ rotationGlobal = rotationGlobal + upAngle;
75
+
76
+ }
77
+ #endif
78
+ //
79
+
80
+ vRotationMultiplier = vec2( cos(rotationGlobal),sin(rotationGlobal) );
81
+
82
+ float radius = vSize/2.0;
83
+
84
+ #ifdef DEPTH_SOFT_ENABLED
85
+
86
+ vFadeDistance = 1.0 / radius;
87
+
88
+ #endif
89
+
90
+ gl_PointSize = resolution.y * projectionMatrix[1][1] * radius / gl_Position.w;
91
+ }`;
92
+ }
93
+
94
+ function make_fragment_shader() {
95
+ return `
96
+ uniform sampler2D tSpriteAtlas;
97
+ uniform sampler2D tDepth;
98
+ uniform float cameraNear;
99
+ uniform float cameraFar;
100
+ uniform mat4 modelViewMatrix;
101
+ uniform mat4 projectionMatrix;
102
+ uniform vec2 resolution;
103
+
104
+ varying float vFadeDistance;
105
+ varying vec4 vPatch;
106
+ varying float vSize;
107
+ varying vec4 vColor;
108
+ varying vec2 vRotationMultiplier;
109
+ varying float vBlending;
110
+
111
+ float depthToLinear( float z ) {
112
+ float f = cameraFar;
113
+ float n = cameraNear;
114
+
115
+ float d_n = 2.0*z - 1.0;
116
+
117
+ float fn = f*n;
118
+
119
+ float z_diff = f - n;
120
+
121
+ float denominator = (f + n - d_n * z_diff );
122
+
123
+ float z_view = (2.0*fn) / denominator;
124
+
125
+ return z_view-n;
126
+ }
127
+
128
+
129
+ float calculateFade(in float particleDepth, in float sceneDepth){
130
+ float zFade;
131
+
132
+ float linearParticleDepth = depthToLinear(particleDepth);
133
+
134
+ float linearSceneDepth = depthToLinear(sceneDepth);
135
+
136
+ float depthDelta = (linearSceneDepth - linearParticleDepth);
137
+
138
+ float inputDepth = depthDelta* vFadeDistance;
139
+
140
+ if(inputDepth <= 0.0){
141
+ return 0.0;
142
+ }
143
+
144
+ if(inputDepth >= 1.0){
145
+ return 1.0;
146
+ }
147
+
148
+ if(inputDepth <= 0.5){
149
+ zFade = 0.5 * pow( clamp(2.0*inputDepth, 0.0, 1.0), 2.0);
150
+ }else{
151
+ zFade = 1.0 - 0.5 * pow( clamp(2.0*(1.0 - inputDepth), 0.0, 1.0), 2.0);
152
+ }
153
+
154
+ return zFade;
155
+ }
156
+
157
+ void main() {
158
+ float fragmentDepth = gl_FragCoord.z;
159
+
160
+ vec2 pixelPosition = gl_FragCoord.xy / resolution;
161
+
162
+ float sceneDepth = texture2D( tDepth, pixelPosition ).x;
163
+
164
+ #ifdef DEPTH_READ_ENABLED
165
+
166
+ if(fragmentDepth + ${DEPTH_ERROR_MARGIN} > sceneDepth){
167
+ discard;
168
+ }
169
+
170
+ #endif
171
+
172
+ vec2 centeredUv = gl_PointCoord.xy - 0.5;
173
+
174
+ vec2 texelCoordinate = vec2( centeredUv.x* vRotationMultiplier.x - centeredUv.y* vRotationMultiplier.y, centeredUv.x * vRotationMultiplier.y + centeredUv.y * vRotationMultiplier.x) + 0.5;
175
+
176
+ texelCoordinate = clamp(texelCoordinate, vec2(0.0), vec2(1.0) );
177
+
178
+ vec2 uv = texelCoordinate*vPatch.zw + vPatch.xy;
179
+
180
+ vec4 spriteColor = texture2D( tSpriteAtlas, uv );
181
+
182
+ if(spriteColor.a == 0.0){
183
+ discard;
184
+ }
185
+
186
+ vec4 texel = spriteColor *vColor;
187
+
188
+ // premultiply alpha
189
+ texel.xyz *= texel.a;
190
+
191
+ if(vBlending > 0.1){
192
+ // additive blending
193
+ texel.a = 0.0;
194
+ }
195
+
196
+ #ifdef DEPTH_SOFT_ENABLED
197
+
198
+ float zFade = calculateFade(fragmentDepth, sceneDepth);
199
+ texel *= zFade;
200
+
201
+ #endif
202
+
203
+ gl_FragColor = texel;
204
+
205
+ }`;
206
+ }
207
+
208
+ /*
209
+ NOTES:
210
+ - To implement per-particle blend modes, we need to have access to what we're blending on to, that is - the color buffer
211
+ Having the color buffer - we can do just about any kind of a blend
212
+
213
+ - Support animation by adding animation sprite sheet to the main sprite atlas, record resolution of the sheet (in frames X,Y) and interpolate over tiles based on some parameter
214
+ */
215
+ export function make_particle_billboard_shader() {
216
+ const shader = new ShaderMaterial({
217
+ defines: {
218
+ DEPTH_READ_ENABLED: true,
219
+ DEPTH_SOFT_ENABLED: true,
220
+ ALIGN_DIRECTION_ENABLED: false,
221
+ },
222
+ uniforms: {
223
+ tSpriteAtlas: {
224
+ type: 't',
225
+ value: null
226
+ },
227
+ cameraNear: {
228
+ type: 'f',
229
+ value: 1,
230
+ },
231
+ cameraFar: {
232
+ type: 'f',
233
+ value: 1,
234
+ },
235
+ tDepth: {
236
+ type: 't',
237
+ value: null
238
+ },
239
+ tColor: {
240
+ type: 't',
241
+ value: null
242
+ },
243
+ modelViewMatrix: {
244
+ type: 'm4',
245
+ value: new Matrix4()
246
+ },
247
+ projectionMatrix: {
248
+ type: 'm4',
249
+ value: new Matrix4()
250
+ },
251
+ resolution: {
252
+ type: 'v2',
253
+ value: new ThreeVector2()
254
+ }
255
+ },
256
+ vertexShader: make_vertex_shader(),
257
+ fragmentShader: make_fragment_shader(),
258
+ blending: CustomBlending,
259
+ lights: false,
260
+ depthTest: true,
261
+ depthWrite: false,
262
+ transparent: true,
263
+ vertexColors: false,
264
+ glslVersion: 2
265
+ });
266
+
267
+ shader.blending = CustomBlending;
268
+ shader.blendEquation = AddEquation;
269
+ shader.blendSrc = OneFactor;
270
+ shader.blendDst = OneMinusSrcAlphaFactor;
271
+
272
+ return shader;
3
273
  }
@@ -0,0 +1,164 @@
1
+ import { EngineHarness } from "../../../../../../EngineHarness.js";
2
+ import { ParticlePool } from "../../emitter/ParticlePool.js";
3
+ import {
4
+ BILLBOARD_PARTICLE_ATTRIBUTE_BLEND,
5
+ BILLBOARD_PARTICLE_ATTRIBUTE_COLOR,
6
+ BILLBOARD_PARTICLE_ATTRIBUTE_POSITION,
7
+ BILLBOARD_PARTICLE_ATTRIBUTE_SIZE,
8
+ BILLBOARD_PARTICLE_ATTRIBUTE_UV,
9
+ BILLBOARD_PARTICLE_SPECIFICATION,
10
+ make_particle_billboard_shader
11
+ } from "./ParticleBillboardMaterial.js";
12
+ import { DataTexture, LinearFilter, LinearMipMapLinearFilter, Matrix4, Points } from "three";
13
+ import { StandardFrameBuffers } from "../../../../../GraphicsEngine.js";
14
+ import { ManagedAtlas } from "../../../../../texture/atlas/ManagedTextureAtlas.js";
15
+ import { writeSample2DDataToDataTexture } from "../../../../../texture/sampler/writeSampler2DDataToDataTexture.js";
16
+ import { ImageRGBADataLoader } from "../../../../../../asset/loaders/image/ImageRGBADataLoader.js";
17
+ import { EngineConfiguration } from "../../../../../../EngineConfiguration.js";
18
+ import { MeshSystem } from "../../../../../ecs/mesh/MeshSystem.js";
19
+ import EntityBuilder from "../../../../../../ecs/EntityBuilder.js";
20
+ import { Transform } from "../../../../../../ecs/transform/Transform.js";
21
+ import Mesh from "../../../../../ecs/mesh/Mesh.js";
22
+ import Vector3 from "../../../../../../../core/geom/Vector3.js";
23
+ import { RenderPassType } from "../../../../../render/RenderPassType.js";
24
+
25
+
26
+ const engineHarness = new EngineHarness();
27
+
28
+ async function init(engineHarness) {
29
+
30
+ const engine = await engineHarness.initialize();
31
+
32
+ const config = new EngineConfiguration();
33
+
34
+ config.addSystem(new MeshSystem(engine.graphics, engine.assetManager));
35
+ config.addLoader('image', new ImageRGBADataLoader());
36
+
37
+ await config.apply(engine);
38
+
39
+ main(engine);
40
+ }
41
+
42
+ /**
43
+ *
44
+ * @param {Engine} engine
45
+ * @returns {Promise<void>}
46
+ */
47
+ async function main(engine) {
48
+ const ecd = engine.entityManager.dataset;
49
+
50
+
51
+ const particle_pool = new ParticlePool(BILLBOARD_PARTICLE_SPECIFICATION);
52
+
53
+ const particle_a = particle_pool.create();
54
+
55
+ particle_pool.writeAttributeScalar(particle_a, BILLBOARD_PARTICLE_ATTRIBUTE_SIZE, 5);
56
+ particle_pool.writeAttributeVector3(particle_a, BILLBOARD_PARTICLE_ATTRIBUTE_POSITION, 5, 2, 5);
57
+ particle_pool.writeAttributeVector4(particle_a, BILLBOARD_PARTICLE_ATTRIBUTE_UV, 0, 0, 1, 1);
58
+ particle_pool.writeAttributeVector4(particle_a, BILLBOARD_PARTICLE_ATTRIBUTE_COLOR, 1, 1, 1, 1);
59
+ particle_pool.writeAttributeScalar(particle_a, BILLBOARD_PARTICLE_ATTRIBUTE_BLEND, 0);
60
+
61
+ const particle_b = particle_pool.create();
62
+
63
+ particle_pool.writeAttributeScalar(particle_b, BILLBOARD_PARTICLE_ATTRIBUTE_SIZE, 5);
64
+ particle_pool.writeAttributeVector3(particle_b, BILLBOARD_PARTICLE_ATTRIBUTE_POSITION, 10, 2, 5);
65
+ particle_pool.writeAttributeVector4(particle_b, BILLBOARD_PARTICLE_ATTRIBUTE_UV, 0, 0, 1, 1);
66
+ particle_pool.writeAttributeVector4(particle_b, BILLBOARD_PARTICLE_ATTRIBUTE_COLOR, 1, 1, 1, 1);
67
+ particle_pool.writeAttributeScalar(particle_b, BILLBOARD_PARTICLE_ATTRIBUTE_BLEND, 1);
68
+
69
+ const particle_c = particle_pool.create();
70
+
71
+ particle_pool.writeAttributeScalar(particle_c, BILLBOARD_PARTICLE_ATTRIBUTE_SIZE, 5);
72
+ particle_pool.writeAttributeVector3(particle_c, BILLBOARD_PARTICLE_ATTRIBUTE_POSITION, 10, 2, 10);
73
+ particle_pool.writeAttributeVector4(particle_c, BILLBOARD_PARTICLE_ATTRIBUTE_UV, 0, 0, 1, 1);
74
+ particle_pool.writeAttributeVector4(particle_c, BILLBOARD_PARTICLE_ATTRIBUTE_COLOR, 1, 1, 1, 1);
75
+ particle_pool.writeAttributeScalar(particle_c, BILLBOARD_PARTICLE_ATTRIBUTE_BLEND, 1);
76
+
77
+ const particle_d = particle_pool.create();
78
+
79
+ particle_pool.writeAttributeScalar(particle_d, BILLBOARD_PARTICLE_ATTRIBUTE_SIZE, 5);
80
+ particle_pool.writeAttributeVector3(particle_d, BILLBOARD_PARTICLE_ATTRIBUTE_POSITION, 5, 2, 10);
81
+ particle_pool.writeAttributeVector4(particle_d, BILLBOARD_PARTICLE_ATTRIBUTE_UV, 0, 0, 1, 1);
82
+ particle_pool.writeAttributeVector4(particle_d, BILLBOARD_PARTICLE_ATTRIBUTE_COLOR, 1, 1, 1, 1);
83
+ particle_pool.writeAttributeScalar(particle_d, BILLBOARD_PARTICLE_ATTRIBUTE_BLEND, 0);
84
+
85
+ particle_pool.compact();
86
+
87
+ const managedAtlas = new ManagedAtlas(engine.assetManager);
88
+ const sprite_atlas_texture = new DataTexture(new Uint8Array(4), 1, 1);
89
+ sprite_atlas_texture.generateMipmaps = true;
90
+ sprite_atlas_texture.minFilter = LinearMipMapLinearFilter;
91
+ sprite_atlas_texture.magFilter = LinearFilter;
92
+ sprite_atlas_texture.anisotropy = 0; // billboards don't need anisotropy
93
+
94
+
95
+ managedAtlas.acquire('data/textures/utility/uv_map_reference.jpg');
96
+ // managedAtlas.acquire('data/textures/particle/UETools/Star_41.png');
97
+
98
+ const shaderMaterial = make_particle_billboard_shader();
99
+
100
+ shaderMaterial.uniforms.tSpriteAtlas.value = sprite_atlas_texture;
101
+
102
+ managedAtlas.atlas.on.painted.add(() => {
103
+ writeSample2DDataToDataTexture(managedAtlas.atlas.sampler, sprite_atlas_texture);
104
+ });
105
+
106
+ const points = new Points(particle_pool.geometry.getValue(), shaderMaterial);
107
+ points.frustumCulled = false;
108
+
109
+ const layer = engine.graphics.layers.create('x');
110
+
111
+ layer.managed = true;
112
+ layer.visibleSet.initializeUpdate();
113
+ layer.visibleSet.push(points);
114
+ layer.visibleSet.finalizeUpdate();
115
+
116
+ layer.renderPass = RenderPassType.Transparent;
117
+
118
+ engine.graphics.on.visibilityConstructionStarted.add((renderer, camera, scene) => {
119
+ renderer.getSize(shaderMaterial.uniforms.resolution.value);
120
+
121
+ const projectionMatrix = camera.projectionMatrix;
122
+ const modelViewMatrix = (new Matrix4()).multiplyMatrices(camera.matrixWorldInverse, camera.matrixWorld);
123
+ const cameraNear = camera.near;
124
+ const cameraFar = camera.far;
125
+
126
+ const uniforms = shaderMaterial.uniforms;
127
+
128
+ uniforms.projectionMatrix.value = projectionMatrix;
129
+ uniforms.modelViewMatrix.value = modelViewMatrix;
130
+ uniforms.cameraNear.value = cameraNear;
131
+ uniforms.cameraFar.value = cameraFar;
132
+
133
+ const fb = engine.graphics.frameBuffers.getById(StandardFrameBuffers.ColorAndDepth);
134
+
135
+ uniforms.tDepth.value = fb.renderTarget.depthTexture;
136
+ uniforms.tColor.value = fb.renderTarget.texture;
137
+ });
138
+
139
+ EngineHarness.buildCamera({
140
+ engine,
141
+ target: new Vector3(5, 2, 5)
142
+ });
143
+
144
+ EngineHarness.buildOrbitalCameraController({
145
+ engine
146
+ });
147
+
148
+ EngineHarness.buildLights({
149
+ engine
150
+ });
151
+
152
+ EngineHarness.buildTerrain({
153
+ engine,
154
+ enableWater: false
155
+ });
156
+
157
+
158
+ new EntityBuilder()
159
+ .add(Mesh.fromJSON({ url: 'data/models/Jauntmessina/Red_Robot/gltf/Model.gltf' }))
160
+ .add(new Transform())
161
+ .build(ecd)
162
+ }
163
+
164
+ init(engineHarness);