forked from mrdoob/three.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Copy to async implementation from mrdoob#24466
- Loading branch information
Showing
4 changed files
with
475 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.