Skip to content

Commit e07583b

Browse files
authored
NodeMaterial: Introduce .maskNode and improve shapeCircle() (#31127)
* always check `alphaTest` but optimize uniform to constant if necessary * Introduce `.maskNode` * improve `shapeCircle` * `webgpu_compute_particles`: use `shapeCirle()`
1 parent 3765bd0 commit e07583b

File tree

3 files changed

+38
-13
lines changed

3 files changed

+38
-13
lines changed

examples/webgpu_compute_particles.html

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
<script type="module">
3939

4040
import * as THREE from 'three';
41-
import { Fn, If, uniform, float, uv, vec2, vec3, hash,
41+
import { Fn, If, uniform, float, uv, vec2, vec3, hash, shapeCircle,
4242
instancedArray, instanceIndex } from 'three/tsl';
4343

4444
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
@@ -133,13 +133,14 @@
133133
computeParticles = computeUpdate().compute( particleCount );
134134

135135
// create particles
136-
136+
137137
const material = new THREE.SpriteNodeMaterial();
138138
material.colorNode = uv().mul( colors.element( instanceIndex ) );
139139
material.positionNode = positions.toAttribute();
140140
material.scaleNode = size;
141-
material.alphaTestNode = uv().mul( 2 ).distance( vec2( 1 ) );
142-
material.transparent = false;
141+
material.opacityNode = shapeCircle();
142+
material.alphaToCoverage = true;
143+
material.transparent = true;
143144

144145
const particles = new THREE.Sprite( material );
145146
particles.count = particleCount;

src/materials/nodes/NodeMaterial.js

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { positionLocal, positionView } from '../../nodes/accessors/Position.js';
1313
import { skinning } from '../../nodes/accessors/SkinningNode.js';
1414
import { morphReference } from '../../nodes/accessors/MorphNode.js';
1515
import { mix } from '../../nodes/math/MathNode.js';
16-
import { float, vec3, vec4 } from '../../nodes/tsl/TSLBase.js';
16+
import { float, vec3, vec4, bool } from '../../nodes/tsl/TSLBase.js';
1717
import AONode from '../../nodes/lighting/AONode.js';
1818
import { lightingContext } from '../../nodes/lighting/LightingContextNode.js';
1919
import IrradianceNode from '../../nodes/lighting/IrradianceNode.js';
@@ -229,6 +229,15 @@ class NodeMaterial extends Material {
229229
*/
230230
this.alphaTestNode = null;
231231

232+
233+
/**
234+
* Discards the fragment if the mask value is `false`.
235+
*
236+
* @type {?Node<bool>}
237+
* @default null
238+
*/
239+
this.maskNode = null;
240+
232241
/**
233242
* The local vertex positions are computed based on multiple factors like the
234243
* attribute data, morphing or skinning. This node property allows to overwrite
@@ -774,6 +783,14 @@ class NodeMaterial extends Material {
774783

775784
let colorNode = this.colorNode ? vec4( this.colorNode ) : materialColor;
776785

786+
// MASK
787+
788+
if ( this.maskNode !== null ) {
789+
790+
bool( this.maskNode ).discard();
791+
792+
}
793+
777794
// VERTEX COLORS
778795

779796
if ( this.vertexColors === true && geometry.hasAttribute( 'color' ) ) {
@@ -782,7 +799,7 @@ class NodeMaterial extends Material {
782799

783800
}
784801

785-
// Instanced colors
802+
// INSTANCED COLORS
786803

787804
if ( object.instanceColor ) {
788805

@@ -800,7 +817,6 @@ class NodeMaterial extends Material {
800817

801818
}
802819

803-
804820
// COLOR
805821

806822
diffuseColor.assign( colorNode );
@@ -812,14 +828,20 @@ class NodeMaterial extends Material {
812828

813829
// ALPHA TEST
814830

831+
let alphaTestNode;
832+
815833
if ( this.alphaTestNode !== null || this.alphaTest > 0 ) {
816834

817-
const alphaTestNode = this.alphaTestNode !== null ? float( this.alphaTestNode ) : materialAlphaTest;
835+
alphaTestNode = this.alphaTestNode !== null ? float( this.alphaTestNode ) : materialAlphaTest;
836+
837+
} else {
818838

819-
diffuseColor.a.lessThanEqual( alphaTestNode ).discard();
839+
alphaTestNode = float( 0 );
820840

821841
}
822842

843+
diffuseColor.a.lessThanEqual( alphaTestNode ).discard();
844+
823845
// ALPHA HASH
824846

825847
if ( this.alphaHash === true ) {
@@ -1189,6 +1211,7 @@ class NodeMaterial extends Material {
11891211
this.backdropNode = source.backdropNode;
11901212
this.backdropAlphaNode = source.backdropAlphaNode;
11911213
this.alphaTestNode = source.alphaTestNode;
1214+
this.maskNode = source.maskNode;
11921215

11931216
this.positionNode = source.positionNode;
11941217
this.geometryNode = source.geometryNode;

src/nodes/shapes/Shapes.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Fn, float } from '../tsl/TSLBase.js';
1+
import { Fn, float, select } from '../tsl/TSLBase.js';
22
import { lengthSq, smoothstep } from '../math/MathNode.js';
33
import { uv } from '../accessors/UV.js';
44

@@ -12,18 +12,19 @@ import { uv } from '../accessors/UV.js';
1212
*/
1313
export const shapeCircle = Fn( ( [ coord = uv() ], { renderer, material } ) => {
1414

15-
const alpha = float( 1 ).toVar();
1615
const len2 = lengthSq( coord.mul( 2 ).sub( 1 ) );
1716

17+
let alpha;
18+
1819
if ( material.alphaToCoverage && renderer.samples > 1 ) {
1920

2021
const dlen = float( len2.fwidth() ).toVar();
2122

22-
alpha.assign( smoothstep( dlen.oneMinus(), dlen.add( 1 ), len2 ).oneMinus() );
23+
alpha = smoothstep( dlen.oneMinus(), dlen.add( 1 ), len2 ).oneMinus();
2324

2425
} else {
2526

26-
len2.greaterThan( 1.0 ).discard();
27+
alpha = select( len2.greaterThan( 1.0 ), 0, 1 );
2728

2829
}
2930

0 commit comments

Comments
 (0)