@zephyr3d/scene 0.9.25 → 0.9.27
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/animationset.js +92 -30
- package/dist/animation/animationset.js.map +1 -1
- 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/convex_collider.js +320 -0
- package/dist/animation/joint_dynamics/convex_collider.js.map +1 -0
- 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 +79 -25
- 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 +184 -69
- package/dist/asset/model.js.map +1 -1
- package/dist/camera/camera.js +268 -44
- 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 +9044 -5139
- package/dist/index.js +17 -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 +48 -10
- 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 +106 -19
- 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 +734 -23
- 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 +2059 -72
- 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 +664 -56
- package/dist/posteffect/motionblur.js.map +1 -1
- package/dist/posteffect/posteffect.js +12 -1
- package/dist/posteffect/posteffect.js.map +1 -1
- package/dist/posteffect/sao.js +46 -44
- package/dist/posteffect/sao.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 +121 -36
- 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 +8 -2
- package/dist/render/abuffer_oit.js.map +1 -1
- package/dist/render/clipmap.js +156 -5
- package/dist/render/clipmap.js.map +1 -1
- package/dist/render/cull_visitor.js +20 -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 +3 -2
- 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 +6 -3
- package/dist/render/fbm_wavegenerator.js.map +1 -1
- package/dist/render/fft_wavegenerator.js +57 -15
- package/dist/render/fft_wavegenerator.js.map +1 -1
- package/dist/render/gerstner_wavegenerator.js +130 -20
- 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/hzb.js +80 -22
- package/dist/render/hzb.js.map +1 -1
- package/dist/render/lightpass.js +6 -3
- package/dist/render/lightpass.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 +39 -0
- package/dist/render/render_queue.js.map +1 -1
- package/dist/render/renderer.js +4 -0
- package/dist/render/renderer.js.map +1 -1
- package/dist/render/rendergraph/blackboard.js +1 -0
- package/dist/render/rendergraph/blackboard.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 +379 -10
- package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
- package/dist/render/rendergraph/frame_resource_requirements.js +1 -0
- package/dist/render/rendergraph/frame_resource_requirements.js.map +1 -1
- package/dist/render/rendergraph/history_resources.js +8 -1
- package/dist/render/rendergraph/history_resources.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/underwater.js +624 -0
- package/dist/render/underwater.js.map +1 -0
- package/dist/render/water_caustics.js +1380 -0
- package/dist/render/water_caustics.js.map +1 -0
- package/dist/render/weightedblended_oit.js +3 -2
- 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 +3 -0
- 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 +546 -4
- 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/shaders/water.js +22 -19
- package/dist/shaders/water.js.map +1 -1
- package/dist/shaders/water_medium.js +56 -0
- package/dist/shaders/water_medium.js.map +1 -0
- 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 +1 -1
- 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 +434 -101
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +401 -5
- 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 +186 -26
- 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 +4 -0
- 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 +1105 -21
- package/dist/utility/serialization/scene/water.js.map +1 -1
- package/dist/utility/serialization/types.js.map +1 -1
- package/dist/utility/shprojector.js +9 -8
- package/dist/utility/shprojector.js.map +1 -1
- package/dist/values.js +49 -2
- package/dist/values.js.map +1 -1
- package/package.json +3 -3
- package/dist/render/rendergraph/frame_graph_context.js +0 -41
- package/dist/render/rendergraph/frame_graph_context.js.map +0 -1
- package/dist/shaders/ssgi.js +0 -63
- package/dist/shaders/ssgi.js.map +0 -1
- package/dist/shaders/ssgi_reprojection.js +0 -118
- package/dist/shaders/ssgi_reprojection.js.map +0 -1
package/dist/scene/mesh.js
CHANGED
|
@@ -7,11 +7,14 @@ import '../material/unlit.js';
|
|
|
7
7
|
import '../material/particle.js';
|
|
8
8
|
import '../material/subsurfaceprofile.js';
|
|
9
9
|
import '../material/skin.js';
|
|
10
|
+
import '../material/eye.js';
|
|
10
11
|
import { PBStructTypeInfo, PBArrayTypeInfo, PBPrimitiveTypeInfo, PBPrimitiveType } from '@zephyr3d/device';
|
|
11
|
-
import { MORPH_WEIGHTS_VECTOR_COUNT, MORPH_ATTRIBUTE_VECTOR_COUNT,
|
|
12
|
+
import { QUEUE_OPAQUE, MORPH_WEIGHTS_VECTOR_COUNT, MORPH_ATTRIBUTE_VECTOR_COUNT, getMorphTargetLimit, getActiveMorphTargetLimit } from '../values.js';
|
|
12
13
|
import { RenderBundleWrapper } from '../render/renderbundle_wrapper.js';
|
|
13
14
|
import { getDevice } from '../app/api.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';
|
|
@@ -25,6 +28,40 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
25
28
|
import { mixinDrawable } from '../render/drawable_mixin.js';
|
|
26
29
|
import { calculateMorphBoundingBox } from '../animation/morphtarget.js';
|
|
27
30
|
|
|
31
|
+
const MORPH_WEIGHT_CAPACITY = MORPH_WEIGHTS_VECTOR_COUNT * 4;
|
|
32
|
+
const MORPH_ATTRIBUTE_CAPACITY = MORPH_ATTRIBUTE_VECTOR_COUNT * 4;
|
|
33
|
+
const MORPH_INFO_DATA_LENGTH = 4 + MORPH_WEIGHT_CAPACITY + MORPH_ATTRIBUTE_CAPACITY;
|
|
34
|
+
const MORPH_RENDER_INDEX_OFFSET = 4 + MORPH_WEIGHT_CAPACITY;
|
|
35
|
+
const MORPH_RENDER_ATTRIBUTE_OFFSET = MORPH_RENDER_INDEX_OFFSET + MORPH_WEIGHT_CAPACITY;
|
|
36
|
+
const MORPH_RENDER_INFO_DATA_LENGTH = MORPH_RENDER_ATTRIBUTE_OFFSET + MORPH_ATTRIBUTE_CAPACITY;
|
|
37
|
+
const ACTIVE_MORPH_WEIGHT_EPSILON = 1e-5;
|
|
38
|
+
function normalizeMorphInfoData(data) {
|
|
39
|
+
const normalized = new Float32Array(MORPH_INFO_DATA_LENGTH);
|
|
40
|
+
for(let i = 0; i < MORPH_ATTRIBUTE_CAPACITY; i++){
|
|
41
|
+
normalized[4 + MORPH_WEIGHT_CAPACITY + i] = -1;
|
|
42
|
+
}
|
|
43
|
+
normalized.set(data.subarray(0, Math.min(data.length, normalized.length)));
|
|
44
|
+
const declaredCount = Math.max(0, Math.floor(Number(normalized[3]) || 0));
|
|
45
|
+
const supportedCount = Math.min(declaredCount, getMorphTargetLimit(), MORPH_WEIGHT_CAPACITY, Math.max(0, data.length - 4));
|
|
46
|
+
normalized[3] = supportedCount;
|
|
47
|
+
return {
|
|
48
|
+
data: normalized,
|
|
49
|
+
declaredCount,
|
|
50
|
+
supportedCount
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function createMorphInfoBuffer(data) {
|
|
54
|
+
const bufferData = new Float32Array(data);
|
|
55
|
+
const bufferType = new PBStructTypeInfo('dummy', 'std140', [
|
|
56
|
+
{
|
|
57
|
+
name: ShaderHelper.getMorphInfoUniformName(),
|
|
58
|
+
type: new PBArrayTypeInfo(new PBPrimitiveTypeInfo(PBPrimitiveType.F32VEC4), 1 + MORPH_WEIGHTS_VECTOR_COUNT * 2 + MORPH_ATTRIBUTE_VECTOR_COUNT)
|
|
59
|
+
}
|
|
60
|
+
]);
|
|
61
|
+
return getDevice().createStructuredBuffer(bufferType, {
|
|
62
|
+
usage: 'uniform'
|
|
63
|
+
}, bufferData);
|
|
64
|
+
}
|
|
28
65
|
const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
29
66
|
/**
|
|
30
67
|
* Mesh node
|
|
@@ -37,9 +74,16 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
37
74
|
/** @internal */ _animatedBoundingBox;
|
|
38
75
|
/** @internal */ _skinBindingName;
|
|
39
76
|
/** @internal */ _boneMatrices;
|
|
77
|
+
/** @internal */ _skinInfluenceData;
|
|
40
78
|
/** @internal */ _morphData;
|
|
41
79
|
/** @internal */ _morphInfo;
|
|
80
|
+
/** @internal */ _renderMorphInfo;
|
|
42
81
|
/** @internal */ _morphBoundingInfo;
|
|
82
|
+
/** @internal */ _morphSource;
|
|
83
|
+
/** @internal */ _morphSourceData;
|
|
84
|
+
/** @internal */ _activeMorphTargetIndices;
|
|
85
|
+
/** @internal */ _compactMorphData;
|
|
86
|
+
/** @internal */ _activeMorphCandidates;
|
|
43
87
|
/** @internal */ _morphDirty;
|
|
44
88
|
/** @internal */ _instanceHash;
|
|
45
89
|
/** @internal */ _batchable;
|
|
@@ -61,9 +105,16 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
61
105
|
this._skinnedBoundingInfo = null;
|
|
62
106
|
this._animatedBoundingBox = null;
|
|
63
107
|
this._boneMatrices = new DRef();
|
|
108
|
+
this._skinInfluenceData = null;
|
|
64
109
|
this._morphData = null;
|
|
65
110
|
this._morphInfo = null;
|
|
111
|
+
this._renderMorphInfo = null;
|
|
66
112
|
this._morphBoundingInfo = null;
|
|
113
|
+
this._morphSource = null;
|
|
114
|
+
this._morphSourceData = null;
|
|
115
|
+
this._activeMorphTargetIndices = new Uint32Array(0);
|
|
116
|
+
this._compactMorphData = false;
|
|
117
|
+
this._activeMorphCandidates = [];
|
|
67
118
|
this._morphDirty = false;
|
|
68
119
|
this._instanceHash = null;
|
|
69
120
|
this._pickTarget = {
|
|
@@ -154,6 +205,12 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
154
205
|
this.invalidateBoundingVolume();
|
|
155
206
|
RenderBundleWrapper.drawableChanged(this);
|
|
156
207
|
this._primitiveChangeTag = null;
|
|
208
|
+
if (this._morphData) {
|
|
209
|
+
this._ensureWebGLVertexIndexAttribute('morphing');
|
|
210
|
+
}
|
|
211
|
+
if (this._skinInfluenceData && this._skinInfluenceData.influenceCount > 4) {
|
|
212
|
+
this._ensureWebGLVertexIndexAttribute('skinning');
|
|
213
|
+
}
|
|
157
214
|
this.dispatchEvent('primitive_changed', prim);
|
|
158
215
|
}
|
|
159
216
|
}
|
|
@@ -215,12 +272,61 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
215
272
|
}
|
|
216
273
|
}
|
|
217
274
|
/**
|
|
275
|
+
* Sets additional per-vertex skinning influences packed in a texture.
|
|
276
|
+
* The first 4 influences remain in the vertex attributes; this payload stores the remainder.
|
|
277
|
+
* @param data - Extra influence texture payload, or null to clear it
|
|
278
|
+
*/ setSkinInfluenceData(data) {
|
|
279
|
+
if (!data) {
|
|
280
|
+
if (this._skinInfluenceData) {
|
|
281
|
+
this._skinInfluenceData.texture?.get()?.dispose();
|
|
282
|
+
this._skinInfluenceData = null;
|
|
283
|
+
this._renderBundle = {};
|
|
284
|
+
RenderBundleWrapper.drawableChanged(this);
|
|
285
|
+
}
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (!this._skinInfluenceData) {
|
|
289
|
+
this._skinInfluenceData = {
|
|
290
|
+
texture: new DRef(),
|
|
291
|
+
width: 0,
|
|
292
|
+
height: 0,
|
|
293
|
+
influenceCount: 4,
|
|
294
|
+
data: new Float32Array(0)
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
this._skinInfluenceData.width = data.width;
|
|
298
|
+
this._skinInfluenceData.height = data.height;
|
|
299
|
+
this._skinInfluenceData.influenceCount = data.influenceCount;
|
|
300
|
+
this._skinInfluenceData.data = data.data.slice();
|
|
301
|
+
if (data.texture?.get()) {
|
|
302
|
+
this._skinInfluenceData.texture.set(data.texture.get());
|
|
303
|
+
} else {
|
|
304
|
+
let tex = this._skinInfluenceData.texture?.get() ?? null;
|
|
305
|
+
if (!tex || tex.width !== data.width || tex.height !== data.height) {
|
|
306
|
+
tex?.dispose();
|
|
307
|
+
tex = getDevice().createTexture2D('rgba32f', data.width, data.height, {
|
|
308
|
+
mipmapping: false,
|
|
309
|
+
samplerOptions: {
|
|
310
|
+
minFilter: 'nearest',
|
|
311
|
+
magFilter: 'nearest',
|
|
312
|
+
mipFilter: 'none'
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
this._skinInfluenceData.texture.set(tex);
|
|
316
|
+
}
|
|
317
|
+
tex.update(data.data, 0, 0, data.width, data.height);
|
|
318
|
+
}
|
|
319
|
+
this._ensureWebGLVertexIndexAttribute('skinning');
|
|
320
|
+
this._renderBundle = {};
|
|
321
|
+
RenderBundleWrapper.drawableChanged(this);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
218
324
|
* Sets the texture that contains the morph target data
|
|
219
325
|
* @param data - The texture that contains the morph target data
|
|
220
326
|
*/ setMorphData(data) {
|
|
221
327
|
if (!data) {
|
|
222
328
|
if (this._morphData) {
|
|
223
|
-
this._morphData
|
|
329
|
+
this._morphData.texture?.get()?.dispose();
|
|
224
330
|
this._morphData = null;
|
|
225
331
|
this._renderBundle = {};
|
|
226
332
|
RenderBundleWrapper.drawableChanged(this);
|
|
@@ -237,19 +343,27 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
237
343
|
if (data.texture?.get()) {
|
|
238
344
|
this._morphData.texture.set(data.texture.get());
|
|
239
345
|
} else {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
346
|
+
let tex = this._morphData.texture?.get() ?? null;
|
|
347
|
+
if (!tex || tex.width !== data.width || tex.height !== data.height) {
|
|
348
|
+
tex?.dispose();
|
|
349
|
+
tex = getDevice().createTexture2D('rgba32f', data.width, data.height, {
|
|
350
|
+
mipmapping: false,
|
|
351
|
+
samplerOptions: {
|
|
352
|
+
minFilter: 'nearest',
|
|
353
|
+
magFilter: 'nearest',
|
|
354
|
+
mipFilter: 'none'
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
this._morphData.texture.set(tex);
|
|
358
|
+
}
|
|
248
359
|
tex.update(data.data, 0, 0, data.width, data.height);
|
|
249
|
-
this._morphData.texture.set(tex);
|
|
250
360
|
}
|
|
361
|
+
this._ensureWebGLVertexIndexAttribute('morphing');
|
|
251
362
|
this._renderBundle = {};
|
|
252
363
|
RenderBundleWrapper.drawableChanged(this);
|
|
364
|
+
if (this._morphInfo && !this._morphSourceData) {
|
|
365
|
+
this.updateRenderMorphInfo(this.collectActiveMorphTargetIndices(), false);
|
|
366
|
+
}
|
|
253
367
|
}
|
|
254
368
|
}
|
|
255
369
|
/**
|
|
@@ -264,41 +378,86 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
264
378
|
return this._morphData;
|
|
265
379
|
}
|
|
266
380
|
/**
|
|
381
|
+
* {@inheritDoc Drawable.getSkinInfluenceData}
|
|
382
|
+
*/ getSkinInfluenceData() {
|
|
383
|
+
return this._skinInfluenceData;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Gets the external morph source descriptor.
|
|
387
|
+
*/ getMorphSource() {
|
|
388
|
+
return this._morphSource;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Sets the external morph source descriptor.
|
|
392
|
+
* @param source - The morph source descriptor
|
|
393
|
+
*/ setMorphSource(source) {
|
|
394
|
+
this._morphSource = source ? {
|
|
395
|
+
...source
|
|
396
|
+
} : null;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Gets the CPU-side morph source data.
|
|
400
|
+
*/ getMorphSourceData() {
|
|
401
|
+
return this._morphSourceData;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Sets the CPU-side morph source data used to rebuild GPU morph textures on demand.
|
|
405
|
+
*/ setMorphSourceData(data) {
|
|
406
|
+
this._morphSourceData = data ?? null;
|
|
407
|
+
this._activeMorphTargetIndices = new Uint32Array(0);
|
|
408
|
+
this._compactMorphData = false;
|
|
409
|
+
this._morphDirty = true;
|
|
410
|
+
if (!data) {
|
|
411
|
+
this.setMorphData(null);
|
|
412
|
+
this.setRenderMorphInfo(null);
|
|
413
|
+
} else if (this._morphInfo) {
|
|
414
|
+
this.setMorphData(null);
|
|
415
|
+
this.setRenderMorphInfo(null);
|
|
416
|
+
this.rebuildActiveMorphData();
|
|
417
|
+
this._morphDirty = false;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
267
421
|
* Sets the buffer that contains the morph target information
|
|
268
422
|
* @param info - The buffer that contains the morph target information
|
|
269
423
|
*/ setMorphInfo(info) {
|
|
270
424
|
if (!info) {
|
|
271
425
|
if (this._morphInfo) {
|
|
272
|
-
this._morphInfo.buffer?.dispose();
|
|
273
426
|
this._morphInfo = null;
|
|
274
|
-
this._renderBundle = {};
|
|
275
|
-
RenderBundleWrapper.drawableChanged(this);
|
|
276
427
|
}
|
|
428
|
+
this.setMorphData(null);
|
|
429
|
+
this.setRenderMorphInfo(null);
|
|
430
|
+
this._activeMorphTargetIndices = new Uint32Array(0);
|
|
431
|
+
this._compactMorphData = false;
|
|
432
|
+
this._renderBundle = {};
|
|
433
|
+
RenderBundleWrapper.drawableChanged(this);
|
|
277
434
|
} else {
|
|
278
435
|
if (!this._morphInfo) {
|
|
279
|
-
this._morphInfo = {
|
|
280
|
-
buffer: new DRef()
|
|
281
|
-
};
|
|
436
|
+
this._morphInfo = {};
|
|
282
437
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
this.
|
|
438
|
+
const { data, declaredCount, supportedCount } = normalizeMorphInfoData(info.data);
|
|
439
|
+
if (declaredCount !== supportedCount) {
|
|
440
|
+
console.warn(`Morph target count truncated from ${declaredCount} to ${supportedCount} to fit the runtime buffer layout`);
|
|
441
|
+
}
|
|
442
|
+
const names = {};
|
|
443
|
+
for (const [name, index] of Object.entries(info.names ?? {})){
|
|
444
|
+
if (Number.isInteger(index) && index >= 0 && index < supportedCount) {
|
|
445
|
+
names[name] = index;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
this._morphInfo.data = data;
|
|
449
|
+
this._morphInfo.names = names;
|
|
450
|
+
this._morphDirty = true;
|
|
451
|
+
if (this._morphSourceData) {
|
|
452
|
+
this.setMorphData(null);
|
|
453
|
+
this.setRenderMorphInfo(null);
|
|
454
|
+
this.rebuildActiveMorphData();
|
|
455
|
+
this._morphDirty = false;
|
|
456
|
+
} else if (this._morphData) {
|
|
457
|
+
this.setRenderMorphInfo(null);
|
|
458
|
+
this.updateRenderMorphInfo(this.collectActiveMorphTargetIndices(), false);
|
|
459
|
+
this._morphDirty = false;
|
|
300
460
|
}
|
|
301
|
-
this._morphDirty = false;
|
|
302
461
|
this.refreshAnimatedBoundingBox();
|
|
303
462
|
this._renderBundle = {};
|
|
304
463
|
RenderBundleWrapper.drawableChanged(this);
|
|
@@ -309,10 +468,228 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
309
468
|
*/ getMorphInfo() {
|
|
310
469
|
return this._morphInfo;
|
|
311
470
|
}
|
|
471
|
+
/** @internal */ getRenderMorphInfo() {
|
|
472
|
+
return this._renderMorphInfo;
|
|
473
|
+
}
|
|
474
|
+
/** @internal */ setRenderMorphInfo(info) {
|
|
475
|
+
if (!info) {
|
|
476
|
+
if (this._renderMorphInfo) {
|
|
477
|
+
this._renderMorphInfo.buffer?.dispose();
|
|
478
|
+
this._renderMorphInfo = null;
|
|
479
|
+
}
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
if (!this._renderMorphInfo) {
|
|
483
|
+
this._renderMorphInfo = {
|
|
484
|
+
buffer: new DRef()
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
this._renderMorphInfo.data = info.data;
|
|
488
|
+
this._renderMorphInfo.names = info.names;
|
|
489
|
+
if (!this._renderMorphInfo.buffer?.get()) {
|
|
490
|
+
this._renderMorphInfo.buffer.set(createMorphInfoBuffer(info.data));
|
|
491
|
+
} else {
|
|
492
|
+
this._renderMorphInfo.buffer.get().bufferSubData(0, info.data);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
/** @internal */ collectActiveMorphTargetIndices() {
|
|
496
|
+
if (!this._morphInfo) {
|
|
497
|
+
return new Uint32Array(0);
|
|
498
|
+
}
|
|
499
|
+
const count = this.getNumMorphTargets();
|
|
500
|
+
const activeLimit = Math.min(getActiveMorphTargetLimit(), count);
|
|
501
|
+
if (activeLimit <= 0) {
|
|
502
|
+
return new Uint32Array(0);
|
|
503
|
+
}
|
|
504
|
+
const weighted = this._activeMorphCandidates;
|
|
505
|
+
let weightedCount = 0;
|
|
506
|
+
for(let i = 0; i < count; i++){
|
|
507
|
+
const weight = this._morphInfo.data[4 + i];
|
|
508
|
+
if (Math.abs(weight) > ACTIVE_MORPH_WEIGHT_EPSILON) {
|
|
509
|
+
const candidate = weighted[weightedCount] ?? {
|
|
510
|
+
index: i,
|
|
511
|
+
weight: 0
|
|
512
|
+
};
|
|
513
|
+
candidate.index = i;
|
|
514
|
+
candidate.weight = Math.abs(weight);
|
|
515
|
+
weighted[weightedCount] = candidate;
|
|
516
|
+
weightedCount++;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
weighted.length = weightedCount;
|
|
520
|
+
let selectedCount = weightedCount;
|
|
521
|
+
if (weightedCount > activeLimit) {
|
|
522
|
+
weighted.sort((a, b)=>b.weight - a.weight);
|
|
523
|
+
selectedCount = activeLimit;
|
|
524
|
+
}
|
|
525
|
+
for(let i = 1; i < selectedCount; i++){
|
|
526
|
+
const candidate = weighted[i];
|
|
527
|
+
let targetIndex = i;
|
|
528
|
+
while(targetIndex > 0 && weighted[targetIndex - 1].index > candidate.index){
|
|
529
|
+
weighted[targetIndex] = weighted[targetIndex - 1];
|
|
530
|
+
targetIndex--;
|
|
531
|
+
}
|
|
532
|
+
weighted[targetIndex] = candidate;
|
|
533
|
+
}
|
|
534
|
+
const activeIndices = new Uint32Array(selectedCount);
|
|
535
|
+
for(let i = 0; i < selectedCount; i++){
|
|
536
|
+
activeIndices[i] = weighted[i].index;
|
|
537
|
+
}
|
|
538
|
+
return activeIndices;
|
|
539
|
+
}
|
|
540
|
+
/** @internal */ rebuildActiveMorphData() {
|
|
541
|
+
if (!this._morphInfo || !this._morphSourceData) {
|
|
542
|
+
this.setMorphData(null);
|
|
543
|
+
this.setRenderMorphInfo(null);
|
|
544
|
+
this._activeMorphTargetIndices = new Uint32Array(0);
|
|
545
|
+
this._compactMorphData = false;
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const activeIndices = this.collectActiveMorphTargetIndices();
|
|
549
|
+
const sameActiveSet = this._activeMorphTargetIndices.length === activeIndices.length && this._activeMorphTargetIndices.every((value, index)=>value === activeIndices[index]);
|
|
550
|
+
if (this._morphData && (!this._compactMorphData || sameActiveSet)) {
|
|
551
|
+
this.updateRenderMorphInfo(activeIndices, this._compactMorphData);
|
|
552
|
+
this._activeMorphTargetIndices = activeIndices;
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
const attributes = Object.keys(this._morphSourceData.targets).map((key)=>Number(key)).filter((value)=>Number.isInteger(value) && value >= 0 && value < MORPH_ATTRIBUTE_CAPACITY).sort((a, b)=>a - b);
|
|
556
|
+
const numVertices = this._morphSourceData.numVertices;
|
|
557
|
+
const textureTargetCount = Math.min(this.getNumMorphTargets(), this._morphSourceData.numTargets);
|
|
558
|
+
if (numVertices <= 0 || attributes.length === 0 || textureTargetCount <= 0) {
|
|
559
|
+
this.setMorphData(null);
|
|
560
|
+
this.setRenderMorphInfo(null);
|
|
561
|
+
this._activeMorphTargetIndices = new Uint32Array(0);
|
|
562
|
+
this._compactMorphData = false;
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
const maxTextureSize = getDevice().getDeviceCaps().textureCaps.maxTextureSize;
|
|
566
|
+
const fullTextureSize = Math.ceil(Math.sqrt(numVertices * attributes.length * textureTargetCount));
|
|
567
|
+
let textureTargetIndices;
|
|
568
|
+
if (fullTextureSize <= maxTextureSize) {
|
|
569
|
+
textureTargetIndices = new Uint32Array(textureTargetCount);
|
|
570
|
+
for(let i = 0; i < textureTargetCount; i++){
|
|
571
|
+
textureTargetIndices[i] = i;
|
|
572
|
+
}
|
|
573
|
+
this._compactMorphData = false;
|
|
574
|
+
} else if (activeIndices.length > 0) {
|
|
575
|
+
textureTargetIndices = activeIndices;
|
|
576
|
+
this._compactMorphData = true;
|
|
577
|
+
} else {
|
|
578
|
+
this.setMorphData(null);
|
|
579
|
+
this.setRenderMorphInfo(null);
|
|
580
|
+
this._activeMorphTargetIndices = activeIndices;
|
|
581
|
+
this._compactMorphData = true;
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
const textureSize = Math.ceil(Math.sqrt(numVertices * attributes.length * textureTargetIndices.length));
|
|
585
|
+
if (textureSize > maxTextureSize) {
|
|
586
|
+
console.warn(`Active morph target texture too large for mesh "${this.name ?? ''}": ${textureSize} exceeds device limit`);
|
|
587
|
+
this.setMorphData(null);
|
|
588
|
+
this.setRenderMorphInfo(null);
|
|
589
|
+
this._activeMorphTargetIndices = new Uint32Array(0);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
const textureData = new Float32Array(textureSize * textureSize * 4);
|
|
593
|
+
const attributeOffsets = new Float32Array(MORPH_ATTRIBUTE_CAPACITY);
|
|
594
|
+
for(let i = 0; i < MORPH_ATTRIBUTE_CAPACITY; i++){
|
|
595
|
+
attributeOffsets[i] = -1;
|
|
596
|
+
}
|
|
597
|
+
let offset = 0;
|
|
598
|
+
for (const attrib of attributes){
|
|
599
|
+
const source = this._morphSourceData.targets[attrib];
|
|
600
|
+
if (!source) {
|
|
601
|
+
continue;
|
|
602
|
+
}
|
|
603
|
+
attributeOffsets[attrib] = offset >> 2;
|
|
604
|
+
for(let slot = 0; slot < textureTargetIndices.length; slot++){
|
|
605
|
+
const targetIndex = textureTargetIndices[slot];
|
|
606
|
+
const targetData = source.data[targetIndex];
|
|
607
|
+
const sparseIndices = source.indices?.[targetIndex];
|
|
608
|
+
const baseOffset = offset + slot * numVertices * 4;
|
|
609
|
+
if (sparseIndices && targetData) {
|
|
610
|
+
for(let i = 0; i < sparseIndices.length; i++){
|
|
611
|
+
const vertexOffset = baseOffset + sparseIndices[i] * 4;
|
|
612
|
+
for(let j = 0; j < source.numComponents; j++){
|
|
613
|
+
textureData[vertexOffset + j] = targetData[i * source.numComponents + j];
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
} else if (targetData) {
|
|
617
|
+
for(let vertex = 0; vertex < numVertices; vertex++){
|
|
618
|
+
const vertexOffset = baseOffset + vertex * 4;
|
|
619
|
+
for(let j = 0; j < source.numComponents; j++){
|
|
620
|
+
textureData[vertexOffset + j] = targetData[vertex * source.numComponents + j];
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
offset += numVertices * 4 * textureTargetIndices.length;
|
|
626
|
+
}
|
|
627
|
+
this.setMorphData({
|
|
628
|
+
width: textureSize,
|
|
629
|
+
height: textureSize,
|
|
630
|
+
data: textureData
|
|
631
|
+
});
|
|
632
|
+
this.updateRenderMorphInfo(activeIndices, this._compactMorphData, attributeOffsets);
|
|
633
|
+
this._activeMorphTargetIndices = activeIndices;
|
|
634
|
+
}
|
|
635
|
+
/** @internal */ updateRenderMorphInfo(activeIndices, useCompactSlots, attributeOffsets) {
|
|
636
|
+
if (!this._morphInfo || !this._morphData) {
|
|
637
|
+
this.setRenderMorphInfo(null);
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
const infoData = this._renderMorphInfo?.data instanceof Float32Array && this._renderMorphInfo.data.length === MORPH_RENDER_INFO_DATA_LENGTH ? this._renderMorphInfo.data : new Float32Array(MORPH_RENDER_INFO_DATA_LENGTH);
|
|
641
|
+
infoData[0] = this._morphData.width;
|
|
642
|
+
infoData[1] = this._morphData.height;
|
|
643
|
+
infoData[2] = this._morphSourceData?.numVertices ?? (Number(this._morphInfo.data[2]) || 0);
|
|
644
|
+
infoData[3] = activeIndices.length;
|
|
645
|
+
infoData.fill(0, 4, MORPH_RENDER_ATTRIBUTE_OFFSET);
|
|
646
|
+
for(let slot = 0; slot < activeIndices.length; slot++){
|
|
647
|
+
const targetIndex = activeIndices[slot];
|
|
648
|
+
infoData[4 + slot] = this._morphInfo.data[4 + targetIndex];
|
|
649
|
+
infoData[MORPH_RENDER_INDEX_OFFSET + slot] = useCompactSlots ? slot : targetIndex;
|
|
650
|
+
}
|
|
651
|
+
if (attributeOffsets) {
|
|
652
|
+
infoData.fill(-1, MORPH_RENDER_ATTRIBUTE_OFFSET);
|
|
653
|
+
infoData.set(attributeOffsets, MORPH_RENDER_ATTRIBUTE_OFFSET);
|
|
654
|
+
} else if (!this._renderMorphInfo) {
|
|
655
|
+
infoData.fill(-1, MORPH_RENDER_ATTRIBUTE_OFFSET);
|
|
656
|
+
for(let attrib = 0; attrib < MORPH_ATTRIBUTE_CAPACITY; attrib++){
|
|
657
|
+
infoData[MORPH_RENDER_ATTRIBUTE_OFFSET + attrib] = this._morphInfo.data[4 + MORPH_WEIGHT_CAPACITY + attrib] ?? -1;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
this.setRenderMorphInfo({
|
|
661
|
+
data: infoData,
|
|
662
|
+
names: this._renderMorphInfo?.names ?? {}
|
|
663
|
+
});
|
|
664
|
+
}
|
|
312
665
|
/** @internal */ resolveAnimatedBoundingBox(morphBoundingBox) {
|
|
313
666
|
const skinnedBoundingBox = this._boneMatrices.get() && this._skinnedBoundingInfo?.boundingBox?.isValid() ? this._skinnedBoundingInfo.boundingBox : null;
|
|
314
667
|
if (skinnedBoundingBox && morphBoundingBox) {
|
|
315
|
-
|
|
668
|
+
// Skinning and morphing both active. The two boxes live in different
|
|
669
|
+
// frames: the skinned box already reflects where the geometry actually
|
|
670
|
+
// ended up, while the morph box is still expressed around the rest pose.
|
|
671
|
+
// Unioning them therefore spans the gap between rest and posed positions
|
|
672
|
+
// and produces a wildly oversized box - which is why that union was
|
|
673
|
+
// removed. But dropping the morph side entirely loses the displacement,
|
|
674
|
+
// since the skinned box is built from rest-pose representative vertices
|
|
675
|
+
// (SkinBinding.computeBoundingBox) and never sees morph offsets - so a
|
|
676
|
+
// large facial expression could reach outside its own bounds and be
|
|
677
|
+
// culled.
|
|
678
|
+
//
|
|
679
|
+
// Transfer only what is frame-independent: the displacement. Clamped so
|
|
680
|
+
// it can only grow the box, because a morph that pushes geometry one way
|
|
681
|
+
// must not be allowed to shrink the opposite side.
|
|
682
|
+
const box = skinnedBoundingBox.clone();
|
|
683
|
+
const displacement = this.calculateMorphDisplacement();
|
|
684
|
+
if (displacement) {
|
|
685
|
+
const min = box.minPoint;
|
|
686
|
+
const max = box.maxPoint;
|
|
687
|
+
const dmin = displacement.minPoint;
|
|
688
|
+
const dmax = displacement.maxPoint;
|
|
689
|
+
min.setXYZ(min.x + Math.min(0, dmin.x), min.y + Math.min(0, dmin.y), min.z + Math.min(0, dmin.z));
|
|
690
|
+
max.setXYZ(max.x + Math.max(0, dmax.x), max.y + Math.max(0, dmax.y), max.z + Math.max(0, dmax.z));
|
|
691
|
+
}
|
|
692
|
+
return box;
|
|
316
693
|
}
|
|
317
694
|
return skinnedBoundingBox?.clone() ?? morphBoundingBox ?? null;
|
|
318
695
|
}
|
|
@@ -321,7 +698,7 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
321
698
|
*
|
|
322
699
|
* @returns The number of morph targets
|
|
323
700
|
*/ getNumMorphTargets() {
|
|
324
|
-
return this._morphInfo
|
|
701
|
+
return this._morphInfo ? Math.min(this._morphInfo.data[3], MORPH_WEIGHT_CAPACITY) : 0;
|
|
325
702
|
}
|
|
326
703
|
/**
|
|
327
704
|
* Get the name of the morph target by index
|
|
@@ -329,7 +706,7 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
329
706
|
* @param index - The index of the morph target
|
|
330
707
|
* @returns The name of the morph target, or null if not found
|
|
331
708
|
*/ getMorphTargetName(index) {
|
|
332
|
-
if (this._morphInfo && index >= 0 && index < this.
|
|
709
|
+
if (this._morphInfo && index >= 0 && index < this.getNumMorphTargets()) {
|
|
333
710
|
const name = Object.keys(this._morphInfo.names).find((key)=>this._morphInfo.names[key] === index);
|
|
334
711
|
return name ?? null;
|
|
335
712
|
}
|
|
@@ -359,9 +736,10 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
359
736
|
* @param index - The index of the morph target
|
|
360
737
|
* @param weight - The weight of the morph target
|
|
361
738
|
*/ setMorphWeightByIndex(index, weight) {
|
|
362
|
-
if (index >= 0 && index < this.
|
|
363
|
-
|
|
364
|
-
|
|
739
|
+
if (index >= 0 && index < this.getNumMorphTargets()) {
|
|
740
|
+
const normalizedWeight = Math.fround(weight);
|
|
741
|
+
if (this._morphInfo.data[4 + index] !== normalizedWeight) {
|
|
742
|
+
this._morphInfo.data[4 + index] = normalizedWeight;
|
|
365
743
|
this._morphDirty = true;
|
|
366
744
|
this.refreshAnimatedBoundingBox();
|
|
367
745
|
this.scene.queueUpdateNode(this);
|
|
@@ -377,7 +755,7 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
377
755
|
* @returns The weight of the morph target, or 0 if not found
|
|
378
756
|
*/ getMorphWeight(name) {
|
|
379
757
|
const index = this._morphInfo?.names?.[name];
|
|
380
|
-
if (index !== undefined && index >= 0 && index < this.
|
|
758
|
+
if (index !== undefined && index >= 0 && index < this.getNumMorphTargets()) {
|
|
381
759
|
return this._morphInfo.data[4 + index];
|
|
382
760
|
}
|
|
383
761
|
return 0;
|
|
@@ -387,8 +765,18 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
387
765
|
*
|
|
388
766
|
* @param weight - The morph target weights. The length must not exceed the mesh's morph target count.
|
|
389
767
|
*/ updateMorphWeights(weight) {
|
|
390
|
-
if (this._morphInfo && weight && weight.length <= this.
|
|
391
|
-
|
|
768
|
+
if (this._morphInfo && weight && weight.length <= this.getNumMorphTargets()) {
|
|
769
|
+
let changed = false;
|
|
770
|
+
for(let i = 0; i < weight.length; i++){
|
|
771
|
+
const normalizedWeight = Math.fround(weight[i] ?? 0);
|
|
772
|
+
if (this._morphInfo.data[4 + i] !== normalizedWeight) {
|
|
773
|
+
this._morphInfo.data[4 + i] = normalizedWeight;
|
|
774
|
+
changed = true;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
if (!changed) {
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
392
780
|
this._morphDirty = true;
|
|
393
781
|
this.refreshAnimatedBoundingBox();
|
|
394
782
|
this.scene.queueUpdateNode(this);
|
|
@@ -439,17 +827,35 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
439
827
|
*/ needSceneDepth() {
|
|
440
828
|
return this.material?.needSceneDepth() ?? false;
|
|
441
829
|
}
|
|
442
|
-
/** @internal */
|
|
830
|
+
/** @internal */ /**
|
|
831
|
+
* Weighted morph displacement, relative to the rest pose - i.e. how far the
|
|
832
|
+
* active morph targets push geometry beyond `originBox`, not where that
|
|
833
|
+
* geometry ends up.
|
|
834
|
+
*
|
|
835
|
+
* Kept separate from {@link calculateMorphBoundingBox} because the two are
|
|
836
|
+
* useful in different frames of reference: the absolute box is meaningful for
|
|
837
|
+
* an unskinned mesh, while for a skinned one only the displacement transfers -
|
|
838
|
+
* the rest-space position is superseded by the skinning result.
|
|
839
|
+
*
|
|
840
|
+
* @internal
|
|
841
|
+
*/ calculateMorphDisplacement() {
|
|
443
842
|
if (!this._morphInfo || !this._morphBoundingInfo) {
|
|
444
843
|
return null;
|
|
445
844
|
}
|
|
446
|
-
const numTargets = Math.min(this.
|
|
845
|
+
const numTargets = Math.min(this.getNumMorphTargets(), this._morphBoundingInfo.targetBoxes.length);
|
|
447
846
|
if (numTargets <= 0) {
|
|
448
847
|
return null;
|
|
449
848
|
}
|
|
450
849
|
const weights = this._morphInfo.data instanceof Float32Array ? this._morphInfo.data.subarray(4, 4 + numTargets) : new Float32Array(Array.from(this._morphInfo.data.subarray(4, 4 + numTargets)));
|
|
451
850
|
const bbox = new BoundingBox();
|
|
452
851
|
calculateMorphBoundingBox(bbox, this._morphBoundingInfo.targetBoxes, weights, numTargets);
|
|
852
|
+
return bbox;
|
|
853
|
+
}
|
|
854
|
+
/** @internal */ calculateMorphBoundingBox() {
|
|
855
|
+
const bbox = this.calculateMorphDisplacement();
|
|
856
|
+
if (!bbox) {
|
|
857
|
+
return null;
|
|
858
|
+
}
|
|
453
859
|
bbox.minPoint.addBy(this._morphBoundingInfo.originBox.minPoint);
|
|
454
860
|
bbox.maxPoint.addBy(this._morphBoundingInfo.originBox.maxPoint);
|
|
455
861
|
return bbox;
|
|
@@ -459,7 +865,13 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
459
865
|
}
|
|
460
866
|
/** @internal */ updateMorphState() {
|
|
461
867
|
if (this._morphInfo && this._morphDirty) {
|
|
462
|
-
this.
|
|
868
|
+
if (this._morphSourceData) {
|
|
869
|
+
this.rebuildActiveMorphData();
|
|
870
|
+
} else if (this._morphData) {
|
|
871
|
+
const activeIndices = this.collectActiveMorphTargetIndices();
|
|
872
|
+
this.updateRenderMorphInfo(activeIndices, false);
|
|
873
|
+
this._activeMorphTargetIndices = activeIndices;
|
|
874
|
+
}
|
|
463
875
|
this.refreshAnimatedBoundingBox();
|
|
464
876
|
this._morphDirty = false;
|
|
465
877
|
}
|
|
@@ -546,8 +958,11 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
546
958
|
this._primitive.dispose();
|
|
547
959
|
this._material.dispose();
|
|
548
960
|
this._boneMatrices.dispose();
|
|
961
|
+
this.setSkinInfluenceData(null);
|
|
549
962
|
this.setMorphData(null);
|
|
963
|
+
this.setRenderMorphInfo(null);
|
|
550
964
|
this.setMorphInfo(null);
|
|
965
|
+
this.setMorphSourceData(null);
|
|
551
966
|
this.setMorphBoundingInfo(null);
|
|
552
967
|
this._renderBundle = null;
|
|
553
968
|
RenderBundleWrapper.drawableChanged(this);
|
|
@@ -555,6 +970,25 @@ const MeshBase = castObservable(applyMixins(GraphNode, mixinDrawable))();
|
|
|
555
970
|
/** @internal */ _onBoundingboxChange() {
|
|
556
971
|
this.invalidateBoundingVolume();
|
|
557
972
|
}
|
|
973
|
+
/** @internal */ _ensureWebGLVertexIndexAttribute(feature) {
|
|
974
|
+
const primitive = this._primitive.get();
|
|
975
|
+
if (!primitive || getDevice().type !== 'webgl') {
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
if (primitive.getVertexBuffer('texCoord7')) {
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
const numVertices = primitive.getNumVertices();
|
|
982
|
+
if (numVertices <= 0) {
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
const vertexIndices = new Float32Array(numVertices);
|
|
986
|
+
for(let i = 0; i < numVertices; i++){
|
|
987
|
+
vertexIndices[i] = i;
|
|
988
|
+
}
|
|
989
|
+
primitive.createAndSetVertexBuffer('tex7_f32', vertexIndices);
|
|
990
|
+
console.info(`Injected texCoord7 vertex indices for WebGL ${feature} on mesh "${this.name ?? ''}"`);
|
|
991
|
+
}
|
|
558
992
|
/** @internal */ static _defaultMaterial = null;
|
|
559
993
|
/** @internal */ static _getDefaultMaterial() {
|
|
560
994
|
if (!this._defaultMaterial) {
|