Skip to content

Commit

Permalink
Nodes & WebGPURenderer: RangeNode (mrdoob#24240)
Browse files Browse the repository at this point in the history
* Move render object dependencies to renderObject() like WebGLRenderer

* add RangeNode

* update webgpu examples
  • Loading branch information
sunag authored and snagy committed Sep 21, 2022
1 parent f30a562 commit 926ff86
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 26 deletions.
13 changes: 11 additions & 2 deletions examples/jsm/nodes/Nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ import TextureNode from './accessors/TextureNode.js';
import UVNode from './accessors/UVNode.js';
import UserDataNode from './accessors/UserDataNode.js';

// geometry
import RangeNode from './geometry/RangeNode.js';

// gpgpu
import ComputeNode from './gpgpu/ComputeNode.js';

Expand Down Expand Up @@ -130,7 +133,10 @@ const nodeLib = {
VarNode,
VaryNode,

// compute
// geometry
RangeNode,

// gpgpu
ComputeNode,

// accessors
Expand Down Expand Up @@ -234,7 +240,10 @@ export {
VarNode,
VaryNode,

// compute
// geometry
RangeNode,

// gpgpu
ComputeNode,

// accessors
Expand Down
101 changes: 101 additions & 0 deletions examples/jsm/nodes/geometry/RangeNode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import Node from '../core/Node.js';
import { attribute, float } from '../shadernode/ShaderNodeBaseElements.js';
import { MathUtils, InstancedBufferAttribute } from 'three';

class RangeNode extends Node {

constructor( min, max ) {

super();

this.min = min;
this.max = max;

}

getVectorLength() {

const min = this.min;

let length = 1;

if ( min.isVector2 ) length = 2;
else if ( min.isVector3 ) length = 3;
else if ( min.isVector4 ) length = 4;
else if ( min.isColor ) length = 3;

return length;

}

getNodeType( builder ) {

return ( builder.object.isInstancedMesh === true ) ? builder.getTypeFromLength( this.getVectorLength() ) : 'float';

}

construct( builder ) {

const { min, max } = this;
const { object, geometry } = builder;

const vectorLength = this.getVectorLength();
const attributeName = 'node' + this.id;

let output = null;

if ( object.isInstancedMesh === true ) {

const length = vectorLength * object.count;
const array = new Float32Array( length );

if ( vectorLength === 1 ) {

for ( let i = 0; i < length; i ++ ) {

array[ i ] = MathUtils.lerp( min, max, Math.random() );

}

} else if ( min.isColor ) {

for ( let i = 0; i < length; i += 3 ) {

array[ i ] = MathUtils.lerp( min.r, max.r, Math.random() );
array[ i + 1 ] = MathUtils.lerp( min.g, max.g, Math.random() );
array[ i + 2 ] = MathUtils.lerp( min.b, max.b, Math.random() );

}

} else {

for ( let i = 0; i < length; i ++ ) {

const index = i % vectorLength;

const minValue = min.getComponent( index );
const maxValue = max.getComponent( index );

array[ i ] = MathUtils.lerp( minValue, maxValue, Math.random() );

}

}

geometry.setAttribute( attributeName, new InstancedBufferAttribute( array, vectorLength ) );

output = attribute( attributeName, builder.getTypeFromLength( vectorLength ) );

} else {

output = float( 0 );

}

return output;

}

}

export default RangeNode;
7 changes: 7 additions & 0 deletions examples/jsm/nodes/shadernode/ShaderNodeElements.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import OscNode from '../utils/OscNode.js';
import SpriteSheetUVNode from '../utils/SpriteSheetUVNode.js';
import TimerNode from '../utils/TimerNode.js';

// geometry
import RangeNode from '../geometry/RangeNode.js';

// procedural
import CheckerNode from '../procedural/CheckerNode.js';

Expand Down Expand Up @@ -101,6 +104,10 @@ export const timerLocal = ( timeScale ) => nodeObject( new TimerNode( TimerNode.
export const timerGlobal = ( timeScale ) => nodeObject( new TimerNode( TimerNode.GLOBAL, timeScale ) );
export const timerDelta = ( timeScale ) => nodeObject( new TimerNode( TimerNode.DELTA, timeScale ) );

// geometry

export const range = ( min, max ) => nodeObject( new RangeNode( min, max ) );

// procedural

export const checker = nodeProxy( CheckerNode );
Expand Down
45 changes: 23 additions & 22 deletions examples/jsm/renderers/webgpu/WebGPURenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -770,20 +770,6 @@ class WebGPURenderer {

const { object, geometry, material, group } = renderItem;

object.onBeforeRender( this, scene, camera, geometry, material, group );

object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
object.normalMatrix.getNormalMatrix( object.modelViewMatrix );

this._objects.update( object );

// send scene properties to object

const objectProperties = this._properties.get( object );

objectProperties.lightsNode = lightsNode;
objectProperties.scene = scene;

if ( camera.isArrayCamera ) {

const cameras = camera.cameras;
Expand All @@ -800,30 +786,46 @@ class WebGPURenderer {

passEncoder.setViewport( vp.x, vp.y, vp.width, vp.height, minDepth, maxDepth );

this._nodes.update( object, camera2 );
this._bindings.update( object );
this._renderObject( object, passEncoder );
this._renderObject( object, scene, camera2, geometry, material, group, lightsNode, passEncoder );

}

}

} else {

this._nodes.update( object, camera );
this._bindings.update( object );
this._renderObject( object, passEncoder );
this._renderObject( object, scene, camera, geometry, material, group, lightsNode, passEncoder );

}

}

}

_renderObject( object, passEncoder ) {
_renderObject( object, scene, camera, geometry, material, group, lightsNode, passEncoder ) {

const info = this._info;

// send scene properties to object

const objectProperties = this._properties.get( object );

objectProperties.lightsNode = lightsNode;
objectProperties.scene = scene;

//

object.onBeforeRender( this, scene, camera, geometry, material, group );

object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
object.normalMatrix.getNormalMatrix( object.modelViewMatrix );

// updates

this._nodes.update( object, camera );
this._bindings.update( object );
this._objects.update( object );

// pipeline

const renderPipeline = this._renderPipelines.get( object );
Expand All @@ -836,7 +838,6 @@ class WebGPURenderer {

// index

const geometry = object.geometry;
const index = geometry.index;

const hasIndex = ( index !== null );
Expand Down
8 changes: 6 additions & 2 deletions examples/webgpu_instance_mesh.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import Stats from './jsm/libs/stats.module.js';
import { GUI } from './jsm/libs/lil-gui.module.min.js';

import { normalWorld } from 'three-nodes/Nodes.js';
import { mix, range, normalWorld, oscSine, timerLocal } from 'three-nodes/Nodes.js';

import WebGPU from './jsm/capabilities/WebGPU.js';
import WebGPURenderer from './jsm/renderers/webgpu/WebGPURenderer.js';
Expand Down Expand Up @@ -61,7 +61,11 @@
scene = new THREE.Scene();

const material = new THREE.MeshBasicMaterial();
material.colorNode = normalWorld;

// random colors between instances from 0x000000 to 0xFFFFFF
const randomColors = range( new THREE.Color( 0x000000 ), new THREE.Color( 0xFFFFFF ) );

material.colorNode = mix( normalWorld, randomColors, oscSine( timerLocal( .1 ) ) );

const loader = new THREE.BufferGeometryLoader();
loader.load( 'models/json/suzanne_buffergeometry.json', function ( geometry ) {
Expand Down
10 changes: 10 additions & 0 deletions examples/webgpu_skinning_instancing.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import * as THREE from 'three';
import * as Nodes from 'three-nodes/Nodes.js';

import { mix, range, color, oscSine, timerLocal } from 'three-nodes/Nodes.js';

import { FBXLoader } from './jsm/loaders/FBXLoader.js';

import WebGPU from './jsm/capabilities/WebGPU.js';
Expand Down Expand Up @@ -83,8 +85,16 @@

if ( child.isMesh ) {

// random colors between instances from 0x000000 to 0xFFFFFF
const randomColors = range( new THREE.Color( 0x000000 ), new THREE.Color( 0xFFFFFF ) );

// random [ 0, 1 ] values between instances
const randomMetalness = range( 0, 1 );

child.material = new Nodes.MeshStandardNodeMaterial();
child.material.roughness = .1;
child.material.metalnessNode = randomMetalness;
child.material.colorNode = mix( color( 0xFFFFFF ), randomColors, oscSine( timerLocal( .1 ) ) );

child.isInstancedMesh = true;
child.instanceMatrix = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 16 ), 16 );
Expand Down

0 comments on commit 926ff86

Please sign in to comment.