@zephyr3d/scene 0.9.25 → 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 +4019 -1278
- package/dist/index.js +15 -5
- 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 +330 -20
- 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/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 +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 +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 +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 +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 +49 -2
- package/dist/values.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Vector3, Vector4, Vector2, REVERSE_Z, DEPTH_FARTHEST, DEPTH_REDUCE_CLOSER, DEPTH_REDUCE_FARTHER } from '@zephyr3d/base';
|
|
2
|
-
import { RENDER_PASS_TYPE_DEPTH, RENDER_PASS_TYPE_SHADOWMAP, RENDER_PASS_TYPE_OBJECT_COLOR, RENDER_PASS_TYPE_LIGHT, MaterialVaryingFlags, MORPH_WEIGHTS_VECTOR_COUNT, MORPH_TARGET_POSITION, MORPH_TARGET_NORMAL, MORPH_TARGET_TANGENT, MORPH_ATTRIBUTE_VECTOR_COUNT } from '../../values.js';
|
|
2
|
+
import { RENDER_PASS_TYPE_DEPTH, RENDER_PASS_TYPE_SHADOWMAP, RENDER_PASS_TYPE_OBJECT_COLOR, RENDER_PASS_TYPE_LIGHT, MaterialVaryingFlags, MAX_SKIN_EXTRA_INFLUENCE_PAIRS, MORPH_WEIGHTS_VECTOR_COUNT, MORPH_TARGET_POSITION, MORPH_TARGET_NORMAL, MORPH_TARGET_TANGENT, MORPH_ATTRIBUTE_VECTOR_COUNT, LIGHT_TYPE_DIRECTIONAL } from '../../values.js';
|
|
3
3
|
import { ProgramBuilder } from '@zephyr3d/device';
|
|
4
4
|
import { decodeNormalizedFloatFromRGBA, linearToGamma } from '../../shaders/misc.js';
|
|
5
5
|
import { getSamplerOptions, fetchSampler } from '../../utility/misc.js';
|
|
@@ -7,6 +7,7 @@ import { PHYSICAL_BAKE_EXPOSURE } from '../../utility/physical.js';
|
|
|
7
7
|
import { getDevice } from '../../app/api.js';
|
|
8
8
|
import { getDefaultAtmosphereParams, getAtmosphereParamsStruct } from '../../shaders/atmosphere.js';
|
|
9
9
|
import { getDefaultHeightFogParams, getHeightFogParamsStruct, calculateFog } from '../../shaders/fog.js';
|
|
10
|
+
import { getShadowReceiverNoL, getShadowReceiverBiasFactor } from '../../shadow/receiver_bias.js';
|
|
10
11
|
|
|
11
12
|
const UNIFORM_NAME_LIGHT_BUFFER = 'Z_UniformLightBuffer';
|
|
12
13
|
const UNIFORM_NAME_LIGHT_INDEX_TEXTURE = 'Z_UniformLightIndexTex';
|
|
@@ -32,6 +33,8 @@ const UNIFORM_NAME_INSTANCE_DATA_OFFSET = 'Z_UniformInstanceDataOffset';
|
|
|
32
33
|
const UNIFORM_NAME_BONE_MATRICES = 'Z_UniformBoneMatrices';
|
|
33
34
|
const UNIFORM_NAME_BONE_TEXTURE_SIZE = 'Z_UniformBoneTexSize';
|
|
34
35
|
const UNIFORM_NAME_BONE_INV_BIND_MATRIX = 'Z_UniformBoneInvBindMatrix';
|
|
36
|
+
const UNIFORM_NAME_SKIN_INFLUENCE_DATA = 'Z_UniformSkinInfluenceData';
|
|
37
|
+
const UNIFORM_NAME_SKIN_INFLUENCE_INFO = 'Z_UniformSkinInfluenceInfo';
|
|
35
38
|
const UNIFORM_NAME_MORPH_DATA = 'Z_UniformMorphData';
|
|
36
39
|
const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
37
40
|
/**
|
|
@@ -46,6 +49,7 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
46
49
|
/** @internal */ static SKIN_MATRIX_NAME = 'Z_SkinMatrix';
|
|
47
50
|
static SKIN_PREV_MATRIX_NAME = 'Z_PrevSkinMatrix';
|
|
48
51
|
static SKIN_BONE_OFFSET = 'Z_boneOffset';
|
|
52
|
+
static RESOLVED_VERTEX_NORMAL_NAME = 'Z_ResolvedVertexNormal';
|
|
49
53
|
/** @internal */ static _drawableBindGroupLayouts = {};
|
|
50
54
|
/** @internal */ static _lightUniformShadow = {
|
|
51
55
|
sunDir: new Vector3(),
|
|
@@ -101,6 +105,12 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
101
105
|
static getBoneInvBindMatrixUniformName() {
|
|
102
106
|
return UNIFORM_NAME_BONE_INV_BIND_MATRIX;
|
|
103
107
|
}
|
|
108
|
+
static getSkinInfluenceDataUniformName() {
|
|
109
|
+
return UNIFORM_NAME_SKIN_INFLUENCE_DATA;
|
|
110
|
+
}
|
|
111
|
+
static getSkinInfluenceInfoUniformName() {
|
|
112
|
+
return UNIFORM_NAME_SKIN_INFLUENCE_INFO;
|
|
113
|
+
}
|
|
104
114
|
static getMorphDataUniformName() {
|
|
105
115
|
return UNIFORM_NAME_MORPH_DATA;
|
|
106
116
|
}
|
|
@@ -183,10 +193,22 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
183
193
|
pb.vec4('directionCutoff'),
|
|
184
194
|
pb.mat4('viewMatrix'),
|
|
185
195
|
pb.vec4('depthBias'),
|
|
196
|
+
// Same slot the lighting pass exposes through getShadowImplParams. A
|
|
197
|
+
// caster normally has no use for it, but one that encodes something
|
|
198
|
+
// beyond depth - deep opacity map layers - needs the same parameters the
|
|
199
|
+
// receiver will decode with.
|
|
200
|
+
pb.vec4('implParams'),
|
|
186
201
|
pb.int('lightType')
|
|
187
202
|
]);
|
|
188
203
|
scope.camera = cameraStruct().uniform(0);
|
|
189
204
|
scope.light = lightStruct().uniform(0);
|
|
205
|
+
// Lets the shadow implementation add its own caster inputs. Only deep
|
|
206
|
+
// opacity maps use this, to read the frontmost depth its first pass wrote.
|
|
207
|
+
const shadowLight = ctx.renderPass.light;
|
|
208
|
+
const casterParams = shadowLight ? ctx.shadowMapInfo?.get(shadowLight) : null;
|
|
209
|
+
if (casterParams) {
|
|
210
|
+
casterParams.impl?.declareCasterUniforms(scope, casterParams);
|
|
211
|
+
}
|
|
190
212
|
} else if (ctx.renderPass.type === RENDER_PASS_TYPE_DEPTH || ctx.renderPass.type === RENDER_PASS_TYPE_OBJECT_COLOR) {
|
|
191
213
|
scope.camera = cameraStruct().uniform(0);
|
|
192
214
|
} else if (ctx.renderPass.type === RENDER_PASS_TYPE_LIGHT) {
|
|
@@ -322,6 +344,8 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
322
344
|
return null;
|
|
323
345
|
}
|
|
324
346
|
const pb = scope.$builder;
|
|
347
|
+
const isWebGL = pb.getDevice().type === 'webgl';
|
|
348
|
+
const supportsTextureLoad = !isWebGL;
|
|
325
349
|
const funcNameGetBoneMatrixFromTexture = 'Z_getBoneMatrixFromTexture';
|
|
326
350
|
pb.func(funcNameGetBoneMatrixFromTexture, [
|
|
327
351
|
pb.int('boneIndex')
|
|
@@ -354,6 +378,33 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
354
378
|
this.$l.m2 = scope.$g[funcNameGetBoneMatrixFromTexture](pb.int(blendIndices[2]));
|
|
355
379
|
this.$l.m3 = scope.$g[funcNameGetBoneMatrixFromTexture](pb.int(blendIndices[3]));
|
|
356
380
|
this.$l.m = pb.add(pb.mul(this.m0, blendWeights.x), pb.mul(this.m1, blendWeights.y), pb.mul(this.m2, blendWeights.z), pb.mul(this.m3, blendWeights.w));
|
|
381
|
+
this.$l.skinInfo = this[UNIFORM_NAME_SKIN_INFLUENCE_INFO];
|
|
382
|
+
this.$if(pb.greaterThan(this.skinInfo.z, 4), function() {
|
|
383
|
+
this.$l.vertexIndex = isWebGL ? pb.int(scope.$inputs.zFakeVertexID) : pb.int(scope.$builtins.vertexIndex);
|
|
384
|
+
this.$l.texWidth = pb.int(this.skinInfo.x);
|
|
385
|
+
this.$l.pairCount = pb.int(this.skinInfo.w);
|
|
386
|
+
this.$for(pb.int('pairIndex'), 0, MAX_SKIN_EXTRA_INFLUENCE_PAIRS, function() {
|
|
387
|
+
this.$if(pb.greaterThanEqual(this.pairIndex, this.pairCount), function() {
|
|
388
|
+
this.$break();
|
|
389
|
+
});
|
|
390
|
+
this.$l.pixelIndex = pb.add(pb.mul(this.vertexIndex, this.pairCount), this.pairIndex);
|
|
391
|
+
this.$l.xIndex = pb.mod(this.pixelIndex, this.texWidth);
|
|
392
|
+
this.$l.yIndex = pb.div(this.pixelIndex, this.texWidth);
|
|
393
|
+
if (supportsTextureLoad) {
|
|
394
|
+
this.$l.extra = pb.textureLoad(this[UNIFORM_NAME_SKIN_INFLUENCE_DATA], pb.ivec2(this.xIndex, this.yIndex), 0);
|
|
395
|
+
} else {
|
|
396
|
+
this.$l.u = pb.div(pb.add(pb.float(this.xIndex), 0.5), this.skinInfo.x);
|
|
397
|
+
this.$l.v = pb.div(pb.add(pb.float(this.yIndex), 0.5), this.skinInfo.y);
|
|
398
|
+
this.$l.extra = pb.textureSampleLevel(this[UNIFORM_NAME_SKIN_INFLUENCE_DATA], pb.vec2(this.u, this.v), 0);
|
|
399
|
+
}
|
|
400
|
+
this.$if(pb.greaterThan(this.extra.y, 0), function() {
|
|
401
|
+
this.m = pb.add(this.m, pb.mul(scope.$g[funcNameGetBoneMatrixFromTexture](pb.int(this.extra.x)), this.extra.y));
|
|
402
|
+
});
|
|
403
|
+
this.$if(pb.greaterThan(this.extra.w, 0), function() {
|
|
404
|
+
this.m = pb.add(this.m, pb.mul(scope.$g[funcNameGetBoneMatrixFromTexture](pb.int(this.extra.z)), this.extra.w));
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
});
|
|
357
408
|
this.$return(pb.mul(invBindMatrix, this.m));
|
|
358
409
|
});
|
|
359
410
|
return scope.$g[funcNameGetSkinningMatrix]();
|
|
@@ -389,7 +440,8 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
389
440
|
});
|
|
390
441
|
this.$l.weight = morphInfo.at(pb.add(1, this.i)).at(this.j);
|
|
391
442
|
this.$if(pb.notEqual(this.weight, 0), function() {
|
|
392
|
-
this.$l.
|
|
443
|
+
this.$l.targetIndex = pb.int(morphInfo.at(pb.add(1 + MORPH_WEIGHTS_VECTOR_COUNT, this.i)).at(this.j));
|
|
444
|
+
this.$l.pixelIndex = pb.float(pb.add(this.offset, pb.mul(this.targetIndex, this.numVertices), this.vertexIndex));
|
|
393
445
|
this.$l.xIndex = pb.mod(this.pixelIndex, this.texWidth);
|
|
394
446
|
this.$l.yIndex = pb.floor(pb.div(this.pixelIndex, this.texWidth));
|
|
395
447
|
this.$l.u = pb.div(pb.add(this.xIndex, 0.5), this.texWidth);
|
|
@@ -405,7 +457,8 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
405
457
|
this.$l.j = pb.compAnd(this.t, 3);
|
|
406
458
|
this.$l.weight = morphInfo.at(pb.add(1, this.i)).at(this.j);
|
|
407
459
|
this.$if(pb.notEqual(this.weight, 0), function() {
|
|
408
|
-
this.$l.
|
|
460
|
+
this.$l.targetIndex = pb.int(morphInfo.at(pb.add(1 + MORPH_WEIGHTS_VECTOR_COUNT, this.i)).at(this.j));
|
|
461
|
+
this.$l.pixelIndex = pb.float(pb.add(this.offset, pb.mul(this.targetIndex, this.numVertices), this.vertexIndex));
|
|
409
462
|
this.$l.xIndex = pb.mod(this.pixelIndex, this.texWidth);
|
|
410
463
|
this.$l.yIndex = pb.floor(pb.div(this.pixelIndex, this.texWidth));
|
|
411
464
|
this.$l.u = pb.div(pb.add(this.xIndex, 0.5), this.texWidth);
|
|
@@ -417,17 +470,166 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
417
470
|
}
|
|
418
471
|
this.$return(this.value);
|
|
419
472
|
});
|
|
420
|
-
const pos = 1 + MORPH_WEIGHTS_VECTOR_COUNT + (attrib >> 2);
|
|
473
|
+
const pos = 1 + MORPH_WEIGHTS_VECTOR_COUNT * 2 + (attrib >> 2);
|
|
421
474
|
const comp = attrib & 3;
|
|
422
475
|
const offset = scope[this.getMorphInfoUniformName()][pos][comp];
|
|
423
476
|
return scope[funcName](pb.int(offset));
|
|
424
477
|
}
|
|
478
|
+
/**
|
|
479
|
+
* Normalize a morphed direction without allowing cancellation between
|
|
480
|
+
* multiple morph targets to turn a valid base direction into NaN/noise.
|
|
481
|
+
*
|
|
482
|
+
* Morph normal/tangent data is additive. When two targets cancel the base
|
|
483
|
+
* direction, the zero-length result is not a meaningful direction, so the
|
|
484
|
+
* authored vertex direction is the least surprising fallback.
|
|
485
|
+
* @internal
|
|
486
|
+
*/ static defineNormalizeMorphedDirection(scope) {
|
|
487
|
+
const pb = scope.$builder;
|
|
488
|
+
const funcName = 'Z_normalizeMorphedDirection';
|
|
489
|
+
pb.func(funcName, [
|
|
490
|
+
pb.vec3('base'),
|
|
491
|
+
pb.vec3('delta')
|
|
492
|
+
], function() {
|
|
493
|
+
this.$l.morphed = pb.add(this.base, this.delta);
|
|
494
|
+
this.$l.lengthSquared = pb.dot(this.morphed, this.morphed);
|
|
495
|
+
this.$if(pb.greaterThan(this.lengthSquared, 1e-6), function() {
|
|
496
|
+
this.$return(pb.mul(this.morphed, pb.inverseSqrt(this.lengthSquared)));
|
|
497
|
+
});
|
|
498
|
+
this.$l.baseLengthSquared = pb.dot(this.base, this.base);
|
|
499
|
+
this.$if(pb.greaterThan(this.baseLengthSquared, 1e-6), function() {
|
|
500
|
+
this.$return(pb.mul(this.base, pb.inverseSqrt(this.baseLengthSquared)));
|
|
501
|
+
});
|
|
502
|
+
this.$return(pb.vec3(0, 0, 1));
|
|
503
|
+
});
|
|
504
|
+
return funcName;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Mixes morph directions according to the amount of positional deformation
|
|
508
|
+
* contributed by each active target. This avoids letting a target with a
|
|
509
|
+
* large authored normal delta dominate a target that actually moves the
|
|
510
|
+
* surface much farther at the current vertex.
|
|
511
|
+
*
|
|
512
|
+
* The additive result remains the fallback for assets without position
|
|
513
|
+
* morph data, and for vertices whose position deltas are all zero.
|
|
514
|
+
* @internal
|
|
515
|
+
*/ static calculateMorphDirectionByDisplacement(scope, base, attrib) {
|
|
516
|
+
const pb = scope.$builder;
|
|
517
|
+
const isWebGL1 = pb.getDevice().type === 'webgl';
|
|
518
|
+
if (pb.shaderKind !== 'vertex') {
|
|
519
|
+
throw new Error(`ShaderHelper.calculateMorphDirectionByDisplacement(): must be called at vertex stage`);
|
|
520
|
+
}
|
|
521
|
+
const that = this;
|
|
522
|
+
const funcName = 'Z_calculateMorphDirectionByDisplacement';
|
|
523
|
+
const normalizeName = this.defineNormalizeMorphedDirection(scope);
|
|
524
|
+
pb.func(funcName, [
|
|
525
|
+
pb.vec3('base'),
|
|
526
|
+
pb.int('directionOffset'),
|
|
527
|
+
pb.int('positionOffset')
|
|
528
|
+
], function() {
|
|
529
|
+
this.$l.vertexIndex = isWebGL1 ? pb.int(scope.$inputs.zFakeVertexID) : pb.int(scope.$builtins.vertexIndex);
|
|
530
|
+
const morphInfo = scope[that.getMorphInfoUniformName()];
|
|
531
|
+
this.$l.metaData = pb.ivec4(morphInfo[0]);
|
|
532
|
+
this.$l.texWidth = pb.float(this.metaData.x);
|
|
533
|
+
this.$l.texHeight = pb.float(this.metaData.y);
|
|
534
|
+
this.$l.numVertices = this.metaData.z;
|
|
535
|
+
this.$l.numTargets = this.metaData.w;
|
|
536
|
+
this.$l.directionDelta = pb.vec3(0);
|
|
537
|
+
this.$l.weightedDirection = pb.vec3(0);
|
|
538
|
+
this.$l.weightSum = pb.float(0);
|
|
539
|
+
const accumulateTarget = (targetScope)=>{
|
|
540
|
+
targetScope.$if(pb.notEqual(targetScope.weight, 0), function() {
|
|
541
|
+
this.$l.targetIndex = pb.int(targetScope['targetIndex']);
|
|
542
|
+
this.$l.positionValue = pb.vec3(0);
|
|
543
|
+
this.$l.directionValue = pb.vec3(0);
|
|
544
|
+
this.$if(pb.greaterThanEqual(targetScope['directionOffset'], 0), function() {
|
|
545
|
+
this.$l.pixelIndex = pb.float(pb.add(targetScope['directionOffset'], pb.mul(this.targetIndex, targetScope['numVertices']), targetScope['vertexIndex']));
|
|
546
|
+
this.$l.xIndex = pb.mod(this.pixelIndex, targetScope['texWidth']);
|
|
547
|
+
this.$l.yIndex = pb.floor(pb.div(this.pixelIndex, targetScope['texWidth']));
|
|
548
|
+
this.$l.u = pb.div(pb.add(this.xIndex, 0.5), targetScope['texWidth']);
|
|
549
|
+
this.$l.v = pb.div(pb.add(this.yIndex, 0.5), targetScope['texHeight']);
|
|
550
|
+
this.directionValue = pb.textureSampleLevel(scope[that.getMorphDataUniformName()], pb.vec2(this.u, this.v), 0).xyz;
|
|
551
|
+
});
|
|
552
|
+
this.$if(pb.greaterThanEqual(targetScope['positionOffset'], 0), function() {
|
|
553
|
+
this.$l.pixelIndex = pb.float(pb.add(targetScope['positionOffset'], pb.mul(this.targetIndex, targetScope['numVertices']), targetScope['vertexIndex']));
|
|
554
|
+
this.$l.xIndex = pb.mod(this.pixelIndex, targetScope['texWidth']);
|
|
555
|
+
this.$l.yIndex = pb.floor(pb.div(this.pixelIndex, targetScope['texWidth']));
|
|
556
|
+
this.$l.u = pb.div(pb.add(this.xIndex, 0.5), targetScope['texWidth']);
|
|
557
|
+
this.$l.v = pb.div(pb.add(this.yIndex, 0.5), targetScope['texHeight']);
|
|
558
|
+
this.positionValue = pb.textureSampleLevel(scope[that.getMorphDataUniformName()], pb.vec2(this.u, this.v), 0).xyz;
|
|
559
|
+
});
|
|
560
|
+
this.directionDelta = pb.add(this.directionDelta, pb.mul(this.directionValue, targetScope.weight));
|
|
561
|
+
this.$l.targetDirection = scope.$g[normalizeName](this.base, pb.mul(this.directionValue, targetScope.weight));
|
|
562
|
+
this.$l.displacementWeight = pb.mul(pb.abs(targetScope.weight), pb.sqrt(pb.dot(this.positionValue, this.positionValue)));
|
|
563
|
+
this.weightedDirection = pb.add(this.weightedDirection, pb.mul(this.targetDirection, this.displacementWeight));
|
|
564
|
+
this.weightSum = pb.add(this.weightSum, this.displacementWeight);
|
|
565
|
+
});
|
|
566
|
+
};
|
|
567
|
+
if (isWebGL1) {
|
|
568
|
+
this.$for(pb.int('i'), 0, MORPH_WEIGHTS_VECTOR_COUNT, function() {
|
|
569
|
+
this.$for(pb.int('j'), 0, 4, function() {
|
|
570
|
+
this.$l.index = pb.add(pb.mul(this.i, 4), this.j);
|
|
571
|
+
this.$if(pb.greaterThanEqual(this.index, this.numTargets), function() {
|
|
572
|
+
this.$break();
|
|
573
|
+
});
|
|
574
|
+
this.$l.weight = morphInfo.at(pb.add(1, this.i)).at(this.j);
|
|
575
|
+
this.$l.targetIndex = pb.int(morphInfo.at(pb.add(1 + MORPH_WEIGHTS_VECTOR_COUNT, this.i)).at(this.j));
|
|
576
|
+
accumulateTarget(this);
|
|
577
|
+
});
|
|
578
|
+
});
|
|
579
|
+
} else {
|
|
580
|
+
this.$for(pb.int('t'), 0, this.numTargets, function() {
|
|
581
|
+
this.$l.i = pb.sar(this.t, 2);
|
|
582
|
+
this.$l.j = pb.compAnd(this.t, 3);
|
|
583
|
+
this.$l.weight = morphInfo.at(pb.add(1, this.i)).at(this.j);
|
|
584
|
+
this.$l.targetIndex = pb.int(morphInfo.at(pb.add(1 + MORPH_WEIGHTS_VECTOR_COUNT, this.i)).at(this.j));
|
|
585
|
+
accumulateTarget(this);
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
this.$l.fallback = scope.$g[normalizeName](this.base, this.directionDelta);
|
|
589
|
+
this.$if(pb.lessThan(this.weightSum, 1e-6), function() {
|
|
590
|
+
this.$return(this.fallback);
|
|
591
|
+
});
|
|
592
|
+
this.$l.weightedLengthSquared = pb.dot(this.weightedDirection, this.weightedDirection);
|
|
593
|
+
this.$if(pb.greaterThan(this.weightedLengthSquared, 1e-6), function() {
|
|
594
|
+
this.$return(pb.mul(this.weightedDirection, pb.inverseSqrt(this.weightedLengthSquared)));
|
|
595
|
+
});
|
|
596
|
+
this.$return(this.fallback);
|
|
597
|
+
});
|
|
598
|
+
const directionPos = 1 + MORPH_WEIGHTS_VECTOR_COUNT * 2 + (attrib >> 2);
|
|
599
|
+
const directionComp = attrib & 3;
|
|
600
|
+
const positionPos = 1 + MORPH_WEIGHTS_VECTOR_COUNT * 2 + (MORPH_TARGET_POSITION >> 2);
|
|
601
|
+
const positionComp = MORPH_TARGET_POSITION & 3;
|
|
602
|
+
const morphInfo = scope[this.getMorphInfoUniformName()];
|
|
603
|
+
return scope.$g[funcName](base.xyz, pb.int(morphInfo[directionPos][directionComp]), pb.int(morphInfo[positionPos][positionComp]));
|
|
604
|
+
}
|
|
605
|
+
/** @internal */ static orthogonalizeMorphedTangent(scope, normal, tangent) {
|
|
606
|
+
const pb = scope.$builder;
|
|
607
|
+
const funcName = 'Z_orthogonalizeMorphedTangent';
|
|
608
|
+
pb.func(funcName, [
|
|
609
|
+
pb.vec3('normal'),
|
|
610
|
+
pb.vec3('tangent')
|
|
611
|
+
], function() {
|
|
612
|
+
this.$l.normalLengthSquared = pb.dot(this.normal, this.normal);
|
|
613
|
+
this.$if(pb.greaterThan(this.normalLengthSquared, 1e-6), function() {
|
|
614
|
+
this.$l.n = pb.mul(this.normal, pb.inverseSqrt(this.normalLengthSquared));
|
|
615
|
+
this.$l.projected = pb.sub(this.tangent, pb.mul(this.n, pb.dot(this.n, this.tangent)));
|
|
616
|
+
this.$l.tangentLengthSquared = pb.dot(this.projected, this.projected);
|
|
617
|
+
this.$if(pb.greaterThan(this.tangentLengthSquared, 1e-6), function() {
|
|
618
|
+
this.$return(pb.mul(this.projected, pb.inverseSqrt(this.tangentLengthSquared)));
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
this.$return(this.tangent);
|
|
622
|
+
});
|
|
623
|
+
return scope.$g[funcName](normal.xyz, tangent.xyz);
|
|
624
|
+
}
|
|
425
625
|
/** @internal */ static prepareSkinAnimation(scope) {
|
|
426
626
|
if (!this.hasSkinning(scope)) {
|
|
427
627
|
return;
|
|
428
628
|
}
|
|
429
629
|
const that = this;
|
|
430
630
|
const pb = scope.$builder;
|
|
631
|
+
const isWebGL = pb.getDevice().type === 'webgl';
|
|
632
|
+
const supportsTextureLoad = !isWebGL;
|
|
431
633
|
const funcNameGetBoneMatrixFromTexture = 'Z_getBoneMatrixFromTexture';
|
|
432
634
|
pb.func(funcNameGetBoneMatrixFromTexture, [
|
|
433
635
|
pb.float('boneIndex'),
|
|
@@ -461,6 +663,33 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
461
663
|
this.$l.m2 = scope.$g[funcNameGetBoneMatrixFromTexture](blendIndices[2], this.boneOffset);
|
|
462
664
|
this.$l.m3 = scope.$g[funcNameGetBoneMatrixFromTexture](blendIndices[3], this.boneOffset);
|
|
463
665
|
this.$l.m = pb.add(pb.mul(this.m0, blendWeights.x), pb.mul(this.m1, blendWeights.y), pb.mul(this.m2, blendWeights.z), pb.mul(this.m3, blendWeights.w));
|
|
666
|
+
this.$l.skinInfo = this[UNIFORM_NAME_SKIN_INFLUENCE_INFO];
|
|
667
|
+
this.$if(pb.greaterThan(this.skinInfo.z, 4), function() {
|
|
668
|
+
this.$l.vertexIndex = isWebGL ? pb.int(scope.$inputs.zFakeVertexID) : pb.int(scope.$builtins.vertexIndex);
|
|
669
|
+
this.$l.texWidth = pb.int(this.skinInfo.x);
|
|
670
|
+
this.$l.pairCount = pb.int(this.skinInfo.w);
|
|
671
|
+
this.$for(pb.int('pairIndex'), 0, MAX_SKIN_EXTRA_INFLUENCE_PAIRS, function() {
|
|
672
|
+
this.$if(pb.greaterThanEqual(this.pairIndex, this.pairCount), function() {
|
|
673
|
+
this.$break();
|
|
674
|
+
});
|
|
675
|
+
this.$l.pixelIndex = pb.add(pb.mul(this.vertexIndex, this.pairCount), this.pairIndex);
|
|
676
|
+
this.$l.xIndex = pb.mod(this.pixelIndex, this.texWidth);
|
|
677
|
+
this.$l.yIndex = pb.div(this.pixelIndex, this.texWidth);
|
|
678
|
+
if (supportsTextureLoad) {
|
|
679
|
+
this.$l.extra = pb.textureLoad(this[UNIFORM_NAME_SKIN_INFLUENCE_DATA], pb.ivec2(this.xIndex, this.yIndex), 0);
|
|
680
|
+
} else {
|
|
681
|
+
this.$l.u = pb.div(pb.add(pb.float(this.xIndex), 0.5), this.skinInfo.x);
|
|
682
|
+
this.$l.v = pb.div(pb.add(pb.float(this.yIndex), 0.5), this.skinInfo.y);
|
|
683
|
+
this.$l.extra = pb.textureSampleLevel(this[UNIFORM_NAME_SKIN_INFLUENCE_DATA], pb.vec2(this.u, this.v), 0);
|
|
684
|
+
}
|
|
685
|
+
this.$if(pb.greaterThan(this.extra.y, 0), function() {
|
|
686
|
+
this.m = pb.add(this.m, pb.mul(scope.$g[funcNameGetBoneMatrixFromTexture](this.extra.x, this.boneOffset), this.extra.y));
|
|
687
|
+
});
|
|
688
|
+
this.$if(pb.greaterThan(this.extra.w, 0), function() {
|
|
689
|
+
this.m = pb.add(this.m, pb.mul(scope.$g[funcNameGetBoneMatrixFromTexture](this.extra.z, this.boneOffset), this.extra.w));
|
|
690
|
+
});
|
|
691
|
+
});
|
|
692
|
+
});
|
|
464
693
|
this.$return(pb.mul(invBindMatrix, this.m));
|
|
465
694
|
});
|
|
466
695
|
const motionVector = !!this.getUnjitteredViewProjectionMatrix(scope);
|
|
@@ -535,6 +764,19 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
535
764
|
}
|
|
536
765
|
}
|
|
537
766
|
/**
|
|
767
|
+
* Gets the skinning matrix in the vertex shader, if the mesh being drawn is skinned.
|
|
768
|
+
*
|
|
769
|
+
* @remarks
|
|
770
|
+
* Lets a material apply the same skinning transform to its own uniform-supplied
|
|
771
|
+
* object-space vectors that {@link ShaderHelper.resolveVertexNormal} applies to
|
|
772
|
+
* the normal attribute, so such vectors stay attached to the deforming mesh.
|
|
773
|
+
*
|
|
774
|
+
* @param scope - Current shader scope, must be vertex stage
|
|
775
|
+
* @returns The skinning matrix of type mat4, or null when the mesh is not skinned
|
|
776
|
+
*/ static getSkinMatrix(scope) {
|
|
777
|
+
return scope[this.SKIN_MATRIX_NAME] ?? null;
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
538
780
|
* Calculates the normal vector of type vec3 in object space
|
|
539
781
|
*
|
|
540
782
|
* @param scope - Current shader scope
|
|
@@ -550,6 +792,10 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
550
792
|
if (!funcScope || !funcScope.$isMain()) {
|
|
551
793
|
throw new Error(`ShaderHelper.resolveVertexNormal(): must be called at entry function`);
|
|
552
794
|
}
|
|
795
|
+
const useVertexAttrib = !normal;
|
|
796
|
+
if (useVertexAttrib && scope[this.RESOLVED_VERTEX_NORMAL_NAME]) {
|
|
797
|
+
return scope[this.RESOLVED_VERTEX_NORMAL_NAME];
|
|
798
|
+
}
|
|
553
799
|
if (!normal) {
|
|
554
800
|
if (!scope.$getVertexAttrib('normal')) {
|
|
555
801
|
scope.$inputs.Z_normal = pb.vec3().attrib('normal');
|
|
@@ -557,13 +803,17 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
557
803
|
normal = scope.$getVertexAttrib('normal');
|
|
558
804
|
}
|
|
559
805
|
if (this.hasMorphing(scope)) {
|
|
560
|
-
normal =
|
|
806
|
+
normal = this.calculateMorphDirectionByDisplacement(scope, normal, MORPH_TARGET_NORMAL);
|
|
561
807
|
}
|
|
808
|
+
let resolvedNormal = normal;
|
|
562
809
|
if (scope[this.SKIN_MATRIX_NAME]) {
|
|
563
|
-
|
|
564
|
-
}
|
|
565
|
-
|
|
810
|
+
resolvedNormal = pb.mul(scope[this.SKIN_MATRIX_NAME], pb.vec4(normal, 0)).xyz;
|
|
811
|
+
}
|
|
812
|
+
if (useVertexAttrib) {
|
|
813
|
+
scope.$l[this.RESOLVED_VERTEX_NORMAL_NAME] = resolvedNormal;
|
|
814
|
+
resolvedNormal = scope[this.RESOLVED_VERTEX_NORMAL_NAME];
|
|
566
815
|
}
|
|
816
|
+
return resolvedNormal;
|
|
567
817
|
}
|
|
568
818
|
/**
|
|
569
819
|
* Calculates the tangent vector of type vec3 in object space
|
|
@@ -588,13 +838,16 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
588
838
|
tangent = scope.$getVertexAttrib('tangent');
|
|
589
839
|
}
|
|
590
840
|
if (this.hasMorphing(scope)) {
|
|
591
|
-
tangent = pb.
|
|
841
|
+
tangent = pb.vec4(this.calculateMorphDirectionByDisplacement(scope, tangent.xyz, MORPH_TARGET_TANGENT), tangent.w);
|
|
592
842
|
}
|
|
593
843
|
if (scope[this.SKIN_MATRIX_NAME]) {
|
|
594
|
-
|
|
595
|
-
} else {
|
|
596
|
-
return tangent;
|
|
844
|
+
tangent = pb.vec4(pb.mul(scope[this.SKIN_MATRIX_NAME], pb.vec4(tangent.xyz, 0)).xyz, tangent.w);
|
|
597
845
|
}
|
|
846
|
+
if (this.hasMorphing(scope) && scope.$getVertexAttrib('normal')) {
|
|
847
|
+
const resolvedNormal = scope[this.RESOLVED_VERTEX_NORMAL_NAME] ?? this.resolveVertexNormal(scope);
|
|
848
|
+
tangent = pb.vec4(this.orthogonalizeMorphedTangent(scope, resolvedNormal, tangent.xyz), tangent.w);
|
|
849
|
+
}
|
|
850
|
+
return tangent;
|
|
598
851
|
}
|
|
599
852
|
/**
|
|
600
853
|
* Gets the uniform variable of type mat4 which holds the world matrix of current object to be drawn
|
|
@@ -676,10 +929,12 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
676
929
|
scope[UNIFORM_NAME_BONE_MATRICES] = pb.tex2D().uniform(1).sampleType('unfilterable-float');
|
|
677
930
|
scope[UNIFORM_NAME_BONE_INV_BIND_MATRIX] = pb.mat4().uniform(1);
|
|
678
931
|
scope[UNIFORM_NAME_BONE_TEXTURE_SIZE] = pb.vec2().uniform(1);
|
|
932
|
+
scope[UNIFORM_NAME_SKIN_INFLUENCE_DATA] = pb.tex2D().uniform(1).sampleType('unfilterable-float');
|
|
933
|
+
scope[UNIFORM_NAME_SKIN_INFLUENCE_INFO] = pb.vec4().uniform(1);
|
|
679
934
|
}
|
|
680
935
|
if (morphing) {
|
|
681
936
|
scope[UNIFORM_NAME_MORPH_DATA] = pb.tex2D().uniform(1).sampleType('unfilterable-float');
|
|
682
|
-
scope[UNIFORM_NAME_MORPH_INFO] = pb.vec4[1 + MORPH_WEIGHTS_VECTOR_COUNT + MORPH_ATTRIBUTE_VECTOR_COUNT]().uniformBuffer(1);
|
|
937
|
+
scope[UNIFORM_NAME_MORPH_INFO] = pb.vec4[1 + MORPH_WEIGHTS_VECTOR_COUNT * 2 + MORPH_ATTRIBUTE_VECTOR_COUNT]().uniformBuffer(1);
|
|
683
938
|
}
|
|
684
939
|
}
|
|
685
940
|
/** @internal */ static prepareVertexShaderCommon(pb, ctx) {
|
|
@@ -735,8 +990,10 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
735
990
|
directionCutoff: light.directionAndCutoff,
|
|
736
991
|
viewMatrix: light.viewMatrix,
|
|
737
992
|
depthBias: shadowMapParams.depthBiasValues[0],
|
|
993
|
+
implParams: shadowMapParams.impl.getParams(this._lightUniformShadow.implParams),
|
|
738
994
|
lightType: light.lightType
|
|
739
995
|
});
|
|
996
|
+
shadowMapParams.impl?.applyCasterUniforms(bindGroup, shadowMapParams);
|
|
740
997
|
}
|
|
741
998
|
}
|
|
742
999
|
/** @internal */ static setFogUniforms(bindGroup, withAerialPerspective, fogType, additive, atmosphereParams, heightFogParams, aerialPerspectiveLUT, skyDistantLightLUT) {
|
|
@@ -1291,18 +1548,67 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
1291
1548
|
return scope[UNIFORM_NAME_SHADOW_MAP];
|
|
1292
1549
|
}
|
|
1293
1550
|
/**
|
|
1551
|
+
* Per-cascade scale for both bias terms.
|
|
1552
|
+
*
|
|
1553
|
+
* @remarks
|
|
1554
|
+
* Only `depthBiasValues[0]` is uploaded; every cascade's value is recovered by
|
|
1555
|
+
* multiplying with this ratio. It is derived from the `.x` components, but
|
|
1556
|
+
* since `.x` and the normal offset `.y` are both proportional to the cascade's
|
|
1557
|
+
* texel world size, the same ratio applies to either.
|
|
1558
|
+
* @internal
|
|
1559
|
+
*/ static getShadowCascadeBiasScale(scope, split) {
|
|
1560
|
+
const pb = scope.$builder;
|
|
1561
|
+
const splitFlags = pb.vec4(pb.float(pb.equal(split, 0)), pb.float(pb.equal(split, 1)), pb.float(pb.equal(split, 2)), pb.float(pb.equal(split, 3)));
|
|
1562
|
+
return pb.dot(this.getDepthBiasScales(scope), splitFlags);
|
|
1563
|
+
}
|
|
1564
|
+
/**
|
|
1565
|
+
* Moves the receiver along its normal before the shadow lookup.
|
|
1566
|
+
*
|
|
1567
|
+
* @remarks
|
|
1568
|
+
* Grazing-angle self-shadowing cannot be fixed with a depth bias: the depth
|
|
1569
|
+
* spanned by one shadow texel is `texelWorldSize * tan(theta)`, which diverges
|
|
1570
|
+
* as NdotL approaches zero. Offsetting the sample position sideways moves it
|
|
1571
|
+
* out of the offending texel instead, and the required distance is bounded.
|
|
1572
|
+
*
|
|
1573
|
+
* `depthBiasValues.y` carries the world-space distance of one `normalBias`
|
|
1574
|
+
* unit (see `ShadowMapper.calcDepthBiasParams`).
|
|
1575
|
+
* @internal
|
|
1576
|
+
*/ static applyShadowNormalOffset(lightType, scope, worldPos, worldNormal, NdotL, cascadeScale) {
|
|
1577
|
+
const pb = scope.$builder;
|
|
1578
|
+
const depthBiasParam = this.getDepthBiasValues(scope);
|
|
1579
|
+
const receiverNoL = getShadowReceiverNoL(scope, NdotL, lightType);
|
|
1580
|
+
// sin(theta): 0 when facing the light, 1 at grazing incidence.
|
|
1581
|
+
const sinTheta = pb.sqrt(pb.clamp(pb.sub(1, pb.mul(receiverNoL, receiverNoL)), 0, 1));
|
|
1582
|
+
let offset = pb.mul(depthBiasParam.y, getShadowReceiverBiasFactor(scope), sinTheta);
|
|
1583
|
+
if (cascadeScale) {
|
|
1584
|
+
offset = pb.mul(offset, cascadeScale);
|
|
1585
|
+
}
|
|
1586
|
+
if (lightType !== LIGHT_TYPE_DIRECTIONAL) {
|
|
1587
|
+
// Perspective shadow cameras: one texel covers more world space further
|
|
1588
|
+
// from the light. depthBiasValues.w is the far/near footprint ratio.
|
|
1589
|
+
const posRange = this.getLightPositionAndRangeForShadow(scope);
|
|
1590
|
+
const linearDepth = pb.clamp(pb.div(pb.distance(worldPos, posRange.xyz), pb.max(posRange.w, 1e-6)), 0, 1);
|
|
1591
|
+
offset = pb.mul(offset, pb.mix(1, depthBiasParam.w, linearDepth));
|
|
1592
|
+
}
|
|
1593
|
+
// Guard against a degenerate interpolated normal rather than normalize()ing
|
|
1594
|
+
// a possibly-zero vector into NaN.
|
|
1595
|
+
const unitNormal = pb.mul(worldNormal, pb.div(1, pb.max(pb.length(worldNormal), 1e-6)));
|
|
1596
|
+
return pb.add(worldPos, pb.mul(unitNormal, offset));
|
|
1597
|
+
}
|
|
1598
|
+
/**
|
|
1294
1599
|
* Calculates shadow of current fragment
|
|
1295
1600
|
*
|
|
1296
1601
|
* @param scope - Shader scope
|
|
1297
1602
|
* @param NoL - NdotL vector
|
|
1298
1603
|
* @returns Shadow of current fragment, 1 means no shadow and 0 means full shadowed.
|
|
1299
|
-
*/ static calculateShadow(scope, worldPos, NoL, ctx) {
|
|
1604
|
+
*/ static calculateShadow(scope, worldPos, worldNormal, NoL, ctx) {
|
|
1300
1605
|
const pb = scope.$builder;
|
|
1301
1606
|
const that = this;
|
|
1302
1607
|
const shadowMapParams = ctx.shadowMapInfo.get(ctx.currentShadowLight);
|
|
1303
1608
|
const funcName = 'Z_calculateShadow';
|
|
1304
1609
|
pb.func(funcName, [
|
|
1305
1610
|
pb.vec3('worldPos'),
|
|
1611
|
+
pb.vec3('worldNormal'),
|
|
1306
1612
|
pb.float('NoL')
|
|
1307
1613
|
], function() {
|
|
1308
1614
|
if (shadowMapParams.numShadowCascades > 1) {
|
|
@@ -1313,18 +1619,21 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
1313
1619
|
this.$l.comparison = pb.vec4(pb.greaterThan(pb.vec4(this.linearDepth), this.splitDistances));
|
|
1314
1620
|
this.$l.cascadeFlags = pb.vec4(pb.float(pb.greaterThan(this.shadowCascades, 0)), pb.float(pb.greaterThan(this.shadowCascades, 1)), pb.float(pb.greaterThan(this.shadowCascades, 2)), pb.float(pb.greaterThan(this.shadowCascades, 3)));
|
|
1315
1621
|
this.$l.split = pb.int(pb.dot(this.comparison, this.cascadeFlags));
|
|
1622
|
+
// Normal offset bias: move the receiver out of the shadow texel that
|
|
1623
|
+
// would self-occlude it before projecting into shadow space. Scaled per
|
|
1624
|
+
// cascade, because each cascade has its own texel world size.
|
|
1625
|
+
this.$l.biasedPos = that.applyShadowNormalOffset(shadowMapParams.lightType, this, this.worldPos, this.worldNormal, this.NoL, that.getShadowCascadeBiasScale(this, this.split));
|
|
1316
1626
|
if (ctx.device.type === 'webgl') {
|
|
1317
1627
|
this.$l.shadowVertex = pb.vec4();
|
|
1318
1628
|
this.$for(pb.int('cascade'), 0, 4, function() {
|
|
1319
1629
|
this.$if(pb.equal(this.cascade, this.split), function() {
|
|
1320
|
-
this.shadowVertex = that.calculateShadowSpaceVertex(this, pb.vec4(this.
|
|
1630
|
+
this.shadowVertex = that.calculateShadowSpaceVertex(this, pb.vec4(this.biasedPos, 1), this.cascade);
|
|
1321
1631
|
this.$break();
|
|
1322
1632
|
});
|
|
1323
1633
|
});
|
|
1324
1634
|
} else {
|
|
1325
|
-
this.$l.shadowVertex = that.calculateShadowSpaceVertex(this, pb.vec4(this.
|
|
1635
|
+
this.$l.shadowVertex = that.calculateShadowSpaceVertex(this, pb.vec4(this.biasedPos, 1), this.split);
|
|
1326
1636
|
}
|
|
1327
|
-
const shadowMapParams = ctx.shadowMapInfo.get(ctx.currentShadowLight);
|
|
1328
1637
|
this.$l.shadow = shadowMapParams.impl.computeShadowCSM(shadowMapParams, this, this.shadowVertex, this.NoL, this.split);
|
|
1329
1638
|
this.shadow = pb.clamp(this.shadow, 0, 1);
|
|
1330
1639
|
this.$l.shadowDistance = that.getShadowCameraParams(scope).w;
|
|
@@ -1336,8 +1645,9 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
1336
1645
|
});
|
|
1337
1646
|
this.$return(this.shadow);
|
|
1338
1647
|
} else {
|
|
1339
|
-
|
|
1340
|
-
|
|
1648
|
+
// Normal offset bias - see the cascaded branch above.
|
|
1649
|
+
this.$l.biasedPos = that.applyShadowNormalOffset(shadowMapParams.lightType, this, this.worldPos, this.worldNormal, this.NoL);
|
|
1650
|
+
this.$l.shadowVertex = that.calculateShadowSpaceVertex(this, pb.vec4(this.biasedPos, 1));
|
|
1341
1651
|
this.$l.shadow = shadowMapParams.impl.computeShadow(shadowMapParams, this, this.shadowVertex, this.NoL);
|
|
1342
1652
|
this.shadow = pb.clamp(this.shadow, 0, 1);
|
|
1343
1653
|
this.$l.shadowDistance = that.getShadowCameraParams(scope).w;
|
|
@@ -1347,7 +1657,7 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
|
|
|
1347
1657
|
this.$return(this.shadow);
|
|
1348
1658
|
}
|
|
1349
1659
|
});
|
|
1350
|
-
return pb.getGlobalScope()[funcName](worldPos, NoL);
|
|
1660
|
+
return pb.getGlobalScope()[funcName](worldPos, worldNormal, NoL);
|
|
1351
1661
|
}
|
|
1352
1662
|
static applyFog(scope, worldPos, color, ctx) {
|
|
1353
1663
|
const pb = scope.$builder;
|