@zephyr3d/scene 0.2.0 → 0.3.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 (76) hide show
  1. package/dist/asset/assetmanager.js +85 -93
  2. package/dist/asset/assetmanager.js.map +1 -1
  3. package/dist/camera/camera.js +1 -0
  4. package/dist/camera/camera.js.map +1 -1
  5. package/dist/index.d.ts +2511 -2329
  6. package/dist/index.js +2 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/material/blinn.js +5 -5
  9. package/dist/material/grassmaterial.js +14 -14
  10. package/dist/material/material.js +32 -54
  11. package/dist/material/material.js.map +1 -1
  12. package/dist/material/meshmaterial.js +215 -80
  13. package/dist/material/meshmaterial.js.map +1 -1
  14. package/dist/material/mixins/albedocolor.js +11 -7
  15. package/dist/material/mixins/albedocolor.js.map +1 -1
  16. package/dist/material/mixins/foliage.js +7 -7
  17. package/dist/material/mixins/lightmodel/blinnphong.js +5 -5
  18. package/dist/material/mixins/lightmodel/lambert.js +5 -5
  19. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +5 -5
  20. package/dist/material/mixins/lit.js +72 -72
  21. package/dist/material/mixins/pbr/common.js +4 -4
  22. package/dist/material/mixins/texture.js +6 -6
  23. package/dist/material/mixins/vertexcolor.js +5 -5
  24. package/dist/material/pbrmr.js +5 -5
  25. package/dist/material/shader/helper.js +20 -18
  26. package/dist/material/shader/helper.js.map +1 -1
  27. package/dist/material/terrainmaterial.js +12 -12
  28. package/dist/posteffect/bloom.js +1 -0
  29. package/dist/posteffect/bloom.js.map +1 -1
  30. package/dist/posteffect/compositor.js +1 -0
  31. package/dist/posteffect/compositor.js.map +1 -1
  32. package/dist/posteffect/water.js +1 -0
  33. package/dist/posteffect/water.js.map +1 -1
  34. package/dist/render/cull_visitor.js +24 -3
  35. package/dist/render/cull_visitor.js.map +1 -1
  36. package/dist/render/primitive.js +31 -0
  37. package/dist/render/primitive.js.map +1 -1
  38. package/dist/render/render_queue.js +111 -38
  39. package/dist/render/render_queue.js.map +1 -1
  40. package/dist/render/renderer.js +9 -0
  41. package/dist/render/renderer.js.map +1 -1
  42. package/dist/render/sky.js +2 -4
  43. package/dist/render/sky.js.map +1 -1
  44. package/dist/scene/batchgroup.js +126 -0
  45. package/dist/scene/batchgroup.js.map +1 -0
  46. package/dist/scene/environment.js +1 -0
  47. package/dist/scene/environment.js.map +1 -1
  48. package/dist/scene/graph_node.js +8 -0
  49. package/dist/scene/graph_node.js.map +1 -1
  50. package/dist/scene/mesh.js +35 -2
  51. package/dist/scene/mesh.js.map +1 -1
  52. package/dist/scene/octree.js +37 -72
  53. package/dist/scene/octree.js.map +1 -1
  54. package/dist/scene/octree_update_visitor.js +5 -1
  55. package/dist/scene/octree_update_visitor.js.map +1 -1
  56. package/dist/scene/scene.js +7 -17
  57. package/dist/scene/scene.js.map +1 -1
  58. package/dist/scene/scene_node.js +57 -44
  59. package/dist/scene/scene_node.js.map +1 -1
  60. package/dist/scene/xform.js +61 -36
  61. package/dist/scene/xform.js.map +1 -1
  62. package/dist/shadow/esm.js +1 -0
  63. package/dist/shadow/esm.js.map +1 -1
  64. package/dist/shadow/shadowmapper.js +22 -6
  65. package/dist/shadow/shadowmapper.js.map +1 -1
  66. package/dist/shadow/vsm.js +1 -0
  67. package/dist/shadow/vsm.js.map +1 -1
  68. package/dist/shapes/box.js +15 -6
  69. package/dist/shapes/box.js.map +1 -1
  70. package/dist/shapes/cylinder.js +1 -4
  71. package/dist/shapes/cylinder.js.map +1 -1
  72. package/dist/shapes/shape.js +5 -0
  73. package/dist/shapes/shape.js.map +1 -1
  74. package/dist/shapes/sphere.js +3 -0
  75. package/dist/shapes/sphere.js.map +1 -1
  76. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ export { SceneRenderer } from './render/renderer.js';
15
15
  export { LightPass } from './render/lightpass.js';
16
16
  export { ShadowMapPass } from './render/shadowmap_pass.js';
17
17
  export { DepthPass } from './render/depthpass.js';
18
- export { RenderQueue } from './render/render_queue.js';
18
+ export { InstanceBindGroupAllocator, RenderQueue } from './render/render_queue.js';
19
19
  export { SkyRenderer } from './render/sky.js';
20
20
  export { Clipmap } from './render/clipmap.js';
21
21
  export { EnvConstantAmbient, EnvHemisphericAmbient, EnvIBL, EnvironmentLighting } from './render/envlight.js';
@@ -51,6 +51,7 @@ export { Mesh } from './scene/mesh.js';
51
51
  export { Model } from './scene/model.js';
52
52
  export { Octree, OctreeNode, OctreeNodeChunk, OctreePlacement } from './scene/octree.js';
53
53
  export { SceneNode } from './scene/scene_node.js';
54
+ export { BatchGroup } from './scene/batchgroup.js';
54
55
  export { Terrain } from './scene/terrain/terrain.js';
55
56
  export { HeightField, HeightfieldBBoxTree } from './scene/terrain/heightfield.js';
56
57
  export { TerrainPatch } from './scene/terrain/patch.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -3,14 +3,14 @@ import { mixinVertexColor } from './mixins/vertexcolor.js';
3
3
  import { mixinBlinnPhong } from './mixins/lightmodel/blinnphong.js';
4
4
  import { ShaderHelper } from './shader/helper.js';
5
5
 
6
- /**
7
- * Blinn material
8
- * @public
6
+ /**
7
+ * Blinn material
8
+ * @public
9
9
  */ class BlinnMaterial extends applyMaterialMixins(MeshMaterial, mixinBlinnPhong, mixinVertexColor) {
10
10
  /** @internal */ static FEATURE_VERTEX_NORMAL = this.defineFeature();
11
11
  /** @internal */ static FEATURE_VERTEX_TANGENT = this.defineFeature();
12
- /**
13
- * Creates an instance of BlinnMaterial class
12
+ /**
13
+ * Creates an instance of BlinnMaterial class
14
14
  */ constructor(){
15
15
  super();
16
16
  this.useFeature(BlinnMaterial.FEATURE_VERTEX_NORMAL, true);
@@ -5,18 +5,18 @@ import { RENDER_PASS_TYPE_LIGHT } from '../values.js';
5
5
  import { ShaderHelper } from './shader/helper.js';
6
6
  import { mixinFoliage } from './mixins/foliage.js';
7
7
 
8
- /**
9
- * Terrain grass material
10
- * @public
8
+ /**
9
+ * Terrain grass material
10
+ * @public
11
11
  */ class GrassMaterial extends applyMaterialMixins(MeshMaterial, mixinPBRMetallicRoughness, mixinFoliage) {
12
12
  /** @internal */ _terrainSize;
13
13
  /** @internal */ _terrainNormalMap;
14
14
  /** @internal */ _textureSize;
15
- /**
16
- * Creates an instance of GrassMaterial class
17
- * @param terrainSize - terrain size
18
- * @param normalMap - normal map
19
- * @param grassTexture - grass texture
15
+ /**
16
+ * Creates an instance of GrassMaterial class
17
+ * @param terrainSize - terrain size
18
+ * @param normalMap - normal map
19
+ * @param grassTexture - grass texture
20
20
  */ constructor(terrainSize, normalMap, grassTexture){
21
21
  super();
22
22
  this.metallic = 0;
@@ -31,15 +31,15 @@ import { mixinFoliage } from './mixins/foliage.js';
31
31
  this._textureSize.setXY(grassTexture.width, grassTexture.height);
32
32
  }
33
33
  }
34
- /**
35
- * {@inheritDoc MeshMaterial.isTransparentPass}
36
- * @override
34
+ /**
35
+ * {@inheritDoc MeshMaterial.isTransparentPass}
36
+ * @override
37
37
  */ isTransparentPass(pass) {
38
38
  return false;
39
39
  }
40
- /**
41
- * {@inheritDoc Material.supportLighting}
42
- * @override
40
+ /**
41
+ * {@inheritDoc Material.supportLighting}
42
+ * @override
43
43
  */ supportLighting() {
44
44
  return true;
45
45
  }
@@ -4,48 +4,6 @@ import { Application } from '../app.js';
4
4
  import { QUEUE_OPAQUE, RENDER_PASS_TYPE_LIGHT, RENDER_PASS_TYPE_SHADOWMAP, RENDER_PASS_TYPE_DEPTH } from '../values.js';
5
5
  import { ShaderHelper } from './shader/helper.js';
6
6
 
7
- class InstanceBindGroupPool {
8
- _bindGroups;
9
- _frameStamp;
10
- constructor(){
11
- this._bindGroups = [];
12
- this._frameStamp = -1;
13
- }
14
- apply(hash, index, worldMatrices) {
15
- const device = Application.instance.device;
16
- const maxSize = device.getDeviceCaps().shaderCaps.maxUniformBufferSize;
17
- if (device.frameInfo.frameCounter !== this._frameStamp) {
18
- this._frameStamp = device.frameInfo.frameCounter;
19
- for (const bindGroup of this._bindGroups){
20
- bindGroup.freeSize = maxSize;
21
- }
22
- }
23
- let bindGroupIndex = -1;
24
- for(let i = 0; i < this._bindGroups.length; i++){
25
- if (this._bindGroups[i].freeSize >= worldMatrices.length * 64) {
26
- bindGroupIndex = i;
27
- break;
28
- }
29
- }
30
- if (bindGroupIndex < 0) {
31
- const program = Material.getProgramByHashIndex(hash, index);
32
- const bindGroup = program?.bindGroupLayouts[3] ? device.createBindGroup(program.bindGroupLayouts[3]) : null;
33
- this._bindGroups.push({
34
- bindGroup: bindGroup,
35
- freeSize: maxSize
36
- });
37
- bindGroupIndex = this._bindGroups.length - 1;
38
- }
39
- const bindGroup = this._bindGroups[bindGroupIndex];
40
- const offset = (maxSize - bindGroup.freeSize) / 64;
41
- for (const matrix of worldMatrices){
42
- bindGroup.bindGroup.setRawData(ShaderHelper.getWorldMatricesUniformName(), maxSize - bindGroup.freeSize, matrix);
43
- bindGroup.freeSize -= 64;
44
- }
45
- device.setBindGroup(3, bindGroup.bindGroup);
46
- return offset;
47
- }
48
- }
49
7
  /**
50
8
  * Base class for any kind of materials
51
9
  *
@@ -66,7 +24,7 @@ class InstanceBindGroupPool {
66
24
  inactiveTimeDuration: 30000
67
25
  };
68
26
  /** @internal */ static _boneMatrixTextureSampler = null;
69
- /** @internal */ static _instanceBindGroupPool = new InstanceBindGroupPool();
27
+ /** @internal */ //private static _instanceBindGroupPool: InstanceBindGroupPool = new InstanceBindGroupPool();
70
28
  /** @internal */ static _drawableBindGroupMap = new WeakMap();
71
29
  /** @internal */ _numPasses;
72
30
  /** @internal */ _hash;
@@ -88,7 +46,7 @@ class InstanceBindGroupPool {
88
46
  this._optionTag = 0;
89
47
  this._materialBindGroup = null;
90
48
  }
91
- /** Unique identifier of the material */ get id() {
49
+ /** Unique identifier of the material */ get instanceId() {
92
50
  return this._id;
93
51
  }
94
52
  get numPasses() {
@@ -125,7 +83,7 @@ class InstanceBindGroupPool {
125
83
  return true;
126
84
  }
127
85
  /** Returns true if this material supports geometry instancing */ isBatchable() {
128
- return true;
86
+ return false;
129
87
  }
130
88
  /**
131
89
  * Draws a primitive using this material
@@ -146,7 +104,6 @@ class InstanceBindGroupPool {
146
104
  * @param ctx - The context of current drawing task
147
105
  * @returns true if succeeded, otherwise false
148
106
  */ beginDraw(pass, ctx) {
149
- const numInstances = ctx.instanceData?.worldMatrices?.length || 1;
150
107
  const device = Application.instance.device;
151
108
  const programInfo = this.getOrCreateProgram(ctx, pass);
152
109
  if (programInfo) {
@@ -159,7 +116,7 @@ class InstanceBindGroupPool {
159
116
  }
160
117
  this._materialBindGroup = this.applyMaterialBindGroups(ctx, hash, pass);
161
118
  if (pass === 0) {
162
- if (numInstances > 1) {
119
+ if (ctx.instanceData) {
163
120
  this.applyInstanceBindGroups(ctx, hash);
164
121
  } else {
165
122
  this.applyDrawableBindGroups(ctx, hash);
@@ -203,7 +160,7 @@ class InstanceBindGroupPool {
203
160
  */ getOrCreateProgram(ctx, pass) {
204
161
  const programMap = Material._programMap;
205
162
  const renderPassType = ctx.renderPass.type;
206
- const hash = `${this.getHash(renderPassType, pass)}:${!!ctx.target.getBoneMatrices()}:${Number(!!(ctx.instanceData?.worldMatrices.length > 1))}:${ctx.renderPassHash}`;
163
+ const hash = `${this.getHash(renderPassType, pass)}:${!!ctx.target.getBoneMatrices()}:${Number(!!ctx.instanceData)}:${ctx.renderPassHash}`;
207
164
  let programInfo = programMap[hash];
208
165
  if (!programInfo || programInfo.programs[renderPassType] === undefined) {
209
166
  const program = this.createProgram(ctx, pass) ?? null;
@@ -363,11 +320,20 @@ class InstanceBindGroupPool {
363
320
  return drawableBindGroup;
364
321
  }
365
322
  /** @internal */ applyInstanceBindGroups(ctx, hash) {
366
- const index = ctx.renderPass.type;
367
- const offset = Material._instanceBindGroupPool.apply(hash, index, ctx.instanceData.worldMatrices);
368
- const bindGroup = this.getDrawableBindGroup(ctx, hash).bindGroup?.[index];
323
+ if (ctx.instanceData) {
324
+ if (ctx.instanceData.bindGroup.dirty) {
325
+ ctx.instanceData.bindGroup.bindGroup.setRawData(ShaderHelper.getWorldMatricesUniformName(), 0, ctx.instanceData.bindGroup.buffer, 0, ctx.instanceData.currentSize * 4);
326
+ ctx.instanceData.bindGroup.dirty = false;
327
+ }
328
+ Application.instance.device.setBindGroup(3, ctx.instanceData.bindGroup.bindGroup ?? null);
329
+ } else {
330
+ Application.instance.device.setBindGroup(3, null);
331
+ }
332
+ const bindGroup = this.getDrawableBindGroup(ctx, hash).bindGroup?.[ctx.renderPass.type];
369
333
  if (bindGroup) {
370
- bindGroup.setValue(ShaderHelper.getInstanceBufferOffsetUniformName(), offset);
334
+ if (ctx.instanceData) {
335
+ bindGroup.setValue(ShaderHelper.getInstanceBufferStrideUniformName(), ctx.instanceData.stride);
336
+ }
371
337
  Application.instance.device.setBindGroup(1, bindGroup);
372
338
  } else {
373
339
  Application.instance.device.setBindGroup(1, null);
@@ -460,8 +426,8 @@ class InstanceBindGroupPool {
460
426
  */ drawPrimitive(pass, primitive, ctx, numInstances) {
461
427
  if (numInstances > 0) {
462
428
  primitive.drawInstanced(numInstances);
463
- } else if (ctx.instanceData?.worldMatrices.length > 1) {
464
- primitive.drawInstanced(ctx.instanceData.worldMatrices.length);
429
+ } else if (ctx.instanceData) {
430
+ primitive.drawInstanced(ctx.instanceData.currentSize / ctx.instanceData.stride);
465
431
  } else {
466
432
  primitive.draw();
467
433
  }
@@ -493,6 +459,18 @@ class InstanceBindGroupPool {
493
459
  */ _createHash(renderPassType) {
494
460
  return '';
495
461
  }
462
+ /**
463
+ * True if this is a material instance
464
+ * @internal
465
+ **/ get $isInstance() {
466
+ return false;
467
+ }
468
+ /**
469
+ * Returns the instance uniforms if this is a material instance
470
+ * @internal
471
+ **/ get $instanceUniforms() {
472
+ return null;
473
+ }
496
474
  }
497
475
 
498
476
  export { Material };
@@ -1 +1 @@
1
- {"version":3,"file":"material.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"material.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -4,14 +4,15 @@ import { Material } from './material.js';
4
4
  import { encodeNormalizedFloatToRGBA } from '../shaders/misc.js';
5
5
  import { Application } from '../app.js';
6
6
  import { ShaderHelper } from './shader/helper.js';
7
+ import { Vector4, Vector3, Vector2 } from '@zephyr3d/base';
7
8
 
8
- /**
9
- * Apply material mixins to specific material class
10
- * @param target - Material class
11
- * @param mixins - mixins
12
- * @returns Mixed mesh material class
13
- *
14
- * @public
9
+ /**
10
+ * Apply material mixins to specific material class
11
+ * @param target - Material class
12
+ * @param mixins - mixins
13
+ * @returns Mixed mesh material class
14
+ *
15
+ * @public
15
16
  */ function applyMaterialMixins(target, ...mixins) {
16
17
  let r = target;
17
18
  for (const m of mixins){
@@ -22,11 +23,12 @@ import { ShaderHelper } from './shader/helper.js';
22
23
  let FEATURE_ALPHATEST = 0;
23
24
  let FEATURE_ALPHABLEND = 0;
24
25
  let FEATURE_ALPHATOCOVERAGE = 0;
25
- /**
26
- * Base class for any kind of mesh materials
27
- *
28
- * @public
26
+ /**
27
+ * Base class for any kind of mesh materials
28
+ *
29
+ * @public
29
30
  */ class MeshMaterial extends Material {
31
+ /** @internal */ static INSTANCE_UNIFORMS = [];
30
32
  /** @internal */ static NEXT_FEATURE_INDEX = 3;
31
33
  /** @internal */ _featureStates;
32
34
  /** @internal */ _alphaCutoff;
@@ -35,9 +37,9 @@ let FEATURE_ALPHATOCOVERAGE = 0;
35
37
  /** @internal */ _opacity;
36
38
  /** @internal */ _ctx;
37
39
  /** @internal */ _materialPass;
38
- /**
39
- * Creates an instance of MeshMaterial class
40
- * @param args - constructor arguments
40
+ /**
41
+ * Creates an instance of MeshMaterial class
42
+ * @param args - constructor arguments
41
43
  */ constructor(...args){
42
44
  super();
43
45
  this._featureStates = [];
@@ -56,6 +58,136 @@ let FEATURE_ALPHATOCOVERAGE = 0;
56
58
  this.NEXT_FEATURE_INDEX++;
57
59
  return val;
58
60
  }
61
+ /** Define instance uniform index */ static defineInstanceUniform(prop, type) {
62
+ if (this.INSTANCE_UNIFORMS.findIndex((val)=>val[0] === prop) >= 0) {
63
+ throw new Error(`${this.name}.defineInstanceUniform(): ${prop} was already defined`);
64
+ }
65
+ if (type !== 'float' && type !== 'vec2' && type !== 'vec3' && type !== 'vec4') {
66
+ throw new Error(`${this.name}.defineInstanceUniform(): invalid uniform type ${type}`);
67
+ }
68
+ this.INSTANCE_UNIFORMS = [
69
+ ...this.INSTANCE_UNIFORMS,
70
+ [
71
+ prop,
72
+ type
73
+ ]
74
+ ];
75
+ return this.INSTANCE_UNIFORMS.length - 1;
76
+ }
77
+ getInstancedUniform(scope, uniformIndex) {
78
+ //return ShaderHelper.getInstancedUniform(scope, 4 + uniformIndex);
79
+ const pb = scope.$builder;
80
+ const instanceID = pb.shaderKind === 'vertex' ? scope.$builtins.instanceIndex : scope.$inputs.zInstanceID;
81
+ const uniformName = ShaderHelper.getWorldMatricesUniformName();
82
+ const strideName = ShaderHelper.getInstanceBufferStrideUniformName();
83
+ return scope[uniformName].at(pb.add(pb.mul(scope[strideName], instanceID), 4 + uniformIndex));
84
+ }
85
+ /** Create material instance */ createInstance() {
86
+ const instanceUniforms = this.constructor.INSTANCE_UNIFORMS;
87
+ const uniformsHolder = instanceUniforms.length > 0 ? new Float32Array(4 * instanceUniforms.length) : null;
88
+ const batchable = Application.instance.device.type !== 'webgl';
89
+ // Copy original uniform values
90
+ for(let i = 0; i < instanceUniforms.length; i++){
91
+ const [prop, type] = instanceUniforms[i];
92
+ const value = this[prop];
93
+ switch(type){
94
+ case 'float':
95
+ {
96
+ uniformsHolder[i * 4] = Number(value);
97
+ break;
98
+ }
99
+ case 'vec2':
100
+ {
101
+ if (!(value instanceof Vector2)) {
102
+ throw new Error(`Instance uniform property ${prop} must be of type Vector2`);
103
+ }
104
+ uniformsHolder[i * 4] = value.x;
105
+ uniformsHolder[i * 4 + 1] = value.y;
106
+ break;
107
+ }
108
+ case 'vec3':
109
+ {
110
+ if (!(value instanceof Vector3)) {
111
+ throw new Error(`Instance uniform property ${prop} must be of type Vector3`);
112
+ }
113
+ uniformsHolder[i * 4] = value.x;
114
+ uniformsHolder[i * 4 + 1] = value.y;
115
+ uniformsHolder[i * 4 + 2] = value.z;
116
+ break;
117
+ }
118
+ case 'vec4':
119
+ {
120
+ if (!(value instanceof Vector4)) {
121
+ throw new Error(`Instance uniform property ${prop} must be of type Vector4`);
122
+ }
123
+ uniformsHolder[i * 4] = value.x;
124
+ uniformsHolder[i * 4 + 1] = value.y;
125
+ uniformsHolder[i * 4 + 2] = value.z;
126
+ uniformsHolder[i * 4 + 3] = value.w;
127
+ break;
128
+ }
129
+ }
130
+ }
131
+ const handler = {
132
+ get (target, prop, receiver) {
133
+ if (prop === 'isBatchable') {
134
+ return ()=>batchable;
135
+ } else if (prop === '$instanceUniforms') {
136
+ return uniformsHolder;
137
+ } else if (prop === '$isInstance') {
138
+ return true;
139
+ } else if (prop === 'beginDraw') {
140
+ if (!batchable || !target.isBatchable()) {
141
+ for(let i = 0; i < instanceUniforms.length; i++){
142
+ const name = instanceUniforms[i][0];
143
+ const type = instanceUniforms[i][1];
144
+ switch(type){
145
+ case 'float':
146
+ target[name] = uniformsHolder[i * 4];
147
+ break;
148
+ case 'vec2':
149
+ target[name] = new Vector2(uniformsHolder[i * 4], uniformsHolder[i * 4 + 1]);
150
+ break;
151
+ case 'vec3':
152
+ target[name] = new Vector3(uniformsHolder[i * 4], uniformsHolder[i * 4 + 1], uniformsHolder[i * 4 + 2]);
153
+ case 'vec4':
154
+ target[name] = new Vector4(uniformsHolder[i * 4], uniformsHolder[i * 4 + 1], uniformsHolder[i * 4 + 2], uniformsHolder[i * 4 + 3]);
155
+ }
156
+ }
157
+ }
158
+ } else if (typeof prop === 'string') {
159
+ const index = instanceUniforms.findIndex((val)=>val[0] === prop);
160
+ if (index >= 0) {
161
+ switch(instanceUniforms[index][1]){
162
+ case 'float':
163
+ return uniformsHolder[index * 4];
164
+ case 'vec2':
165
+ return new Vector2(uniformsHolder[index * 4], uniformsHolder[index * 4 + 1]);
166
+ case 'vec3':
167
+ return new Vector3(uniformsHolder[index * 4], uniformsHolder[index * 4 + 1], uniformsHolder[index * 4 + 2]);
168
+ case 'vec4':
169
+ return new Vector4(uniformsHolder[index * 4], uniformsHolder[index * 4 + 1], uniformsHolder[index * 4 + 2], uniformsHolder[index * 4 + 3]);
170
+ }
171
+ }
172
+ }
173
+ return Reflect.get(target, prop, receiver);
174
+ },
175
+ set (target, prop, value, receiver) {
176
+ const i = instanceUniforms.findIndex((val)=>val[0] === prop);
177
+ if (i >= 0) {
178
+ if (typeof value === 'number') {
179
+ uniformsHolder[i * 4 + 0] = value;
180
+ } else if (value instanceof Float32Array) {
181
+ uniformsHolder.set(value);
182
+ }
183
+ return true;
184
+ } else {
185
+ return Reflect.set(target, prop, value, receiver);
186
+ }
187
+ }
188
+ };
189
+ return new Proxy(this, handler);
190
+ }
59
191
  /** Draw context for shader creation */ get drawContext() {
60
192
  return this._ctx;
61
193
  }
@@ -107,10 +239,10 @@ let FEATURE_ALPHATOCOVERAGE = 0;
107
239
  /** Returns true if shading of the material will be affected by lights */ supportLighting() {
108
240
  return true;
109
241
  }
110
- /**
111
- * Update render states according to draw context and current material pass
112
- * @param pass - Current material pass
113
- * @param ctx - Draw context
242
+ /**
243
+ * Update render states according to draw context and current material pass
244
+ * @param pass - Current material pass
245
+ * @param ctx - Draw context
114
246
  */ updateRenderStates(pass, ctx) {
115
247
  const blending = this.featureUsed(FEATURE_ALPHABLEND) || ctx.lightBlending;
116
248
  const a2c = this.featureUsed(FEATURE_ALPHATOCOVERAGE);
@@ -144,12 +276,12 @@ let FEATURE_ALPHATOCOVERAGE = 0;
144
276
  this.stateSet.defaultRasterizerState();
145
277
  }
146
278
  }
147
- /**
148
- * Submit Uniform values before rendering with this material.
149
- *
150
- * @param bindGroup - Bind group for this material
151
- * @param ctx - Draw context
152
- * @param pass - Current pass of the material
279
+ /**
280
+ * Submit Uniform values before rendering with this material.
281
+ *
282
+ * @param bindGroup - Bind group for this material
283
+ * @param ctx - Draw context
284
+ * @param pass - Current pass of the material
153
285
  */ applyUniformValues(bindGroup, ctx, pass) {
154
286
  if (this.featureUsed(FEATURE_ALPHATEST)) {
155
287
  bindGroup.setValue('zAlphaCutoff', this._alphaCutoff);
@@ -158,21 +290,21 @@ let FEATURE_ALPHATOCOVERAGE = 0;
158
290
  bindGroup.setValue('zOpacity', this._opacity);
159
291
  }
160
292
  }
161
- /**
162
- * Determine which queue should be used to render this material.
163
- * @returns QUEUE_TRANSPARENT or QUEUE_OPAQUE
293
+ /**
294
+ * Determine which queue should be used to render this material.
295
+ * @returns QUEUE_TRANSPARENT or QUEUE_OPAQUE
164
296
  */ getQueueType() {
165
297
  return this.isTransparentPass(0) ? QUEUE_TRANSPARENT : QUEUE_OPAQUE;
166
298
  }
167
- /**
168
- * Determine if a certain pass of this material is translucent.
169
- * @param pass - Pass of the material
170
- * @returns True if it is translucent, otherwise false.
299
+ /**
300
+ * Determine if a certain pass of this material is translucent.
301
+ * @param pass - Pass of the material
302
+ * @returns True if it is translucent, otherwise false.
171
303
  */ isTransparentPass(pass) {
172
304
  return this.featureUsed(FEATURE_ALPHABLEND);
173
305
  }
174
- /**
175
- * {@inheritdoc Material.beginDraw}
306
+ /**
307
+ * {@inheritdoc Material.beginDraw}
176
308
  */ beginDraw(pass, ctx) {
177
309
  this.updateRenderStates(pass, ctx);
178
310
  return super.beginDraw(pass, ctx);
@@ -185,51 +317,51 @@ let FEATURE_ALPHATOCOVERAGE = 0;
185
317
  }
186
318
  return this._createProgram(pb, ctx, pass);
187
319
  }
188
- /**
189
- * Check if a feature is in use for given render pass type.
190
- *
191
- * @param feature - The feature index
192
- * @returns true if the feature is in use, otherwise false.
320
+ /**
321
+ * Check if a feature is in use for given render pass type.
322
+ *
323
+ * @param feature - The feature index
324
+ * @returns true if the feature is in use, otherwise false.
193
325
  */ featureUsed(feature) {
194
326
  return this._featureStates[feature];
195
327
  }
196
- /**
197
- * Use or unuse a feature of the material, this will cause the shader to be rebuild.
198
- *
199
- * @param feature - Which feature will be used or unused
200
- * @param use - true if use the feature, otherwise false
328
+ /**
329
+ * Use or unuse a feature of the material, this will cause the shader to be rebuild.
330
+ *
331
+ * @param feature - Which feature will be used or unused
332
+ * @param use - true if use the feature, otherwise false
201
333
  */ useFeature(feature, use) {
202
334
  if (this._featureStates[feature] !== use) {
203
335
  this._featureStates[feature] = use;
204
336
  this.optionChanged(true);
205
337
  }
206
338
  }
207
- /**
208
- * {@inheritDoc Material._createHash}
209
- * @override
210
- *
211
- * @internal
339
+ /**
340
+ * {@inheritDoc Material._createHash}
341
+ * @override
342
+ *
343
+ * @internal
212
344
  */ _createHash(renderPassType) {
213
345
  return this._featureStates.map((val)=>val === undefined ? '' : val).join('|');
214
346
  }
215
- /**
216
- * {@inheritDoc Material._applyUniforms}
217
- * @override
218
- *
219
- * @internal
347
+ /**
348
+ * {@inheritDoc Material._applyUniforms}
349
+ * @override
350
+ *
351
+ * @internal
220
352
  */ _applyUniforms(bindGroup, ctx, pass) {
221
353
  this.applyUniformValues(bindGroup, ctx, pass);
222
354
  }
223
- /**
224
- * Check if the color should be computed in fragment shader, this is required for forward render pass or alpha test is in use or alpha to coverage is in use.
225
- *
226
- * @returns - true if the color should be computed in fragment shader, otherwise false.
355
+ /**
356
+ * Check if the color should be computed in fragment shader, this is required for forward render pass or alpha test is in use or alpha to coverage is in use.
357
+ *
358
+ * @returns - true if the color should be computed in fragment shader, otherwise false.
227
359
  */ needFragmentColor(ctx) {
228
360
  return (ctx ?? this.drawContext).renderPass.type === RENDER_PASS_TYPE_LIGHT || this._alphaCutoff > 0 || this.alphaToCoverage;
229
361
  }
230
- /**
231
- * Vertex shader implementation of this material
232
- * @param scope - Shader scope
362
+ /**
363
+ * Vertex shader implementation of this material
364
+ * @param scope - Shader scope
233
365
  */ vertexShader(scope) {
234
366
  const pb = scope.$builder;
235
367
  ShaderHelper.prepareVertexShader(pb, this.drawContext);
@@ -237,10 +369,13 @@ let FEATURE_ALPHATOCOVERAGE = 0;
237
369
  scope.$inputs.zBlendIndices = pb.vec4().attrib('blendIndices');
238
370
  scope.$inputs.zBlendWeights = pb.vec4().attrib('blendWeights');
239
371
  }
372
+ if (this.drawContext.instanceData) {
373
+ scope.$outputs.zInstanceID = scope.$builtins.instanceIndex;
374
+ }
240
375
  }
241
- /**
242
- * Fragment shader implementation of this material
243
- * @param scope - Shader scope
376
+ /**
377
+ * Fragment shader implementation of this material
378
+ * @param scope - Shader scope
244
379
  */ fragmentShader(scope) {
245
380
  const pb = scope.$builder;
246
381
  ShaderHelper.prepareFragmentShader(pb, this.drawContext);
@@ -253,11 +388,11 @@ let FEATURE_ALPHATOCOVERAGE = 0;
253
388
  }
254
389
  }
255
390
  }
256
- /**
257
- * {@inheritDoc Material._createProgram}
258
- * @override
259
- *
260
- * @internal
391
+ /**
392
+ * {@inheritDoc Material._createProgram}
393
+ * @override
394
+ *
395
+ * @internal
261
396
  */ _createProgram(pb, ctx, pass) {
262
397
  const that = this;
263
398
  this._ctx = ctx;
@@ -275,20 +410,20 @@ let FEATURE_ALPHATOCOVERAGE = 0;
275
410
  });
276
411
  }
277
412
  });
278
- /*
279
- if (program) {
280
- console.log(program.getShaderSource('vertex'));
281
- console.log(program.getShaderSource('fragment'));
282
- }
413
+ /*
414
+ if (program) {
415
+ console.log(program.getShaderSource('vertex'));
416
+ console.log(program.getShaderSource('fragment'));
417
+ }
283
418
  */ return program;
284
419
  }
285
- /**
286
- * Calculate final fragment color for output.
287
- *
288
- * @param scope - Shader scope
289
- * @param color - Lit fragment color
290
- *
291
- * @returns The final fragment color
420
+ /**
421
+ * Calculate final fragment color for output.
422
+ *
423
+ * @param scope - Shader scope
424
+ * @param color - Lit fragment color
425
+ *
426
+ * @returns The final fragment color
292
427
  */ outputFragmentColor(scope, worldPos, color) {
293
428
  const pb = scope.$builder;
294
429
  const that = this;
@@ -1 +1 @@
1
- {"version":3,"file":"meshmaterial.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"meshmaterial.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}