|
@@ -29,10 +29,10 @@
|
|
import * as Nodes from 'three-nodes/Nodes.js';
|
|
import * as Nodes from 'three-nodes/Nodes.js';
|
|
|
|
|
|
import {
|
|
import {
|
|
- compute,
|
|
|
|
- color, add, uniform, element, storage, func,
|
|
|
|
- assign, float, mul,
|
|
|
|
- positionLocal, instanceIndex
|
|
|
|
|
|
+ ShaderNode, compute,
|
|
|
|
+ uniform, element, storage, temp,
|
|
|
|
+ assign, add, sub, cond, abs, negate, max, min, length, vec3, color,
|
|
|
|
+ greaterThanEqual, lessThanEqual, positionLocal, instanceIndex
|
|
} from 'three-nodes/Nodes.js';
|
|
} from 'three-nodes/Nodes.js';
|
|
|
|
|
|
import { GUI } from './jsm/libs/lil-gui.module.min.js';
|
|
import { GUI } from './jsm/libs/lil-gui.module.min.js';
|
|
@@ -43,7 +43,7 @@
|
|
let camera, scene, renderer;
|
|
let camera, scene, renderer;
|
|
let computeNode;
|
|
let computeNode;
|
|
|
|
|
|
- const pointer = new THREE.Vector2( - 10.0, - 10.0 ); // Out of bounds first
|
|
|
|
|
|
+ const pointerVector = new THREE.Vector2( - 10.0, - 10.0 ); // Out of bounds first
|
|
const scaleVector = new THREE.Vector2( 1, 1 );
|
|
const scaleVector = new THREE.Vector2( 1, 1 );
|
|
|
|
|
|
init().then( animate ).catch( error );
|
|
init().then( animate ).catch( error );
|
|
@@ -89,95 +89,36 @@
|
|
const particleBufferNode = storage( particleBuffer, 'vec3' );
|
|
const particleBufferNode = storage( particleBuffer, 'vec3' );
|
|
const velocityBufferNode = storage( velocityBuffer, 'vec3' );
|
|
const velocityBufferNode = storage( velocityBuffer, 'vec3' );
|
|
|
|
|
|
- // create wgsl function
|
|
|
|
|
|
+ // create function
|
|
|
|
|
|
- const WGSLFnNode = func( `( pointer:vec2<f32>, limit:vec2<f32> ) {
|
|
|
|
|
|
+ const FnNode = new ShaderNode( ( inputs, builder ) => {
|
|
|
|
|
|
- var position = particle + velocity;
|
|
|
|
|
|
+ const particle = element( particleBufferNode, instanceIndex );
|
|
|
|
+ const velocity = element( velocityBufferNode, instanceIndex );
|
|
|
|
|
|
- if ( abs( position.x ) >= limit.x ) {
|
|
|
|
|
|
+ const pointer = uniform( pointerVector );
|
|
|
|
+ const limit = uniform( scaleVector );
|
|
|
|
|
|
- if ( position.x > 0.0 ) {
|
|
|
|
|
|
+ const position = temp( vec3() );
|
|
|
|
+ assign( position, add( particle, velocity ) ).build( builder ); // workaround
|
|
|
|
|
|
- position.x = limit.x;
|
|
|
|
|
|
+ assign( velocity.x, cond( greaterThanEqual( abs( position.x ), limit.x ), negate( velocity.x ), velocity.x ) ).build( builder );
|
|
|
|
+ assign( velocity.y, cond( greaterThanEqual( abs( position.y ), limit.y ), negate( velocity.y ), velocity.y ) ).build( builder );
|
|
|
|
|
|
- } else {
|
|
|
|
|
|
+ assign( position, max( negate( limit ), min( limit, position ) ) ).build( builder );
|
|
|
|
|
|
- position.x = -limit.x;
|
|
|
|
|
|
+ const pointerSize = 0.1;
|
|
|
|
+ const distanceFromPointer = length( sub( pointer, position ) );
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ assign( particle, cond( lessThanEqual( distanceFromPointer, pointerSize ), vec3(), position ) ).build( builder );
|
|
|
|
|
|
- velocity.x = - velocity.x;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if ( abs( position.y ) >= limit.y ) {
|
|
|
|
-
|
|
|
|
- if ( position.y > 0.0 ) {
|
|
|
|
-
|
|
|
|
- position.y = limit.y;
|
|
|
|
-
|
|
|
|
- } else {
|
|
|
|
-
|
|
|
|
- position.y = -limit.y;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- velocity.y = - velocity.y ;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let POINTER_SIZE = .1;
|
|
|
|
-
|
|
|
|
- let dx = pointer.x - position.x;
|
|
|
|
- let dy = pointer.y - position.y;
|
|
|
|
- let distanceFromPointer = sqrt( dx * dx + dy * dy );
|
|
|
|
-
|
|
|
|
- if ( distanceFromPointer <= POINTER_SIZE ) {
|
|
|
|
-
|
|
|
|
- position.x = 0.0;
|
|
|
|
- position.y = 0.0;
|
|
|
|
- position.z = 0.0;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- particle = position;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
- ` );
|
|
|
|
-
|
|
|
|
- // define particle and velocity keywords in wgsl function
|
|
|
|
- // it's used in case of needed change a global variable like this storageBuffer
|
|
|
|
-
|
|
|
|
- const particleNode = element( particleBufferNode, instanceIndex );
|
|
|
|
- const velocityNode = element( velocityBufferNode, instanceIndex );
|
|
|
|
-
|
|
|
|
- WGSLFnNode.keywords[ 'particle' ] = particleNode;
|
|
|
|
- WGSLFnNode.keywords[ 'velocity' ] = velocityNode;
|
|
|
|
|
|
+ } );
|
|
|
|
|
|
// compute
|
|
// compute
|
|
|
|
|
|
computeNode = compute( particleNum );
|
|
computeNode = compute( particleNum );
|
|
|
|
|
|
- // Example 1: Calling a WGSL function
|
|
|
|
-
|
|
|
|
- computeNode.computeNode = WGSLFnNode.call( {
|
|
|
|
- pointer: uniform( pointer ),
|
|
|
|
- limit: uniform( scaleVector )
|
|
|
|
- } );
|
|
|
|
-
|
|
|
|
- // Example 2: Creating single storage assign
|
|
|
|
-
|
|
|
|
- //computeNode.computeNode = assign( particleNode, add( particleNode, velocityNode ) );
|
|
|
|
-
|
|
|
|
- // Example 3: Creating multiples storage assign
|
|
|
|
-
|
|
|
|
- /*computeNode.computeNode = new Nodes.ShaderNode( ( {}, builder ) => {
|
|
|
|
-
|
|
|
|
- assign( particleNode, add( particleNode, velocityNode ) ).build( builder );
|
|
|
|
- assign( velocityNode, mul( velocityNode, float( 0.99 ) ) ).build( builder );
|
|
|
|
-
|
|
|
|
- } );/**/
|
|
|
|
|
|
+ computeNode.computeNode = FnNode;
|
|
|
|
|
|
// use a compute shader to animate the point cloud's vertex data.
|
|
// use a compute shader to animate the point cloud's vertex data.
|
|
|
|
|
|
@@ -225,7 +166,7 @@
|
|
const width = window.innerWidth;
|
|
const width = window.innerWidth;
|
|
const height = window.innerHeight;
|
|
const height = window.innerHeight;
|
|
|
|
|
|
- pointer.set(
|
|
|
|
|
|
+ pointerVector.set(
|
|
( x / width - 0.5 ) * 2.0,
|
|
( x / width - 0.5 ) * 2.0,
|
|
( - y / height + 0.5 ) * 2.0
|
|
( - y / height + 0.5 ) * 2.0
|
|
);
|
|
);
|