Skip to content

Commit

Permalink
Copy to async implementation from mrdoob#24466
Browse files Browse the repository at this point in the history
  • Loading branch information
gkjohnson committed May 5, 2024
1 parent 3f53946 commit 304f612
Show file tree
Hide file tree
Showing 4 changed files with 475 additions and 15 deletions.
286 changes: 286 additions & 0 deletions examples/gi_test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - simple global illumination</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> - simple global illumination (<a href="http://www.iquilezles.org/www/articles/simplegi/simplegi.htm">article</a>)
</div>

<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>

<script type="importmap">
{
"imports": {
"three": "../build/three.module.js"
}
}
</script>

<script type="module">

import * as THREE from 'three';

import { OrbitControls } from './jsm/controls/OrbitControls.js';

class GIMesh extends THREE.Mesh {

copy( source ) {

super.copy( source );

this.geometry = source.geometry.clone();

return this;

}

}

//

const SimpleGI = function ( renderer, scene ) {

const SIZE = 48, SIZE2 = SIZE * SIZE, BLOCKSIZE = SIZE2 * 4;

const camera = new THREE.PerspectiveCamera( 90, 1, 0.01, 100 );

scene.updateMatrixWorld( true );

let clone = scene.clone();
clone.autoUpdate = false;

const rt = new THREE.WebGLRenderTarget( SIZE, SIZE );

const normalMatrix = new THREE.Matrix3();

const position = new THREE.Vector3();
const normal = new THREE.Vector3();

const color = new THREE.Color();
const tmp = new THREE.Color();

const buffer = new Uint8Array( BLOCKSIZE * SIZE );

const object = torus = scene.children[ 0 ]; // torusKnot
const geometry = object.geometry;

const attributes = geometry.attributes;
const positions = attributes.position.array;

if ( attributes.color === undefined ) {

const colors = new Float32Array( positions.length );
geometry.setAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).setUsage( THREE.DynamicDrawUsage ) );

}

const normals = attributes.normal.array;
const colors = attributes.color.array;

let free = [];
let waiting = [];
let bounces = 0;
let currentVertex = 0;
const totalVertex = positions.length / 3;

function compute() {

if ( bounces === 5 ) return;

if ( waiting.length > 0 ) {

const readback = waiting.shift();
renderer.readbackPixels( readback.glBuffer, buffer );

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

color.setScalar( 0 );

for ( let k = BLOCKSIZE * i, kl = ( BLOCKSIZE * i ) + BLOCKSIZE; k < kl; k += 4 ) {

tmp.fromArray( buffer, k )
color.add( tmp );

}

color.multiplyScalar( 1 / ( SIZE2 * 255 ) );
color.toArray( colors, 3 * ( readback.start + i ) );

}

attributes.color.needsUpdate = true;

free.push( readback.glBuffer );

} else {

const state = {
start: currentVertex,
length: Math.min( SIZE, totalVertex - currentVertex ),
glBuffer: ( free.length > 0 ) ? free.pop() : renderer.createReadbackBuffer( BLOCKSIZE * SIZE )
}


renderer.setRenderTarget( rt );

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

const vertexIndex = state.start + i;
position.fromArray( positions, vertexIndex * 3 );
position.applyMatrix4( object.matrixWorld );

normal.fromArray( normals, vertexIndex * 3 );
normal.applyMatrix3( normalMatrix.getNormalMatrix( object.matrixWorld ) ).normalize();

camera.position.copy( position );
camera.lookAt( position.add( normal ) );

renderer.render( clone, camera );

const options = {
interval: 4,
readback: false,
glBuffer: state.glBuffer,
sync: ( i == state.length - 1 ),
byteOffset: SIZE2 * 4 * i,
};

renderer.readRenderTargetPixelsAsync( rt, 0, 0, SIZE, SIZE, buffer, undefined, options )
.then( ( result ) => {
if ( result ) waiting.push( state );
} );

};


currentVertex += state.length;

if ( currentVertex >= totalVertex ) {

clone = scene.clone();
clone.autoUpdate = false;

bounces ++;
currentVertex = 0;

}

}

setTimeout( compute, debouncer )

}

setTimeout( compute )

};

//

const debouncer = 4 // ms
let camera, controls, scene, renderer, torus;

init();
animate();

function init() {

camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 100 );
camera.position.z = 5;
camera.position.y = 0.2;

scene = new THREE.Scene();
scene.background = new THREE.Color( '#030100' );

// torus knot

const torusGeometry = new THREE.TorusKnotGeometry( 0.75, 0.3, 128, 32, 1 );
const material = new THREE.MeshBasicMaterial( { vertexColors: true } );

const torusKnot = new GIMesh( torusGeometry, material );
scene.add( torusKnot );

// room

const materials = [];

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

materials.push( new THREE.MeshBasicMaterial( { color: 0x0, side: THREE.BackSide } ) );

}

let p0, p1;

// (r-l)
p0 = Math.random(), p1 = Math.random();
materials[0].color.setHSL( p0, p1, p0 * 0.4 + 0.3 );
materials[1].color.setHSL( p1, p0, p1 * 0.4 + 0.3 );

// (u-d)
p0 = Math.random(), p1 = Math.random();
materials[2].color.setHSL( p0, p1, p0 * 0.80 );
materials[3].color.setHSL( p1, p0, p1 * 0.05 );

// (f-b)
p0 = Math.random(), p1 = Math.random();
materials[4].color.setHSL( p0, p1, p0 * 0.40 );
materials[5].color.setHSL( p1, p0, p1 * 0.20 )


const boxGeometry = new THREE.BoxGeometry( 3, 3, 3 );

const box = new THREE.Mesh( boxGeometry, materials );
scene.add( box );

//

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

new SimpleGI( renderer, scene );

controls = new OrbitControls( camera, renderer.domElement );
controls.autoRotate = true;
controls.autoRotateSpeed = -4.5;
controls.minDistance = 1;
controls.maxDistance = 10;

window.addEventListener( 'resize', onWindowResize );

}

function onWindowResize() {

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

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

}

function animate() {

controls.update();

requestAnimationFrame( animate );

renderer.setRenderTarget( null );
renderer.render( scene, camera );

}

</script>

</body>
</html>
28 changes: 16 additions & 12 deletions examples/webgl_interactive_cubes_gpu.html
Original file line number Diff line number Diff line change
Expand Up @@ -261,23 +261,27 @@
const pixelBuffer = new Int32Array( 4 );

// read the pixel
renderer.readRenderTargetPixels( pickingTexture, 0, 0, 1, 1, pixelBuffer );
renderer
.readRenderTargetPixelsAsync( pickingTexture, 0, 0, 1, 1, pixelBuffer )
.then( () => {

const id = pixelBuffer[ 0 ];
if ( id !== - 1 ) {
const id = pixelBuffer[ 0 ];
if ( id !== - 1 ) {

// move our highlightBox so that it surrounds the picked object
const data = pickingData[ id ];
highlightBox.position.copy( data.position );
highlightBox.rotation.copy( data.rotation );
highlightBox.scale.copy( data.scale ).add( offset );
highlightBox.visible = true;
// move our highlightBox so that it surrounds the picked object
const data = pickingData[ id ];
highlightBox.position.copy( data.position );
highlightBox.rotation.copy( data.rotation );
highlightBox.scale.copy( data.scale ).add( offset );
highlightBox.visible = true;

} else {
} else {

highlightBox.visible = false;
highlightBox.visible = false;

}
}

} );

}

Expand Down
Loading

0 comments on commit 304f612

Please sign in to comment.