Skip to content

Commit

Permalink
add webgpu_compute_texture_pingpong example
Browse files Browse the repository at this point in the history
  • Loading branch information
sunag committed Sep 15, 2023
1 parent 178f7b7 commit 922025b
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@
"webgpu_compute",
"webgpu_compute_particles",
"webgpu_compute_texture",
"webgpu_compute_texture_pingpong",
"webgpu_cubemap_adjustments",
"webgpu_cubemap_dynamic",
"webgpu_cubemap_mix",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
178 changes: 178 additions & 0 deletions examples/webgpu_compute_texture_pingpong.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<html lang="en">
<head>
<title>three.js - WebGPU - Compute Ping/Pong Texture</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>

<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> WebGPU - Compute Ping/Pong Texture
<br>Texture generated using GPU Compute.
</div>

<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>

<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/",
"three/nodes": "./jsm/nodes/Nodes.js"
}
}
</script>

<script type="module">

import * as THREE from 'three';
import { texture, textureStore, wgslFn, code, instanceIndex } from 'three/nodes';

import WebGPU from 'three/addons/capabilities/WebGPU.js';
import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
import StorageTexture from 'three/addons/renderers/common/StorageTexture.js';

let camera, scene, renderer;
let computeToPing, computeToPong;
let pingTexture, pongTexture;
let material;
let phase = true;

init();
render();

function init() {

if ( WebGPU.isAvailable() === false ) {

document.body.appendChild( WebGPU.getErrorMessage() );

throw new Error( 'No WebGPU support' );

}

const aspect = window.innerWidth / window.innerHeight;
camera = new THREE.OrthographicCamera( - aspect, aspect, 1, - 1, 0, 2 );
camera.position.z = 1;

scene = new THREE.Scene();

// texture

const width = 512, height = 512;

pingTexture = new StorageTexture( width, height );
pongTexture = new StorageTexture( width, height );

// compute init

const rand2 = code( `
fn rand2( n: vec2f ) -> f32 {
return fract( sin( dot( n, vec2f( 12.9898, 4.1414 ) ) ) * 43758.5453 );
}
` );

const computeInitWGSL = wgslFn( `
fn computeInitWGSL( writeTex: texture_storage_2d<rgba8unorm, write>, index: u32 ) -> void {
let posX = index % ${ width };
let posY = index / ${ width };
let indexUV = vec2u( posX, posY );
let uv = getUV( posX, posY );
textureStore( writeTex, indexUV, vec4f( vec3f( rand2( uv ) ), 1 ) );
}
fn getUV( posX: u32, posY: u32 ) -> vec2f {
let uv = vec2f( f32( posX ) / ${ width }.0, f32( posY ) / ${ height }.0 );
return uv;
}
`, [ rand2 ] );

const computeInitNode = computeInitWGSL( { writeTex: textureStore( pingTexture ), index: instanceIndex } ).compute( width * height );

// compute loop

const computePingPongWGSL = wgslFn( `
fn computePingPongWGSL( readTex: texture_2d<f32>, writeTex: texture_storage_2d<rgba8unorm, write>, index: u32 ) -> void {
let posX = index % ${ width };
let posY = index / ${ width };
let indexUV = vec2u( posX, posY );
let color = vec3f( rand2( textureLoad( readTex, indexUV, 0 ).xy ) );
textureStore( writeTex, indexUV, vec4f( color, 1 ) );
}
`, [ rand2 ] );

computeToPong = computePingPongWGSL( { readTex: texture( pingTexture ), writeTex: textureStore( pongTexture ), index: instanceIndex } ).compute( width * height );
computeToPing = computePingPongWGSL( { readTex: texture( pongTexture ), writeTex: textureStore( pingTexture ), index: instanceIndex } ).compute( width * height );

//

material = new THREE.MeshBasicMaterial( { color: 0xffffff, map: pongTexture } );

const plane = new THREE.Mesh( new THREE.PlaneGeometry( 1, 1 ), material );
scene.add( plane );

renderer = new WebGPURenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( render );
document.body.appendChild( renderer.domElement );

window.addEventListener( 'resize', onWindowResize );

// compute init

renderer.compute( computeInitNode );

}

function onWindowResize() {

renderer.setSize( window.innerWidth, window.innerHeight );

const aspect = window.innerWidth / window.innerHeight;

const frustumHeight = camera.top - camera.bottom;

camera.left = - frustumHeight * aspect / 2;
camera.right = frustumHeight * aspect / 2;

camera.updateProjectionMatrix();

render();

}

function render() {

// compute step

renderer.compute( phase ? computeToPong : computeToPing );

material.map = phase ? pongTexture : pingTexture;

phase = ! phase;

// render step

// update material texture node

renderer.render( scene, camera );

}

</script>
</body>
</html>
1 change: 1 addition & 0 deletions test/e2e/puppeteer.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ const exceptionList = [
'webgpu_compute',
'webgpu_compute_particles',
'webgpu_compute_texture',
'webgpu_compute_texture_pingpong',
'webgpu_cubemap_dynamic',
'webgpu_depth_texture',
'webgpu_instance_mesh',
Expand Down

0 comments on commit 922025b

Please sign in to comment.