@plastic-software/three 0.179.0 → 0.180.1
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/build/three.cjs +167 -107
- package/build/three.core.js +112 -20
- package/build/three.core.min.js +1 -1
- package/build/three.module.js +56 -90
- package/build/three.module.min.js +1 -1
- package/build/three.tsl.js +30 -5
- package/build/three.tsl.min.js +1 -1
- package/build/three.webgpu.js +2896 -1048
- package/build/three.webgpu.min.js +1 -1
- package/build/three.webgpu.nodes.js +2896 -1048
- package/build/three.webgpu.nodes.min.js +1 -1
- package/examples/jsm/Addons.js +1 -1
- package/examples/jsm/controls/ArcballControls.js +7 -7
- package/examples/jsm/controls/DragControls.js +6 -56
- package/examples/jsm/controls/FirstPersonControls.js +2 -2
- package/examples/jsm/controls/PointerLockControls.js +0 -8
- package/examples/jsm/exporters/GLTFExporter.js +30 -22
- package/examples/jsm/exporters/KTX2Exporter.js +4 -2
- package/examples/jsm/exporters/PLYExporter.js +1 -1
- package/examples/jsm/libs/ktx-parse.module.js +1 -1
- package/examples/jsm/lines/Line2.js +3 -3
- package/examples/jsm/lines/LineGeometry.js +1 -1
- package/examples/jsm/lines/LineSegments2.js +2 -2
- package/examples/jsm/lines/Wireframe.js +2 -2
- package/examples/jsm/lines/WireframeGeometry2.js +1 -1
- package/examples/jsm/lines/webgpu/LineSegments2.js +1 -1
- package/examples/jsm/lines/webgpu/Wireframe.js +1 -1
- package/examples/jsm/loaders/ColladaLoader.js +1 -1
- package/examples/jsm/loaders/EXRLoader.js +5 -5
- package/examples/jsm/loaders/GLTFLoader.js +9 -5
- package/examples/jsm/loaders/HDRCubeTextureLoader.js +5 -5
- package/examples/jsm/loaders/HDRLoader.js +486 -0
- package/examples/jsm/loaders/KTX2Loader.js +112 -32
- package/examples/jsm/loaders/RGBELoader.js +7 -473
- package/examples/jsm/loaders/TTFLoader.js +4 -4
- package/examples/jsm/loaders/UltraHDRLoader.js +1 -1
- package/examples/jsm/loaders/lwo/IFFParser.js +1 -1
- package/examples/jsm/materials/WoodNodeMaterial.js +533 -0
- package/examples/jsm/math/ColorSpaces.js +19 -1
- package/examples/jsm/math/ConvexHull.js +2 -2
- package/examples/jsm/math/Lut.js +2 -2
- package/examples/jsm/misc/MD2CharacterComplex.js +1 -1
- package/examples/jsm/misc/ProgressiveLightMap.js +1 -1
- package/examples/jsm/misc/Volume.js +1 -1
- package/examples/jsm/postprocessing/OutlinePass.js +1 -1
- package/examples/jsm/postprocessing/SSRPass.js +37 -8
- package/examples/jsm/shaders/UnpackDepthRGBAShader.js +1 -1
- package/examples/jsm/transpiler/GLSLDecoder.js +22 -19
- package/examples/jsm/transpiler/TSLEncoder.js +2 -10
- package/examples/jsm/transpiler/WGSLEncoder.js +24 -0
- package/examples/jsm/tsl/display/AnamorphicNode.js +27 -4
- package/examples/jsm/tsl/display/BloomNode.js +3 -3
- package/examples/jsm/tsl/display/ChromaticAberrationNode.js +2 -1
- package/examples/jsm/tsl/display/DepthOfFieldNode.js +439 -90
- package/examples/jsm/tsl/display/GTAONode.js +8 -0
- package/examples/jsm/tsl/display/GaussianBlurNode.js +47 -35
- package/examples/jsm/tsl/display/OutlineNode.js +2 -2
- package/examples/jsm/tsl/display/SSRNode.js +180 -65
- package/examples/jsm/tsl/display/TRAANode.js +1 -1
- package/examples/jsm/tsl/display/boxBlur.js +64 -0
- package/examples/jsm/tsl/display/hashBlur.js +15 -18
- package/examples/jsm/utils/BufferGeometryUtils.js +1 -1
- package/examples/jsm/utils/ShadowMapViewerGPU.js +12 -5
- package/examples/jsm/webxr/OculusHandModel.js +1 -1
- package/package.json +1 -1
- package/src/Three.Core.js +1 -0
- package/src/Three.TSL.js +29 -4
- package/src/animation/AnimationClip.js +17 -2
- package/src/constants.js +11 -3
- package/src/core/BufferGeometry.js +2 -2
- package/src/extras/TextureUtils.js +2 -1
- package/src/extras/lib/earcut.js +1 -1
- package/src/lights/webgpu/ProjectorLight.js +1 -1
- package/src/materials/Material.js +12 -0
- package/src/materials/MeshDistanceMaterial.js +1 -1
- package/src/materials/nodes/PointsNodeMaterial.js +81 -28
- package/src/materials/nodes/SpriteNodeMaterial.js +3 -15
- package/src/materials/nodes/manager/NodeMaterialObserver.js +1 -1
- package/src/math/ColorManagement.js +7 -1
- package/src/nodes/Nodes.js +3 -0
- package/src/nodes/TSL.js +3 -0
- package/src/nodes/accessors/BufferNode.js +1 -1
- package/src/nodes/accessors/Camera.js +133 -7
- package/src/nodes/accessors/ClippingNode.js +6 -5
- package/src/nodes/accessors/CubeTextureNode.js +2 -2
- package/src/nodes/accessors/InstanceNode.js +3 -1
- package/src/nodes/accessors/Object3DNode.js +1 -1
- package/src/nodes/accessors/ReferenceBaseNode.js +1 -1
- package/src/nodes/accessors/ReferenceNode.js +1 -1
- package/src/nodes/accessors/Texture3DNode.js +13 -0
- package/src/nodes/accessors/TextureNode.js +71 -19
- package/src/nodes/code/FunctionCallNode.js +19 -0
- package/src/nodes/code/FunctionNode.js +23 -0
- package/src/nodes/core/AssignNode.js +4 -3
- package/src/nodes/core/ContextNode.js +24 -0
- package/src/nodes/core/Node.js +16 -20
- package/src/nodes/core/NodeBuilder.js +48 -14
- package/src/nodes/core/NodeFrame.js +1 -1
- package/src/nodes/core/NodeUniform.js +1 -1
- package/src/nodes/core/NodeUtils.js +1 -2
- package/src/nodes/core/StackNode.js +29 -4
- package/src/nodes/core/StructNode.js +5 -5
- package/src/nodes/core/StructTypeNode.js +1 -0
- package/src/nodes/core/SubBuildNode.js +2 -2
- package/src/nodes/core/UniformNode.js +16 -9
- package/src/nodes/core/VarNode.js +0 -21
- package/src/nodes/display/FrontFacingNode.js +4 -8
- package/src/nodes/display/PassNode.js +1 -1
- package/src/nodes/display/ScreenNode.js +42 -13
- package/src/nodes/display/ViewportDepthTextureNode.js +16 -4
- package/src/nodes/display/ViewportSharedTextureNode.js +12 -0
- package/src/nodes/display/ViewportTextureNode.js +42 -12
- package/src/nodes/gpgpu/SubgroupFunctionNode.js +430 -0
- package/src/nodes/lighting/LightsNode.js +1 -1
- package/src/nodes/math/BitcastNode.js +156 -0
- package/src/nodes/math/ConditionalNode.js +18 -2
- package/src/nodes/math/MathNode.js +3 -15
- package/src/nodes/math/OperatorNode.js +4 -3
- package/src/nodes/tsl/TSLCore.js +432 -152
- package/src/nodes/utils/JoinNode.js +3 -1
- package/src/nodes/utils/MemberNode.js +58 -7
- package/src/nodes/utils/RTTNode.js +1 -1
- package/src/nodes/utils/ReflectorNode.js +51 -7
- package/src/nodes/utils/SampleNode.js +12 -2
- package/src/nodes/utils/SplitNode.js +11 -0
- package/src/nodes/utils/Timer.js +0 -47
- package/src/objects/BatchedMesh.js +2 -2
- package/src/objects/LOD.js +1 -1
- package/src/objects/Sprite.js +2 -2
- package/src/renderers/WebGLRenderer.js +1 -10
- package/src/renderers/common/Attributes.js +1 -1
- package/src/renderers/common/Backend.js +19 -1
- package/src/renderers/common/Bindings.js +2 -0
- package/src/renderers/common/ChainMap.js +1 -1
- package/src/renderers/common/DataMap.js +1 -1
- package/src/renderers/common/Pipelines.js +1 -1
- package/src/renderers/common/RenderContext.js +2 -2
- package/src/renderers/common/RenderObject.js +14 -2
- package/src/renderers/common/Renderer.js +39 -19
- package/src/renderers/common/SampledTexture.js +1 -1
- package/src/renderers/common/Sampler.js +25 -13
- package/src/renderers/common/Textures.js +34 -12
- package/src/renderers/common/TimestampQueryPool.js +3 -3
- package/src/renderers/common/XRManager.js +35 -19
- package/src/renderers/common/nodes/NodeBuilderState.js +1 -1
- package/src/renderers/common/nodes/NodeLibrary.js +5 -5
- package/src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +7 -15
- package/src/renderers/shaders/ShaderLib/depth.glsl.js +1 -1
- package/src/renderers/webgl/WebGLProgram.js +4 -4
- package/src/renderers/webgl/WebGLShadowMap.js +1 -1
- package/src/renderers/webgl/WebGLTextures.js +1 -0
- package/src/renderers/webgl/WebGLUtils.js +3 -2
- package/src/renderers/webgl-fallback/WebGLBackend.js +186 -135
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +110 -17
- package/src/renderers/webgl-fallback/utils/WebGLState.js +1 -1
- package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +52 -3
- package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +9 -10
- package/src/renderers/webgl-fallback/utils/WebGLUtils.js +3 -2
- package/src/renderers/webgpu/WebGPUBackend.js +35 -31
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +124 -34
- package/src/renderers/webgpu/utils/WebGPUConstants.js +2 -2
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +9 -18
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +114 -25
- package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +3 -3
- package/src/renderers/webxr/WebXRManager.js +39 -24
- package/src/textures/ExternalTexture.js +15 -4
- package/src/textures/Source.js +1 -1
- package/src/textures/VideoTexture.js +0 -3
- package/examples/jsm/loaders/RGBMLoader.js +0 -1148
|
@@ -25,8 +25,11 @@ class GaussianBlurNode extends TempNode {
|
|
|
25
25
|
* @param {TextureNode} textureNode - The texture node that represents the input of the effect.
|
|
26
26
|
* @param {Node<vec2|float>} directionNode - Defines the direction and radius of the blur.
|
|
27
27
|
* @param {number} sigma - Controls the kernel of the blur filter. Higher values mean a wider blur radius.
|
|
28
|
+
* @param {Object} [options={}] - Additional options for the gaussian blur effect.
|
|
29
|
+
* @param {boolean} [options.premultipliedAlpha=false] - Whether to use premultiplied alpha for the blur effect.
|
|
30
|
+
* @param {Vector2} [options.resolution=new Vector2(1, 1)] - The resolution of the effect. 0.5 means half the resolution of the texture node.
|
|
28
31
|
*/
|
|
29
|
-
constructor( textureNode, directionNode = null, sigma = 4 ) {
|
|
32
|
+
constructor( textureNode, directionNode = null, sigma = 4, options = {} ) {
|
|
30
33
|
|
|
31
34
|
super( 'vec4' );
|
|
32
35
|
|
|
@@ -105,12 +108,12 @@ class GaussianBlurNode extends TempNode {
|
|
|
105
108
|
this.updateBeforeType = NodeUpdateType.FRAME;
|
|
106
109
|
|
|
107
110
|
/**
|
|
108
|
-
*
|
|
111
|
+
* The resolution scale.
|
|
109
112
|
*
|
|
110
|
-
* @type {
|
|
111
|
-
* @default (1
|
|
113
|
+
* @type {float}
|
|
114
|
+
* @default (1)
|
|
112
115
|
*/
|
|
113
|
-
this.
|
|
116
|
+
this.resolutionScale = options.resolutionScale || 1;
|
|
114
117
|
|
|
115
118
|
/**
|
|
116
119
|
* Whether the effect should use premultiplied alpha or not. Set this to `true`
|
|
@@ -119,32 +122,7 @@ class GaussianBlurNode extends TempNode {
|
|
|
119
122
|
* @type {boolean}
|
|
120
123
|
* @default false
|
|
121
124
|
*/
|
|
122
|
-
this.premultipliedAlpha = false;
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Sets the given premultiplied alpha value.
|
|
128
|
-
*
|
|
129
|
-
* @param {boolean} value - Whether the effect should use premultiplied alpha or not.
|
|
130
|
-
* @return {GaussianBlurNode} height - A reference to this node.
|
|
131
|
-
*/
|
|
132
|
-
setPremultipliedAlpha( value ) {
|
|
133
|
-
|
|
134
|
-
this.premultipliedAlpha = value;
|
|
135
|
-
|
|
136
|
-
return this;
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Returns the premultiplied alpha value.
|
|
142
|
-
*
|
|
143
|
-
* @return {boolean} Whether the effect should use premultiplied alpha or not.
|
|
144
|
-
*/
|
|
145
|
-
getPremultipliedAlpha() {
|
|
146
|
-
|
|
147
|
-
return this.premultipliedAlpha;
|
|
125
|
+
this.premultipliedAlpha = options.premultipliedAlpha || false;
|
|
148
126
|
|
|
149
127
|
}
|
|
150
128
|
|
|
@@ -156,8 +134,8 @@ class GaussianBlurNode extends TempNode {
|
|
|
156
134
|
*/
|
|
157
135
|
setSize( width, height ) {
|
|
158
136
|
|
|
159
|
-
width = Math.max( Math.round( width * this.
|
|
160
|
-
height = Math.max( Math.round( height * this.
|
|
137
|
+
width = Math.max( Math.round( width * this.resolutionScale ), 1 );
|
|
138
|
+
height = Math.max( Math.round( height * this.resolutionScale ), 1 );
|
|
161
139
|
|
|
162
140
|
this._invSize.value.set( 1 / width, 1 / height );
|
|
163
141
|
this._horizontalRT.setSize( width, height );
|
|
@@ -280,6 +258,7 @@ class GaussianBlurNode extends TempNode {
|
|
|
280
258
|
const sample2 = sampleTexture( uvNode.sub( uvOffset ) );
|
|
281
259
|
|
|
282
260
|
diffuseSum.addAssign( sample1.add( sample2 ).mul( w ) );
|
|
261
|
+
|
|
283
262
|
}
|
|
284
263
|
|
|
285
264
|
return output( diffuseSum );
|
|
@@ -337,6 +316,29 @@ class GaussianBlurNode extends TempNode {
|
|
|
337
316
|
|
|
338
317
|
}
|
|
339
318
|
|
|
319
|
+
/**
|
|
320
|
+
* The resolution scale.
|
|
321
|
+
*
|
|
322
|
+
* @deprecated
|
|
323
|
+
* @type {Vector2}
|
|
324
|
+
* @default {(1,1)}
|
|
325
|
+
*/
|
|
326
|
+
get resolution() {
|
|
327
|
+
|
|
328
|
+
console.warn( 'THREE.GaussianBlurNode: The "resolution" property has been renamed to "resolutionScale" and is now of type `number`.' ); // @deprecated r180
|
|
329
|
+
|
|
330
|
+
return new Vector2( this.resolutionScale, this.resolutionScale );
|
|
331
|
+
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
set resolution( value ) {
|
|
335
|
+
|
|
336
|
+
console.warn( 'THREE.GaussianBlurNode: The "resolution" property has been renamed to "resolutionScale" and is now of type `number`.' ); // @deprecated r180
|
|
337
|
+
|
|
338
|
+
this.resolutionScale = value.x;
|
|
339
|
+
|
|
340
|
+
}
|
|
341
|
+
|
|
340
342
|
}
|
|
341
343
|
|
|
342
344
|
export default GaussianBlurNode;
|
|
@@ -349,18 +351,28 @@ export default GaussianBlurNode;
|
|
|
349
351
|
* @param {Node<vec4>} node - The node that represents the input of the effect.
|
|
350
352
|
* @param {Node<vec2|float>} directionNode - Defines the direction and radius of the blur.
|
|
351
353
|
* @param {number} sigma - Controls the kernel of the blur filter. Higher values mean a wider blur radius.
|
|
354
|
+
* @param {Object} [options={}] - Additional options for the gaussian blur effect.
|
|
355
|
+
* @param {boolean} [options.premultipliedAlpha=false] - Whether to use premultiplied alpha for the blur effect.
|
|
356
|
+
* @param {Vector2} [options.resolution=new Vector2(1, 1)] - The resolution of the effect. 0.5 means half the resolution of the texture node.
|
|
352
357
|
* @returns {GaussianBlurNode}
|
|
353
358
|
*/
|
|
354
|
-
export const gaussianBlur = ( node, directionNode, sigma ) => nodeObject( new GaussianBlurNode( convertToTexture( node ), directionNode, sigma ) );
|
|
359
|
+
export const gaussianBlur = ( node, directionNode, sigma, options = {} ) => nodeObject( new GaussianBlurNode( convertToTexture( node ), directionNode, sigma, options ) );
|
|
355
360
|
|
|
356
361
|
/**
|
|
357
362
|
* TSL function for creating a gaussian blur node for post processing with enabled premultiplied alpha.
|
|
358
363
|
*
|
|
359
364
|
* @tsl
|
|
360
365
|
* @function
|
|
366
|
+
* @deprecated since r180. Use `gaussianBlur()` with `premultipliedAlpha: true` option instead.
|
|
361
367
|
* @param {Node<vec4>} node - The node that represents the input of the effect.
|
|
362
368
|
* @param {Node<vec2|float>} directionNode - Defines the direction and radius of the blur.
|
|
363
369
|
* @param {number} sigma - Controls the kernel of the blur filter. Higher values mean a wider blur radius.
|
|
364
370
|
* @returns {GaussianBlurNode}
|
|
365
371
|
*/
|
|
366
|
-
export
|
|
372
|
+
export function premultipliedGaussianBlur( node, directionNode, sigma ) {
|
|
373
|
+
|
|
374
|
+
console.warn( 'THREE.TSL: "premultipliedGaussianBlur()" is deprecated. Use "gaussianBlur()" with "premultipliedAlpha: true" option instead.' ); // deprecated, r180
|
|
375
|
+
|
|
376
|
+
return gaussianBlur( node, directionNode, sigma, { premultipliedAlpha: true } );
|
|
377
|
+
|
|
378
|
+
}
|
|
@@ -56,7 +56,7 @@ class OutlineNode extends TempNode {
|
|
|
56
56
|
* @param {Scene} scene - A reference to the scene.
|
|
57
57
|
* @param {Camera} camera - The camera the scene is rendered with.
|
|
58
58
|
* @param {Object} params - The configuration parameters.
|
|
59
|
-
* @param {Array<Object3D>} params.selectedObjects - An array of selected objects.
|
|
59
|
+
* @param {Array<Object3D>} [params.selectedObjects] - An array of selected objects.
|
|
60
60
|
* @param {Node<float>} [params.edgeThickness=float(1)] - The thickness of the edges.
|
|
61
61
|
* @param {Node<float>} [params.edgeGlow=float(0)] - Can be used for an animated glow/pulse effects.
|
|
62
62
|
* @param {number} [params.downSampleRatio=2] - The downsample ratio.
|
|
@@ -742,7 +742,7 @@ export default OutlineNode;
|
|
|
742
742
|
* @param {Scene} scene - A reference to the scene.
|
|
743
743
|
* @param {Camera} camera - The camera the scene is rendered with.
|
|
744
744
|
* @param {Object} params - The configuration parameters.
|
|
745
|
-
* @param {Array<Object3D>} params.selectedObjects - An array of selected objects.
|
|
745
|
+
* @param {Array<Object3D>} [params.selectedObjects] - An array of selected objects.
|
|
746
746
|
* @param {Node<float>} [params.edgeThickness=float(1)] - The thickness of the edges.
|
|
747
747
|
* @param {Node<float>} [params.edgeGlow=float(0)] - Can be used for animated glow/pulse effects.
|
|
748
748
|
* @param {number} [params.downSampleRatio=2] - The downsample ratio.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { reference, viewZToPerspectiveDepth, logarithmicDepthToViewZ, getScreenPosition, getViewPosition, sqrt, mul, div, cross, float, Continue, Break, Loop, int, max, abs, sub, If, dot, reflect, normalize, screenCoordinate, nodeObject, Fn, passTexture, uv, uniform, perspectiveDepthToViewZ, orthographicDepthToViewZ, vec2, vec3, vec4 } from 'three/tsl';
|
|
1
|
+
import { HalfFloatType, RenderTarget, Vector2, RendererUtils, QuadMesh, TempNode, NodeMaterial, NodeUpdateType, LinearFilter, LinearMipmapLinearFilter } from 'three/webgpu';
|
|
2
|
+
import { texture, reference, viewZToPerspectiveDepth, logarithmicDepthToViewZ, getScreenPosition, getViewPosition, sqrt, mul, div, cross, float, Continue, Break, Loop, int, max, abs, sub, If, dot, reflect, normalize, screenCoordinate, nodeObject, Fn, passTexture, uv, uniform, perspectiveDepthToViewZ, orthographicDepthToViewZ, vec2, vec3, vec4 } from 'three/tsl';
|
|
3
|
+
import { boxBlur } from './boxBlur.js';
|
|
3
4
|
|
|
4
5
|
const _quadMesh = /*@__PURE__*/ new QuadMesh();
|
|
5
6
|
const _size = /*@__PURE__*/ new Vector2();
|
|
@@ -28,9 +29,10 @@ class SSRNode extends TempNode {
|
|
|
28
29
|
* @param {Node<float>} depthNode - A node that represents the beauty pass's depth.
|
|
29
30
|
* @param {Node<vec3>} normalNode - A node that represents the beauty pass's normals.
|
|
30
31
|
* @param {Node<float>} metalnessNode - A node that represents the beauty pass's metalness.
|
|
31
|
-
* @param {
|
|
32
|
+
* @param {?Node<float>} [roughnessNode=null] - A node that represents the beauty pass's roughness.
|
|
33
|
+
* @param {?Camera} [camera=null] - The camera the scene is rendered with.
|
|
32
34
|
*/
|
|
33
|
-
constructor( colorNode, depthNode, normalNode, metalnessNode, camera ) {
|
|
35
|
+
constructor( colorNode, depthNode, normalNode, metalnessNode, roughnessNode = null, camera = null ) {
|
|
34
36
|
|
|
35
37
|
super( 'vec4' );
|
|
36
38
|
|
|
@@ -63,22 +65,26 @@ class SSRNode extends TempNode {
|
|
|
63
65
|
this.metalnessNode = metalnessNode;
|
|
64
66
|
|
|
65
67
|
/**
|
|
66
|
-
*
|
|
68
|
+
* Whether the SSR reflections should be blurred or not. Blurring is a costly
|
|
69
|
+
* operation so turn it off if you encounter performance issues on certain
|
|
70
|
+
* devices.
|
|
67
71
|
*
|
|
68
|
-
* @
|
|
72
|
+
* @private
|
|
73
|
+
* @type {Node<float>}
|
|
74
|
+
* @default false
|
|
69
75
|
*/
|
|
70
|
-
this.
|
|
76
|
+
this.roughnessNode = roughnessNode;
|
|
71
77
|
|
|
72
78
|
/**
|
|
73
|
-
* The resolution scale.
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
79
|
+
* The resolution scale. Valid values are in the range
|
|
80
|
+
* `[0,1]`. `1` means best quality but also results in
|
|
81
|
+
* more computational overhead. Setting to `0.5` means
|
|
82
|
+
* the effect is computed in half-resolution.
|
|
77
83
|
*
|
|
78
84
|
* @type {number}
|
|
79
|
-
* @default
|
|
85
|
+
* @default 1
|
|
80
86
|
*/
|
|
81
|
-
this.resolutionScale =
|
|
87
|
+
this.resolutionScale = 1;
|
|
82
88
|
|
|
83
89
|
/**
|
|
84
90
|
* The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders
|
|
@@ -90,17 +96,8 @@ class SSRNode extends TempNode {
|
|
|
90
96
|
this.updateBeforeType = NodeUpdateType.FRAME;
|
|
91
97
|
|
|
92
98
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* @private
|
|
96
|
-
* @type {RenderTarget}
|
|
97
|
-
*/
|
|
98
|
-
this._ssrRenderTarget = new RenderTarget( 1, 1, { depthBuffer: false, minFilter: NearestFilter, magFilter: NearestFilter } );
|
|
99
|
-
this._ssrRenderTarget.texture.name = 'SSRNode.SSR';
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Controls how far a fragment can reflect.
|
|
103
|
-
*
|
|
99
|
+
* Controls how far a fragment can reflect. Increasing this value result in more
|
|
100
|
+
* computational overhead but also increases the reflection distance.
|
|
104
101
|
*
|
|
105
102
|
* @type {UniformNode<float>}
|
|
106
103
|
*/
|
|
@@ -114,12 +111,63 @@ class SSRNode extends TempNode {
|
|
|
114
111
|
this.thickness = uniform( 0.1 );
|
|
115
112
|
|
|
116
113
|
/**
|
|
117
|
-
* Controls the
|
|
114
|
+
* Controls how the SSR reflections are blended with the beauty pass.
|
|
118
115
|
*
|
|
119
116
|
* @type {UniformNode<float>}
|
|
120
117
|
*/
|
|
121
118
|
this.opacity = uniform( 1 );
|
|
122
119
|
|
|
120
|
+
/**
|
|
121
|
+
* This parameter controls how detailed the raymarching process works.
|
|
122
|
+
* The value ranges is `[0,1]` where `1` means best quality (the maximum number
|
|
123
|
+
* of raymarching iterations/samples) and `0` means no samples at all.
|
|
124
|
+
*
|
|
125
|
+
* A quality of `0.5` is usually sufficient for most use cases. Try to keep
|
|
126
|
+
* this parameter as low as possible. Larger values result in noticeable more
|
|
127
|
+
* overhead.
|
|
128
|
+
*
|
|
129
|
+
* @type {UniformNode<float>}
|
|
130
|
+
*/
|
|
131
|
+
this.quality = uniform( 0.5 );
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* The quality of the blur. Must be an integer in the range `[1,3]`.
|
|
135
|
+
*
|
|
136
|
+
* @type {UniformNode<int>}
|
|
137
|
+
*/
|
|
138
|
+
this.blurQuality = uniform( 2 );
|
|
139
|
+
|
|
140
|
+
//
|
|
141
|
+
|
|
142
|
+
if ( camera === null ) {
|
|
143
|
+
|
|
144
|
+
if ( this.colorNode.passNode && this.colorNode.passNode.isPassNode === true ) {
|
|
145
|
+
|
|
146
|
+
camera = this.colorNode.passNode.camera;
|
|
147
|
+
|
|
148
|
+
} else {
|
|
149
|
+
|
|
150
|
+
throw new Error( 'THREE.TSL: No camera found. ssr() requires a camera.' );
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The camera the scene is rendered with.
|
|
158
|
+
*
|
|
159
|
+
* @type {Camera}
|
|
160
|
+
*/
|
|
161
|
+
this.camera = camera;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* The spread of the blur. Automatically set when generating mips.
|
|
165
|
+
*
|
|
166
|
+
* @private
|
|
167
|
+
* @type {UniformNode<int>}
|
|
168
|
+
*/
|
|
169
|
+
this._blurSpread = uniform( 1 );
|
|
170
|
+
|
|
123
171
|
/**
|
|
124
172
|
* Represents the projection matrix of the scene's camera.
|
|
125
173
|
*
|
|
@@ -158,7 +206,7 @@ class SSRNode extends TempNode {
|
|
|
158
206
|
* @private
|
|
159
207
|
* @type {UniformNode<bool>}
|
|
160
208
|
*/
|
|
161
|
-
this._isPerspectiveCamera = uniform( camera.isPerspectiveCamera
|
|
209
|
+
this._isPerspectiveCamera = uniform( camera.isPerspectiveCamera );
|
|
162
210
|
|
|
163
211
|
/**
|
|
164
212
|
* The resolution of the pass.
|
|
@@ -169,13 +217,23 @@ class SSRNode extends TempNode {
|
|
|
169
217
|
this._resolution = uniform( new Vector2() );
|
|
170
218
|
|
|
171
219
|
/**
|
|
172
|
-
*
|
|
173
|
-
* the maximum raymarching steps in the fragment shader.
|
|
220
|
+
* The render target the SSR is rendered into.
|
|
174
221
|
*
|
|
175
222
|
* @private
|
|
176
|
-
* @type {
|
|
223
|
+
* @type {RenderTarget}
|
|
224
|
+
*/
|
|
225
|
+
this._ssrRenderTarget = new RenderTarget( 1, 1, { depthBuffer: false, type: HalfFloatType } );
|
|
226
|
+
this._ssrRenderTarget.texture.name = 'SSRNode.SSR';
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The render target for the blurred SSR reflections.
|
|
230
|
+
*
|
|
231
|
+
* @private
|
|
232
|
+
* @type {RenderTarget}
|
|
177
233
|
*/
|
|
178
|
-
this.
|
|
234
|
+
this._blurRenderTarget = new RenderTarget( 1, 1, { depthBuffer: false, type: HalfFloatType, minFilter: LinearMipmapLinearFilter, magFilter: LinearFilter } );
|
|
235
|
+
this._blurRenderTarget.texture.name = 'SSRNode.Blur';
|
|
236
|
+
this._blurRenderTarget.texture.mipmaps.push( {}, {}, {}, {}, {} );
|
|
179
237
|
|
|
180
238
|
/**
|
|
181
239
|
* The material that is used to render the effect.
|
|
@@ -183,8 +241,26 @@ class SSRNode extends TempNode {
|
|
|
183
241
|
* @private
|
|
184
242
|
* @type {NodeMaterial}
|
|
185
243
|
*/
|
|
186
|
-
this.
|
|
187
|
-
this.
|
|
244
|
+
this._ssrMaterial = new NodeMaterial();
|
|
245
|
+
this._ssrMaterial.name = 'SSRNode.SSR';
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The blur material.
|
|
249
|
+
*
|
|
250
|
+
* @private
|
|
251
|
+
* @type {NodeMaterial}
|
|
252
|
+
*/
|
|
253
|
+
this._blurMaterial = new NodeMaterial();
|
|
254
|
+
this._blurMaterial.name = 'SSRNode.Blur';
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* The copy material.
|
|
258
|
+
*
|
|
259
|
+
* @private
|
|
260
|
+
* @type {NodeMaterial}
|
|
261
|
+
*/
|
|
262
|
+
this._copyMaterial = new NodeMaterial();
|
|
263
|
+
this._copyMaterial.name = 'SSRNode.Copy';
|
|
188
264
|
|
|
189
265
|
/**
|
|
190
266
|
* The result of the effect is represented as a separate texture node.
|
|
@@ -194,6 +270,25 @@ class SSRNode extends TempNode {
|
|
|
194
270
|
*/
|
|
195
271
|
this._textureNode = passTexture( this, this._ssrRenderTarget.texture );
|
|
196
272
|
|
|
273
|
+
let blurredTextureNode = null;
|
|
274
|
+
|
|
275
|
+
if ( this.roughnessNode !== null ) {
|
|
276
|
+
|
|
277
|
+
const mips = this._blurRenderTarget.texture.mipmaps.length - 1;
|
|
278
|
+
const lod = float( this.roughnessNode ).mul( mips ).clamp( 0, mips );
|
|
279
|
+
|
|
280
|
+
blurredTextureNode = passTexture( this, this._blurRenderTarget.texture ).level( lod );
|
|
281
|
+
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Holds the blurred SSR reflections.
|
|
286
|
+
*
|
|
287
|
+
* @private
|
|
288
|
+
* @type {?PassTextureNode}
|
|
289
|
+
*/
|
|
290
|
+
this._blurredTextureNode = blurredTextureNode;
|
|
291
|
+
|
|
197
292
|
}
|
|
198
293
|
|
|
199
294
|
/**
|
|
@@ -203,7 +298,7 @@ class SSRNode extends TempNode {
|
|
|
203
298
|
*/
|
|
204
299
|
getTextureNode() {
|
|
205
300
|
|
|
206
|
-
return this._textureNode;
|
|
301
|
+
return this.roughnessNode !== null ? this._blurredTextureNode : this._textureNode;
|
|
207
302
|
|
|
208
303
|
}
|
|
209
304
|
|
|
@@ -219,9 +314,8 @@ class SSRNode extends TempNode {
|
|
|
219
314
|
height = Math.round( this.resolutionScale * height );
|
|
220
315
|
|
|
221
316
|
this._resolution.value.set( width, height );
|
|
222
|
-
this._maxStep.value = Math.round( Math.sqrt( width * width + height * height ) );
|
|
223
|
-
|
|
224
317
|
this._ssrRenderTarget.setSize( width, height );
|
|
318
|
+
this._blurRenderTarget.setSize( width, height );
|
|
225
319
|
|
|
226
320
|
}
|
|
227
321
|
|
|
@@ -236,9 +330,12 @@ class SSRNode extends TempNode {
|
|
|
236
330
|
|
|
237
331
|
_rendererState = RendererUtils.resetRendererState( renderer, _rendererState );
|
|
238
332
|
|
|
333
|
+
const ssrRenderTarget = this._ssrRenderTarget;
|
|
334
|
+
const blurRenderTarget = this._blurRenderTarget;
|
|
335
|
+
|
|
239
336
|
const size = renderer.getDrawingBufferSize( _size );
|
|
240
337
|
|
|
241
|
-
_quadMesh.material = this.
|
|
338
|
+
_quadMesh.material = this._ssrMaterial;
|
|
242
339
|
|
|
243
340
|
this.setSize( size.width, size.height );
|
|
244
341
|
|
|
@@ -249,9 +346,27 @@ class SSRNode extends TempNode {
|
|
|
249
346
|
|
|
250
347
|
// ssr
|
|
251
348
|
|
|
252
|
-
renderer.setRenderTarget(
|
|
349
|
+
renderer.setRenderTarget( ssrRenderTarget );
|
|
253
350
|
_quadMesh.render( renderer );
|
|
254
351
|
|
|
352
|
+
// blur (optional)
|
|
353
|
+
|
|
354
|
+
if ( this.roughnessNode !== null ) {
|
|
355
|
+
|
|
356
|
+
// blur mips but leave the base mip unblurred
|
|
357
|
+
|
|
358
|
+
for ( let i = 0; i < blurRenderTarget.texture.mipmaps.length; i ++ ) {
|
|
359
|
+
|
|
360
|
+
_quadMesh.material = ( i === 0 ) ? this._copyMaterial : this._blurMaterial;
|
|
361
|
+
|
|
362
|
+
this._blurSpread.value = i;
|
|
363
|
+
renderer.setRenderTarget( blurRenderTarget, 0, i );
|
|
364
|
+
_quadMesh.render( renderer );
|
|
365
|
+
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
}
|
|
369
|
+
|
|
255
370
|
// restore
|
|
256
371
|
|
|
257
372
|
RendererUtils.restoreRendererState( renderer, _rendererState );
|
|
@@ -326,7 +441,7 @@ class SSRNode extends TempNode {
|
|
|
326
441
|
|
|
327
442
|
const ssr = Fn( () => {
|
|
328
443
|
|
|
329
|
-
const metalness = this.metalnessNode
|
|
444
|
+
const metalness = float( this.metalnessNode );
|
|
330
445
|
|
|
331
446
|
// fragments with no metalness do not reflect their environment
|
|
332
447
|
metalness.equal( 0.0 ).discard();
|
|
@@ -349,7 +464,7 @@ class SSRNode extends TempNode {
|
|
|
349
464
|
const d1viewPosition = viewPosition.add( viewReflectDir.mul( maxReflectRayLen ) ).toVar();
|
|
350
465
|
|
|
351
466
|
// check if d1viewPosition lies behind the camera near plane
|
|
352
|
-
If( this._isPerspectiveCamera.
|
|
467
|
+
If( this._isPerspectiveCamera.and( d1viewPosition.z.greaterThan( this._cameraNear.negate() ) ), () => {
|
|
353
468
|
|
|
354
469
|
// if so, ensure d1viewPosition is clamped on the near plane.
|
|
355
470
|
// this prevents artifacts during the ray marching process
|
|
@@ -374,7 +489,7 @@ class SSRNode extends TempNode {
|
|
|
374
489
|
// determine the larger delta
|
|
375
490
|
// The larger difference will help to determine how much to travel in the X and Y direction each iteration and
|
|
376
491
|
// how many iterations are needed to travel the entire ray
|
|
377
|
-
const totalStep = max( abs( xLen ), abs( yLen ) ).
|
|
492
|
+
const totalStep = int( max( abs( xLen ), abs( yLen ) ).mul( this.quality.clamp() ) ).toConst();
|
|
378
493
|
|
|
379
494
|
// step sizes in the x and y directions
|
|
380
495
|
const xSpan = xLen.div( totalStep ).toVar();
|
|
@@ -385,23 +500,9 @@ class SSRNode extends TempNode {
|
|
|
385
500
|
// the actual ray marching loop
|
|
386
501
|
// starting from d0, the code gradually travels along the ray and looks for an intersection with the geometry.
|
|
387
502
|
// it does not exceed d1 (the maximum ray extend)
|
|
388
|
-
Loop(
|
|
389
|
-
|
|
390
|
-
// TODO: Remove this when Chrome is fixed, see https://issues.chromium.org/issues/372714384#comment14
|
|
391
|
-
If( metalness.equal( 0 ), () => {
|
|
503
|
+
Loop( totalStep, ( { i } ) => {
|
|
392
504
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
} );
|
|
396
|
-
|
|
397
|
-
// stop if the maximum number of steps is reached for this specific ray
|
|
398
|
-
If( float( i ).greaterThanEqual( totalStep ), () => {
|
|
399
|
-
|
|
400
|
-
Break();
|
|
401
|
-
|
|
402
|
-
} );
|
|
403
|
-
|
|
404
|
-
// advance on the ray by computing a new position in screen space
|
|
505
|
+
// advance on the ray by computing a new position in screen coordinates
|
|
405
506
|
const xy = vec2( d0.x.add( xSpan.mul( float( i ) ) ), d0.y.add( ySpan.mul( float( i ) ) ) ).toVar();
|
|
406
507
|
|
|
407
508
|
// stop processing if the new position lies outside of the screen
|
|
@@ -411,11 +512,10 @@ class SSRNode extends TempNode {
|
|
|
411
512
|
|
|
412
513
|
} );
|
|
413
514
|
|
|
414
|
-
// compute new uv, depth
|
|
515
|
+
// compute new uv, depth and viewZ for the next fragment
|
|
415
516
|
const uvNode = xy.div( this._resolution );
|
|
416
517
|
const d = sampleDepth( uvNode ).toVar();
|
|
417
518
|
const vZ = getViewZ( d ).toVar();
|
|
418
|
-
const vP = getViewPosition( uvNode, d, this._cameraProjectionMatrixInverse ).toVar();
|
|
419
519
|
|
|
420
520
|
const viewReflectRayZ = float( 0 ).toVar();
|
|
421
521
|
|
|
@@ -423,7 +523,7 @@ class SSRNode extends TempNode {
|
|
|
423
523
|
const s = xy.sub( d0 ).length().div( totalLen );
|
|
424
524
|
|
|
425
525
|
// depending on the camera type, we now compute the z-coordinate of the reflected ray at the current step in view space
|
|
426
|
-
If( this._isPerspectiveCamera
|
|
526
|
+
If( this._isPerspectiveCamera, () => {
|
|
427
527
|
|
|
428
528
|
const recipVPZ = float( 1 ).div( viewPosition.z ).toVar();
|
|
429
529
|
viewReflectRayZ.assign( float( 1 ).div( recipVPZ.add( s.mul( float( 1 ).div( d1viewPosition.z ).sub( recipVPZ ) ) ) ) );
|
|
@@ -439,6 +539,7 @@ class SSRNode extends TempNode {
|
|
|
439
539
|
|
|
440
540
|
// compute the distance of the new location to the ray in view space
|
|
441
541
|
// to clarify vP is the fragment's view position which is not an exact point on the ray
|
|
542
|
+
const vP = getViewPosition( uvNode, d, this._cameraProjectionMatrixInverse ).toVar();
|
|
442
543
|
const away = pointToLineDistance( vP, viewPosition, d1viewPosition ).toVar();
|
|
443
544
|
|
|
444
545
|
// compute the minimum thickness between the current fragment and its neighbor in the x-direction.
|
|
@@ -499,12 +600,22 @@ class SSRNode extends TempNode {
|
|
|
499
600
|
|
|
500
601
|
} );
|
|
501
602
|
|
|
502
|
-
this.
|
|
503
|
-
this.
|
|
603
|
+
this._ssrMaterial.fragmentNode = ssr().context( builder.getSharedContext() );
|
|
604
|
+
this._ssrMaterial.needsUpdate = true;
|
|
605
|
+
|
|
606
|
+
// below materials are used for blurring
|
|
607
|
+
|
|
608
|
+
const reflectionBuffer = texture( this._ssrRenderTarget.texture );
|
|
609
|
+
|
|
610
|
+
this._blurMaterial.fragmentNode = boxBlur( reflectionBuffer, { size: this.blurQuality, separation: this._blurSpread } );
|
|
611
|
+
this._blurMaterial.needsUpdate = true;
|
|
612
|
+
|
|
613
|
+
this._copyMaterial.fragmentNode = reflectionBuffer;
|
|
614
|
+
this._copyMaterial.needsUpdate = true;
|
|
504
615
|
|
|
505
616
|
//
|
|
506
617
|
|
|
507
|
-
return this.
|
|
618
|
+
return this.getTextureNode();
|
|
508
619
|
|
|
509
620
|
}
|
|
510
621
|
|
|
@@ -515,8 +626,11 @@ class SSRNode extends TempNode {
|
|
|
515
626
|
dispose() {
|
|
516
627
|
|
|
517
628
|
this._ssrRenderTarget.dispose();
|
|
629
|
+
this._blurRenderTarget.dispose();
|
|
518
630
|
|
|
519
|
-
this.
|
|
631
|
+
this._ssrMaterial.dispose();
|
|
632
|
+
this._blurMaterial.dispose();
|
|
633
|
+
this._copyMaterial.dispose();
|
|
520
634
|
|
|
521
635
|
}
|
|
522
636
|
|
|
@@ -533,7 +647,8 @@ export default SSRNode;
|
|
|
533
647
|
* @param {Node<float>} depthNode - A node that represents the beauty pass's depth.
|
|
534
648
|
* @param {Node<vec3>} normalNode - A node that represents the beauty pass's normals.
|
|
535
649
|
* @param {Node<float>} metalnessNode - A node that represents the beauty pass's metalness.
|
|
536
|
-
* @param {
|
|
650
|
+
* @param {?Node<float>} [roughnessNode=null] - A node that represents the beauty pass's roughness.
|
|
651
|
+
* @param {?Camera} [camera=null] - The camera the scene is rendered with.
|
|
537
652
|
* @returns {SSRNode}
|
|
538
653
|
*/
|
|
539
|
-
export const ssr = ( colorNode, depthNode, normalNode, metalnessNode, camera ) => nodeObject( new SSRNode( nodeObject( colorNode ), nodeObject( depthNode ), nodeObject( normalNode ), nodeObject( metalnessNode ), camera ) );
|
|
654
|
+
export const ssr = ( colorNode, depthNode, normalNode, metalnessNode, roughnessNode = null, camera = null ) => nodeObject( new SSRNode( nodeObject( colorNode ), nodeObject( depthNode ), nodeObject( normalNode ), nodeObject( metalnessNode ), nodeObject( roughnessNode ), camera ) );
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Fn, vec2, uv, Loop, vec4, premultiplyAlpha, unpremultiplyAlpha, max, int, textureSize, nodeObject, convertToTexture } from 'three/tsl';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Applies a box blur effect to the given texture node.
|
|
5
|
+
*
|
|
6
|
+
* Compared to Gaussian blur, box blur produces a more blocky result but with better performance when correctly
|
|
7
|
+
* configured. It is intended for mobile devices or performance restricted use cases where Gaussian is too heavy.
|
|
8
|
+
*
|
|
9
|
+
* The (kernel) `size` parameter should be small (1, 2 or 3) since it determines the number of samples based on (size * 2 + 1)^2.
|
|
10
|
+
* This implementation uses a single pass approach so the kernel is not applied as a separable filter. That means larger
|
|
11
|
+
* kernels won't perform well. Use Gaussian instead if you need a more high-quality blur.
|
|
12
|
+
*
|
|
13
|
+
* To produce wider blurs, increase the `separation` parameter instead which has no influence on the performance.
|
|
14
|
+
*
|
|
15
|
+
* Reference: {@link https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/fragment/box-blur.frag}.
|
|
16
|
+
*
|
|
17
|
+
* @function
|
|
18
|
+
* @param {Node<vec4>} textureNode - The texture node that should be blurred.
|
|
19
|
+
* @param {Object} [options={}] - Additional options for the hash blur effect.
|
|
20
|
+
* @param {Node<int>} [options.size=int(1)] - Controls the blur's kernel. For performant results, the range should within [1, 3].
|
|
21
|
+
* @param {Node<int>} [options.separation=int(1)] - Spreads out the blur without having to sample additional fragments. Ranges from [1, Infinity].
|
|
22
|
+
* @param {boolean} [options.premultipliedAlpha=false] - Whether to use premultiplied alpha for the blur effect.
|
|
23
|
+
* @return {Node<vec4>} The blurred texture node.
|
|
24
|
+
*/
|
|
25
|
+
export const boxBlur = /*#__PURE__*/ Fn( ( [ textureNode, options = {} ] ) => {
|
|
26
|
+
|
|
27
|
+
textureNode = convertToTexture( textureNode );
|
|
28
|
+
|
|
29
|
+
const size = nodeObject( options.size ) || int( 1 );
|
|
30
|
+
const separation = nodeObject( options.separation ) || int( 1 );
|
|
31
|
+
const premultipliedAlpha = options.premultipliedAlpha || false;
|
|
32
|
+
|
|
33
|
+
const tap = ( uv ) => {
|
|
34
|
+
|
|
35
|
+
const sample = textureNode.sample( uv );
|
|
36
|
+
|
|
37
|
+
return premultipliedAlpha ? premultiplyAlpha( sample ) : sample;
|
|
38
|
+
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const targetUV = textureNode.uvNode || uv();
|
|
42
|
+
|
|
43
|
+
const result = vec4( 0 );
|
|
44
|
+
const sep = max( separation, 1 );
|
|
45
|
+
const count = int( 0 );
|
|
46
|
+
const pixelStep = vec2( 1 ).div( textureSize( textureNode ) );
|
|
47
|
+
|
|
48
|
+
Loop( { start: size.negate(), end: size, name: 'i', condition: '<=' }, ( { i } ) => {
|
|
49
|
+
|
|
50
|
+
Loop( { start: size.negate(), end: size, name: 'j', condition: '<=' }, ( { j } ) => {
|
|
51
|
+
|
|
52
|
+
const uvs = targetUV.add( vec2( i, j ).mul( pixelStep ).mul( sep ) );
|
|
53
|
+
result.addAssign( tap( uvs ) );
|
|
54
|
+
count.addAssign( 1 );
|
|
55
|
+
|
|
56
|
+
} );
|
|
57
|
+
|
|
58
|
+
} );
|
|
59
|
+
|
|
60
|
+
result.divAssign( count );
|
|
61
|
+
|
|
62
|
+
return premultipliedAlpha ? unpremultiplyAlpha( result ) : result;
|
|
63
|
+
|
|
64
|
+
} );
|