@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PBShaderExp } from '@zephyr3d/device';
|
|
2
2
|
import { ConstantScalarNode, ConstantVec2Node, ConstantVec3Node, ConstantVec4Node, ConstantBooleanNode, ConstantBVec2Node, ConstantBVec3Node, ConstantBVec4Node } from '../common/constants.js';
|
|
3
3
|
import { ASSERT } from '@zephyr3d/base';
|
|
4
|
-
import { BaseTextureNode, TextureSampleNode, PannerNode } from './texture.js';
|
|
4
|
+
import { BaseTextureNode, TextureSampleNode, ChannelSDFMaskNode, MorphBlurNode, PannerNode, TexturePropertyNode } from './texture.js';
|
|
5
5
|
import { MakeVectorNode, SwizzleNode, CompComparisonNode, AnyConditionNode, AllConditionNode, SelectionNode, Hash1Node, Hash2Node, Hash3Node, SimplexNoise2DNode, PerlinNoise2DNode, GenericMathNode, TransformNode, RotateAboutAxisNode } from '../common/math.js';
|
|
6
6
|
import { ResolveVertexPositionNode, ResolveVertexNormalNode, ResolveVertexTangentNode, VertexOutputNode, VertexIndexNode, InstanceIndexNode, VertexColorNode, VertexUVNode, VertexPositionNode, PixelWorldPositionNode, VertexNormalNode, PixelNormalNode, VertexTangentNode, VertexBinormalNode, ViewMatrixNode, ProjectionMatrixNode, ViewProjMatrixNode, InvProjMatrixNode, InvViewProjMatrixNode, BillboardMatrixNode, CameraPositionNode, CameraVectorNode, CameraNearFarNode, SkyEnvTextureNode, ElapsedTimeNode } from './inputs.js';
|
|
7
7
|
import { ShaderHelper } from '../../../material/shader/helper.js';
|
|
@@ -100,15 +100,19 @@ import { VertexBlockNode } from './pbr.js';
|
|
|
100
100
|
*/ class IRConstantf extends IRExpression {
|
|
101
101
|
/** The constant float value */ value;
|
|
102
102
|
/** The uniform parameter name, or empty string for literals */ name;
|
|
103
|
+
/** Optional lower bound for editor-facing scalar parameters */ minValue;
|
|
104
|
+
/** Optional upper bound for editor-facing scalar parameters */ maxValue;
|
|
103
105
|
/**
|
|
104
106
|
* Creates a constant float expression
|
|
105
107
|
*
|
|
106
108
|
* @param value - The float value
|
|
107
109
|
* @param paramName - The uniform parameter name, or empty string for literals
|
|
108
|
-
*/ constructor(value, paramName){
|
|
110
|
+
*/ constructor(value, paramName, minValue, maxValue){
|
|
109
111
|
super();
|
|
110
112
|
this.value = value;
|
|
111
113
|
this.name = paramName;
|
|
114
|
+
this.minValue = minValue;
|
|
115
|
+
this.maxValue = maxValue;
|
|
112
116
|
}
|
|
113
117
|
/**
|
|
114
118
|
* Generates shader code for this constant
|
|
@@ -139,7 +143,13 @@ import { VertexBlockNode } from './pbr.js';
|
|
|
139
143
|
value: [
|
|
140
144
|
this.value
|
|
141
145
|
],
|
|
142
|
-
type: 'float'
|
|
146
|
+
type: 'float',
|
|
147
|
+
...this.minValue !== undefined ? {
|
|
148
|
+
minValue: this.minValue
|
|
149
|
+
} : {},
|
|
150
|
+
...this.maxValue !== undefined ? {
|
|
151
|
+
maxValue: this.maxValue
|
|
152
|
+
} : {}
|
|
143
153
|
} : null;
|
|
144
154
|
}
|
|
145
155
|
}
|
|
@@ -418,6 +428,7 @@ import { VertexBlockNode } from './pbr.js';
|
|
|
418
428
|
/** The function call node from the graph */ node;
|
|
419
429
|
/** Array of argument expressions */ args;
|
|
420
430
|
/** Cached temporary variable name if result is referenced multiple times */ tmpName;
|
|
431
|
+
textureArgSamplerNames;
|
|
421
432
|
/**
|
|
422
433
|
* Creates a function call expression
|
|
423
434
|
*
|
|
@@ -428,9 +439,58 @@ import { VertexBlockNode } from './pbr.js';
|
|
|
428
439
|
this.node = node;
|
|
429
440
|
this.args = args;
|
|
430
441
|
this.tmpName = '';
|
|
442
|
+
this.textureArgSamplerNames = new Map();
|
|
431
443
|
}
|
|
432
444
|
/** Reset for next creation */ reset() {
|
|
433
445
|
this.tmpName = '';
|
|
446
|
+
this.textureArgSamplerNames.clear();
|
|
447
|
+
}
|
|
448
|
+
getTextureSamplerVarName(argName) {
|
|
449
|
+
let name = this.textureArgSamplerNames.get(argName);
|
|
450
|
+
if (!name) {
|
|
451
|
+
name = `${argName}__sampler`;
|
|
452
|
+
this.textureArgSamplerNames.set(argName, name);
|
|
453
|
+
}
|
|
454
|
+
return name;
|
|
455
|
+
}
|
|
456
|
+
buildTextureFunctionParams(pb) {
|
|
457
|
+
const params = [];
|
|
458
|
+
for (const arg of this.node.args){
|
|
459
|
+
// @ts-ignore
|
|
460
|
+
params.push(pb[arg.type](arg.name));
|
|
461
|
+
if (arg.type === 'tex2D' && pb.getDevice().type === 'webgpu') {
|
|
462
|
+
params.push(pb.sampler(this.getTextureSamplerVarName(arg.name)));
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return params;
|
|
466
|
+
}
|
|
467
|
+
buildTextureFunctionCallArgs(pb) {
|
|
468
|
+
const args = [];
|
|
469
|
+
for(let i = 0; i < this.node.args.length; i++){
|
|
470
|
+
const argDef = this.node.args[i];
|
|
471
|
+
const argExp = this.args[i].create(pb);
|
|
472
|
+
args.push(argExp);
|
|
473
|
+
if (argDef.type === 'tex2D' && pb.getDevice().type === 'webgpu') {
|
|
474
|
+
if (!(argExp instanceof PBShaderExp)) {
|
|
475
|
+
throw new Error(`Material function '${this.node.name}' expects texture argument '${argDef.name}'`);
|
|
476
|
+
}
|
|
477
|
+
let sampler = pb.getDefaultSampler(argExp, false);
|
|
478
|
+
if (!sampler && argExp.$str) {
|
|
479
|
+
sampler = pb.getCurrentScope()[this.getTextureSamplerVarName(argExp.$str)];
|
|
480
|
+
}
|
|
481
|
+
if (!sampler) {
|
|
482
|
+
throw new Error(`Material function '${this.node.name}' cannot resolve sampler for texture argument '${argDef.name}'`);
|
|
483
|
+
}
|
|
484
|
+
args.push(sampler);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return args;
|
|
488
|
+
}
|
|
489
|
+
isSingleTextureOutput() {
|
|
490
|
+
return this.node.outs.length === 1 && this.node.outs[0].type === 'tex2D';
|
|
491
|
+
}
|
|
492
|
+
hasTextureOutput() {
|
|
493
|
+
return this.node.outs.some((output)=>output.type === 'tex2D');
|
|
434
494
|
}
|
|
435
495
|
/**
|
|
436
496
|
* Generates shader code for the function definition and call
|
|
@@ -446,21 +506,34 @@ import { VertexBlockNode } from './pbr.js';
|
|
|
446
506
|
if (this.tmpName) {
|
|
447
507
|
return pb.getCurrentScope()[this.tmpName];
|
|
448
508
|
}
|
|
509
|
+
if (this.hasTextureOutput() && !this.isSingleTextureOutput()) {
|
|
510
|
+
throw new Error(`Material function '${this.node.name}' only supports tex2D as a single standalone output`);
|
|
511
|
+
}
|
|
449
512
|
const that = this;
|
|
450
513
|
const ir = this.node.IR;
|
|
451
|
-
|
|
452
|
-
const params = this.node.args.map((v)=>pb[v.type](v.name));
|
|
514
|
+
const params = this.buildTextureFunctionParams(pb);
|
|
453
515
|
pb.func(this.node.name, params, function() {
|
|
454
516
|
const outputs = ir.create(pb);
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
return
|
|
461
|
-
})
|
|
517
|
+
const orderedOutputs = that.node.outs.map((output)=>{
|
|
518
|
+
const index = ir.DAG.roots.indexOf(output.index);
|
|
519
|
+
if (index < 0 || !outputs[index]) {
|
|
520
|
+
throw new Error(`Material function '${that.node.name}' cannot resolve output '${output.name}'`);
|
|
521
|
+
}
|
|
522
|
+
return outputs[index];
|
|
523
|
+
});
|
|
524
|
+
if (that.isSingleTextureOutput()) {
|
|
525
|
+
this.$return(orderedOutputs[0].exp);
|
|
526
|
+
} else {
|
|
527
|
+
const rettype = pb.defineStruct(that.node.outputs.map((output, index)=>{
|
|
528
|
+
// @ts-ignore
|
|
529
|
+
return pb[that.node.outs[index].type](output.swizzle);
|
|
530
|
+
}));
|
|
531
|
+
this.$return(rettype(...orderedOutputs.map((output)=>{
|
|
532
|
+
return output.exp;
|
|
533
|
+
})));
|
|
534
|
+
}
|
|
462
535
|
});
|
|
463
|
-
const args = this.
|
|
536
|
+
const args = this.buildTextureFunctionCallArgs(pb);
|
|
464
537
|
const exp = pb.getGlobalScope()[this.node.name](...args);
|
|
465
538
|
if (this._ref === 1) {
|
|
466
539
|
return exp;
|
|
@@ -779,7 +852,21 @@ class IRComparison extends IRExpression {
|
|
|
779
852
|
} else {
|
|
780
853
|
throw new Error('Invalid texture coordinate');
|
|
781
854
|
}
|
|
782
|
-
let exp
|
|
855
|
+
let exp;
|
|
856
|
+
if (pb.getDevice().type === 'webgpu') {
|
|
857
|
+
let sampler = pb.getDefaultSampler(texExp, false);
|
|
858
|
+
if (!sampler && texExp.$str) {
|
|
859
|
+
sampler = pb.getCurrentScope()[`${texExp.$str}__sampler`];
|
|
860
|
+
}
|
|
861
|
+
if (sampler) {
|
|
862
|
+
// @ts-ignore ProgramBuilder runtime supports the explicit WebGPU sampler overload.
|
|
863
|
+
exp = pb.textureSample(texExp, sampler, coordExp);
|
|
864
|
+
} else {
|
|
865
|
+
exp = pb.textureSample(texExp, coordExp);
|
|
866
|
+
}
|
|
867
|
+
} else {
|
|
868
|
+
exp = pb.textureSample(texExp, coordExp);
|
|
869
|
+
}
|
|
783
870
|
if (this.samplerType === 'Normal') {
|
|
784
871
|
exp = pb.sub(pb.mul(exp, pb.vec4(2, 2, 2, 1)), pb.vec4(1, 1, 1, 0));
|
|
785
872
|
}
|
|
@@ -792,6 +879,284 @@ class IRComparison extends IRExpression {
|
|
|
792
879
|
}
|
|
793
880
|
}
|
|
794
881
|
}
|
|
882
|
+
class IRMorphBlur extends IRExpression {
|
|
883
|
+
tex;
|
|
884
|
+
coord;
|
|
885
|
+
morphRadius;
|
|
886
|
+
blurRadius;
|
|
887
|
+
channelMask;
|
|
888
|
+
tmpName;
|
|
889
|
+
constructor(tex, coord, morphRadius, blurRadius, channelMask){
|
|
890
|
+
super();
|
|
891
|
+
this.tex = tex.addRef();
|
|
892
|
+
this.coord = coord.addRef();
|
|
893
|
+
this.morphRadius = morphRadius instanceof IRExpression ? morphRadius.addRef() : morphRadius;
|
|
894
|
+
this.blurRadius = blurRadius instanceof IRExpression ? blurRadius.addRef() : blurRadius;
|
|
895
|
+
this.channelMask = channelMask instanceof IRExpression ? channelMask.addRef() : channelMask.slice();
|
|
896
|
+
this.tmpName = '';
|
|
897
|
+
}
|
|
898
|
+
reset() {
|
|
899
|
+
this.tmpName = '';
|
|
900
|
+
}
|
|
901
|
+
create(pb) {
|
|
902
|
+
if (this.tmpName) {
|
|
903
|
+
return pb.getCurrentScope()[this.tmpName];
|
|
904
|
+
}
|
|
905
|
+
const texExp = this.tex.create(pb);
|
|
906
|
+
const coordExp = this.coord.create(pb);
|
|
907
|
+
const morphExp = this.morphRadius instanceof IRExpression ? this.morphRadius.create(pb) : this.morphRadius;
|
|
908
|
+
const blurExp = this.blurRadius instanceof IRExpression ? this.blurRadius.create(pb) : this.blurRadius;
|
|
909
|
+
const maskExpRaw = this.channelMask instanceof IRExpression ? this.channelMask.create(pb) : pb.vec4(this.channelMask[0] ?? 0, this.channelMask[1] ?? 0, this.channelMask[2] ?? 0, this.channelMask[3] ?? 0);
|
|
910
|
+
if (!(texExp instanceof PBShaderExp) || !(coordExp instanceof PBShaderExp) || !(maskExpRaw instanceof PBShaderExp)) {
|
|
911
|
+
throw new Error('Invalid texture sampling input');
|
|
912
|
+
}
|
|
913
|
+
const maskExp = maskExpRaw;
|
|
914
|
+
const texVarName = texExp.$str || 'Texture';
|
|
915
|
+
const funcName = `Z_MorphBlur_${texVarName.replace(/[^A-Za-z0-9_]/g, '_')}`;
|
|
916
|
+
const sampleMaskedName = `${funcName}_sampleMasked`;
|
|
917
|
+
const morphValueName = `${funcName}_morphValue`;
|
|
918
|
+
const blurBaseName = `${funcName}_blurBase`;
|
|
919
|
+
const texelSize = pb.div(pb.vec2(1), pb.vec2(pb.textureDimensions(texExp, 0)));
|
|
920
|
+
pb.func(sampleMaskedName, [
|
|
921
|
+
pb.tex2D('texture'),
|
|
922
|
+
...pb.getDevice().type === 'webgpu' ? [
|
|
923
|
+
pb.sampler('texture__sampler')
|
|
924
|
+
] : [],
|
|
925
|
+
pb.vec2('uv'),
|
|
926
|
+
pb.vec4('channelMask')
|
|
927
|
+
], function() {
|
|
928
|
+
this.$l.sampled = pb.getDevice().type === 'webgpu' ? pb.textureSample(this.texture, this.texture__sampler, this.uv) : pb.textureSample(this.texture, this.uv);
|
|
929
|
+
this.$return(pb.dot(this.sampled, this.channelMask));
|
|
930
|
+
});
|
|
931
|
+
pb.func(morphValueName, [
|
|
932
|
+
pb.tex2D('texture'),
|
|
933
|
+
...pb.getDevice().type === 'webgpu' ? [
|
|
934
|
+
pb.sampler('texture__sampler')
|
|
935
|
+
] : [],
|
|
936
|
+
pb.vec2('uv'),
|
|
937
|
+
pb.vec2('texelSize'),
|
|
938
|
+
pb.float('morphRadius'),
|
|
939
|
+
pb.vec4('channelMask')
|
|
940
|
+
], function() {
|
|
941
|
+
this.$l.morphStep = pb.abs(this.morphRadius);
|
|
942
|
+
this.$l.morphOffsets = pb.vec2[5]();
|
|
943
|
+
this.morphOffsets.setAt(0, pb.vec2(0, 0));
|
|
944
|
+
this.morphOffsets.setAt(1, pb.vec2(this.morphStep, 0));
|
|
945
|
+
this.morphOffsets.setAt(2, pb.vec2(pb.neg(this.morphStep), 0));
|
|
946
|
+
this.morphOffsets.setAt(3, pb.vec2(0, this.morphStep));
|
|
947
|
+
this.morphOffsets.setAt(4, pb.vec2(0, pb.neg(this.morphStep)));
|
|
948
|
+
this.$if(pb.greaterThan(this.morphRadius, 0), function() {
|
|
949
|
+
this.$l.dilateValue = pb.float(0);
|
|
950
|
+
this.$for(pb.int('morphIndex'), 0, 5, function() {
|
|
951
|
+
this.$l.sampleUV = pb.add(this.uv, pb.mul(this.morphOffsets.at(this.morphIndex), this.texelSize));
|
|
952
|
+
this.$l.sampleValue = pb.getDevice().type === 'webgpu' ? this[sampleMaskedName](this.texture, this.texture__sampler, this.sampleUV, this.channelMask) : this[sampleMaskedName](this.texture, this.sampleUV, this.channelMask);
|
|
953
|
+
this.$if(pb.equal(this.morphIndex, 0), function() {
|
|
954
|
+
this.dilateValue = this.sampleValue;
|
|
955
|
+
}).$else(function() {
|
|
956
|
+
this.dilateValue = pb.max(this.dilateValue, this.sampleValue);
|
|
957
|
+
});
|
|
958
|
+
});
|
|
959
|
+
this.$return(this.dilateValue);
|
|
960
|
+
}).$elseif(pb.lessThan(this.morphRadius, 0), function() {
|
|
961
|
+
this.$l.erodeValue = pb.float(0);
|
|
962
|
+
this.$for(pb.int('morphIndex'), 0, 5, function() {
|
|
963
|
+
this.$l.sampleUV = pb.add(this.uv, pb.mul(this.morphOffsets.at(this.morphIndex), this.texelSize));
|
|
964
|
+
this.$l.sampleValue = pb.getDevice().type === 'webgpu' ? this[sampleMaskedName](this.texture, this.texture__sampler, this.sampleUV, this.channelMask) : this[sampleMaskedName](this.texture, this.sampleUV, this.channelMask);
|
|
965
|
+
this.$if(pb.equal(this.morphIndex, 0), function() {
|
|
966
|
+
this.erodeValue = this.sampleValue;
|
|
967
|
+
}).$else(function() {
|
|
968
|
+
this.erodeValue = pb.min(this.erodeValue, this.sampleValue);
|
|
969
|
+
});
|
|
970
|
+
});
|
|
971
|
+
this.$return(this.erodeValue);
|
|
972
|
+
}).$else(function() {
|
|
973
|
+
this.$return(pb.getDevice().type === 'webgpu' ? this[sampleMaskedName](this.texture, this.texture__sampler, this.uv, this.channelMask) : this[sampleMaskedName](this.texture, this.uv, this.channelMask));
|
|
974
|
+
});
|
|
975
|
+
});
|
|
976
|
+
pb.func(blurBaseName, [
|
|
977
|
+
pb.tex2D('texture'),
|
|
978
|
+
...pb.getDevice().type === 'webgpu' ? [
|
|
979
|
+
pb.sampler('texture__sampler')
|
|
980
|
+
] : [],
|
|
981
|
+
pb.vec2('uv'),
|
|
982
|
+
pb.vec2('texelSize'),
|
|
983
|
+
pb.float('blurRadius'),
|
|
984
|
+
pb.vec4('channelMask'),
|
|
985
|
+
pb.float('morphRadius'),
|
|
986
|
+
pb.bool('useMorph')
|
|
987
|
+
], function() {
|
|
988
|
+
this.$l.radius = pb.max(this.blurRadius, 0);
|
|
989
|
+
this.$l.sigma = pb.max(pb.mul(this.radius, 0.6), 0.85);
|
|
990
|
+
this.$l.invSigma2 = pb.div(0.5, pb.mul(this.sigma, this.sigma));
|
|
991
|
+
this.$l.kernelRadius = pb.int(2);
|
|
992
|
+
this.$if(pb.greaterThan(this.radius, 1.5), function() {
|
|
993
|
+
this.kernelRadius = pb.int(3);
|
|
994
|
+
});
|
|
995
|
+
this.$if(pb.greaterThan(this.radius, 3), function() {
|
|
996
|
+
this.kernelRadius = pb.int(4);
|
|
997
|
+
});
|
|
998
|
+
this.$if(pb.greaterThan(this.radius, 5), function() {
|
|
999
|
+
this.kernelRadius = pb.int(5);
|
|
1000
|
+
});
|
|
1001
|
+
this.$if(pb.greaterThan(this.radius, 7.5), function() {
|
|
1002
|
+
this.kernelRadius = pb.int(6);
|
|
1003
|
+
});
|
|
1004
|
+
this.$if(pb.greaterThan(this.radius, 9), function() {
|
|
1005
|
+
this.kernelRadius = pb.int(7);
|
|
1006
|
+
});
|
|
1007
|
+
this.$if(pb.greaterThan(this.radius, 10.5), function() {
|
|
1008
|
+
this.kernelRadius = pb.int(8);
|
|
1009
|
+
});
|
|
1010
|
+
this.$if(pb.greaterThan(this.radius, 12), function() {
|
|
1011
|
+
this.kernelRadius = pb.int(9);
|
|
1012
|
+
});
|
|
1013
|
+
this.$if(pb.greaterThan(this.radius, 13.5), function() {
|
|
1014
|
+
this.kernelRadius = pb.int(10);
|
|
1015
|
+
});
|
|
1016
|
+
this.$if(pb.greaterThan(this.radius, 15), function() {
|
|
1017
|
+
this.kernelRadius = pb.int(11);
|
|
1018
|
+
});
|
|
1019
|
+
this.$if(pb.greaterThan(this.radius, 16.5), function() {
|
|
1020
|
+
this.kernelRadius = pb.int(12);
|
|
1021
|
+
});
|
|
1022
|
+
this.$l.kernelRadiusF = pb.max(pb.float(this.kernelRadius), 1);
|
|
1023
|
+
this.$l.sampleStep = pb.max(pb.div(this.radius, this.kernelRadiusF), 1);
|
|
1024
|
+
this.$l.supportRadius = pb.max(this.radius, 1);
|
|
1025
|
+
this.$l.supportRadius2 = pb.mul(this.supportRadius, this.supportRadius);
|
|
1026
|
+
this.$l.sum = pb.float(0);
|
|
1027
|
+
this.$l.weightSum = pb.float(0);
|
|
1028
|
+
this.$for(pb.int('blurY'), 0, 25, function() {
|
|
1029
|
+
this.$l.offsetY = pb.sub(this.blurY, 12);
|
|
1030
|
+
this.$if(pb.lessThanEqual(pb.abs(this.offsetY), this.kernelRadius), function() {
|
|
1031
|
+
this.$for(pb.int('blurX'), 0, 25, function() {
|
|
1032
|
+
this.$l.offsetX = pb.sub(this.blurX, 12);
|
|
1033
|
+
this.$if(pb.lessThanEqual(pb.abs(this.offsetX), this.kernelRadius), function() {
|
|
1034
|
+
this.$l.sampleOffset = pb.mul(pb.vec2(pb.float(this.offsetX), pb.float(this.offsetY)), this.sampleStep);
|
|
1035
|
+
this.$l.sampleRadius2 = pb.dot(this.sampleOffset, this.sampleOffset);
|
|
1036
|
+
this.$if(pb.lessThanEqual(this.sampleRadius2, this.supportRadius2), function() {
|
|
1037
|
+
this.$l.sampleUV = pb.add(this.uv, pb.mul(this.sampleOffset, this.texelSize));
|
|
1038
|
+
this.$l.sampleValue = this.useMorph ? pb.getDevice().type === 'webgpu' ? this[morphValueName](this.texture, this.texture__sampler, this.sampleUV, this.texelSize, this.morphRadius, this.channelMask) : this[morphValueName](this.texture, this.sampleUV, this.texelSize, this.morphRadius, this.channelMask) : pb.getDevice().type === 'webgpu' ? this[sampleMaskedName](this.texture, this.texture__sampler, this.sampleUV, this.channelMask) : this[sampleMaskedName](this.texture, this.sampleUV, this.channelMask);
|
|
1039
|
+
this.$l.weight = pb.exp(pb.neg(pb.mul(this.sampleRadius2, this.invSigma2)));
|
|
1040
|
+
this.sum = pb.add(this.sum, pb.mul(this.sampleValue, this.weight));
|
|
1041
|
+
this.weightSum = pb.add(this.weightSum, this.weight);
|
|
1042
|
+
});
|
|
1043
|
+
});
|
|
1044
|
+
});
|
|
1045
|
+
});
|
|
1046
|
+
});
|
|
1047
|
+
this.$return(pb.div(this.sum, pb.max(this.weightSum, 1e-5)));
|
|
1048
|
+
});
|
|
1049
|
+
pb.func(funcName, [
|
|
1050
|
+
pb.tex2D('texture'),
|
|
1051
|
+
...pb.getDevice().type === 'webgpu' ? [
|
|
1052
|
+
pb.sampler('texture__sampler')
|
|
1053
|
+
] : [],
|
|
1054
|
+
pb.vec2('uv'),
|
|
1055
|
+
pb.vec2('texelSize'),
|
|
1056
|
+
pb.float('morphRadius'),
|
|
1057
|
+
pb.float('blurRadius'),
|
|
1058
|
+
pb.vec4('channelMask')
|
|
1059
|
+
], function() {
|
|
1060
|
+
this.$l.morphAbs = pb.abs(this.morphRadius);
|
|
1061
|
+
this.$l.blurAbs = pb.abs(this.blurRadius);
|
|
1062
|
+
this.$if(pb.lessThanEqual(this.morphAbs, 1e-4), function() {
|
|
1063
|
+
this.$if(pb.lessThanEqual(this.blurAbs, 1e-4), function() {
|
|
1064
|
+
this.$return(pb.getDevice().type === 'webgpu' ? this[sampleMaskedName](this.texture, this.texture__sampler, this.uv, this.channelMask) : this[sampleMaskedName](this.texture, this.uv, this.channelMask));
|
|
1065
|
+
}).$else(function() {
|
|
1066
|
+
this.$return(pb.getDevice().type === 'webgpu' ? this[blurBaseName](this.texture, this.texture__sampler, this.uv, this.texelSize, this.blurRadius, this.channelMask, this.morphRadius, false) : this[blurBaseName](this.texture, this.uv, this.texelSize, this.blurRadius, this.channelMask, this.morphRadius, false));
|
|
1067
|
+
});
|
|
1068
|
+
}).$elseif(pb.lessThanEqual(this.blurAbs, 1e-4), function() {
|
|
1069
|
+
this.$return(pb.getDevice().type === 'webgpu' ? this[morphValueName](this.texture, this.texture__sampler, this.uv, this.texelSize, this.morphRadius, this.channelMask) : this[morphValueName](this.texture, this.uv, this.texelSize, this.morphRadius, this.channelMask));
|
|
1070
|
+
}).$else(function() {
|
|
1071
|
+
this.$return(pb.getDevice().type === 'webgpu' ? this[blurBaseName](this.texture, this.texture__sampler, this.uv, this.texelSize, this.blurRadius, this.channelMask, this.morphRadius, true) : this[blurBaseName](this.texture, this.uv, this.texelSize, this.blurRadius, this.channelMask, this.morphRadius, true));
|
|
1072
|
+
});
|
|
1073
|
+
});
|
|
1074
|
+
const callArgs = [
|
|
1075
|
+
texExp,
|
|
1076
|
+
...pb.getDevice().type === 'webgpu' ? [
|
|
1077
|
+
pb.getDefaultSampler(texExp, false) ?? pb.getCurrentScope()[`${texExp.$str}__sampler`]
|
|
1078
|
+
] : [],
|
|
1079
|
+
coordExp,
|
|
1080
|
+
texelSize,
|
|
1081
|
+
morphExp,
|
|
1082
|
+
blurExp,
|
|
1083
|
+
maskExp
|
|
1084
|
+
];
|
|
1085
|
+
if (pb.getDevice().type === 'webgpu' && !(callArgs[1] instanceof PBShaderExp)) {
|
|
1086
|
+
throw new Error('Cannot resolve sampler for MorphBlur node');
|
|
1087
|
+
}
|
|
1088
|
+
const exp = pb.getGlobalScope()[funcName](...callArgs);
|
|
1089
|
+
if (this._ref === 1) {
|
|
1090
|
+
return exp;
|
|
1091
|
+
}
|
|
1092
|
+
this.tmpName = this.getTmpName(pb.getCurrentScope());
|
|
1093
|
+
pb.getCurrentScope()[this.tmpName] = exp;
|
|
1094
|
+
return pb.getCurrentScope()[this.tmpName];
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
class IRChannelSDFMask extends IRExpression {
|
|
1098
|
+
tex;
|
|
1099
|
+
coord;
|
|
1100
|
+
sizeOffset;
|
|
1101
|
+
feather;
|
|
1102
|
+
spread;
|
|
1103
|
+
edgeCurve;
|
|
1104
|
+
channelMask;
|
|
1105
|
+
tmpName;
|
|
1106
|
+
constructor(tex, coord, sizeOffset, feather, spread, edgeCurve, channelMask){
|
|
1107
|
+
super();
|
|
1108
|
+
this.tex = tex.addRef();
|
|
1109
|
+
this.coord = coord.addRef();
|
|
1110
|
+
this.sizeOffset = sizeOffset instanceof IRExpression ? sizeOffset.addRef() : sizeOffset;
|
|
1111
|
+
this.feather = feather instanceof IRExpression ? feather.addRef() : feather;
|
|
1112
|
+
this.spread = spread instanceof IRExpression ? spread.addRef() : spread;
|
|
1113
|
+
this.edgeCurve = edgeCurve instanceof IRExpression ? edgeCurve.addRef() : edgeCurve;
|
|
1114
|
+
this.channelMask = channelMask instanceof IRExpression ? channelMask.addRef() : channelMask.slice();
|
|
1115
|
+
this.tmpName = '';
|
|
1116
|
+
}
|
|
1117
|
+
reset() {
|
|
1118
|
+
this.tmpName = '';
|
|
1119
|
+
}
|
|
1120
|
+
create(pb) {
|
|
1121
|
+
if (this.tmpName) {
|
|
1122
|
+
return pb.getCurrentScope()[this.tmpName];
|
|
1123
|
+
}
|
|
1124
|
+
const texExp = this.tex.create(pb);
|
|
1125
|
+
const coordExp = this.coord.create(pb);
|
|
1126
|
+
const sizeExp = this.sizeOffset instanceof IRExpression ? this.sizeOffset.create(pb) : this.sizeOffset;
|
|
1127
|
+
const featherExp = this.feather instanceof IRExpression ? this.feather.create(pb) : this.feather;
|
|
1128
|
+
const spreadExp = this.spread instanceof IRExpression ? this.spread.create(pb) : this.spread;
|
|
1129
|
+
const edgeCurveExp = this.edgeCurve instanceof IRExpression ? this.edgeCurve.create(pb) : this.edgeCurve;
|
|
1130
|
+
const maskExpRaw = this.channelMask instanceof IRExpression ? this.channelMask.create(pb) : pb.vec4(this.channelMask[0] ?? 0, this.channelMask[1] ?? 0, this.channelMask[2] ?? 0, this.channelMask[3] ?? 0);
|
|
1131
|
+
if (!(texExp instanceof PBShaderExp) || !(coordExp instanceof PBShaderExp) || !(maskExpRaw instanceof PBShaderExp)) {
|
|
1132
|
+
throw new Error('Invalid texture sampling input');
|
|
1133
|
+
}
|
|
1134
|
+
const maskExp = maskExpRaw;
|
|
1135
|
+
const sampled = pb.dot(pb.textureSample(texExp, coordExp), maskExp);
|
|
1136
|
+
const spreadSafe = pb.max(pb.abs(spreadExp), 1e-5);
|
|
1137
|
+
const featherSafe = pb.max(pb.abs(featherExp), 1e-5);
|
|
1138
|
+
const edgeCurveSafe = pb.max(edgeCurveExp, 1e-5);
|
|
1139
|
+
const signedDistance = pb.mul(pb.sub(sampled, 0.5), pb.mul(spreadSafe, 2));
|
|
1140
|
+
const linearMask = pb.clamp(pb.add(pb.div(pb.add(signedDistance, sizeExp), pb.mul(featherSafe, 2)), 0.5), 0, 1);
|
|
1141
|
+
const linearMask2 = pb.mul(linearMask, linearMask);
|
|
1142
|
+
const linearMask3 = pb.mul(linearMask2, linearMask);
|
|
1143
|
+
const smootherMask = pb.mul(linearMask3, pb.add(pb.mul(linearMask, pb.sub(pb.mul(linearMask, 6), 15)), 10));
|
|
1144
|
+
const softAmount = pb.clamp(pb.sub(1, pb.div(1, edgeCurveSafe)), 0, 1);
|
|
1145
|
+
const softenedMask = pb.mix(linearMask, smootherMask, softAmount);
|
|
1146
|
+
const sharpPower = pb.div(1, edgeCurveSafe);
|
|
1147
|
+
const belowSharp = pb.mul(0.5, pb.pow(pb.mul(linearMask, 2), sharpPower));
|
|
1148
|
+
const aboveSharp = pb.sub(1, pb.mul(0.5, pb.pow(pb.mul(pb.sub(1, linearMask), 2), sharpPower)));
|
|
1149
|
+
const sharpMask = pb.select(aboveSharp, belowSharp, pb.lessThan(linearMask, 0.5));
|
|
1150
|
+
const sharpAmount = pb.clamp(pb.sub(1, edgeCurveSafe), 0, 1);
|
|
1151
|
+
const exp = pb.mix(softenedMask, sharpMask, sharpAmount);
|
|
1152
|
+
if (this._ref === 1) {
|
|
1153
|
+
return exp;
|
|
1154
|
+
}
|
|
1155
|
+
this.tmpName = this.getTmpName(pb.getCurrentScope());
|
|
1156
|
+
pb.getCurrentScope()[this.tmpName] = exp;
|
|
1157
|
+
return pb.getCurrentScope()[this.tmpName];
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
795
1160
|
/**
|
|
796
1161
|
* IR expression for texture uniform constants
|
|
797
1162
|
*
|
|
@@ -823,6 +1188,7 @@ class IRComparison extends IRExpression {
|
|
|
823
1188
|
/** Minification filter mode */ filterMin;
|
|
824
1189
|
/** Magnification filter mode */ filterMag;
|
|
825
1190
|
/** Mipmap filter mode */ filterMip;
|
|
1191
|
+
/** Whether this texture parameter should be exposed to material instances */ exposed;
|
|
826
1192
|
/** Whether texture params is used */ useParams;
|
|
827
1193
|
/**
|
|
828
1194
|
* Creates a texture constant expression
|
|
@@ -836,7 +1202,7 @@ class IRComparison extends IRExpression {
|
|
|
836
1202
|
* @param minFilter - Minification filter
|
|
837
1203
|
* @param magFilter - Magnification filter
|
|
838
1204
|
* @param mipFilter - Mipmap filter
|
|
839
|
-
*/ constructor(name, id, type, sRGB, addressU, addressV, minFilter, magFilter, mipFilter){
|
|
1205
|
+
*/ constructor(name, id, type, sRGB, addressU, addressV, minFilter, magFilter, mipFilter, exposed = true){
|
|
840
1206
|
super();
|
|
841
1207
|
this.name = name;
|
|
842
1208
|
this.id = id;
|
|
@@ -847,6 +1213,7 @@ class IRComparison extends IRExpression {
|
|
|
847
1213
|
this.filterMin = minFilter;
|
|
848
1214
|
this.filterMag = magFilter;
|
|
849
1215
|
this.filterMip = mipFilter;
|
|
1216
|
+
this.exposed = exposed;
|
|
850
1217
|
this.useParams = false;
|
|
851
1218
|
}
|
|
852
1219
|
/**
|
|
@@ -860,7 +1227,14 @@ class IRComparison extends IRExpression {
|
|
|
860
1227
|
*/ create(pb) {
|
|
861
1228
|
if (!pb.getGlobalScope()[this.name]) {
|
|
862
1229
|
// @ts-ignore
|
|
863
|
-
|
|
1230
|
+
const exp = pb[this.type]().uniform(2).withSampler({
|
|
1231
|
+
addressU: this.addressU,
|
|
1232
|
+
addressV: this.addressV,
|
|
1233
|
+
minFilter: this.filterMin,
|
|
1234
|
+
magFilter: this.filterMag,
|
|
1235
|
+
mipFilter: this.filterMip
|
|
1236
|
+
});
|
|
1237
|
+
pb.getGlobalScope()[this.name] = exp;
|
|
864
1238
|
}
|
|
865
1239
|
return pb.getGlobalScope()[this.name];
|
|
866
1240
|
}
|
|
@@ -873,6 +1247,7 @@ class IRComparison extends IRExpression {
|
|
|
873
1247
|
return {
|
|
874
1248
|
name: this.name,
|
|
875
1249
|
texture: this.id,
|
|
1250
|
+
exposed: this.exposed,
|
|
876
1251
|
wrapS: this.addressU,
|
|
877
1252
|
wrapT: this.addressV,
|
|
878
1253
|
minFilter: this.filterMin,
|
|
@@ -910,6 +1285,7 @@ class IRComparison extends IRExpression {
|
|
|
910
1285
|
/** Array of uniform scalar/vector values to be set at runtime */ _uniformValues;
|
|
911
1286
|
/** Array of uniform textures to be bound at runtime */ _uniformTextures;
|
|
912
1287
|
/** Fallback texture uniforms generated for TextureSample nodes without texture input */ _textureSampleFallbackMap;
|
|
1288
|
+
/** Shared fallback texture uniforms keyed by texture identity and sampling config */ _sharedTextureUniformMap;
|
|
913
1289
|
/** Flags indicating which shader features are used */ _behaviors;
|
|
914
1290
|
/** Array of named output expressions (e.g., baseColor, normal, metallic) */ _outputs;
|
|
915
1291
|
/**
|
|
@@ -1060,12 +1436,41 @@ class IRComparison extends IRExpression {
|
|
|
1060
1436
|
this._uniformTextures = [];
|
|
1061
1437
|
this._uniformValues = [];
|
|
1062
1438
|
this._textureSampleFallbackMap = new Map();
|
|
1439
|
+
this._sharedTextureUniformMap = new Map();
|
|
1063
1440
|
this._outputs = null;
|
|
1064
1441
|
this._behaviors = {
|
|
1065
1442
|
useVertexColor: false,
|
|
1066
1443
|
useVertexUV: false
|
|
1067
1444
|
};
|
|
1068
1445
|
}
|
|
1446
|
+
/** Builds a stable key for reusing identical blueprint texture uniforms */ getSharedTextureUniformKey(name, textureId, type, exposed, sRGB, addressU, addressV, filterMin, filterMag, filterMip) {
|
|
1447
|
+
return [
|
|
1448
|
+
name,
|
|
1449
|
+
type,
|
|
1450
|
+
textureId || '__default__',
|
|
1451
|
+
exposed ? 'exposed' : 'hidden',
|
|
1452
|
+
sRGB ? 'srgb' : 'linear',
|
|
1453
|
+
addressU,
|
|
1454
|
+
addressV,
|
|
1455
|
+
filterMin,
|
|
1456
|
+
filterMag,
|
|
1457
|
+
filterMip
|
|
1458
|
+
].join('|');
|
|
1459
|
+
}
|
|
1460
|
+
/** Gets or creates a shared texture uniform for identical fallback texture sample nodes */ getOrCreateSharedTextureUniform(name, textureId, type, exposed, sRGB, addressU, addressV, filterMin, filterMag, filterMip) {
|
|
1461
|
+
const key = this.getSharedTextureUniformKey(name, textureId, type, exposed, sRGB, addressU, addressV, filterMin, filterMag, filterMip);
|
|
1462
|
+
let ir = this._sharedTextureUniformMap.get(key);
|
|
1463
|
+
if (!ir) {
|
|
1464
|
+
ir = new IRConstantTexture(name, textureId, type, sRGB, addressU, addressV, filterMin, filterMag, filterMip, exposed);
|
|
1465
|
+
this._sharedTextureUniformMap.set(key, ir);
|
|
1466
|
+
this._expressions.push(ir);
|
|
1467
|
+
const uniformTexture = ir.asUniformTexture();
|
|
1468
|
+
if (uniformTexture) {
|
|
1469
|
+
this._uniformTextures.push(uniformTexture);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
return ir;
|
|
1473
|
+
}
|
|
1069
1474
|
/**
|
|
1070
1475
|
* Converts a graph node to an IR expression
|
|
1071
1476
|
*
|
|
@@ -1097,6 +1502,10 @@ class IRComparison extends IRExpression {
|
|
|
1097
1502
|
expr = this.constantTexture(node, output);
|
|
1098
1503
|
} else if (node instanceof TextureSampleNode) {
|
|
1099
1504
|
expr = this.textureSample(node, output);
|
|
1505
|
+
} else if (node instanceof ChannelSDFMaskNode) {
|
|
1506
|
+
expr = this.channelSDFMask(node, output);
|
|
1507
|
+
} else if (node instanceof MorphBlurNode) {
|
|
1508
|
+
expr = this.morphBlur(node, output);
|
|
1100
1509
|
} else if (node instanceof PannerNode) {
|
|
1101
1510
|
expr = this.panner(node, output);
|
|
1102
1511
|
} else if (node instanceof MakeVectorNode) {
|
|
@@ -1183,6 +1592,8 @@ class IRComparison extends IRExpression {
|
|
|
1183
1592
|
expr = this.functionInput(node, output);
|
|
1184
1593
|
} else if (node instanceof FunctionOutputNode) {
|
|
1185
1594
|
expr = this.functionOutput(node, output);
|
|
1595
|
+
} else if (node instanceof TexturePropertyNode) {
|
|
1596
|
+
expr = this.textureProperty(node, output);
|
|
1186
1597
|
}
|
|
1187
1598
|
if (expr && originType) {
|
|
1188
1599
|
const outputType = node.getOutputType(output);
|
|
@@ -1611,7 +2022,7 @@ class IRComparison extends IRExpression {
|
|
|
1611
2022
|
return this.getOrCreateIRExpression(node, output, IRCallFunc, node, args);
|
|
1612
2023
|
}
|
|
1613
2024
|
/** Converts a scalar constant node to IR */ constantf(node, output) {
|
|
1614
|
-
return this.getOrCreateIRExpression(node, output, IRConstantf, node.x, node.paramName);
|
|
2025
|
+
return this.getOrCreateIRExpression(node, output, IRConstantf, node.x, node.isUniform ? node.paramName : '', node.isUniform && node.useRange ? node.minValue : undefined, node.isUniform && node.useRange ? node.maxValue : undefined);
|
|
1615
2026
|
}
|
|
1616
2027
|
/** Converts a vector constant node to IR */ constantfv(node, output) {
|
|
1617
2028
|
const value = node instanceof ConstantVec2Node ? [
|
|
@@ -1627,7 +2038,7 @@ class IRComparison extends IRExpression {
|
|
|
1627
2038
|
node.z,
|
|
1628
2039
|
node.w
|
|
1629
2040
|
];
|
|
1630
|
-
return this.getOrCreateIRExpression(node, output, IRConstantfv, value, node.paramName, `vec${value.length}`);
|
|
2041
|
+
return this.getOrCreateIRExpression(node, output, IRConstantfv, value, node.isUniform ? node.paramName : '', `vec${value.length}`);
|
|
1631
2042
|
}
|
|
1632
2043
|
/** Converts a scalar boolean constant node to IR */ constantb(node, output) {
|
|
1633
2044
|
return this.getOrCreateIRExpression(node, output, IRConstantb, node.x);
|
|
@@ -1649,7 +2060,19 @@ class IRComparison extends IRExpression {
|
|
|
1649
2060
|
return this.getOrCreateIRExpression(node, output, IRConstantbv, value);
|
|
1650
2061
|
}
|
|
1651
2062
|
/** Converts a texture constant node to IR */ constantTexture(node, output) {
|
|
1652
|
-
return this.getOrCreateIRExpression(node, output,
|
|
2063
|
+
return this.getOrCreateIRExpression(node, output, class SharedIRConstantTextureProxy extends IRExpression {
|
|
2064
|
+
_shared;
|
|
2065
|
+
constructor(shared){
|
|
2066
|
+
super();
|
|
2067
|
+
this._shared = shared;
|
|
2068
|
+
}
|
|
2069
|
+
create(pb) {
|
|
2070
|
+
return this._shared.create(pb);
|
|
2071
|
+
}
|
|
2072
|
+
asUniformTexture() {
|
|
2073
|
+
return null;
|
|
2074
|
+
}
|
|
2075
|
+
}, this.getOrCreateSharedTextureUniform(node.paramName, node.textureId, node.getOutputType(1), node.expose, node.sRGB, node.addressU, node.addressV, node.filterMin, node.filterMag, node.filterMip));
|
|
1653
2076
|
}
|
|
1654
2077
|
/** Converts a texture sample node to IR */ textureSample(node, output) {
|
|
1655
2078
|
const tex = node.inputs[0].inputNode ? this.ir(node.inputs[0]) : this.textureSampleFallbackTexture(node);
|
|
@@ -1659,16 +2082,58 @@ class IRComparison extends IRExpression {
|
|
|
1659
2082
|
})();
|
|
1660
2083
|
return this.getOrCreateIRExpression(node, output, IRSampleTexture, tex, coord, node.samplerType);
|
|
1661
2084
|
}
|
|
2085
|
+
/** Converts a texture property node to IR */ textureProperty(node, output) {
|
|
2086
|
+
const tex = this.ir(node.inputs[0]);
|
|
2087
|
+
const func = node.property === 'TextureSize' ? (pb, ...params)=>{
|
|
2088
|
+
const texture = params[0];
|
|
2089
|
+
return pb.vec2(pb.textureDimensions(texture, 0));
|
|
2090
|
+
} : (pb, ...params)=>{
|
|
2091
|
+
const texture = params[0];
|
|
2092
|
+
return pb.div(pb.vec2(1), pb.vec2(pb.textureDimensions(texture, 0)));
|
|
2093
|
+
};
|
|
2094
|
+
return this.getOrCreateIRExpression(node, output, IRFunc, [
|
|
2095
|
+
tex
|
|
2096
|
+
], func);
|
|
2097
|
+
}
|
|
2098
|
+
channelSDFMask(node, output) {
|
|
2099
|
+
const tex = node.inputs[0].inputNode ? this.ir(node.inputs[0]) : this.getOrCreateSharedTextureUniform(node.paramName, node.textureId, 'tex2D', node.expose, node.sRGB, node.addressU, node.addressV, node.filterMin, node.filterMag, node.filterMip);
|
|
2100
|
+
const coord = node.inputs[1].inputNode ? this.ir(node.inputs[1]) : (()=>{
|
|
2101
|
+
this._behaviors.useVertexUV = true;
|
|
2102
|
+
return new IRInput((scope)=>scope.zVertexUV);
|
|
2103
|
+
})();
|
|
2104
|
+
const sizeOffset = node.inputs[2].inputNode ? this.ir(node.inputs[2]) : node.inputs[2].defaultValue?.[0] ?? 0;
|
|
2105
|
+
const feather = node.inputs[3].inputNode ? this.ir(node.inputs[3]) : node.inputs[3].defaultValue?.[0] ?? 0;
|
|
2106
|
+
const spread = node.inputs[4].inputNode ? this.ir(node.inputs[4]) : node.inputs[4].defaultValue?.[0] ?? 16;
|
|
2107
|
+
const edgeCurve = node.inputs[5].inputNode ? this.ir(node.inputs[5]) : node.inputs[5].defaultValue?.[0] ?? 1;
|
|
2108
|
+
const channelMask = node.inputs[6].inputNode ? this.ir(node.inputs[6]) : node.inputs[6].defaultValue ?? [
|
|
2109
|
+
1,
|
|
2110
|
+
0,
|
|
2111
|
+
0,
|
|
2112
|
+
0
|
|
2113
|
+
];
|
|
2114
|
+
return this.getOrCreateIRExpression(node, output, IRChannelSDFMask, tex, coord, sizeOffset, feather, spread, edgeCurve, channelMask);
|
|
2115
|
+
}
|
|
2116
|
+
morphBlur(node, output) {
|
|
2117
|
+
const tex = node.inputs[0].inputNode ? this.ir(node.inputs[0]) : this.getOrCreateSharedTextureUniform(node.paramName, node.textureId, 'tex2D', node.expose, node.sRGB, node.addressU, node.addressV, node.filterMin, node.filterMag, node.filterMip);
|
|
2118
|
+
const coord = node.inputs[1].inputNode ? this.ir(node.inputs[1]) : (()=>{
|
|
2119
|
+
this._behaviors.useVertexUV = true;
|
|
2120
|
+
return new IRInput((scope)=>scope.zVertexUV);
|
|
2121
|
+
})();
|
|
2122
|
+
const morphRadius = node.inputs[2].inputNode ? this.ir(node.inputs[2]) : node.inputs[2].defaultValue?.[0] ?? 0;
|
|
2123
|
+
const blurRadius = node.inputs[3].inputNode ? this.ir(node.inputs[3]) : node.inputs[3].defaultValue?.[0] ?? 0;
|
|
2124
|
+
const channelMask = node.inputs[4].inputNode ? this.ir(node.inputs[4]) : node.inputs[4].defaultValue ?? [
|
|
2125
|
+
1,
|
|
2126
|
+
0,
|
|
2127
|
+
0,
|
|
2128
|
+
0
|
|
2129
|
+
];
|
|
2130
|
+
return this.getOrCreateIRExpression(node, output, IRMorphBlur, tex, coord, morphRadius, blurRadius, channelMask);
|
|
2131
|
+
}
|
|
1662
2132
|
/** Gets or creates fallback texture uniform expression for texture sample nodes */ textureSampleFallbackTexture(node) {
|
|
1663
2133
|
let ir = this._textureSampleFallbackMap.get(node);
|
|
1664
2134
|
if (!ir) {
|
|
1665
|
-
ir =
|
|
1666
|
-
this._expressions.push(ir);
|
|
2135
|
+
ir = this.getOrCreateSharedTextureUniform(node.paramName, node.textureId, 'tex2D', node.expose, node.sRGB, node.addressU, node.addressV, node.filterMin, node.filterMag, node.filterMip);
|
|
1667
2136
|
this._textureSampleFallbackMap.set(node, ir);
|
|
1668
|
-
const uniformTexture = ir.asUniformTexture();
|
|
1669
|
-
if (uniformTexture) {
|
|
1670
|
-
this._uniformTextures.push(uniformTexture);
|
|
1671
|
-
}
|
|
1672
2137
|
}
|
|
1673
2138
|
return ir;
|
|
1674
2139
|
}
|