-
-
Notifications
You must be signed in to change notification settings - Fork 35.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21350 from sunag/nodematerial-shared-uniforms
WebGPU: Fix material compile per object and new instance uniform example
- Loading branch information
Showing
8 changed files
with
214 additions
and
21 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
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
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
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
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
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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,198 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>three.js webgpu - instance uniform</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 materials | ||
</div> | ||
|
||
<script type="module"> | ||
|
||
import * as THREE from '../build/three.module.js'; | ||
|
||
import WebGPURenderer from './jsm/renderers/webgpu/WebGPURenderer.js'; | ||
import WebGPU from './jsm/renderers/webgpu/WebGPU.js'; | ||
|
||
import { TeapotGeometry } from './jsm/geometries/TeapotGeometry.js'; | ||
|
||
import Node from './jsm/renderers/nodes/core/Node.js'; | ||
import AttributeNode from './jsm/renderers/nodes/core/AttributeNode.js'; | ||
import { NodeUpdateType } from './jsm/renderers/nodes/core/constants.js'; | ||
import ColorNode from './jsm/renderers/nodes/inputs/ColorNode.js'; | ||
|
||
import Stats from './jsm/libs/stats.module.js'; | ||
|
||
class InstanceUniformNode extends Node { | ||
|
||
constructor() { | ||
|
||
super( 'vec3' ); | ||
|
||
this.updateType = NodeUpdateType.Object; | ||
|
||
this.inputNode = new ColorNode(); | ||
|
||
} | ||
|
||
update( frame ) { | ||
|
||
const mesh = frame.object; | ||
|
||
this.inputNode.value.copy( mesh.color ); | ||
|
||
} | ||
|
||
generate( builder, output ) { | ||
|
||
return this.inputNode.build( builder, output ); | ||
|
||
} | ||
|
||
} | ||
|
||
let stats; | ||
|
||
let camera, scene, renderer; | ||
|
||
const objects = []; | ||
|
||
init().then( animate ).catch( error ); | ||
|
||
async function init() { | ||
|
||
if ( WebGPU.isAvailable() === false ) { | ||
|
||
document.body.appendChild( WebGPU.getErrorMessage() ); | ||
|
||
throw 'No WebGPU support'; | ||
|
||
} | ||
|
||
const container = document.createElement( 'div' ); | ||
document.body.appendChild( container ); | ||
|
||
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 ); | ||
camera.position.set( 0, 200, 800 ); | ||
|
||
scene = new THREE.Scene(); | ||
|
||
// Grid | ||
|
||
const helper = new THREE.GridHelper( 1000, 40, 0x303030, 0x303030 ); | ||
helper.material.colorNode = new AttributeNode( 'color', 'vec3' ); | ||
helper.position.y = - 75; | ||
scene.add( helper ); | ||
|
||
// Materials | ||
|
||
const instanceUniform = new InstanceUniformNode(); | ||
|
||
const material = new THREE.MeshBasicMaterial(); | ||
material.colorNode = instanceUniform; | ||
|
||
// Geometry | ||
|
||
const geometry = new TeapotGeometry( 50, 18 ); | ||
|
||
for ( let i = 0, l = 12; i < l; i ++ ) { | ||
|
||
addMesh( geometry, material ); | ||
|
||
} | ||
|
||
// | ||
|
||
renderer = new WebGPURenderer(); | ||
renderer.setPixelRatio( window.devicePixelRatio ); | ||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
container.appendChild( renderer.domElement ); | ||
|
||
// | ||
|
||
stats = new Stats(); | ||
container.appendChild( stats.dom ); | ||
|
||
// | ||
|
||
window.addEventListener( 'resize', onWindowResize ); | ||
|
||
return renderer.init(); | ||
|
||
} | ||
|
||
function addMesh( geometry, material ) { | ||
|
||
const mesh = new THREE.Mesh( geometry, material ); | ||
|
||
mesh.color = new THREE.Color( Math.random() * 0xffffff ); | ||
|
||
mesh.position.x = ( objects.length % 4 ) * 200 - 400; | ||
mesh.position.z = Math.floor( objects.length / 4 ) * 200 - 200; | ||
|
||
mesh.rotation.x = Math.random() * 200 - 100; | ||
mesh.rotation.y = Math.random() * 200 - 100; | ||
mesh.rotation.z = Math.random() * 200 - 100; | ||
|
||
objects.push( mesh ); | ||
|
||
scene.add( mesh ); | ||
|
||
} | ||
|
||
function onWindowResize() { | ||
|
||
camera.aspect = window.innerWidth / window.innerHeight; | ||
camera.updateProjectionMatrix(); | ||
|
||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
|
||
} | ||
|
||
// | ||
|
||
function animate() { | ||
|
||
requestAnimationFrame( animate ); | ||
|
||
render(); | ||
stats.update(); | ||
|
||
} | ||
|
||
function render() { | ||
|
||
const timer = 0.0001 * Date.now(); | ||
|
||
camera.position.x = Math.cos( timer ) * 1000; | ||
camera.position.z = Math.sin( timer ) * 1000; | ||
|
||
camera.lookAt( scene.position ); | ||
|
||
for ( let i = 0, l = objects.length; i < l; i ++ ) { | ||
|
||
const object = objects[ i ]; | ||
|
||
object.rotation.x += 0.01; | ||
object.rotation.y += 0.005; | ||
|
||
} | ||
|
||
renderer.render( scene, camera ); | ||
|
||
} | ||
|
||
function error( error ) { | ||
|
||
console.error( error ); | ||
|
||
} | ||
|
||
</script> | ||
|
||
</body> | ||
</html> |