Skip to content

Commit

Permalink
Nodes: InstancedPointsNodeMaterial - Add pointWidthNode (mrdoob#2…
Browse files Browse the repository at this point in the history
…9236)

* init

* adjustment

* adjust

* set instancePosition.xyz to fix warning when instancePosition is accessed as a StorageBufferNode in a compute shader

* cleanup and screenshot

* add instance points example to exception

* reduce instanced points complexity

* add pointColorNode usage example, remove unused values

* revision

---------
  • Loading branch information
cmhhelgeson committed Aug 29, 2024
1 parent 3f2956c commit 7506a35
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 33 deletions.
Binary file modified examples/screenshots/webgpu_instance_points.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
86 changes: 55 additions & 31 deletions examples/webgpu_instance_points.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<script type="module">

import * as THREE from 'three';
import { color } from 'three/tsl';
import { color, storage, Fn, instanceIndex, sin, timerLocal, float, uniform, attribute, mix, vec3 } from 'three/tsl';

import Stats from 'three/addons/libs/stats.module.js';

Expand All @@ -42,11 +42,15 @@
let material;
let stats;
let gui;
let effectController;

// viewport
let insetWidth;
let insetHeight;

// compute
let computeSize;

init();

function init() {
Expand All @@ -72,10 +76,16 @@

backgroundNode = color( 0x222222 );

// Position and THREE.Color Data
effectController = {

const positions = [];
const colors = [];
pulseSpeed: uniform( 6 ),
minWidth: uniform( 6 ),
maxWidth: uniform( 12 ),
alphaToCoverage: true,

};

// Position and THREE.Color Data

const points = GeometryUtils.hilbert3D( new THREE.Vector3( 0, 0, 0 ), 20.0, 1, 0, 1, 2, 3, 4, 5, 6, 7 );

Expand All @@ -84,6 +94,10 @@
const point = new THREE.Vector3();
const pointColor = new THREE.Color();

const positions = [];
const colors = [];
const sizes = new Float32Array( divisions );

for ( let i = 0, l = divisions; i < l; i ++ ) {

const t = i / l;
Expand All @@ -94,6 +108,8 @@
pointColor.setHSL( t, 1.0, 0.5, THREE.SRGBColorSpace );
colors.push( pointColor.r, pointColor.g, pointColor.b );

sizes[ i ] = 10.0;

}

// Instanced Points
Expand All @@ -102,31 +118,59 @@
geometry.setPositions( positions );
geometry.setColors( colors );

const instanceSizeBufferAttribute = new THREE.StorageInstancedBufferAttribute( sizes, 1 );
geometry.setAttribute( 'instanceSize', instanceSizeBufferAttribute );
const instanceSizeStorage = storage( instanceSizeBufferAttribute, 'float', instanceSizeBufferAttribute.count );

computeSize = Fn( () => {

const { pulseSpeed, minWidth, maxWidth } = effectController;

const time = timerLocal().add( float( instanceIndex ) );

const sizeFactor = sin( time.mul( pulseSpeed ) ).add( 1 ).div( 2 );

instanceSizeStorage.element( instanceIndex ).assign( sizeFactor.mul( maxWidth.sub( minWidth ) ).add( minWidth ) );

} )().compute( divisions );

geometry.instanceCount = positions.length / 3; // this should not be necessary

material = new THREE.InstancedPointsNodeMaterial( {

color: 0xffffff,
pointWidth: 10, // in pixel units

vertexColors: true,
alphaToCoverage: true,

} );

const attributeRange = attribute( 'instanceSize' ).sub( 1 );

material.pointWidthNode = attribute( 'instanceSize' );
material.pointColorNode = mix( vec3( 0.0 ), attribute( 'instanceColor' ), attributeRange.div( float( effectController.maxWidth.sub( 1 ) ) ) );

const instancedPoints = new InstancedPoints( geometry, material );
instancedPoints.scale.set( 1, 1, 1 );
scene.add( instancedPoints );

//

window.addEventListener( 'resize', onWindowResize );
onWindowResize();

stats = new Stats();
document.body.appendChild( stats.dom );

initGui();
gui = new GUI();

gui.add( effectController, 'alphaToCoverage' ).onChange( function ( val ) {

material.alphaToCoverage = val;

} );

gui.add( effectController.minWidth, 'value', 1, 20, 1 ).name( 'minWidth' );
gui.add( effectController.maxWidth, 'value', 2, 20, 1 ).name( 'maxWidth' );
gui.add( effectController.pulseSpeed, 'value', 1, 20, 0.1 ).name( 'pulseSpeed' );

}

Expand All @@ -149,6 +193,9 @@

stats.update();

// compute
renderer.compute( computeSize );

// main scene

renderer.setViewport( 0, 0, window.innerWidth, window.innerHeight );
Expand Down Expand Up @@ -189,29 +236,6 @@

//

function initGui() {

gui = new GUI();

const param = {
'width': 10,
'alphaToCoverage': true,
};

gui.add( param, 'width', 1, 20, 1 ).onChange( function ( val ) {

material.pointWidth = val;

} );

gui.add( param, 'alphaToCoverage' ).onChange( function ( val ) {

material.alphaToCoverage = val;

} );

}

</script>

</body>
Expand Down
8 changes: 6 additions & 2 deletions src/materials/nodes/InstancedPointsNodeMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class InstancedPointsNodeMaterial extends NodeMaterial {

this.pointColorNode = null;

this.pointWidthNode = null;

this.setDefaultValues( _defaultValues );

this.setupShaders();
Expand All @@ -56,7 +58,7 @@ class InstancedPointsNodeMaterial extends NodeMaterial {
//vUv = uv;
varying( vec2(), 'vUv' ).assign( uv() ); // @TODO: Analyze other way to do this

const instancePosition = attribute( 'instancePosition' );
const instancePosition = attribute( 'instancePosition' ).xyz;

// camera space
const mvPos = property( 'vec4', 'mvPos' );
Expand All @@ -70,7 +72,9 @@ class InstancedPointsNodeMaterial extends NodeMaterial {
// offset in ndc space
const offset = property( 'vec2', 'offset' );
offset.assign( positionGeometry.xy );
offset.assign( offset.mul( materialPointWidth ) );

offset.mulAssign( this.pointWidthNode ? this.pointWidthNode : materialPointWidth );

offset.assign( offset.div( viewport.z ) );
offset.y.assign( offset.y.mul( aspect ) );

Expand Down

0 comments on commit 7506a35

Please sign in to comment.