Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TSL: Introduce array and instancedArray #29881

Draft
wants to merge 4 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions examples/jsm/tsl/lighting/TiledLightsNode.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
storageObject, nodeProxy, int, float, vec2, ivec2, ivec4, uniform, Break, Loop,
array, nodeProxy, int, float, vec2, ivec2, ivec4, uniform, Break, Loop,
Fn, If, Return, textureLoad, instanceIndex, screenCoordinate, directPointLight,
LightsNode, NodeUpdateType, StorageBufferAttribute
LightsNode, NodeUpdateType
} from 'three/tsl';

import { DataTexture, FloatType, RGBAFormat, Vector2, Vector3 } from 'three';
Expand Down Expand Up @@ -290,8 +290,7 @@ class TiledLightsNode extends LightsNode {
const lightsTexture = new DataTexture( lightsData, lightsData.length / 8, 2, RGBAFormat, FloatType );

const lightIndexesArray = new Int32Array( count * 4 * 2 );
const lightIndexesAttribute = new StorageBufferAttribute( lightIndexesArray, 4 );
const lightIndexes = storageObject( lightIndexesAttribute, 'ivec4', lightIndexesAttribute.count ).label( 'lightIndexes' );
const lightIndexes = array( lightIndexesArray, 'ivec4' ).label( 'lightIndexes' );

// compute

Expand Down
26 changes: 14 additions & 12 deletions examples/webgpu_compute_audio.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@
<script type="module">

import * as THREE from 'three';
import { Fn, uniform, storage, storageObject, instanceIndex, float, texture, screenUV, color } from 'three/tsl';
import { Fn, uniform, instanceIndex, instancedArray, float, texture, screenUV, color } from 'three/tsl';

import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

let camera, scene, renderer;
let computeNode;
let waveBuffer, sampleRate;
let waveGPUBuffer;
let waveArray;
let currentAudio, currentAnalyser;
const analyserBuffer = new Uint8Array( 1024 );
let analyserTexture;
Expand All @@ -51,14 +51,14 @@

await renderer.computeAsync( computeNode );

const waveArray = new Float32Array( await renderer.getArrayBufferAsync( waveGPUBuffer ) );
const wave = new Float32Array( await renderer.getArrayBufferAsync( waveArray.value ) );

// play result

const audioOutputContext = new AudioContext( { sampleRate } );
const audioOutputBuffer = audioOutputContext.createBuffer( 1, waveArray.length, sampleRate );
const audioOutputBuffer = audioOutputContext.createBuffer( 1, wave.length, sampleRate );

audioOutputBuffer.copyToChannel( waveArray, 0 );
audioOutputBuffer.copyToChannel( wave, 0 );

const source = audioOutputContext.createBufferSource();
source.connect( audioOutputContext.destination );
Expand Down Expand Up @@ -92,16 +92,18 @@

sampleRate = audioBuffer.sampleRate / audioBuffer.numberOfChannels;


// create webgpu buffers

waveGPUBuffer = new THREE.StorageInstancedBufferAttribute( waveBuffer, 1 );

const waveStorageNode = storage( waveGPUBuffer, 'float', waveBuffer.length );
waveArray = instancedArray( waveBuffer );

// read-only buffer

const waveNode = storageObject( new THREE.StorageInstancedBufferAttribute( waveBuffer, 1 ), 'float', waveBuffer.length ).toReadOnly();
const waveNode = instancedArray( waveBuffer );

// The Pixel Buffer Object (PBO) is required to get the GPU computed data to the CPU in the WebGL2 fallback.
// As used in `renderer.getArrayBufferAsync( waveArray.value )`.

waveNode.setPBO( true );

// params

Expand Down Expand Up @@ -137,7 +139,7 @@

// store

const waveStorageElementNode = waveStorageNode.element( instanceIndex );
const waveStorageElementNode = waveArray.element( instanceIndex );

waveStorageElementNode.assign( wave );

Expand Down Expand Up @@ -181,7 +183,7 @@

// renderer

renderer = new THREE.WebGPURenderer( { antialias: true } );
renderer = new THREE.WebGPURenderer( { antialias: true, forceWebGL: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( render );
Expand Down
34 changes: 11 additions & 23 deletions examples/webgpu_compute_birds.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<script type="module">

import * as THREE from 'three';
import { uniform, varying, vec4, add, sub, max, dot, sin, mat3, uint, negate, cameraProjectionMatrix, cameraViewMatrix, positionLocal, modelWorldMatrix, sqrt, attribute, property, float, storage, storageObject, Fn, If, cos, Loop, Continue, normalize, instanceIndex, length } from 'three/tsl';
import { uniform, varying, vec4, add, sub, max, dot, sin, mat3, uint, negate, array, instancedArray, cameraProjectionMatrix, cameraViewMatrix, positionLocal, modelWorldMatrix, sqrt, attribute, property, float, Fn, If, cos, Loop, Continue, normalize, instanceIndex, length } from 'three/tsl';
Fixed Show fixed Hide fixed

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

Expand Down Expand Up @@ -167,7 +167,7 @@

//

renderer = new THREE.WebGPURenderer( { antialiasing: true } );
renderer = new THREE.WebGPURenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
Expand Down Expand Up @@ -205,26 +205,12 @@

}

// Create storage buffer attributes.

const positionBufferAttribute = new THREE.StorageBufferAttribute( positionArray, 3 );
const velocityBufferAttribute = new THREE.StorageBufferAttribute( velocityArray, 3 );
const phaseBufferAttribute = new THREE.StorageBufferAttribute( phaseArray, 1 );

// Labels applied to storage nodes and uniform nodes are reflected within the shader output,
// and are useful for debugging purposes.

// Access storage buffer attribute data from within shaders with a StorageNode.

const positionStorage = storage( positionBufferAttribute, 'vec3', positionBufferAttribute.count ).label( 'positionStorage' );
const velocityStorage = storage( velocityBufferAttribute, 'vec3', velocityBufferAttribute.count ).label( 'velocityStorage' );
const phaseStorage = storage( phaseBufferAttribute, 'float', phaseBufferAttribute.count ).label( 'phaseStorage' );

// Create read-only storage nodes. Storage nodes can only be accessed outside of compute shaders in a read-only state.

const positionRead = storageObject( positionBufferAttribute, 'vec3', positionBufferAttribute.count ).toReadOnly();
const velocityRead = storageObject( velocityBufferAttribute, 'vec3', velocityBufferAttribute.count ).toReadOnly();
const phaseRead = storageObject( phaseBufferAttribute, 'float', phaseBufferAttribute.count ).toReadOnly();
const positionStorage = array( positionArray, 'vec3' ).label( 'positionStorage' );
const velocityStorage = array( velocityArray, 'vec3' ).label( 'velocityStorage' );
const phaseStorage = array( phaseArray, 'float' ).label( 'phaseStorage' );

// Define Uniforms. Uniforms only need to be defined once rather than per shader.

Expand Down Expand Up @@ -252,8 +238,8 @@
const birdVertex = attribute( 'birdVertex' );

const position = positionLocal.toVar();
const newPhase = phaseRead.element( reference ).toVar();
const newVelocity = normalize( velocityRead.element( reference ) ).toVar();
const newPhase = phaseStorage.element( reference ).toVar();
const newVelocity = normalize( velocityStorage.element( reference ) ).toVar();

If( birdVertex.equal( 4 ).or( birdVertex.equal( 7 ) ), () => {

Expand Down Expand Up @@ -289,17 +275,19 @@
);

const finalVert = maty.mul( matz ).mul( newPosition );
finalVert.addAssign( positionRead.element( reference ) );
finalVert.addAssign( positionStorage.element( reference ) );

return cameraProjectionMatrix.mul( cameraViewMatrix ).mul( finalVert );

} );

birdMaterial.vertexNode = birdVertexTSL();
birdMaterial.side = THREE.DoubleSide;

const birdMesh = new THREE.Mesh( birdGeometry, birdMaterial );
birdMesh.rotation.y = Math.PI / 2;
birdMesh.matrixAutoUpdate = false;
birdMesh.frustumCulled = false;
birdMesh.updateMatrix();

// Define GPU Compute shaders.
Expand Down Expand Up @@ -417,7 +405,7 @@
velocity.assign( normalize( velocity ).mul( limit ) );

} );

} )().compute( BIRDS );

computePosition = Fn( () => {
Expand Down
2 changes: 1 addition & 1 deletion examples/webgpu_compute_geometry.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@

// attributes

const positionAttribute = storage( positionBaseAttribute, 'vec3', count ).toReadOnly();
const positionAttribute = storage( positionBaseAttribute, 'vec3', count );
const positionStorageAttribute = storage( positionStorageBufferAttribute, 'vec3', count );

const speedAttribute = storage( speedBufferAttribute, 'vec3', count );
Expand Down
12 changes: 5 additions & 7 deletions examples/webgpu_compute_particles.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<script type="module">

import * as THREE from 'three';
import { Fn, uniform, texture, instanceIndex, float, hash, vec3, storage, If } from 'three/tsl';
import { Fn, uniform, texture, instancedArray, instanceIndex, float, hash, vec3, storage, If } from 'three/tsl';
Fixed Show fixed Hide fixed

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import Stats from 'three/addons/libs/stats.module.js';
Expand Down Expand Up @@ -77,11 +77,9 @@

//

const createBuffer = () => storage( new THREE.StorageInstancedBufferAttribute( particleCount, 3 ), 'vec3', particleCount );

const positionBuffer = createBuffer();
const velocityBuffer = createBuffer();
const colorBuffer = createBuffer();
const positionBuffer = instancedArray( particleCount, 'vec3' );
const velocityBuffer = instancedArray( particleCount, 'vec3' );
const colorBuffer = instancedArray( particleCount, 'vec3' );

// compute

Expand Down Expand Up @@ -167,7 +165,7 @@

//

renderer = new THREE.WebGPURenderer( { antialias: true, trackTimestamp: true } );
renderer = new THREE.WebGPURenderer( { antialias: true, trackTimestamp: true, forceWebGL: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
Expand Down
12 changes: 5 additions & 7 deletions examples/webgpu_compute_particles_rain.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<script type="module">

import * as THREE from 'three';
import { Fn, texture, uv, uint, positionWorld, billboarding, time, hash, deltaTime, vec2, instanceIndex, positionGeometry, storage, If } from 'three/tsl';
import { Fn, texture, uv, uint, instancedArray, positionWorld, billboarding, time, hash, deltaTime, vec2, instanceIndex, positionGeometry, storage, If } from 'three/tsl';
Fixed Show fixed Hide fixed

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

Expand Down Expand Up @@ -94,12 +94,10 @@

//

const createBuffer = ( type = 'vec3' ) => storage( new THREE.StorageInstancedBufferAttribute( maxParticleCount, 3 ), type, maxParticleCount );

const positionBuffer = createBuffer();
const velocityBuffer = createBuffer();
const ripplePositionBuffer = createBuffer();
const rippleTimeBuffer = createBuffer();
const positionBuffer = instancedArray( maxParticleCount, 'vec3' );
const velocityBuffer = instancedArray( maxParticleCount, 'vec3' );
const ripplePositionBuffer = instancedArray( maxParticleCount, 'vec3' );
const rippleTimeBuffer = instancedArray( maxParticleCount, 'vec3' );

// compute

Expand Down
12 changes: 5 additions & 7 deletions examples/webgpu_compute_particles_snow.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<script type="module">

import * as THREE from 'three';
import { Fn, texture, vec3, pass, color, uint, screenUV, positionWorld, positionLocal, time, vec2, hash, instanceIndex, storage, If } from 'three/tsl';
import { Fn, texture, vec3, pass, color, uint, screenUV, instancedArray, positionWorld, positionLocal, time, vec2, hash, instanceIndex, storage, If } from 'three/tsl';
Fixed Show fixed Hide fixed
import { gaussianBlur } from 'three/addons/tsl/display/GaussianBlurNode.js';

import { TeapotGeometry } from 'three/addons/geometries/TeapotGeometry.js';
Expand Down Expand Up @@ -94,12 +94,10 @@

//

const createBuffer = ( type = 'vec3' ) => storage( new THREE.StorageInstancedBufferAttribute( maxParticleCount, type === 'vec4' ? 4 : 3 ), type, maxParticleCount );

const positionBuffer = createBuffer();
const scaleBuffer = createBuffer();
const staticPositionBuffer = createBuffer();
const dataBuffer = createBuffer( 'vec4' );
const positionBuffer = instancedArray( maxParticleCount, 'vec3' );
const scaleBuffer = instancedArray( maxParticleCount, 'vec3' );
const staticPositionBuffer = instancedArray( maxParticleCount, 'vec3' );
const dataBuffer = instancedArray( maxParticleCount, 'vec4' );

// compute

Expand Down
33 changes: 12 additions & 21 deletions examples/webgpu_compute_points.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<script type="module">

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

import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

Expand All @@ -45,23 +45,17 @@

// initialize particles

const particleNum = 300000;
const particleSize = 2; // vec2
const particlesCount = 300000;

// create buffers

const particleBuffer = new THREE.StorageInstancedBufferAttribute( particleNum, particleSize );
const velocityBuffer = new THREE.StorageInstancedBufferAttribute( particleNum, particleSize );

const particleBufferNode = storage( particleBuffer, 'vec2', particleNum );
const velocityBufferNode = storage( velocityBuffer, 'vec2', particleNum );
const particleArray = instancedArray( particlesCount, 'vec2' );
const velocityArray = instancedArray( particlesCount, 'vec2' );

// create function

const computeShaderFn = Fn( () => {

const particle = particleBufferNode.element( instanceIndex );
const velocity = velocityBufferNode.element( instanceIndex );
const particle = particleArray.element( instanceIndex );
const velocity = velocityArray.element( instanceIndex );

const pointer = uniform( pointerVector );
const limit = uniform( scaleVector );
Expand All @@ -82,7 +76,7 @@

// compute

computeNode = computeShaderFn().compute( particleNum );
computeNode = computeShaderFn().compute( particlesCount );
computeNode.onInit( ( { renderer } ) => {

const precomputeShaderNode = Fn( () => {
Expand All @@ -95,31 +89,28 @@
const velX = randomAngle.sin().mul( randomSpeed );
const velY = randomAngle.cos().mul( randomSpeed );

const velocity = velocityBufferNode.element( instanceIndex );
const velocity = velocityArray.element( instanceIndex );

velocity.xy = vec2( velX, velY );

} );

renderer.computeAsync( precomputeShaderNode().compute( particleNum ) );
renderer.computeAsync( precomputeShaderNode().compute( particlesCount ) );

} );

// use a compute shader to animate the point cloud's vertex data.

const particleNode = attribute( 'particle', 'vec2' );

const pointsGeometry = new THREE.BufferGeometry();
pointsGeometry.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( 3 ), 3 ) ); // single vertex ( not triangle )
pointsGeometry.setAttribute( 'particle', particleBuffer ); // dummy the position points as instances
pointsGeometry.drawRange.count = 1; // force render points as instances ( not triangle )

const pointsMaterial = new THREE.PointsNodeMaterial();
pointsMaterial.colorNode = particleNode.add( color( 0xFFFFFF ) );
pointsMaterial.positionNode = particleNode;
pointsMaterial.colorNode = particleArray.element( instanceIndex ).add( color( 0xFFFFFF ) );
pointsMaterial.positionNode = particleArray.element( instanceIndex );

const mesh = new THREE.Points( pointsGeometry, pointsMaterial );
mesh.count = particleNum;
mesh.count = particlesCount;
scene.add( mesh );

renderer = new THREE.WebGPURenderer( { antialias: true } );
Expand Down
10 changes: 5 additions & 5 deletions examples/webgpu_compute_texture_pingpong.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<script type="module">

import * as THREE from 'three';
import { storageTexture, wgslFn, code, instanceIndex, uniform } from 'three/tsl';
import { storageTexture, wgslFn, code, instanceIndex, uniform, NodeAccess } from 'three/tsl';

import WebGPU from 'three/addons/capabilities/WebGPU.js';

Expand Down Expand Up @@ -72,10 +72,10 @@

const wgslFormat = hdr ? 'rgba16float' : 'rgba8unorm';

const readPing = storageTexture( pingTexture ).setAccess( 'read-only' );
const writePing = storageTexture( pingTexture ).setAccess( 'write-only' );
const readPong = storageTexture( pongTexture ).setAccess( 'read-only' );
const writePong = storageTexture( pongTexture ).setAccess( 'write-only' );
const readPing = storageTexture( pingTexture ).setAccess( NodeAccess.READ_ONLY );
const writePing = storageTexture( pingTexture ).setAccess( NodeAccess.WRITE_ONLY );
const readPong = storageTexture( pongTexture ).setAccess( NodeAccess.READ_ONLY );
const writePong = storageTexture( pongTexture ).setAccess( NodeAccess.WRITE_ONLY );

// compute init

Expand Down
Loading
Loading