@zephyr3d/scene 0.9.24 → 0.9.26
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/dist/animation/hair/gpu_hair_simulation.js +1090 -0
- package/dist/animation/hair/gpu_hair_simulation.js.map +1 -0
- package/dist/animation/joint_dynamics/controller.js +7 -5
- package/dist/animation/joint_dynamics/controller.js.map +1 -1
- package/dist/animation/joint_dynamics/joint_dynamics_system.js +81 -5
- package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
- package/dist/animation/morphtrack.js +3 -4
- package/dist/animation/morphtrack.js.map +1 -1
- package/dist/animation/skeleton.js +58 -24
- package/dist/animation/skeleton.js.map +1 -1
- package/dist/animation/spring/multi_chain_spring_system.js +577 -179
- package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
- package/dist/animation/spring/spring_collider.js +4 -3
- package/dist/animation/spring/spring_collider.js.map +1 -1
- package/dist/animation/spring/spring_node_pose_tracker.js +40 -0
- package/dist/animation/spring/spring_node_pose_tracker.js.map +1 -0
- package/dist/animation/spring/spring_particle.js +2 -0
- package/dist/animation/spring/spring_particle.js.map +1 -1
- package/dist/animation/spring/spring_system.js +11 -3
- package/dist/animation/spring/spring_system.js.map +1 -1
- package/dist/animation/spring_modifier.js +10 -0
- package/dist/animation/spring_modifier.js.map +1 -1
- package/dist/app/engine.js +53 -43
- package/dist/app/engine.js.map +1 -1
- package/dist/app/scriptingsystem.js +119 -6
- package/dist/app/scriptingsystem.js.map +1 -1
- package/dist/app/scriptregistry.js +3 -2
- package/dist/app/scriptregistry.js.map +1 -1
- package/dist/asset/assetmanager.js +284 -67
- package/dist/asset/assetmanager.js.map +1 -1
- package/dist/asset/loaders/zhair/zhair_format.js +288 -0
- package/dist/asset/loaders/zhair/zhair_format.js.map +1 -0
- package/dist/asset/loaders/zhair/zhair_loader.js +221 -0
- package/dist/asset/loaders/zhair/zhair_loader.js.map +1 -0
- package/dist/asset/model.js +178 -67
- package/dist/asset/model.js.map +1 -1
- package/dist/camera/camera.js +193 -21
- package/dist/camera/camera.js.map +1 -1
- package/dist/camera/perspectivecamera.js +3 -1
- package/dist/camera/perspectivecamera.js.map +1 -1
- package/dist/index.d.ts +4040 -1290
- package/dist/index.js +16 -6
- package/dist/index.js.map +1 -1
- package/dist/material/eye.js +932 -0
- package/dist/material/eye.js.map +1 -0
- package/dist/material/hair.js +917 -0
- package/dist/material/hair.js.map +1 -0
- package/dist/material/hairstrand.js +842 -0
- package/dist/material/hairstrand.js.map +1 -0
- package/dist/material/hairstrand_data.js +162 -0
- package/dist/material/hairstrand_data.js.map +1 -0
- package/dist/material/lambert.js +5 -2
- package/dist/material/lambert.js.map +1 -1
- package/dist/material/material.js +338 -300
- package/dist/material/material.js.map +1 -1
- package/dist/material/meshmaterial.js +120 -19
- package/dist/material/meshmaterial.js.map +1 -1
- package/dist/material/mixins/albedocolor.js +1 -1
- package/dist/material/mixins/albedocolor.js.map +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js +5 -3
- package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
- package/dist/material/mixins/lightmodel/lambert.js +5 -4
- package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +3 -3
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +5 -5
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js +3 -3
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
- package/dist/material/mixins/lit.js +73 -18
- package/dist/material/mixins/lit.js.map +1 -1
- package/dist/material/mixins/pbr/common.js +4 -4
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/mixins/texture.js +48 -11
- package/dist/material/mixins/texture.js.map +1 -1
- package/dist/material/mtoon.js +6 -5
- package/dist/material/mtoon.js.map +1 -1
- package/dist/material/pbrblueprint.js +146 -28
- package/dist/material/pbrblueprint.js.map +1 -1
- package/dist/material/pbrblueprint_instance.js +501 -0
- package/dist/material/pbrblueprint_instance.js.map +1 -0
- package/dist/material/pbrmr.js +15 -16
- package/dist/material/pbrmr.js.map +1 -1
- package/dist/material/shader/helper.js +766 -456
- package/dist/material/shader/helper.js.map +1 -1
- package/dist/material/shader/terrain_blend.js +55 -0
- package/dist/material/shader/terrain_blend.js.map +1 -0
- package/dist/material/skin.js +192 -32
- package/dist/material/skin.js.map +1 -1
- package/dist/material/spriteblueprint.js +16 -1
- package/dist/material/spriteblueprint.js.map +1 -1
- package/dist/material/subsurfaceprofile.js +86 -23
- package/dist/material/subsurfaceprofile.js.map +1 -1
- package/dist/material/water.js +3 -1
- package/dist/material/water.js.map +1 -1
- package/dist/posteffect/bloom.js +167 -7
- package/dist/posteffect/bloom.js.map +1 -1
- package/dist/posteffect/coloradjust.js +2 -1
- package/dist/posteffect/coloradjust.js.map +1 -1
- package/dist/posteffect/compositor.js.map +1 -1
- package/dist/posteffect/fxaa.js +2 -1
- package/dist/posteffect/fxaa.js.map +1 -1
- package/dist/posteffect/grayscale.js +3 -1
- package/dist/posteffect/grayscale.js.map +1 -1
- package/dist/posteffect/motionblur.js +4 -1
- package/dist/posteffect/motionblur.js.map +1 -1
- package/dist/posteffect/posteffect.js.map +1 -1
- package/dist/posteffect/skinsss.js +368 -69
- package/dist/posteffect/skinsss.js.map +1 -1
- package/dist/posteffect/ssgi.js +16 -9
- package/dist/posteffect/ssgi.js.map +1 -1
- package/dist/posteffect/ssr.js +3 -0
- package/dist/posteffect/ssr.js.map +1 -1
- package/dist/posteffect/sss.js +91 -34
- package/dist/posteffect/sss.js.map +1 -1
- package/dist/posteffect/taa.js.map +1 -1
- package/dist/posteffect/tonemap.js +44 -1
- package/dist/posteffect/tonemap.js.map +1 -1
- package/dist/render/abuffer_oit.js +45 -39
- package/dist/render/abuffer_oit.js.map +1 -1
- package/dist/render/cluster_light.js +4 -4
- package/dist/render/cluster_light.js.map +1 -1
- package/dist/render/cull_visitor.js +19 -0
- package/dist/render/cull_visitor.js.map +1 -1
- package/dist/render/depthpass.js +36 -2
- package/dist/render/depthpass.js.map +1 -1
- package/dist/render/drawable_mixin.js +26 -1
- package/dist/render/drawable_mixin.js.map +1 -1
- package/dist/render/dualdepthpeeling_oit.js +52 -51
- package/dist/render/dualdepthpeeling_oit.js.map +1 -1
- package/dist/render/envlight.js +1 -1
- package/dist/render/envlight.js.map +1 -1
- package/dist/render/fbm_wavegenerator.js +3 -0
- package/dist/render/fbm_wavegenerator.js.map +1 -1
- package/dist/render/gerstner_wavegenerator.js +3 -0
- package/dist/render/gerstner_wavegenerator.js.map +1 -1
- package/dist/render/globalbindgroup_allocator.js +3 -0
- package/dist/render/globalbindgroup_allocator.js.map +1 -1
- package/dist/render/oit.js +29 -0
- package/dist/render/oit.js.map +1 -0
- package/dist/render/render_queue.js +3 -0
- package/dist/render/render_queue.js.map +1 -1
- package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
- package/dist/render/rendergraph/executor.js +2 -0
- package/dist/render/rendergraph/executor.js.map +1 -1
- package/dist/render/rendergraph/forward_plus_builder.js +61 -1
- package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
- package/dist/render/rendergraph/rendergraph.js.map +1 -1
- package/dist/render/rendergraph/texture_affinity_cache.js +1 -1
- package/dist/render/rendergraph/texture_affinity_cache.js.map +1 -1
- package/dist/render/rendergraph/types.js.map +1 -1
- package/dist/render/shadow_mask_pass.js +73 -8
- package/dist/render/shadow_mask_pass.js.map +1 -1
- package/dist/render/sky.js +166 -126
- package/dist/render/sky.js.map +1 -1
- package/dist/render/weightedblended_oit.js +36 -35
- package/dist/render/weightedblended_oit.js.map +1 -1
- package/dist/scene/basesprite.js +8 -0
- package/dist/scene/basesprite.js.map +1 -1
- package/dist/scene/batchgroup.js +3 -0
- package/dist/scene/batchgroup.js.map +1 -1
- package/dist/scene/environment.js +4 -1
- package/dist/scene/environment.js.map +1 -1
- package/dist/scene/hair.js +963 -0
- package/dist/scene/hair.js.map +1 -0
- package/dist/scene/light.js +5 -1
- package/dist/scene/light.js.map +1 -1
- package/dist/scene/mesh.js +481 -47
- package/dist/scene/mesh.js.map +1 -1
- package/dist/scene/meshdrawable.js +6 -0
- package/dist/scene/meshdrawable.js.map +1 -1
- package/dist/scene/msdftext.js +3 -0
- package/dist/scene/msdftext.js.map +1 -1
- package/dist/scene/msdftextsprite.js +3 -0
- package/dist/scene/msdftextsprite.js.map +1 -1
- package/dist/scene/particlesys.js +6 -0
- package/dist/scene/particlesys.js.map +1 -1
- package/dist/scene/scene.js +3 -0
- package/dist/scene/scene.js.map +1 -1
- package/dist/scene/scene_node.js +6 -1
- package/dist/scene/scene_node.js.map +1 -1
- package/dist/scene/terrain-cm/grass.js +273 -249
- package/dist/scene/terrain-cm/grass.js.map +1 -1
- package/dist/scene/terrain-cm/grassmaterial.js +3 -0
- package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
- package/dist/scene/terrain-cm/terrain-cm.js +6 -0
- package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
- package/dist/scene/terrain-cm/texture_cache.js +309 -0
- package/dist/scene/terrain-cm/texture_cache.js.map +1 -0
- package/dist/scene/water.js +6 -0
- package/dist/scene/water.js.map +1 -1
- package/dist/shaders/atmosphere.js.map +1 -1
- package/dist/shaders/diffusion.js +54 -0
- package/dist/shaders/diffusion.js.map +1 -0
- package/dist/shaders/shadow.js +33 -21
- package/dist/shaders/shadow.js.map +1 -1
- package/dist/shaders/temporal.js +71 -33
- package/dist/shaders/temporal.js.map +1 -1
- package/dist/shadow/dom.js +546 -0
- package/dist/shadow/dom.js.map +1 -0
- package/dist/shadow/pcf_opt.js +3 -5
- package/dist/shadow/pcf_opt.js.map +1 -1
- package/dist/shadow/pcf_pd.js +1 -1
- package/dist/shadow/pcf_pd.js.map +1 -1
- package/dist/shadow/receiver_bias.js +41 -0
- package/dist/shadow/receiver_bias.js.map +1 -0
- package/dist/shadow/shader.js +20 -60
- package/dist/shadow/shader.js.map +1 -1
- package/dist/shadow/shadow_impl.js +89 -0
- package/dist/shadow/shadow_impl.js.map +1 -1
- package/dist/shadow/shadow_region.js +50 -50
- package/dist/shadow/shadow_region.js.map +1 -1
- package/dist/shadow/shadowmapper.js +150 -37
- package/dist/shadow/shadowmapper.js.map +1 -1
- package/dist/shapes/shape.js +11 -2
- package/dist/shapes/shape.js.map +1 -1
- package/dist/shapes/sphere.js +50 -9
- package/dist/shapes/sphere.js.map +1 -1
- package/dist/utility/blueprint/common/constants.js +112 -2
- package/dist/utility/blueprint/common/constants.js.map +1 -1
- package/dist/utility/blueprint/material/func.js +142 -49
- package/dist/utility/blueprint/material/func.js.map +1 -1
- package/dist/utility/blueprint/material/ir.js +490 -25
- package/dist/utility/blueprint/material/ir.js.map +1 -1
- package/dist/utility/blueprint/material/texture.js +898 -4
- package/dist/utility/blueprint/material/texture.js.map +1 -1
- package/dist/utility/serialization/manager.js +431 -100
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +370 -3
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/batch.js +4 -0
- package/dist/utility/serialization/scene/batch.js.map +1 -1
- package/dist/utility/serialization/scene/camera.js +133 -1
- package/dist/utility/serialization/scene/camera.js.map +1 -1
- package/dist/utility/serialization/scene/common.js +26 -5
- package/dist/utility/serialization/scene/common.js.map +1 -1
- package/dist/utility/serialization/scene/hair.js +1141 -0
- package/dist/utility/serialization/scene/hair.js.map +1 -0
- package/dist/utility/serialization/scene/light.js +84 -4
- package/dist/utility/serialization/scene/light.js.map +1 -1
- package/dist/utility/serialization/scene/material.js +1867 -166
- package/dist/utility/serialization/scene/material.js.map +1 -1
- package/dist/utility/serialization/scene/mesh.js +231 -14
- package/dist/utility/serialization/scene/mesh.js.map +1 -1
- package/dist/utility/serialization/scene/node.js +141 -7
- package/dist/utility/serialization/scene/node.js.map +1 -1
- package/dist/utility/serialization/scene/particle.js +4 -0
- package/dist/utility/serialization/scene/particle.js.map +1 -1
- package/dist/utility/serialization/scene/primitive.js +18 -0
- package/dist/utility/serialization/scene/primitive.js.map +1 -1
- package/dist/utility/serialization/scene/sprite.js +4 -0
- package/dist/utility/serialization/scene/sprite.js.map +1 -1
- package/dist/utility/serialization/scene/terrain.js +92 -69
- package/dist/utility/serialization/scene/terrain.js.map +1 -1
- package/dist/utility/serialization/scene/text.js +4 -0
- package/dist/utility/serialization/scene/text.js.map +1 -1
- package/dist/utility/serialization/scene/water.js +4 -0
- package/dist/utility/serialization/scene/water.js.map +1 -1
- package/dist/utility/serialization/types.js.map +1 -1
- package/dist/utility/shprojector.js +96 -95
- package/dist/utility/shprojector.js.map +1 -1
- package/dist/values.js +105 -58
- package/dist/values.js.map +1 -1
- package/package.json +3 -3
|
@@ -11,7 +11,10 @@ import '../../material/unlit.js';
|
|
|
11
11
|
import '../../material/particle.js';
|
|
12
12
|
import '../../material/subsurfaceprofile.js';
|
|
13
13
|
import '../../material/skin.js';
|
|
14
|
+
import '../../material/eye.js';
|
|
14
15
|
import '../../material/meshmaterial.js';
|
|
16
|
+
import '../../material/hair.js';
|
|
17
|
+
import '../../material/hairstrand.js';
|
|
15
18
|
import '../../material/grassmaterial.js';
|
|
16
19
|
import '../../material/terrain-cm.js';
|
|
17
20
|
import '../../material/pbrmr.js';
|
|
@@ -31,30 +34,40 @@ import '../../shaders/atmosphere.js';
|
|
|
31
34
|
import '../../render/rendergraph/scene_render_context.js';
|
|
32
35
|
import { ClipmapGrassMaterial } from './grassmaterial.js';
|
|
33
36
|
|
|
34
|
-
const MAX_INSTANCES_PER_NODE = 2048;
|
|
35
37
|
const INSTANCE_BYTES = 4 * 4;
|
|
38
|
+
/** Number of placement cells along each axis of a grass tile */ const TILE_CELLS = 64;
|
|
39
|
+
/** Default number of placement cells per density map texel along each axis */ const DEFAULT_CELLS_PER_TEXEL = 2;
|
|
40
|
+
const MAX_CELLS_PER_TEXEL = 8;
|
|
36
41
|
/**
|
|
37
|
-
*
|
|
42
|
+
* Deterministic 2D integer hash, returns a value in [0, 1).
|
|
43
|
+
* Grass placement derives everything (jitter, survival threshold, rotation)
|
|
44
|
+
* from this hash so that blade positions are stable across edits and reloads.
|
|
45
|
+
*/ function hashCell(x, z, seed) {
|
|
46
|
+
let h = Math.imul(x, 0x27d4eb2d) ^ Math.imul(z, 0x165667b1) ^ Math.imul(seed, 0x9e3779b9) | 0;
|
|
47
|
+
h = Math.imul(h ^ h >>> 15, 0x85ebca6b);
|
|
48
|
+
h = Math.imul(h ^ h >>> 13, 0xc2b2ae35);
|
|
49
|
+
h ^= h >>> 16;
|
|
50
|
+
return (h >>> 0) / 4294967296;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Grass blade instance buffer for a single tile
|
|
38
54
|
* @internal
|
|
39
55
|
*/ class GrassInstances extends Disposable {
|
|
40
|
-
|
|
56
|
+
_numInstances;
|
|
41
57
|
_baseVertexBuffer;
|
|
42
58
|
_indexBuffer;
|
|
43
59
|
_instanceBuffer;
|
|
44
60
|
_primitive;
|
|
45
61
|
constructor(baseVertexBuffer, indexBuffer){
|
|
46
62
|
super();
|
|
47
|
-
this.
|
|
63
|
+
this._numInstances = 0;
|
|
48
64
|
this._baseVertexBuffer = new DRef(baseVertexBuffer);
|
|
49
65
|
this._indexBuffer = new DRef(indexBuffer);
|
|
50
66
|
this._instanceBuffer = new DRef();
|
|
51
67
|
this._primitive = new DRef();
|
|
52
68
|
}
|
|
53
69
|
get numInstances() {
|
|
54
|
-
return this.
|
|
55
|
-
}
|
|
56
|
-
get instanceBuffer() {
|
|
57
|
-
return this._instanceBuffer.get();
|
|
70
|
+
return this._numInstances;
|
|
58
71
|
}
|
|
59
72
|
setBaseVertexBuffer(baseVertexBuffer) {
|
|
60
73
|
if (baseVertexBuffer !== this._baseVertexBuffer.get()) {
|
|
@@ -62,8 +75,25 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
62
75
|
this._primitive.dispose();
|
|
63
76
|
}
|
|
64
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Sets the packed instance data (x, y, sin, cos per instance)
|
|
80
|
+
*/ setData(data, count) {
|
|
81
|
+
this._numInstances = count;
|
|
82
|
+
if (count === 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const device = getDevice();
|
|
86
|
+
const bytesRequired = count * INSTANCE_BYTES;
|
|
87
|
+
let buffer = this._instanceBuffer.get();
|
|
88
|
+
if (!buffer || buffer.byteLength < bytesRequired) {
|
|
89
|
+
buffer = device.createVertexBuffer('tex1_f32x4', new Uint8Array(nextPowerOf2(bytesRequired)));
|
|
90
|
+
this._instanceBuffer.set(buffer);
|
|
91
|
+
this._primitive.dispose();
|
|
92
|
+
}
|
|
93
|
+
buffer.bufferSubData(0, data.subarray(0, count * 4));
|
|
94
|
+
}
|
|
65
95
|
draw() {
|
|
66
|
-
if (this.
|
|
96
|
+
if (this._numInstances > 0) {
|
|
67
97
|
if (!this._primitive.get()) {
|
|
68
98
|
const primitive = new Primitive();
|
|
69
99
|
primitive.setVertexBuffer(this._baseVertexBuffer.get());
|
|
@@ -74,58 +104,8 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
74
104
|
primitive.indexCount = this._indexBuffer.get().length;
|
|
75
105
|
this._primitive.set(primitive);
|
|
76
106
|
}
|
|
77
|
-
this._primitive.get().drawInstanced(this.
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
updateBuffers() {
|
|
81
|
-
const device = getDevice();
|
|
82
|
-
if (this._instances.length === 0) {
|
|
83
|
-
this._instanceBuffer.set(null);
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
if (this._instances.length > 0 && !this._instanceBuffer.get()) {
|
|
87
|
-
this._instanceBuffer.set(device.createVertexBuffer('tex1_f32x4', new Uint8Array(this._instances.length * INSTANCE_BYTES)));
|
|
88
|
-
}
|
|
89
|
-
let buffer = this._instanceBuffer.get();
|
|
90
|
-
const currentBytes = buffer.byteLength;
|
|
91
|
-
const bytesRequired = this._instances.length * INSTANCE_BYTES;
|
|
92
|
-
if (currentBytes < bytesRequired) {
|
|
93
|
-
buffer = device.createVertexBuffer('tex1_f32x4', new Uint8Array(nextPowerOf2(bytesRequired)));
|
|
94
|
-
this._instanceBuffer.set(buffer);
|
|
95
|
-
this._primitive.dispose();
|
|
96
|
-
}
|
|
97
|
-
const data = new Float32Array(4 * this._instances.length);
|
|
98
|
-
for(let i = 0; i < this._instances.length; i++){
|
|
99
|
-
data[i * 4 + 0] = this._instances[i].x;
|
|
100
|
-
data[i * 4 + 1] = this._instances[i].y;
|
|
101
|
-
data[i * 4 + 2] = Math.sin(this._instances[i].angle);
|
|
102
|
-
data[i * 4 + 3] = Math.cos(this._instances[i].angle);
|
|
103
|
-
}
|
|
104
|
-
buffer.bufferSubData(0, data);
|
|
105
|
-
}
|
|
106
|
-
removeInstances(minX, minZ, maxX, maxZ, num) {
|
|
107
|
-
if (num <= 0) {
|
|
108
|
-
return 0;
|
|
109
|
-
}
|
|
110
|
-
let removed = 0;
|
|
111
|
-
for(let i = this._instances.length - 1; i >= 0; i--){
|
|
112
|
-
const instance = this._instances[i];
|
|
113
|
-
if (instance.x >= minX && instance.x <= maxX && instance.y >= minZ && instance.y <= maxZ) {
|
|
114
|
-
this._instances.splice(i, 1);
|
|
115
|
-
removed++;
|
|
116
|
-
if (removed === num) {
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
if (removed > 0) {
|
|
122
|
-
this.updateBuffers();
|
|
107
|
+
this._primitive.get().drawInstanced(this._numInstances);
|
|
123
108
|
}
|
|
124
|
-
return removed;
|
|
125
|
-
}
|
|
126
|
-
addInstances(instances) {
|
|
127
|
-
this._instances.push(...instances);
|
|
128
|
-
this.updateBuffers();
|
|
129
109
|
}
|
|
130
110
|
onDispose() {
|
|
131
111
|
super.onDispose();
|
|
@@ -137,34 +117,53 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
137
117
|
}
|
|
138
118
|
/**
|
|
139
119
|
* Grass layer class
|
|
120
|
+
*
|
|
140
121
|
* @public
|
|
141
122
|
*/ class GrassLayer extends Disposable {
|
|
142
123
|
static _indexBuffer = new DRef();
|
|
124
|
+
static _cullAABB = new AABB();
|
|
125
|
+
static _visibleTiles = [];
|
|
126
|
+
static _instanceData = new Float32Array(TILE_CELLS * TILE_CELLS * 4);
|
|
143
127
|
_material;
|
|
144
|
-
|
|
128
|
+
_seed;
|
|
145
129
|
_bladeWidth;
|
|
146
130
|
_bladeHeight;
|
|
147
131
|
_baseVertexBuffer;
|
|
132
|
+
_densityWidth;
|
|
133
|
+
_densityHeight;
|
|
134
|
+
_cellsPerTexel;
|
|
135
|
+
_densityMap;
|
|
136
|
+
_tiles;
|
|
137
|
+
_tilesX;
|
|
138
|
+
_tilesZ;
|
|
139
|
+
_numBlades;
|
|
148
140
|
/**
|
|
149
141
|
* Creates an instance of GrassLayer
|
|
150
142
|
* @param terrain - Clipmap terrain object
|
|
143
|
+
* @param seed - Seed for deterministic blade placement, usually the layer index
|
|
151
144
|
* @param bladeWidth - Grass blade width
|
|
152
145
|
* @param bladeHeight - Grass blade height
|
|
153
146
|
* @param albedoMap - Albedo texture for the blade
|
|
154
|
-
*/ constructor(terrain, bladeWidth, bladeHeight, albedoMap){
|
|
147
|
+
*/ constructor(terrain, seed, bladeWidth, bladeHeight, albedoMap){
|
|
155
148
|
super();
|
|
156
149
|
this._material = new DRef(new ClipmapGrassMaterial(terrain));
|
|
157
150
|
this._material.get().albedoTexture = albedoMap ?? null;
|
|
158
151
|
if (albedoMap) {
|
|
159
152
|
this._material.get().setTextureSize(albedoMap.width, albedoMap.height);
|
|
160
153
|
}
|
|
154
|
+
this._seed = seed;
|
|
161
155
|
this._bladeWidth = bladeWidth;
|
|
162
156
|
this._bladeHeight = bladeHeight;
|
|
163
157
|
this._baseVertexBuffer = new DRef(this.createBaseVertexBuffer(this._bladeWidth, this._bladeHeight));
|
|
164
|
-
this.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
158
|
+
this._densityWidth = Math.max(1, terrain.sizeX);
|
|
159
|
+
this._densityHeight = Math.max(1, terrain.sizeZ);
|
|
160
|
+
this._cellsPerTexel = DEFAULT_CELLS_PER_TEXEL;
|
|
161
|
+
this._densityMap = new Uint8Array(this._densityWidth * this._densityHeight);
|
|
162
|
+
this._tiles = new Map();
|
|
163
|
+
this._tilesX = 0;
|
|
164
|
+
this._tilesZ = 0;
|
|
165
|
+
this._numBlades = 0;
|
|
166
|
+
this.updateTileGrid();
|
|
168
167
|
}
|
|
169
168
|
/** @internal */ updateMaterial() {
|
|
170
169
|
this._material.get().uniformChanged();
|
|
@@ -184,21 +183,93 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
184
183
|
*/ getAlbedoMap() {
|
|
185
184
|
return this._material.get().albedoTexture;
|
|
186
185
|
}
|
|
186
|
+
/** How many grass blades are currently generated in this layer */ get numBlades() {
|
|
187
|
+
return this._numBlades;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Density map of this layer, one byte per texel (0 = no grass, 255 = full density).
|
|
191
|
+
* Texel (x, z) covers the normalized terrain region [x/w..(x+1)/w, z/h..(z+1)/h].
|
|
192
|
+
* After modifying the data, call {@link GrassLayer.updateDensityRegion} to
|
|
193
|
+
* regenerate the affected blade instances.
|
|
194
|
+
*/ get densityMap() {
|
|
195
|
+
return this._densityMap;
|
|
196
|
+
}
|
|
197
|
+
/** Width of the density map in texels */ get densityMapWidth() {
|
|
198
|
+
return this._densityWidth;
|
|
199
|
+
}
|
|
200
|
+
/** Height of the density map in texels */ get densityMapHeight() {
|
|
201
|
+
return this._densityHeight;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Number of placement cells per density map texel along each axis.
|
|
205
|
+
* The maximum blade count per texel is the square of this value.
|
|
206
|
+
*/ get cellsPerTexel() {
|
|
207
|
+
return this._cellsPerTexel;
|
|
208
|
+
}
|
|
209
|
+
set cellsPerTexel(val) {
|
|
210
|
+
val = Math.max(1, Math.min(MAX_CELLS_PER_TEXEL, val | 0));
|
|
211
|
+
if (val !== this._cellsPerTexel) {
|
|
212
|
+
this._cellsPerTexel = val;
|
|
213
|
+
this.rebuild();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Replaces the density map and regenerates all blade instances
|
|
218
|
+
* @param width - Density map width in texels
|
|
219
|
+
* @param height - Density map height in texels
|
|
220
|
+
* @param cellsPerTexel - Placement cells per texel along each axis
|
|
221
|
+
* @param data - Density data, one byte per texel
|
|
222
|
+
*/ setDensityData(width, height, cellsPerTexel, data) {
|
|
223
|
+
if (width < 1 || height < 1 || width * height !== data.length) {
|
|
224
|
+
console.error('Invalid grass density data');
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
this._densityWidth = width;
|
|
228
|
+
this._densityHeight = height;
|
|
229
|
+
this._cellsPerTexel = Math.max(1, Math.min(MAX_CELLS_PER_TEXEL, cellsPerTexel | 0));
|
|
230
|
+
this._densityMap = data;
|
|
231
|
+
this.rebuild();
|
|
232
|
+
}
|
|
187
233
|
/**
|
|
188
|
-
*
|
|
189
|
-
* @param
|
|
190
|
-
|
|
191
|
-
|
|
234
|
+
* Regenerates blade instances for all tiles overlapping a density map region
|
|
235
|
+
* @param minTexelX - Minimum x texel of the region (inclusive)
|
|
236
|
+
* @param minTexelZ - Minimum z texel of the region (inclusive)
|
|
237
|
+
* @param maxTexelX - Maximum x texel of the region (exclusive)
|
|
238
|
+
* @param maxTexelZ - Maximum z texel of the region (exclusive)
|
|
239
|
+
*/ updateDensityRegion(minTexelX, minTexelZ, maxTexelX, maxTexelZ) {
|
|
240
|
+
const k = this._cellsPerTexel;
|
|
241
|
+
// expand by one texel to cover the bilinear sampling footprint
|
|
242
|
+
const cx0 = Math.max(0, (minTexelX - 1) * k);
|
|
243
|
+
const cz0 = Math.max(0, (minTexelZ - 1) * k);
|
|
244
|
+
const cx1 = Math.min(this._densityWidth * k, (maxTexelX + 1) * k);
|
|
245
|
+
const cz1 = Math.min(this._densityHeight * k, (maxTexelZ + 1) * k);
|
|
246
|
+
if (cx1 <= cx0 || cz1 <= cz0) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const tx0 = Math.floor(cx0 / TILE_CELLS);
|
|
250
|
+
const tz0 = Math.floor(cz0 / TILE_CELLS);
|
|
251
|
+
const tx1 = Math.min(this._tilesX, Math.ceil(cx1 / TILE_CELLS));
|
|
252
|
+
const tz1 = Math.min(this._tilesZ, Math.ceil(cz1 / TILE_CELLS));
|
|
253
|
+
for(let tz = tz0; tz < tz1; tz++){
|
|
254
|
+
for(let tx = tx0; tx < tx1; tx++){
|
|
255
|
+
this.generateTile(tx, tz);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
192
258
|
}
|
|
193
259
|
/**
|
|
194
|
-
*
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
this.
|
|
260
|
+
* Regenerates blade instances for the entire layer
|
|
261
|
+
*/ rebuild() {
|
|
262
|
+
for (const tile of this._tiles.values()){
|
|
263
|
+
tile.dispose();
|
|
264
|
+
}
|
|
265
|
+
this._tiles.clear();
|
|
266
|
+
this._numBlades = 0;
|
|
267
|
+
this.updateTileGrid();
|
|
268
|
+
for(let tz = 0; tz < this._tilesZ; tz++){
|
|
269
|
+
for(let tx = 0; tx < this._tilesX; tx++){
|
|
270
|
+
this.generateTile(tx, tz);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
202
273
|
}
|
|
203
274
|
/** Grass blade width in this layer */ get bladeWidth() {
|
|
204
275
|
return this._bladeWidth;
|
|
@@ -221,7 +292,92 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
221
292
|
this._bladeWidth = width;
|
|
222
293
|
this._bladeHeight = height;
|
|
223
294
|
this._baseVertexBuffer.set(this.createBaseVertexBuffer(this._bladeWidth, this._bladeHeight));
|
|
224
|
-
|
|
295
|
+
for (const tile of this._tiles.values()){
|
|
296
|
+
tile.setBaseVertexBuffer(this._baseVertexBuffer.get());
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/** @internal */ updateTileGrid() {
|
|
301
|
+
this._tilesX = Math.ceil(this._densityWidth * this._cellsPerTexel / TILE_CELLS);
|
|
302
|
+
this._tilesZ = Math.ceil(this._densityHeight * this._cellsPerTexel / TILE_CELLS);
|
|
303
|
+
}
|
|
304
|
+
/** @internal */ sampleDensity(u, v) {
|
|
305
|
+
const w = this._densityWidth;
|
|
306
|
+
const h = this._densityHeight;
|
|
307
|
+
const x = u * w - 0.5;
|
|
308
|
+
const z = v * h - 0.5;
|
|
309
|
+
const ix = Math.floor(x);
|
|
310
|
+
const iz = Math.floor(z);
|
|
311
|
+
const fx = x - ix;
|
|
312
|
+
const fz = z - iz;
|
|
313
|
+
const x0 = Math.min(Math.max(ix, 0), w - 1);
|
|
314
|
+
const x1 = Math.min(Math.max(ix + 1, 0), w - 1);
|
|
315
|
+
const z0 = Math.min(Math.max(iz, 0), h - 1);
|
|
316
|
+
const z1 = Math.min(Math.max(iz + 1, 0), h - 1);
|
|
317
|
+
const d = this._densityMap;
|
|
318
|
+
const a = d[z0 * w + x0] + (d[z0 * w + x1] - d[z0 * w + x0]) * fx;
|
|
319
|
+
const b = d[z1 * w + x0] + (d[z1 * w + x1] - d[z1 * w + x0]) * fx;
|
|
320
|
+
return (a + (b - a) * fz) * (1 / 255);
|
|
321
|
+
}
|
|
322
|
+
/** @internal */ regionIsEmpty(cx0, cz0, cx1, cz1) {
|
|
323
|
+
const k = this._cellsPerTexel;
|
|
324
|
+
const x0 = Math.max(0, Math.floor(cx0 / k) - 1);
|
|
325
|
+
const z0 = Math.max(0, Math.floor(cz0 / k) - 1);
|
|
326
|
+
const x1 = Math.min(this._densityWidth, Math.ceil(cx1 / k) + 1);
|
|
327
|
+
const z1 = Math.min(this._densityHeight, Math.ceil(cz1 / k) + 1);
|
|
328
|
+
for(let z = z0; z < z1; z++){
|
|
329
|
+
const rowBase = z * this._densityWidth;
|
|
330
|
+
for(let x = x0; x < x1; x++){
|
|
331
|
+
if (this._densityMap[rowBase + x] !== 0) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
/** @internal */ generateTile(tx, tz) {
|
|
339
|
+
const k = this._cellsPerTexel;
|
|
340
|
+
const cw = this._densityWidth * k;
|
|
341
|
+
const ch = this._densityHeight * k;
|
|
342
|
+
const cx0 = tx * TILE_CELLS;
|
|
343
|
+
const cz0 = tz * TILE_CELLS;
|
|
344
|
+
const cx1 = Math.min(cx0 + TILE_CELLS, cw);
|
|
345
|
+
const cz1 = Math.min(cz0 + TILE_CELLS, ch);
|
|
346
|
+
const key = tz * this._tilesX + tx;
|
|
347
|
+
let tile = this._tiles.get(key);
|
|
348
|
+
// fast path: nothing to generate if there is no tile yet and no density
|
|
349
|
+
if (!tile && this.regionIsEmpty(cx0, cz0, cx1, cz1)) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const data = GrassLayer._instanceData;
|
|
353
|
+
const seed = this._seed * 4;
|
|
354
|
+
let count = 0;
|
|
355
|
+
for(let cz = cz0; cz < cz1; cz++){
|
|
356
|
+
for(let cx = cx0; cx < cx1; cx++){
|
|
357
|
+
const u = (cx + hashCell(cx, cz, seed)) / cw;
|
|
358
|
+
const v = (cz + hashCell(cx, cz, seed + 1)) / ch;
|
|
359
|
+
if (this.sampleDensity(u, v) > hashCell(cx, cz, seed + 2)) {
|
|
360
|
+
const angle = hashCell(cx, cz, seed + 3) * Math.PI * 2;
|
|
361
|
+
data[count * 4 + 0] = u;
|
|
362
|
+
data[count * 4 + 1] = v;
|
|
363
|
+
data[count * 4 + 2] = Math.sin(angle);
|
|
364
|
+
data[count * 4 + 3] = Math.cos(angle);
|
|
365
|
+
count++;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
this._numBlades += count - (tile?.numInstances ?? 0);
|
|
370
|
+
if (count === 0) {
|
|
371
|
+
if (tile) {
|
|
372
|
+
tile.dispose();
|
|
373
|
+
this._tiles.delete(key);
|
|
374
|
+
}
|
|
375
|
+
} else {
|
|
376
|
+
if (!tile) {
|
|
377
|
+
tile = new GrassInstances(this._baseVertexBuffer.get(), GrassLayer._getIndexBuffer());
|
|
378
|
+
this._tiles.set(key, tile);
|
|
379
|
+
}
|
|
380
|
+
tile.setData(data, count);
|
|
225
381
|
}
|
|
226
382
|
}
|
|
227
383
|
/** @internal */ static _getIndexBuffer() {
|
|
@@ -323,16 +479,49 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
323
479
|
], vertices);
|
|
324
480
|
}
|
|
325
481
|
/** @internal */ draw(ctx, region, minY, maxY) {
|
|
482
|
+
const visible = GrassLayer._visibleTiles;
|
|
483
|
+
visible.length = 0;
|
|
484
|
+
const camera = ctx.camera;
|
|
485
|
+
const cullAABB = GrassLayer._cullAABB;
|
|
486
|
+
const cellsW = this._densityWidth * this._cellsPerTexel;
|
|
487
|
+
const cellsH = this._densityHeight * this._cellsPerTexel;
|
|
488
|
+
const rx = region.x;
|
|
489
|
+
const rz = region.y;
|
|
490
|
+
const rw = region.z - region.x;
|
|
491
|
+
const rh = region.w - region.y;
|
|
492
|
+
for (const [key, tile] of this._tiles){
|
|
493
|
+
const tx = key % this._tilesX;
|
|
494
|
+
const tz = (key - tx) / this._tilesX;
|
|
495
|
+
const u0 = tx * TILE_CELLS / cellsW;
|
|
496
|
+
const v0 = tz * TILE_CELLS / cellsH;
|
|
497
|
+
const u1 = Math.min(1, (tx + 1) * TILE_CELLS / cellsW);
|
|
498
|
+
const v1 = Math.min(1, (tz + 1) * TILE_CELLS / cellsH);
|
|
499
|
+
cullAABB.minPoint.setXYZ(rx + u0 * rw, minY, rz + v0 * rh);
|
|
500
|
+
cullAABB.maxPoint.setXYZ(rx + u1 * rw, maxY, rz + v1 * rh);
|
|
501
|
+
const clipState = camera.clipMask ? cullAABB.getClipStateWithFrustumMask(camera.frustum, camera.clipMask) : cullAABB.getClipStateWithFrustum(camera.frustum);
|
|
502
|
+
if (clipState !== ClipState.NOT_CLIPPED) {
|
|
503
|
+
visible.push(tile);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
if (visible.length === 0) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
326
509
|
this._material.get().apply(ctx);
|
|
327
510
|
for(let pass = 0; pass < this._material.get().numPasses; pass++){
|
|
328
511
|
this._material.get().bind(ctx.device, pass);
|
|
329
|
-
|
|
512
|
+
for (const tile of visible){
|
|
513
|
+
tile.draw();
|
|
514
|
+
}
|
|
330
515
|
}
|
|
516
|
+
visible.length = 0;
|
|
331
517
|
}
|
|
332
518
|
/** @internal */ onDispose() {
|
|
333
519
|
super.onDispose();
|
|
334
520
|
this._material.dispose();
|
|
335
|
-
this.
|
|
521
|
+
for (const tile of this._tiles.values()){
|
|
522
|
+
tile.dispose();
|
|
523
|
+
}
|
|
524
|
+
this._tiles.clear();
|
|
336
525
|
this._baseVertexBuffer.dispose();
|
|
337
526
|
}
|
|
338
527
|
}
|
|
@@ -341,7 +530,6 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
341
530
|
* @public
|
|
342
531
|
*/ class GrassRenderer extends Disposable {
|
|
343
532
|
_terrain;
|
|
344
|
-
_numGrassBlades;
|
|
345
533
|
_layers;
|
|
346
534
|
/**
|
|
347
535
|
* Creates an instance of GrassRenderer
|
|
@@ -349,7 +537,6 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
349
537
|
*/ constructor(terrain){
|
|
350
538
|
super();
|
|
351
539
|
this._terrain = new DWeakRef(terrain);
|
|
352
|
-
this._numGrassBlades = 0;
|
|
353
540
|
this._layers = [];
|
|
354
541
|
}
|
|
355
542
|
/** @internal */ updateMaterial() {
|
|
@@ -358,7 +545,7 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
358
545
|
}
|
|
359
546
|
}
|
|
360
547
|
/** How many grass blades */ get numGrassBlades() {
|
|
361
|
-
return this.
|
|
548
|
+
return this._layers.reduce((sum, layer)=>sum + layer.numBlades, 0);
|
|
362
549
|
}
|
|
363
550
|
/** How many grass layers */ get numLayers() {
|
|
364
551
|
return this._layers.length;
|
|
@@ -377,7 +564,7 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
377
564
|
* @param albedoMap - Albedo texture of grass blades in this layer
|
|
378
565
|
* @returns Index of the added grass layer
|
|
379
566
|
*/ addLayer(bladeWidth, bladeHeight, albedoMap) {
|
|
380
|
-
const layer = new GrassLayer(this._terrain.get(), bladeWidth, bladeHeight, albedoMap);
|
|
567
|
+
const layer = new GrassLayer(this._terrain.get(), this._layers.length, bladeWidth, bladeHeight, albedoMap);
|
|
381
568
|
this._layers.push(layer);
|
|
382
569
|
return this._layers.length - 1;
|
|
383
570
|
}
|
|
@@ -427,34 +614,6 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
427
614
|
console.error(`Invalid grass layer: ${layer}`);
|
|
428
615
|
}
|
|
429
616
|
}
|
|
430
|
-
/**
|
|
431
|
-
* Add grass instances to the grass layer at given index
|
|
432
|
-
* @param layer - Index of the grass layer
|
|
433
|
-
* @param instances - Grass blade instances to add
|
|
434
|
-
*/ addInstances(layer, instances) {
|
|
435
|
-
const grassLayer = this._layers[layer];
|
|
436
|
-
if (!grassLayer) {
|
|
437
|
-
console.error(`Invalid grass layer: ${layer}`);
|
|
438
|
-
} else {
|
|
439
|
-
this._numGrassBlades += grassLayer.addInstances(instances);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
/**
|
|
443
|
-
* Remove grass instances from the grass layer at given index within a region
|
|
444
|
-
* @param layer - Index of the grass layer
|
|
445
|
-
* @param minX - Minimum x of the region
|
|
446
|
-
* @param minZ - Minimum z of the region
|
|
447
|
-
* @param maxX - Maximum x of the region
|
|
448
|
-
* @param maxZ - Maximum z of the region
|
|
449
|
-
* @param num - How many grass blades to remove
|
|
450
|
-
*/ removeInstances(layer, minX, minZ, maxX, maxZ, num) {
|
|
451
|
-
const grassLayer = this._layers[layer];
|
|
452
|
-
if (!grassLayer) {
|
|
453
|
-
console.error(`Invalid grass layer: ${layer}`);
|
|
454
|
-
} else {
|
|
455
|
-
grassLayer.removeInstances(minX, minZ, maxX, maxZ, num);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
617
|
/** @internal */ draw(ctx) {
|
|
459
618
|
const bv = this._terrain.get().getWorldBoundingVolume().toAABB();
|
|
460
619
|
const minY = bv.minPoint.y;
|
|
@@ -471,141 +630,6 @@ const INSTANCE_BYTES = 4 * 4;
|
|
|
471
630
|
}
|
|
472
631
|
}
|
|
473
632
|
}
|
|
474
|
-
/** @internal */ class GrassQuadtreeNode extends Disposable {
|
|
475
|
-
static _cullAABB = new AABB();
|
|
476
|
-
_grassInstances;
|
|
477
|
-
_children;
|
|
478
|
-
_baseVertexBuffer;
|
|
479
|
-
_indexBuffer;
|
|
480
|
-
_minX;
|
|
481
|
-
_minZ;
|
|
482
|
-
_maxX;
|
|
483
|
-
_maxZ;
|
|
484
|
-
constructor(baseVertexBuffer, indexBuffer){
|
|
485
|
-
super();
|
|
486
|
-
this._baseVertexBuffer = new DRef(baseVertexBuffer);
|
|
487
|
-
this._indexBuffer = new DRef(indexBuffer);
|
|
488
|
-
this._grassInstances = new DRef(new GrassInstances(baseVertexBuffer, indexBuffer));
|
|
489
|
-
this._children = null;
|
|
490
|
-
this._minX = 0;
|
|
491
|
-
this._minZ = 0;
|
|
492
|
-
this._maxX = 1;
|
|
493
|
-
this._maxZ = 1;
|
|
494
|
-
}
|
|
495
|
-
get grassInstances() {
|
|
496
|
-
return this._grassInstances.get();
|
|
497
|
-
}
|
|
498
|
-
get children() {
|
|
499
|
-
return this._children;
|
|
500
|
-
}
|
|
501
|
-
draw(camera, region, minY, maxY, skipClipTest) {
|
|
502
|
-
if (!skipClipTest) {
|
|
503
|
-
const cullAABB = GrassQuadtreeNode._cullAABB;
|
|
504
|
-
const x = region.x;
|
|
505
|
-
const z = region.y;
|
|
506
|
-
const dx = region.z - x;
|
|
507
|
-
const dz = region.w - z;
|
|
508
|
-
cullAABB.minPoint.setXYZ(x + this._minX * dx, minY, z + this._minZ * dz);
|
|
509
|
-
cullAABB.maxPoint.setXYZ(x + this._maxX * dx, maxY, z + this._maxZ * dz);
|
|
510
|
-
const clipState = camera.clipMask ? cullAABB.getClipStateWithFrustumMask(camera.frustum, camera.clipMask) : cullAABB.getClipStateWithFrustum(camera.frustum);
|
|
511
|
-
if (clipState === ClipState.NOT_CLIPPED) {
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
skipClipTest = clipState === ClipState.A_INSIDE_B;
|
|
515
|
-
}
|
|
516
|
-
if (this._grassInstances.get().numInstances > 0) {
|
|
517
|
-
this._grassInstances.get().draw();
|
|
518
|
-
}
|
|
519
|
-
if (this._children) {
|
|
520
|
-
for (const child of this._children){
|
|
521
|
-
child.draw(camera, region, minY, maxY, skipClipTest);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
setBaseVertexBuffer(baseVertexBuffer) {
|
|
526
|
-
if (baseVertexBuffer !== this._baseVertexBuffer.get()) {
|
|
527
|
-
this._baseVertexBuffer.set(baseVertexBuffer);
|
|
528
|
-
this._grassInstances.get().setBaseVertexBuffer(baseVertexBuffer);
|
|
529
|
-
if (this._children) {
|
|
530
|
-
for (const child of this._children){
|
|
531
|
-
child.setBaseVertexBuffer(baseVertexBuffer);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
removeInstances(minX, minZ, maxX, maxZ, numInstances) {
|
|
537
|
-
let n = Math.min(this._grassInstances.get().numInstances, numInstances);
|
|
538
|
-
if (n <= 0) {
|
|
539
|
-
return 0;
|
|
540
|
-
}
|
|
541
|
-
let removed = 0;
|
|
542
|
-
if (this._children) {
|
|
543
|
-
for (const child of this._children){
|
|
544
|
-
if (child._minX < maxX && child._minZ < maxZ && child._maxX > minX && child._maxZ > minZ) {
|
|
545
|
-
removed += child.removeInstances(minX, minZ, maxX, maxZ, n);
|
|
546
|
-
n -= removed;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
if (n > 0) {
|
|
551
|
-
removed += this._grassInstances.get().removeInstances(minX, minZ, maxX, maxZ, n);
|
|
552
|
-
}
|
|
553
|
-
return removed;
|
|
554
|
-
}
|
|
555
|
-
addInstances(instances) {
|
|
556
|
-
if (instances.length === 0) {
|
|
557
|
-
return 0;
|
|
558
|
-
}
|
|
559
|
-
let n = Math.min(instances.length, MAX_INSTANCES_PER_NODE - this._grassInstances.get().numInstances);
|
|
560
|
-
this._grassInstances.get().addInstances(instances.slice(0, n));
|
|
561
|
-
if (n < instances.length) {
|
|
562
|
-
if (!this._children) {
|
|
563
|
-
this._children = [
|
|
564
|
-
new GrassQuadtreeNode(this._baseVertexBuffer.get(), this._indexBuffer.get()),
|
|
565
|
-
new GrassQuadtreeNode(this._baseVertexBuffer.get(), this._indexBuffer.get()),
|
|
566
|
-
new GrassQuadtreeNode(this._baseVertexBuffer.get(), this._indexBuffer.get()),
|
|
567
|
-
new GrassQuadtreeNode(this._baseVertexBuffer.get(), this._indexBuffer.get())
|
|
568
|
-
];
|
|
569
|
-
this._children[0]._minX = this._minX;
|
|
570
|
-
this._children[0]._minZ = this._minZ;
|
|
571
|
-
this._children[0]._maxX = (this._minX + this._maxX) * 0.5;
|
|
572
|
-
this._children[0]._maxZ = (this._minZ + this._maxZ) * 0.5;
|
|
573
|
-
this._children[1]._minX = this._children[0]._maxX;
|
|
574
|
-
this._children[1]._minZ = this._minZ;
|
|
575
|
-
this._children[1]._maxX = this._maxX;
|
|
576
|
-
this._children[1]._maxZ = this._children[0]._maxZ;
|
|
577
|
-
this._children[2]._minX = this._minX;
|
|
578
|
-
this._children[2]._minZ = this._children[0]._maxZ;
|
|
579
|
-
this._children[2]._maxX = this._children[0]._maxX;
|
|
580
|
-
this._children[2]._maxZ = this._maxZ;
|
|
581
|
-
this._children[3]._minX = this._children[0]._maxX;
|
|
582
|
-
this._children[3]._minZ = this._children[0]._maxZ;
|
|
583
|
-
this._children[3]._maxX = this._maxX;
|
|
584
|
-
this._children[3]._maxZ = this._maxZ;
|
|
585
|
-
}
|
|
586
|
-
instances = instances.slice(n);
|
|
587
|
-
for (const child of this._children){
|
|
588
|
-
if (instances.length > 0) {
|
|
589
|
-
const childInstances = instances.filter((val)=>val.x >= child._minX && val.y >= child._minZ && val.x < child._maxX && val.y < child._maxZ);
|
|
590
|
-
n += child.addInstances(childInstances);
|
|
591
|
-
instances = instances.filter((val)=>!(val.x >= child._minX && val.y >= child._minZ && val.x < child._maxX && val.y < child._maxZ));
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
return n;
|
|
596
|
-
}
|
|
597
|
-
onDispose() {
|
|
598
|
-
super.onDispose();
|
|
599
|
-
this._baseVertexBuffer.dispose();
|
|
600
|
-
this._indexBuffer.dispose();
|
|
601
|
-
this._grassInstances.dispose();
|
|
602
|
-
if (this._children) {
|
|
603
|
-
for (const child of this._children){
|
|
604
|
-
child.dispose();
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
633
|
|
|
610
|
-
export { GrassInstances, GrassLayer,
|
|
634
|
+
export { GrassInstances, GrassLayer, GrassRenderer };
|
|
611
635
|
//# sourceMappingURL=grass.js.map
|