Initial commit
This commit is contained in:
219
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/CSS2DRenderer.js
generated
vendored
Normal file
219
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/CSS2DRenderer.js
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
import {
|
||||
Matrix4,
|
||||
Object3D,
|
||||
Vector3
|
||||
} from 'three';
|
||||
|
||||
class CSS2DObject extends Object3D {
|
||||
|
||||
constructor( element = document.createElement( 'div' ) ) {
|
||||
|
||||
super();
|
||||
|
||||
this.element = element;
|
||||
|
||||
this.element.style.position = 'absolute';
|
||||
this.element.style.userSelect = 'none';
|
||||
|
||||
this.element.setAttribute( 'draggable', false );
|
||||
|
||||
this.addEventListener( 'removed', function () {
|
||||
|
||||
this.traverse( function ( object ) {
|
||||
|
||||
if ( object.element instanceof Element && object.element.parentNode !== null ) {
|
||||
|
||||
object.element.parentNode.removeChild( object.element );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
copy( source, recursive ) {
|
||||
|
||||
super.copy( source, recursive );
|
||||
|
||||
this.element = source.element.cloneNode( true );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CSS2DObject.prototype.isCSS2DObject = true;
|
||||
|
||||
//
|
||||
|
||||
const _vector = new Vector3();
|
||||
const _viewMatrix = new Matrix4();
|
||||
const _viewProjectionMatrix = new Matrix4();
|
||||
const _a = new Vector3();
|
||||
const _b = new Vector3();
|
||||
|
||||
class CSS2DRenderer {
|
||||
|
||||
constructor( parameters = {} ) {
|
||||
|
||||
const _this = this;
|
||||
|
||||
let _width, _height;
|
||||
let _widthHalf, _heightHalf;
|
||||
|
||||
const cache = {
|
||||
objects: new WeakMap()
|
||||
};
|
||||
|
||||
const domElement = parameters.element !== undefined ? parameters.element : document.createElement( 'div' );
|
||||
|
||||
domElement.style.overflow = 'hidden';
|
||||
|
||||
this.domElement = domElement;
|
||||
|
||||
this.getSize = function () {
|
||||
|
||||
return {
|
||||
width: _width,
|
||||
height: _height
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
this.render = function ( scene, camera ) {
|
||||
|
||||
if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
|
||||
if ( camera.parent === null ) camera.updateMatrixWorld();
|
||||
|
||||
_viewMatrix.copy( camera.matrixWorldInverse );
|
||||
_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
|
||||
|
||||
renderObject( scene, scene, camera );
|
||||
zOrder( scene );
|
||||
|
||||
};
|
||||
|
||||
this.setSize = function ( width, height ) {
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
_widthHalf = _width / 2;
|
||||
_heightHalf = _height / 2;
|
||||
|
||||
domElement.style.width = width + 'px';
|
||||
domElement.style.height = height + 'px';
|
||||
|
||||
};
|
||||
|
||||
function renderObject( object, scene, camera ) {
|
||||
|
||||
if ( object.isCSS2DObject ) {
|
||||
|
||||
_vector.setFromMatrixPosition( object.matrixWorld );
|
||||
_vector.applyMatrix4( _viewProjectionMatrix );
|
||||
|
||||
const visible = ( object.visible === true ) && ( _vector.z >= - 1 && _vector.z <= 1 ) && ( object.layers.test( camera.layers ) === true );
|
||||
object.element.style.display = ( visible === true ) ? '' : 'none';
|
||||
|
||||
if ( visible === true ) {
|
||||
|
||||
object.onBeforeRender( _this, scene, camera );
|
||||
|
||||
const element = object.element;
|
||||
|
||||
if ( /apple/i.test( navigator.vendor ) ) {
|
||||
|
||||
// https://github.com/mrdoob/three.js/issues/21415
|
||||
element.style.transform = 'translate(-50%,-50%) translate(' + Math.round( _vector.x * _widthHalf + _widthHalf ) + 'px,' + Math.round( - _vector.y * _heightHalf + _heightHalf ) + 'px)';
|
||||
|
||||
} else {
|
||||
|
||||
element.style.transform = 'translate(-50%,-50%) translate(' + ( _vector.x * _widthHalf + _widthHalf ) + 'px,' + ( - _vector.y * _heightHalf + _heightHalf ) + 'px)';
|
||||
|
||||
}
|
||||
|
||||
if ( element.parentNode !== domElement ) {
|
||||
|
||||
domElement.appendChild( element );
|
||||
|
||||
}
|
||||
|
||||
object.onAfterRender( _this, scene, camera );
|
||||
|
||||
}
|
||||
|
||||
const objectData = {
|
||||
distanceToCameraSquared: getDistanceToSquared( camera, object )
|
||||
};
|
||||
|
||||
cache.objects.set( object, objectData );
|
||||
|
||||
}
|
||||
|
||||
for ( let i = 0, l = object.children.length; i < l; i ++ ) {
|
||||
|
||||
renderObject( object.children[ i ], scene, camera );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getDistanceToSquared( object1, object2 ) {
|
||||
|
||||
_a.setFromMatrixPosition( object1.matrixWorld );
|
||||
_b.setFromMatrixPosition( object2.matrixWorld );
|
||||
|
||||
return _a.distanceToSquared( _b );
|
||||
|
||||
}
|
||||
|
||||
function filterAndFlatten( scene ) {
|
||||
|
||||
const result = [];
|
||||
|
||||
scene.traverse( function ( object ) {
|
||||
|
||||
if ( object.isCSS2DObject ) result.push( object );
|
||||
|
||||
} );
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
function zOrder( scene ) {
|
||||
|
||||
const sorted = filterAndFlatten( scene ).sort( function ( a, b ) {
|
||||
|
||||
if ( a.renderOrder !== b.renderOrder ) {
|
||||
|
||||
return b.renderOrder - a.renderOrder;
|
||||
|
||||
}
|
||||
|
||||
const distanceA = cache.objects.get( a ).distanceToCameraSquared;
|
||||
const distanceB = cache.objects.get( b ).distanceToCameraSquared;
|
||||
|
||||
return distanceA - distanceB;
|
||||
|
||||
} );
|
||||
|
||||
const zMax = sorted.length;
|
||||
|
||||
for ( let i = 0, l = sorted.length; i < l; i ++ ) {
|
||||
|
||||
sorted[ i ].element.style.zIndex = zMax - i;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { CSS2DObject, CSS2DRenderer };
|
||||
313
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/CSS3DRenderer.js
generated
vendored
Normal file
313
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/CSS3DRenderer.js
generated
vendored
Normal file
@@ -0,0 +1,313 @@
|
||||
import {
|
||||
Matrix4,
|
||||
Object3D,
|
||||
Quaternion,
|
||||
Vector3
|
||||
} from 'three';
|
||||
|
||||
/**
|
||||
* Based on http://www.emagix.net/academic/mscs-project/item/camera-sync-with-css3-and-webgl-threejs
|
||||
*/
|
||||
|
||||
const _position = new Vector3();
|
||||
const _quaternion = new Quaternion();
|
||||
const _scale = new Vector3();
|
||||
|
||||
class CSS3DObject extends Object3D {
|
||||
|
||||
constructor( element = document.createElement( 'div' ) ) {
|
||||
|
||||
super();
|
||||
|
||||
this.element = element;
|
||||
this.element.style.position = 'absolute';
|
||||
this.element.style.pointerEvents = 'auto';
|
||||
this.element.style.userSelect = 'none';
|
||||
|
||||
this.element.setAttribute( 'draggable', false );
|
||||
|
||||
this.addEventListener( 'removed', function () {
|
||||
|
||||
this.traverse( function ( object ) {
|
||||
|
||||
if ( object.element instanceof Element && object.element.parentNode !== null ) {
|
||||
|
||||
object.element.parentNode.removeChild( object.element );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
copy( source, recursive ) {
|
||||
|
||||
super.copy( source, recursive );
|
||||
|
||||
this.element = source.element.cloneNode( true );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CSS3DObject.prototype.isCSS3DObject = true;
|
||||
|
||||
class CSS3DSprite extends CSS3DObject {
|
||||
|
||||
constructor( element ) {
|
||||
|
||||
super( element );
|
||||
|
||||
this.rotation2D = 0;
|
||||
|
||||
}
|
||||
|
||||
copy( source, recursive ) {
|
||||
|
||||
super.copy( source, recursive );
|
||||
|
||||
this.rotation2D = source.rotation2D;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CSS3DSprite.prototype.isCSS3DSprite = true;
|
||||
|
||||
//
|
||||
|
||||
const _matrix = new Matrix4();
|
||||
const _matrix2 = new Matrix4();
|
||||
|
||||
class CSS3DRenderer {
|
||||
|
||||
constructor( parameters = {} ) {
|
||||
|
||||
const _this = this;
|
||||
|
||||
let _width, _height;
|
||||
let _widthHalf, _heightHalf;
|
||||
|
||||
const cache = {
|
||||
camera: { fov: 0, style: '' },
|
||||
objects: new WeakMap()
|
||||
};
|
||||
|
||||
const domElement = parameters.element !== undefined ? parameters.element : document.createElement( 'div' );
|
||||
|
||||
domElement.style.overflow = 'hidden';
|
||||
|
||||
this.domElement = domElement;
|
||||
|
||||
const cameraElement = document.createElement( 'div' );
|
||||
|
||||
cameraElement.style.transformStyle = 'preserve-3d';
|
||||
cameraElement.style.pointerEvents = 'none';
|
||||
|
||||
domElement.appendChild( cameraElement );
|
||||
|
||||
this.getSize = function () {
|
||||
|
||||
return {
|
||||
width: _width,
|
||||
height: _height
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
this.render = function ( scene, camera ) {
|
||||
|
||||
const fov = camera.projectionMatrix.elements[ 5 ] * _heightHalf;
|
||||
|
||||
if ( cache.camera.fov !== fov ) {
|
||||
|
||||
domElement.style.perspective = camera.isPerspectiveCamera ? fov + 'px' : '';
|
||||
cache.camera.fov = fov;
|
||||
|
||||
}
|
||||
|
||||
if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
|
||||
if ( camera.parent === null ) camera.updateMatrixWorld();
|
||||
|
||||
let tx, ty;
|
||||
|
||||
if ( camera.isOrthographicCamera ) {
|
||||
|
||||
tx = - ( camera.right + camera.left ) / 2;
|
||||
ty = ( camera.top + camera.bottom ) / 2;
|
||||
|
||||
}
|
||||
|
||||
const cameraCSSMatrix = camera.isOrthographicCamera ?
|
||||
'scale(' + fov + ')' + 'translate(' + epsilon( tx ) + 'px,' + epsilon( ty ) + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse ) :
|
||||
'translateZ(' + fov + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse );
|
||||
|
||||
const style = cameraCSSMatrix +
|
||||
'translate(' + _widthHalf + 'px,' + _heightHalf + 'px)';
|
||||
|
||||
if ( cache.camera.style !== style ) {
|
||||
|
||||
cameraElement.style.transform = style;
|
||||
|
||||
cache.camera.style = style;
|
||||
|
||||
}
|
||||
|
||||
renderObject( scene, scene, camera, cameraCSSMatrix );
|
||||
|
||||
};
|
||||
|
||||
this.setSize = function ( width, height ) {
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_widthHalf = _width / 2;
|
||||
_heightHalf = _height / 2;
|
||||
|
||||
domElement.style.width = width + 'px';
|
||||
domElement.style.height = height + 'px';
|
||||
|
||||
cameraElement.style.width = width + 'px';
|
||||
cameraElement.style.height = height + 'px';
|
||||
|
||||
};
|
||||
|
||||
function epsilon( value ) {
|
||||
|
||||
return Math.abs( value ) < 1e-10 ? 0 : value;
|
||||
|
||||
}
|
||||
|
||||
function getCameraCSSMatrix( matrix ) {
|
||||
|
||||
const elements = matrix.elements;
|
||||
|
||||
return 'matrix3d(' +
|
||||
epsilon( elements[ 0 ] ) + ',' +
|
||||
epsilon( - elements[ 1 ] ) + ',' +
|
||||
epsilon( elements[ 2 ] ) + ',' +
|
||||
epsilon( elements[ 3 ] ) + ',' +
|
||||
epsilon( elements[ 4 ] ) + ',' +
|
||||
epsilon( - elements[ 5 ] ) + ',' +
|
||||
epsilon( elements[ 6 ] ) + ',' +
|
||||
epsilon( elements[ 7 ] ) + ',' +
|
||||
epsilon( elements[ 8 ] ) + ',' +
|
||||
epsilon( - elements[ 9 ] ) + ',' +
|
||||
epsilon( elements[ 10 ] ) + ',' +
|
||||
epsilon( elements[ 11 ] ) + ',' +
|
||||
epsilon( elements[ 12 ] ) + ',' +
|
||||
epsilon( - elements[ 13 ] ) + ',' +
|
||||
epsilon( elements[ 14 ] ) + ',' +
|
||||
epsilon( elements[ 15 ] ) +
|
||||
')';
|
||||
|
||||
}
|
||||
|
||||
function getObjectCSSMatrix( matrix ) {
|
||||
|
||||
const elements = matrix.elements;
|
||||
const matrix3d = 'matrix3d(' +
|
||||
epsilon( elements[ 0 ] ) + ',' +
|
||||
epsilon( elements[ 1 ] ) + ',' +
|
||||
epsilon( elements[ 2 ] ) + ',' +
|
||||
epsilon( elements[ 3 ] ) + ',' +
|
||||
epsilon( - elements[ 4 ] ) + ',' +
|
||||
epsilon( - elements[ 5 ] ) + ',' +
|
||||
epsilon( - elements[ 6 ] ) + ',' +
|
||||
epsilon( - elements[ 7 ] ) + ',' +
|
||||
epsilon( elements[ 8 ] ) + ',' +
|
||||
epsilon( elements[ 9 ] ) + ',' +
|
||||
epsilon( elements[ 10 ] ) + ',' +
|
||||
epsilon( elements[ 11 ] ) + ',' +
|
||||
epsilon( elements[ 12 ] ) + ',' +
|
||||
epsilon( elements[ 13 ] ) + ',' +
|
||||
epsilon( elements[ 14 ] ) + ',' +
|
||||
epsilon( elements[ 15 ] ) +
|
||||
')';
|
||||
|
||||
return 'translate(-50%,-50%)' + matrix3d;
|
||||
|
||||
}
|
||||
|
||||
function renderObject( object, scene, camera, cameraCSSMatrix ) {
|
||||
|
||||
if ( object.isCSS3DObject ) {
|
||||
|
||||
const visible = ( object.visible === true ) && ( object.layers.test( camera.layers ) === true );
|
||||
object.element.style.display = ( visible === true ) ? '' : 'none';
|
||||
|
||||
if ( visible === true ) {
|
||||
|
||||
object.onBeforeRender( _this, scene, camera );
|
||||
|
||||
let style;
|
||||
|
||||
if ( object.isCSS3DSprite ) {
|
||||
|
||||
// http://swiftcoder.wordpress.com/2008/11/25/constructing-a-billboard-matrix/
|
||||
|
||||
_matrix.copy( camera.matrixWorldInverse );
|
||||
_matrix.transpose();
|
||||
|
||||
if ( object.rotation2D !== 0 ) _matrix.multiply( _matrix2.makeRotationZ( object.rotation2D ) );
|
||||
|
||||
object.matrixWorld.decompose( _position, _quaternion, _scale );
|
||||
_matrix.setPosition( _position );
|
||||
_matrix.scale( _scale );
|
||||
|
||||
_matrix.elements[ 3 ] = 0;
|
||||
_matrix.elements[ 7 ] = 0;
|
||||
_matrix.elements[ 11 ] = 0;
|
||||
_matrix.elements[ 15 ] = 1;
|
||||
|
||||
style = getObjectCSSMatrix( _matrix );
|
||||
|
||||
} else {
|
||||
|
||||
style = getObjectCSSMatrix( object.matrixWorld );
|
||||
|
||||
}
|
||||
|
||||
const element = object.element;
|
||||
const cachedObject = cache.objects.get( object );
|
||||
|
||||
if ( cachedObject === undefined || cachedObject.style !== style ) {
|
||||
|
||||
element.style.transform = style;
|
||||
|
||||
const objectData = { style: style };
|
||||
cache.objects.set( object, objectData );
|
||||
|
||||
}
|
||||
|
||||
if ( element.parentNode !== cameraElement ) {
|
||||
|
||||
cameraElement.appendChild( element );
|
||||
|
||||
}
|
||||
|
||||
object.onAfterRender( _this, scene, camera );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for ( let i = 0, l = object.children.length; i < l; i ++ ) {
|
||||
|
||||
renderObject( object.children[ i ], scene, camera, cameraCSSMatrix );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { CSS3DObject, CSS3DSprite, CSS3DRenderer };
|
||||
967
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/Projector.js
generated
vendored
Normal file
967
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/Projector.js
generated
vendored
Normal file
@@ -0,0 +1,967 @@
|
||||
import {
|
||||
Box3,
|
||||
Color,
|
||||
DoubleSide,
|
||||
Frustum,
|
||||
Matrix3,
|
||||
Matrix4,
|
||||
Vector2,
|
||||
Vector3,
|
||||
Vector4
|
||||
} from 'three';
|
||||
|
||||
class RenderableObject {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.id = 0;
|
||||
|
||||
this.object = null;
|
||||
this.z = 0;
|
||||
this.renderOrder = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
class RenderableFace {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.id = 0;
|
||||
|
||||
this.v1 = new RenderableVertex();
|
||||
this.v2 = new RenderableVertex();
|
||||
this.v3 = new RenderableVertex();
|
||||
|
||||
this.normalModel = new Vector3();
|
||||
|
||||
this.vertexNormalsModel = [ new Vector3(), new Vector3(), new Vector3() ];
|
||||
this.vertexNormalsLength = 0;
|
||||
|
||||
this.color = new Color();
|
||||
this.material = null;
|
||||
this.uvs = [ new Vector2(), new Vector2(), new Vector2() ];
|
||||
|
||||
this.z = 0;
|
||||
this.renderOrder = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
class RenderableVertex {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.position = new Vector3();
|
||||
this.positionWorld = new Vector3();
|
||||
this.positionScreen = new Vector4();
|
||||
|
||||
this.visible = true;
|
||||
|
||||
}
|
||||
|
||||
copy( vertex ) {
|
||||
|
||||
this.positionWorld.copy( vertex.positionWorld );
|
||||
this.positionScreen.copy( vertex.positionScreen );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
class RenderableLine {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.id = 0;
|
||||
|
||||
this.v1 = new RenderableVertex();
|
||||
this.v2 = new RenderableVertex();
|
||||
|
||||
this.vertexColors = [ new Color(), new Color() ];
|
||||
this.material = null;
|
||||
|
||||
this.z = 0;
|
||||
this.renderOrder = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
class RenderableSprite {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.id = 0;
|
||||
|
||||
this.object = null;
|
||||
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
|
||||
this.rotation = 0;
|
||||
this.scale = new Vector2();
|
||||
|
||||
this.material = null;
|
||||
this.renderOrder = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
class Projector {
|
||||
|
||||
constructor() {
|
||||
|
||||
let _object, _objectCount, _objectPoolLength = 0,
|
||||
_vertex, _vertexCount, _vertexPoolLength = 0,
|
||||
_face, _faceCount, _facePoolLength = 0,
|
||||
_line, _lineCount, _linePoolLength = 0,
|
||||
_sprite, _spriteCount, _spritePoolLength = 0,
|
||||
_modelMatrix;
|
||||
|
||||
const
|
||||
|
||||
_renderData = { objects: [], lights: [], elements: [] },
|
||||
|
||||
_vector3 = new Vector3(),
|
||||
_vector4 = new Vector4(),
|
||||
|
||||
_clipBox = new Box3( new Vector3( - 1, - 1, - 1 ), new Vector3( 1, 1, 1 ) ),
|
||||
_boundingBox = new Box3(),
|
||||
_points3 = new Array( 3 ),
|
||||
|
||||
_viewMatrix = new Matrix4(),
|
||||
_viewProjectionMatrix = new Matrix4(),
|
||||
|
||||
_modelViewProjectionMatrix = new Matrix4(),
|
||||
|
||||
_frustum = new Frustum(),
|
||||
|
||||
_objectPool = [], _vertexPool = [], _facePool = [], _linePool = [], _spritePool = [];
|
||||
|
||||
//
|
||||
|
||||
this.projectVector = function ( vector, camera ) {
|
||||
|
||||
console.warn( 'THREE.Projector: .projectVector() is now vector.project().' );
|
||||
vector.project( camera );
|
||||
|
||||
};
|
||||
|
||||
this.unprojectVector = function ( vector, camera ) {
|
||||
|
||||
console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );
|
||||
vector.unproject( camera );
|
||||
|
||||
};
|
||||
|
||||
this.pickingRay = function () {
|
||||
|
||||
console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
function RenderList() {
|
||||
|
||||
const normals = [];
|
||||
const colors = [];
|
||||
const uvs = [];
|
||||
|
||||
let object = null;
|
||||
|
||||
const normalMatrix = new Matrix3();
|
||||
|
||||
function setObject( value ) {
|
||||
|
||||
object = value;
|
||||
|
||||
normalMatrix.getNormalMatrix( object.matrixWorld );
|
||||
|
||||
normals.length = 0;
|
||||
colors.length = 0;
|
||||
uvs.length = 0;
|
||||
|
||||
}
|
||||
|
||||
function projectVertex( vertex ) {
|
||||
|
||||
const position = vertex.position;
|
||||
const positionWorld = vertex.positionWorld;
|
||||
const positionScreen = vertex.positionScreen;
|
||||
|
||||
positionWorld.copy( position ).applyMatrix4( _modelMatrix );
|
||||
positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix );
|
||||
|
||||
const invW = 1 / positionScreen.w;
|
||||
|
||||
positionScreen.x *= invW;
|
||||
positionScreen.y *= invW;
|
||||
positionScreen.z *= invW;
|
||||
|
||||
vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 &&
|
||||
positionScreen.y >= - 1 && positionScreen.y <= 1 &&
|
||||
positionScreen.z >= - 1 && positionScreen.z <= 1;
|
||||
|
||||
}
|
||||
|
||||
function pushVertex( x, y, z ) {
|
||||
|
||||
_vertex = getNextVertexInPool();
|
||||
_vertex.position.set( x, y, z );
|
||||
|
||||
projectVertex( _vertex );
|
||||
|
||||
}
|
||||
|
||||
function pushNormal( x, y, z ) {
|
||||
|
||||
normals.push( x, y, z );
|
||||
|
||||
}
|
||||
|
||||
function pushColor( r, g, b ) {
|
||||
|
||||
colors.push( r, g, b );
|
||||
|
||||
}
|
||||
|
||||
function pushUv( x, y ) {
|
||||
|
||||
uvs.push( x, y );
|
||||
|
||||
}
|
||||
|
||||
function checkTriangleVisibility( v1, v2, v3 ) {
|
||||
|
||||
if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true;
|
||||
|
||||
_points3[ 0 ] = v1.positionScreen;
|
||||
_points3[ 1 ] = v2.positionScreen;
|
||||
_points3[ 2 ] = v3.positionScreen;
|
||||
|
||||
return _clipBox.intersectsBox( _boundingBox.setFromPoints( _points3 ) );
|
||||
|
||||
}
|
||||
|
||||
function checkBackfaceCulling( v1, v2, v3 ) {
|
||||
|
||||
return ( ( v3.positionScreen.x - v1.positionScreen.x ) *
|
||||
( v2.positionScreen.y - v1.positionScreen.y ) -
|
||||
( v3.positionScreen.y - v1.positionScreen.y ) *
|
||||
( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;
|
||||
|
||||
}
|
||||
|
||||
function pushLine( a, b ) {
|
||||
|
||||
const v1 = _vertexPool[ a ];
|
||||
const v2 = _vertexPool[ b ];
|
||||
|
||||
// Clip
|
||||
|
||||
v1.positionScreen.copy( v1.position ).applyMatrix4( _modelViewProjectionMatrix );
|
||||
v2.positionScreen.copy( v2.position ).applyMatrix4( _modelViewProjectionMatrix );
|
||||
|
||||
if ( clipLine( v1.positionScreen, v2.positionScreen ) === true ) {
|
||||
|
||||
// Perform the perspective divide
|
||||
v1.positionScreen.multiplyScalar( 1 / v1.positionScreen.w );
|
||||
v2.positionScreen.multiplyScalar( 1 / v2.positionScreen.w );
|
||||
|
||||
_line = getNextLineInPool();
|
||||
_line.id = object.id;
|
||||
_line.v1.copy( v1 );
|
||||
_line.v2.copy( v2 );
|
||||
_line.z = Math.max( v1.positionScreen.z, v2.positionScreen.z );
|
||||
_line.renderOrder = object.renderOrder;
|
||||
|
||||
_line.material = object.material;
|
||||
|
||||
if ( object.material.vertexColors ) {
|
||||
|
||||
_line.vertexColors[ 0 ].fromArray( colors, a * 3 );
|
||||
_line.vertexColors[ 1 ].fromArray( colors, b * 3 );
|
||||
|
||||
}
|
||||
|
||||
_renderData.elements.push( _line );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function pushTriangle( a, b, c, material ) {
|
||||
|
||||
const v1 = _vertexPool[ a ];
|
||||
const v2 = _vertexPool[ b ];
|
||||
const v3 = _vertexPool[ c ];
|
||||
|
||||
if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return;
|
||||
|
||||
if ( material.side === DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) {
|
||||
|
||||
_face = getNextFaceInPool();
|
||||
|
||||
_face.id = object.id;
|
||||
_face.v1.copy( v1 );
|
||||
_face.v2.copy( v2 );
|
||||
_face.v3.copy( v3 );
|
||||
_face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
|
||||
_face.renderOrder = object.renderOrder;
|
||||
|
||||
// face normal
|
||||
_vector3.subVectors( v3.position, v2.position );
|
||||
_vector4.subVectors( v1.position, v2.position );
|
||||
_vector3.cross( _vector4 );
|
||||
_face.normalModel.copy( _vector3 );
|
||||
_face.normalModel.applyMatrix3( normalMatrix ).normalize();
|
||||
|
||||
for ( let i = 0; i < 3; i ++ ) {
|
||||
|
||||
const normal = _face.vertexNormalsModel[ i ];
|
||||
normal.fromArray( normals, arguments[ i ] * 3 );
|
||||
normal.applyMatrix3( normalMatrix ).normalize();
|
||||
|
||||
const uv = _face.uvs[ i ];
|
||||
uv.fromArray( uvs, arguments[ i ] * 2 );
|
||||
|
||||
}
|
||||
|
||||
_face.vertexNormalsLength = 3;
|
||||
|
||||
_face.material = material;
|
||||
|
||||
if ( material.vertexColors ) {
|
||||
|
||||
_face.color.fromArray( colors, a * 3 );
|
||||
|
||||
}
|
||||
|
||||
_renderData.elements.push( _face );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
setObject: setObject,
|
||||
projectVertex: projectVertex,
|
||||
checkTriangleVisibility: checkTriangleVisibility,
|
||||
checkBackfaceCulling: checkBackfaceCulling,
|
||||
pushVertex: pushVertex,
|
||||
pushNormal: pushNormal,
|
||||
pushColor: pushColor,
|
||||
pushUv: pushUv,
|
||||
pushLine: pushLine,
|
||||
pushTriangle: pushTriangle
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const renderList = new RenderList();
|
||||
|
||||
function projectObject( object ) {
|
||||
|
||||
if ( object.visible === false ) return;
|
||||
|
||||
if ( object.isLight ) {
|
||||
|
||||
_renderData.lights.push( object );
|
||||
|
||||
} else if ( object.isMesh || object.isLine || object.isPoints ) {
|
||||
|
||||
if ( object.material.visible === false ) return;
|
||||
if ( object.frustumCulled === true && _frustum.intersectsObject( object ) === false ) return;
|
||||
|
||||
addObject( object );
|
||||
|
||||
} else if ( object.isSprite ) {
|
||||
|
||||
if ( object.material.visible === false ) return;
|
||||
if ( object.frustumCulled === true && _frustum.intersectsSprite( object ) === false ) return;
|
||||
|
||||
addObject( object );
|
||||
|
||||
}
|
||||
|
||||
const children = object.children;
|
||||
|
||||
for ( let i = 0, l = children.length; i < l; i ++ ) {
|
||||
|
||||
projectObject( children[ i ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function addObject( object ) {
|
||||
|
||||
_object = getNextObjectInPool();
|
||||
_object.id = object.id;
|
||||
_object.object = object;
|
||||
|
||||
_vector3.setFromMatrixPosition( object.matrixWorld );
|
||||
_vector3.applyMatrix4( _viewProjectionMatrix );
|
||||
_object.z = _vector3.z;
|
||||
_object.renderOrder = object.renderOrder;
|
||||
|
||||
_renderData.objects.push( _object );
|
||||
|
||||
}
|
||||
|
||||
this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
|
||||
|
||||
_faceCount = 0;
|
||||
_lineCount = 0;
|
||||
_spriteCount = 0;
|
||||
|
||||
_renderData.elements.length = 0;
|
||||
|
||||
if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
|
||||
if ( camera.parent === null ) camera.updateMatrixWorld();
|
||||
|
||||
_viewMatrix.copy( camera.matrixWorldInverse );
|
||||
_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
|
||||
|
||||
_frustum.setFromProjectionMatrix( _viewProjectionMatrix );
|
||||
|
||||
//
|
||||
|
||||
_objectCount = 0;
|
||||
|
||||
_renderData.objects.length = 0;
|
||||
_renderData.lights.length = 0;
|
||||
|
||||
projectObject( scene );
|
||||
|
||||
if ( sortObjects === true ) {
|
||||
|
||||
_renderData.objects.sort( painterSort );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const objects = _renderData.objects;
|
||||
|
||||
for ( let o = 0, ol = objects.length; o < ol; o ++ ) {
|
||||
|
||||
const object = objects[ o ].object;
|
||||
const geometry = object.geometry;
|
||||
|
||||
renderList.setObject( object );
|
||||
|
||||
_modelMatrix = object.matrixWorld;
|
||||
|
||||
_vertexCount = 0;
|
||||
|
||||
if ( object.isMesh ) {
|
||||
|
||||
if ( geometry.isBufferGeometry ) {
|
||||
|
||||
let material = object.material;
|
||||
|
||||
const isMultiMaterial = Array.isArray( material );
|
||||
|
||||
const attributes = geometry.attributes;
|
||||
const groups = geometry.groups;
|
||||
|
||||
if ( attributes.position === undefined ) continue;
|
||||
|
||||
const positions = attributes.position.array;
|
||||
|
||||
for ( let i = 0, l = positions.length; i < l; i += 3 ) {
|
||||
|
||||
let x = positions[ i ];
|
||||
let y = positions[ i + 1 ];
|
||||
let z = positions[ i + 2 ];
|
||||
|
||||
const morphTargets = geometry.morphAttributes.position;
|
||||
|
||||
if ( morphTargets !== undefined ) {
|
||||
|
||||
const morphTargetsRelative = geometry.morphTargetsRelative;
|
||||
const morphInfluences = object.morphTargetInfluences;
|
||||
|
||||
for ( let t = 0, tl = morphTargets.length; t < tl; t ++ ) {
|
||||
|
||||
const influence = morphInfluences[ t ];
|
||||
|
||||
if ( influence === 0 ) continue;
|
||||
|
||||
const target = morphTargets[ t ];
|
||||
|
||||
if ( morphTargetsRelative ) {
|
||||
|
||||
x += target.getX( i / 3 ) * influence;
|
||||
y += target.getY( i / 3 ) * influence;
|
||||
z += target.getZ( i / 3 ) * influence;
|
||||
|
||||
} else {
|
||||
|
||||
x += ( target.getX( i / 3 ) - positions[ i ] ) * influence;
|
||||
y += ( target.getY( i / 3 ) - positions[ i + 1 ] ) * influence;
|
||||
z += ( target.getZ( i / 3 ) - positions[ i + 2 ] ) * influence;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
renderList.pushVertex( x, y, z );
|
||||
|
||||
}
|
||||
|
||||
if ( attributes.normal !== undefined ) {
|
||||
|
||||
const normals = attributes.normal.array;
|
||||
|
||||
for ( let i = 0, l = normals.length; i < l; i += 3 ) {
|
||||
|
||||
renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( attributes.color !== undefined ) {
|
||||
|
||||
const colors = attributes.color.array;
|
||||
|
||||
for ( let i = 0, l = colors.length; i < l; i += 3 ) {
|
||||
|
||||
renderList.pushColor( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( attributes.uv !== undefined ) {
|
||||
|
||||
const uvs = attributes.uv.array;
|
||||
|
||||
for ( let i = 0, l = uvs.length; i < l; i += 2 ) {
|
||||
|
||||
renderList.pushUv( uvs[ i ], uvs[ i + 1 ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( geometry.index !== null ) {
|
||||
|
||||
const indices = geometry.index.array;
|
||||
|
||||
if ( groups.length > 0 ) {
|
||||
|
||||
for ( let g = 0; g < groups.length; g ++ ) {
|
||||
|
||||
const group = groups[ g ];
|
||||
|
||||
material = isMultiMaterial === true
|
||||
? object.material[ group.materialIndex ]
|
||||
: object.material;
|
||||
|
||||
if ( material === undefined ) continue;
|
||||
|
||||
for ( let i = group.start, l = group.start + group.count; i < l; i += 3 ) {
|
||||
|
||||
renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ], material );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for ( let i = 0, l = indices.length; i < l; i += 3 ) {
|
||||
|
||||
renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ], material );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ( groups.length > 0 ) {
|
||||
|
||||
for ( let g = 0; g < groups.length; g ++ ) {
|
||||
|
||||
const group = groups[ g ];
|
||||
|
||||
material = isMultiMaterial === true
|
||||
? object.material[ group.materialIndex ]
|
||||
: object.material;
|
||||
|
||||
if ( material === undefined ) continue;
|
||||
|
||||
for ( let i = group.start, l = group.start + group.count; i < l; i += 3 ) {
|
||||
|
||||
renderList.pushTriangle( i, i + 1, i + 2, material );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for ( let i = 0, l = positions.length / 3; i < l; i += 3 ) {
|
||||
|
||||
renderList.pushTriangle( i, i + 1, i + 2, material );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if ( geometry.isGeometry ) {
|
||||
|
||||
console.error( 'THREE.Projector no longer supports Geometry. Use THREE.BufferGeometry instead.' );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
} else if ( object.isLine ) {
|
||||
|
||||
_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
|
||||
|
||||
if ( geometry.isBufferGeometry ) {
|
||||
|
||||
const attributes = geometry.attributes;
|
||||
|
||||
if ( attributes.position !== undefined ) {
|
||||
|
||||
const positions = attributes.position.array;
|
||||
|
||||
for ( let i = 0, l = positions.length; i < l; i += 3 ) {
|
||||
|
||||
renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
|
||||
|
||||
}
|
||||
|
||||
if ( attributes.color !== undefined ) {
|
||||
|
||||
const colors = attributes.color.array;
|
||||
|
||||
for ( let i = 0, l = colors.length; i < l; i += 3 ) {
|
||||
|
||||
renderList.pushColor( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( geometry.index !== null ) {
|
||||
|
||||
const indices = geometry.index.array;
|
||||
|
||||
for ( let i = 0, l = indices.length; i < l; i += 2 ) {
|
||||
|
||||
renderList.pushLine( indices[ i ], indices[ i + 1 ] );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
const step = object.isLineSegments ? 2 : 1;
|
||||
|
||||
for ( let i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) {
|
||||
|
||||
renderList.pushLine( i, i + 1 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if ( geometry.isGeometry ) {
|
||||
|
||||
console.error( 'THREE.Projector no longer supports Geometry. Use THREE.BufferGeometry instead.' );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
} else if ( object.isPoints ) {
|
||||
|
||||
_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
|
||||
|
||||
if ( geometry.isGeometry ) {
|
||||
|
||||
console.error( 'THREE.Projector no longer supports Geometry. Use THREE.BufferGeometry instead.' );
|
||||
return;
|
||||
|
||||
} else if ( geometry.isBufferGeometry ) {
|
||||
|
||||
const attributes = geometry.attributes;
|
||||
|
||||
if ( attributes.position !== undefined ) {
|
||||
|
||||
const positions = attributes.position.array;
|
||||
|
||||
for ( let i = 0, l = positions.length; i < l; i += 3 ) {
|
||||
|
||||
_vector4.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ], 1 );
|
||||
_vector4.applyMatrix4( _modelViewProjectionMatrix );
|
||||
|
||||
pushPoint( _vector4, object, camera );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if ( object.isSprite ) {
|
||||
|
||||
object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
|
||||
_vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 );
|
||||
_vector4.applyMatrix4( _viewProjectionMatrix );
|
||||
|
||||
pushPoint( _vector4, object, camera );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( sortElements === true ) {
|
||||
|
||||
_renderData.elements.sort( painterSort );
|
||||
|
||||
}
|
||||
|
||||
return _renderData;
|
||||
|
||||
};
|
||||
|
||||
function pushPoint( _vector4, object, camera ) {
|
||||
|
||||
const invW = 1 / _vector4.w;
|
||||
|
||||
_vector4.z *= invW;
|
||||
|
||||
if ( _vector4.z >= - 1 && _vector4.z <= 1 ) {
|
||||
|
||||
_sprite = getNextSpriteInPool();
|
||||
_sprite.id = object.id;
|
||||
_sprite.x = _vector4.x * invW;
|
||||
_sprite.y = _vector4.y * invW;
|
||||
_sprite.z = _vector4.z;
|
||||
_sprite.renderOrder = object.renderOrder;
|
||||
_sprite.object = object;
|
||||
|
||||
_sprite.rotation = object.rotation;
|
||||
|
||||
_sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) );
|
||||
_sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) );
|
||||
|
||||
_sprite.material = object.material;
|
||||
|
||||
_renderData.elements.push( _sprite );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Pools
|
||||
|
||||
function getNextObjectInPool() {
|
||||
|
||||
if ( _objectCount === _objectPoolLength ) {
|
||||
|
||||
const object = new RenderableObject();
|
||||
_objectPool.push( object );
|
||||
_objectPoolLength ++;
|
||||
_objectCount ++;
|
||||
return object;
|
||||
|
||||
}
|
||||
|
||||
return _objectPool[ _objectCount ++ ];
|
||||
|
||||
}
|
||||
|
||||
function getNextVertexInPool() {
|
||||
|
||||
if ( _vertexCount === _vertexPoolLength ) {
|
||||
|
||||
const vertex = new RenderableVertex();
|
||||
_vertexPool.push( vertex );
|
||||
_vertexPoolLength ++;
|
||||
_vertexCount ++;
|
||||
return vertex;
|
||||
|
||||
}
|
||||
|
||||
return _vertexPool[ _vertexCount ++ ];
|
||||
|
||||
}
|
||||
|
||||
function getNextFaceInPool() {
|
||||
|
||||
if ( _faceCount === _facePoolLength ) {
|
||||
|
||||
const face = new RenderableFace();
|
||||
_facePool.push( face );
|
||||
_facePoolLength ++;
|
||||
_faceCount ++;
|
||||
return face;
|
||||
|
||||
}
|
||||
|
||||
return _facePool[ _faceCount ++ ];
|
||||
|
||||
|
||||
}
|
||||
|
||||
function getNextLineInPool() {
|
||||
|
||||
if ( _lineCount === _linePoolLength ) {
|
||||
|
||||
const line = new RenderableLine();
|
||||
_linePool.push( line );
|
||||
_linePoolLength ++;
|
||||
_lineCount ++;
|
||||
return line;
|
||||
|
||||
}
|
||||
|
||||
return _linePool[ _lineCount ++ ];
|
||||
|
||||
}
|
||||
|
||||
function getNextSpriteInPool() {
|
||||
|
||||
if ( _spriteCount === _spritePoolLength ) {
|
||||
|
||||
const sprite = new RenderableSprite();
|
||||
_spritePool.push( sprite );
|
||||
_spritePoolLength ++;
|
||||
_spriteCount ++;
|
||||
return sprite;
|
||||
|
||||
}
|
||||
|
||||
return _spritePool[ _spriteCount ++ ];
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
function painterSort( a, b ) {
|
||||
|
||||
if ( a.renderOrder !== b.renderOrder ) {
|
||||
|
||||
return a.renderOrder - b.renderOrder;
|
||||
|
||||
} else if ( a.z !== b.z ) {
|
||||
|
||||
return b.z - a.z;
|
||||
|
||||
} else if ( a.id !== b.id ) {
|
||||
|
||||
return a.id - b.id;
|
||||
|
||||
} else {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function clipLine( s1, s2 ) {
|
||||
|
||||
let alpha1 = 0, alpha2 = 1;
|
||||
|
||||
// Calculate the boundary coordinate of each vertex for the near and far clip planes,
|
||||
// Z = -1 and Z = +1, respectively.
|
||||
|
||||
const bc1near = s1.z + s1.w,
|
||||
bc2near = s2.z + s2.w,
|
||||
bc1far = - s1.z + s1.w,
|
||||
bc2far = - s2.z + s2.w;
|
||||
|
||||
if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
|
||||
|
||||
// Both vertices lie entirely within all clip planes.
|
||||
return true;
|
||||
|
||||
} else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) {
|
||||
|
||||
// Both vertices lie entirely outside one of the clip planes.
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
// The line segment spans at least one clip plane.
|
||||
|
||||
if ( bc1near < 0 ) {
|
||||
|
||||
// v1 lies outside the near plane, v2 inside
|
||||
alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );
|
||||
|
||||
} else if ( bc2near < 0 ) {
|
||||
|
||||
// v2 lies outside the near plane, v1 inside
|
||||
alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );
|
||||
|
||||
}
|
||||
|
||||
if ( bc1far < 0 ) {
|
||||
|
||||
// v1 lies outside the far plane, v2 inside
|
||||
alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );
|
||||
|
||||
} else if ( bc2far < 0 ) {
|
||||
|
||||
// v2 lies outside the far plane, v2 inside
|
||||
alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );
|
||||
|
||||
}
|
||||
|
||||
if ( alpha2 < alpha1 ) {
|
||||
|
||||
// The line segment spans two boundaries, but is outside both of them.
|
||||
// (This can't happen when we're only clipping against just near/far but good
|
||||
// to leave the check here for future usage if other clip planes are added.)
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
// Update the s1 and s2 vertices to match the clipped line segment.
|
||||
s1.lerp( s2, alpha1 );
|
||||
s2.lerp( s1, 1 - alpha2 );
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { RenderableObject, RenderableFace, RenderableVertex, RenderableLine, RenderableSprite, Projector };
|
||||
553
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/SVGRenderer.js
generated
vendored
Normal file
553
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/SVGRenderer.js
generated
vendored
Normal file
@@ -0,0 +1,553 @@
|
||||
import {
|
||||
Box2,
|
||||
Camera,
|
||||
Color,
|
||||
Matrix3,
|
||||
Matrix4,
|
||||
Object3D,
|
||||
Vector3
|
||||
} from 'three';
|
||||
import { Projector } from '../renderers/Projector.js';
|
||||
import { RenderableFace } from '../renderers/Projector.js';
|
||||
import { RenderableLine } from '../renderers/Projector.js';
|
||||
import { RenderableSprite } from '../renderers/Projector.js';
|
||||
|
||||
class SVGObject extends Object3D {
|
||||
|
||||
constructor( node ) {
|
||||
|
||||
super();
|
||||
|
||||
this.node = node;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SVGObject.prototype.isSVGObject = true;
|
||||
|
||||
class SVGRenderer {
|
||||
|
||||
constructor() {
|
||||
|
||||
let _renderData, _elements, _lights,
|
||||
_svgWidth, _svgHeight, _svgWidthHalf, _svgHeightHalf,
|
||||
|
||||
_v1, _v2, _v3,
|
||||
|
||||
_svgNode,
|
||||
_pathCount = 0,
|
||||
|
||||
_precision = null,
|
||||
_quality = 1,
|
||||
|
||||
_currentPath, _currentStyle;
|
||||
|
||||
const _this = this,
|
||||
_clipBox = new Box2(),
|
||||
_elemBox = new Box2(),
|
||||
|
||||
_color = new Color(),
|
||||
_diffuseColor = new Color(),
|
||||
_ambientLight = new Color(),
|
||||
_directionalLights = new Color(),
|
||||
_pointLights = new Color(),
|
||||
_clearColor = new Color(),
|
||||
|
||||
_vector3 = new Vector3(), // Needed for PointLight
|
||||
_centroid = new Vector3(),
|
||||
_normal = new Vector3(),
|
||||
_normalViewMatrix = new Matrix3(),
|
||||
|
||||
_viewMatrix = new Matrix4(),
|
||||
_viewProjectionMatrix = new Matrix4(),
|
||||
|
||||
_svgPathPool = [],
|
||||
|
||||
_projector = new Projector(),
|
||||
_svg = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' );
|
||||
|
||||
this.domElement = _svg;
|
||||
|
||||
this.autoClear = true;
|
||||
this.sortObjects = true;
|
||||
this.sortElements = true;
|
||||
|
||||
this.overdraw = 0.5;
|
||||
|
||||
this.info = {
|
||||
|
||||
render: {
|
||||
|
||||
vertices: 0,
|
||||
faces: 0
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.setQuality = function ( quality ) {
|
||||
|
||||
switch ( quality ) {
|
||||
|
||||
case 'high': _quality = 1; break;
|
||||
case 'low': _quality = 0; break;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.setClearColor = function ( color ) {
|
||||
|
||||
_clearColor.set( color );
|
||||
|
||||
};
|
||||
|
||||
this.setPixelRatio = function () {};
|
||||
|
||||
this.setSize = function ( width, height ) {
|
||||
|
||||
_svgWidth = width; _svgHeight = height;
|
||||
_svgWidthHalf = _svgWidth / 2; _svgHeightHalf = _svgHeight / 2;
|
||||
|
||||
_svg.setAttribute( 'viewBox', ( - _svgWidthHalf ) + ' ' + ( - _svgHeightHalf ) + ' ' + _svgWidth + ' ' + _svgHeight );
|
||||
_svg.setAttribute( 'width', _svgWidth );
|
||||
_svg.setAttribute( 'height', _svgHeight );
|
||||
|
||||
_clipBox.min.set( - _svgWidthHalf, - _svgHeightHalf );
|
||||
_clipBox.max.set( _svgWidthHalf, _svgHeightHalf );
|
||||
|
||||
};
|
||||
|
||||
this.getSize = function () {
|
||||
|
||||
return {
|
||||
width: _svgWidth,
|
||||
height: _svgHeight
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
this.setPrecision = function ( precision ) {
|
||||
|
||||
_precision = precision;
|
||||
|
||||
};
|
||||
|
||||
function removeChildNodes() {
|
||||
|
||||
_pathCount = 0;
|
||||
|
||||
while ( _svg.childNodes.length > 0 ) {
|
||||
|
||||
_svg.removeChild( _svg.childNodes[ 0 ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function convert( c ) {
|
||||
|
||||
return _precision !== null ? c.toFixed( _precision ) : c;
|
||||
|
||||
}
|
||||
|
||||
this.clear = function () {
|
||||
|
||||
removeChildNodes();
|
||||
_svg.style.backgroundColor = _clearColor.getStyle();
|
||||
|
||||
};
|
||||
|
||||
this.render = function ( scene, camera ) {
|
||||
|
||||
if ( camera instanceof Camera === false ) {
|
||||
|
||||
console.error( 'THREE.SVGRenderer.render: camera is not an instance of Camera.' );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
const background = scene.background;
|
||||
|
||||
if ( background && background.isColor ) {
|
||||
|
||||
removeChildNodes();
|
||||
_svg.style.backgroundColor = background.getStyle();
|
||||
|
||||
} else if ( this.autoClear === true ) {
|
||||
|
||||
this.clear();
|
||||
|
||||
}
|
||||
|
||||
_this.info.render.vertices = 0;
|
||||
_this.info.render.faces = 0;
|
||||
|
||||
_viewMatrix.copy( camera.matrixWorldInverse );
|
||||
_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
|
||||
|
||||
_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
|
||||
_elements = _renderData.elements;
|
||||
_lights = _renderData.lights;
|
||||
|
||||
_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
|
||||
|
||||
calculateLights( _lights );
|
||||
|
||||
// reset accumulated path
|
||||
|
||||
_currentPath = '';
|
||||
_currentStyle = '';
|
||||
|
||||
for ( let e = 0, el = _elements.length; e < el; e ++ ) {
|
||||
|
||||
const element = _elements[ e ];
|
||||
const material = element.material;
|
||||
|
||||
if ( material === undefined || material.opacity === 0 ) continue;
|
||||
|
||||
_elemBox.makeEmpty();
|
||||
|
||||
if ( element instanceof RenderableSprite ) {
|
||||
|
||||
_v1 = element;
|
||||
_v1.x *= _svgWidthHalf; _v1.y *= - _svgHeightHalf;
|
||||
|
||||
renderSprite( _v1, element, material );
|
||||
|
||||
} else if ( element instanceof RenderableLine ) {
|
||||
|
||||
_v1 = element.v1; _v2 = element.v2;
|
||||
|
||||
_v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf;
|
||||
_v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf;
|
||||
|
||||
_elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen ] );
|
||||
|
||||
if ( _clipBox.intersectsBox( _elemBox ) === true ) {
|
||||
|
||||
renderLine( _v1, _v2, material );
|
||||
|
||||
}
|
||||
|
||||
} else if ( element instanceof RenderableFace ) {
|
||||
|
||||
_v1 = element.v1; _v2 = element.v2; _v3 = element.v3;
|
||||
|
||||
if ( _v1.positionScreen.z < - 1 || _v1.positionScreen.z > 1 ) continue;
|
||||
if ( _v2.positionScreen.z < - 1 || _v2.positionScreen.z > 1 ) continue;
|
||||
if ( _v3.positionScreen.z < - 1 || _v3.positionScreen.z > 1 ) continue;
|
||||
|
||||
_v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf;
|
||||
_v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf;
|
||||
_v3.positionScreen.x *= _svgWidthHalf; _v3.positionScreen.y *= - _svgHeightHalf;
|
||||
|
||||
if ( this.overdraw > 0 ) {
|
||||
|
||||
expand( _v1.positionScreen, _v2.positionScreen, this.overdraw );
|
||||
expand( _v2.positionScreen, _v3.positionScreen, this.overdraw );
|
||||
expand( _v3.positionScreen, _v1.positionScreen, this.overdraw );
|
||||
|
||||
}
|
||||
|
||||
_elemBox.setFromPoints( [
|
||||
_v1.positionScreen,
|
||||
_v2.positionScreen,
|
||||
_v3.positionScreen
|
||||
] );
|
||||
|
||||
if ( _clipBox.intersectsBox( _elemBox ) === true ) {
|
||||
|
||||
renderFace3( _v1, _v2, _v3, element, material );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
flushPath(); // just to flush last svg:path
|
||||
|
||||
scene.traverseVisible( function ( object ) {
|
||||
|
||||
if ( object.isSVGObject ) {
|
||||
|
||||
_vector3.setFromMatrixPosition( object.matrixWorld );
|
||||
_vector3.applyMatrix4( _viewProjectionMatrix );
|
||||
|
||||
if ( _vector3.z < - 1 || _vector3.z > 1 ) return;
|
||||
|
||||
const x = _vector3.x * _svgWidthHalf;
|
||||
const y = - _vector3.y * _svgHeightHalf;
|
||||
|
||||
const node = object.node;
|
||||
node.setAttribute( 'transform', 'translate(' + x + ',' + y + ')' );
|
||||
|
||||
_svg.appendChild( node );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
};
|
||||
|
||||
function calculateLights( lights ) {
|
||||
|
||||
_ambientLight.setRGB( 0, 0, 0 );
|
||||
_directionalLights.setRGB( 0, 0, 0 );
|
||||
_pointLights.setRGB( 0, 0, 0 );
|
||||
|
||||
for ( let l = 0, ll = lights.length; l < ll; l ++ ) {
|
||||
|
||||
const light = lights[ l ];
|
||||
const lightColor = light.color;
|
||||
|
||||
if ( light.isAmbientLight ) {
|
||||
|
||||
_ambientLight.r += lightColor.r;
|
||||
_ambientLight.g += lightColor.g;
|
||||
_ambientLight.b += lightColor.b;
|
||||
|
||||
} else if ( light.isDirectionalLight ) {
|
||||
|
||||
_directionalLights.r += lightColor.r;
|
||||
_directionalLights.g += lightColor.g;
|
||||
_directionalLights.b += lightColor.b;
|
||||
|
||||
} else if ( light.isPointLight ) {
|
||||
|
||||
_pointLights.r += lightColor.r;
|
||||
_pointLights.g += lightColor.g;
|
||||
_pointLights.b += lightColor.b;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function calculateLight( lights, position, normal, color ) {
|
||||
|
||||
for ( let l = 0, ll = lights.length; l < ll; l ++ ) {
|
||||
|
||||
const light = lights[ l ];
|
||||
const lightColor = light.color;
|
||||
|
||||
if ( light.isDirectionalLight ) {
|
||||
|
||||
const lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();
|
||||
|
||||
let amount = normal.dot( lightPosition );
|
||||
|
||||
if ( amount <= 0 ) continue;
|
||||
|
||||
amount *= light.intensity;
|
||||
|
||||
color.r += lightColor.r * amount;
|
||||
color.g += lightColor.g * amount;
|
||||
color.b += lightColor.b * amount;
|
||||
|
||||
} else if ( light.isPointLight ) {
|
||||
|
||||
const lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );
|
||||
|
||||
let amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() );
|
||||
|
||||
if ( amount <= 0 ) continue;
|
||||
|
||||
amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );
|
||||
|
||||
if ( amount == 0 ) continue;
|
||||
|
||||
amount *= light.intensity;
|
||||
|
||||
color.r += lightColor.r * amount;
|
||||
color.g += lightColor.g * amount;
|
||||
color.b += lightColor.b * amount;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function renderSprite( v1, element, material ) {
|
||||
|
||||
let scaleX = element.scale.x * _svgWidthHalf;
|
||||
let scaleY = element.scale.y * _svgHeightHalf;
|
||||
|
||||
if ( material.isPointsMaterial ) {
|
||||
|
||||
scaleX *= material.size;
|
||||
scaleY *= material.size;
|
||||
|
||||
}
|
||||
|
||||
const path = 'M' + convert( v1.x - scaleX * 0.5 ) + ',' + convert( v1.y - scaleY * 0.5 ) + 'h' + convert( scaleX ) + 'v' + convert( scaleY ) + 'h' + convert( - scaleX ) + 'z';
|
||||
let style = '';
|
||||
|
||||
if ( material.isSpriteMaterial || material.isPointsMaterial ) {
|
||||
|
||||
style = 'fill:' + material.color.getStyle() + ';fill-opacity:' + material.opacity;
|
||||
|
||||
}
|
||||
|
||||
addPath( style, path );
|
||||
|
||||
}
|
||||
|
||||
function renderLine( v1, v2, material ) {
|
||||
|
||||
const path = 'M' + convert( v1.positionScreen.x ) + ',' + convert( v1.positionScreen.y ) + 'L' + convert( v2.positionScreen.x ) + ',' + convert( v2.positionScreen.y );
|
||||
|
||||
if ( material.isLineBasicMaterial ) {
|
||||
|
||||
let style = 'fill:none;stroke:' + material.color.getStyle() + ';stroke-opacity:' + material.opacity + ';stroke-width:' + material.linewidth + ';stroke-linecap:' + material.linecap;
|
||||
|
||||
if ( material.isLineDashedMaterial ) {
|
||||
|
||||
style = style + ';stroke-dasharray:' + material.dashSize + ',' + material.gapSize;
|
||||
|
||||
}
|
||||
|
||||
addPath( style, path );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function renderFace3( v1, v2, v3, element, material ) {
|
||||
|
||||
_this.info.render.vertices += 3;
|
||||
_this.info.render.faces ++;
|
||||
|
||||
const path = 'M' + convert( v1.positionScreen.x ) + ',' + convert( v1.positionScreen.y ) + 'L' + convert( v2.positionScreen.x ) + ',' + convert( v2.positionScreen.y ) + 'L' + convert( v3.positionScreen.x ) + ',' + convert( v3.positionScreen.y ) + 'z';
|
||||
let style = '';
|
||||
|
||||
if ( material.isMeshBasicMaterial ) {
|
||||
|
||||
_color.copy( material.color );
|
||||
|
||||
if ( material.vertexColors ) {
|
||||
|
||||
_color.multiply( element.color );
|
||||
|
||||
}
|
||||
|
||||
} else if ( material.isMeshLambertMaterial || material.isMeshPhongMaterial || material.isMeshStandardMaterial ) {
|
||||
|
||||
_diffuseColor.copy( material.color );
|
||||
|
||||
if ( material.vertexColors ) {
|
||||
|
||||
_diffuseColor.multiply( element.color );
|
||||
|
||||
}
|
||||
|
||||
_color.copy( _ambientLight );
|
||||
|
||||
_centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 );
|
||||
|
||||
calculateLight( _lights, _centroid, element.normalModel, _color );
|
||||
|
||||
_color.multiply( _diffuseColor ).add( material.emissive );
|
||||
|
||||
} else if ( material.isMeshNormalMaterial ) {
|
||||
|
||||
_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix ).normalize();
|
||||
|
||||
_color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
|
||||
|
||||
}
|
||||
|
||||
if ( material.wireframe ) {
|
||||
|
||||
style = 'fill:none;stroke:' + _color.getStyle() + ';stroke-opacity:' + material.opacity + ';stroke-width:' + material.wireframeLinewidth + ';stroke-linecap:' + material.wireframeLinecap + ';stroke-linejoin:' + material.wireframeLinejoin;
|
||||
|
||||
} else {
|
||||
|
||||
style = 'fill:' + _color.getStyle() + ';fill-opacity:' + material.opacity;
|
||||
|
||||
}
|
||||
|
||||
addPath( style, path );
|
||||
|
||||
}
|
||||
|
||||
// Hide anti-alias gaps
|
||||
|
||||
function expand( v1, v2, pixels ) {
|
||||
|
||||
let x = v2.x - v1.x, y = v2.y - v1.y;
|
||||
const det = x * x + y * y;
|
||||
|
||||
if ( det === 0 ) return;
|
||||
|
||||
const idet = pixels / Math.sqrt( det );
|
||||
|
||||
x *= idet; y *= idet;
|
||||
|
||||
v2.x += x; v2.y += y;
|
||||
v1.x -= x; v1.y -= y;
|
||||
|
||||
}
|
||||
|
||||
function addPath( style, path ) {
|
||||
|
||||
if ( _currentStyle === style ) {
|
||||
|
||||
_currentPath += path;
|
||||
|
||||
} else {
|
||||
|
||||
flushPath();
|
||||
|
||||
_currentStyle = style;
|
||||
_currentPath = path;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function flushPath() {
|
||||
|
||||
if ( _currentPath ) {
|
||||
|
||||
_svgNode = getPathNode( _pathCount ++ );
|
||||
_svgNode.setAttribute( 'd', _currentPath );
|
||||
_svgNode.setAttribute( 'style', _currentStyle );
|
||||
_svg.appendChild( _svgNode );
|
||||
|
||||
}
|
||||
|
||||
_currentPath = '';
|
||||
_currentStyle = '';
|
||||
|
||||
}
|
||||
|
||||
function getPathNode( id ) {
|
||||
|
||||
if ( _svgPathPool[ id ] == null ) {
|
||||
|
||||
_svgPathPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
|
||||
|
||||
if ( _quality == 0 ) {
|
||||
|
||||
_svgPathPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
|
||||
|
||||
}
|
||||
|
||||
return _svgPathPool[ id ];
|
||||
|
||||
}
|
||||
|
||||
return _svgPathPool[ id ];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { SVGObject, SVGRenderer };
|
||||
22
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgl/nodes/SlotNode.js
generated
vendored
Normal file
22
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgl/nodes/SlotNode.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import Node from 'three-nodes/core/Node.js';
|
||||
|
||||
class SlotNode extends Node {
|
||||
|
||||
constructor( node, name, nodeType ) {
|
||||
|
||||
super( nodeType );
|
||||
|
||||
this.node = node;
|
||||
this.name = name;
|
||||
|
||||
}
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
return this.node.build( builder, this.getNodeType( builder ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SlotNode;
|
||||
540
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js
generated
vendored
Normal file
540
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js
generated
vendored
Normal file
@@ -0,0 +1,540 @@
|
||||
import NodeBuilder, { shaderStages } from 'three-nodes/core/NodeBuilder.js';
|
||||
import SlotNode from './SlotNode.js';
|
||||
import GLSLNodeParser from 'three-nodes/parsers/GLSLNodeParser.js';
|
||||
import WebGLPhysicalContextNode from './WebGLPhysicalContextNode.js';
|
||||
|
||||
import { ShaderChunk, ShaderLib, UniformsUtils, UniformsLib,
|
||||
LinearEncoding, RGBAFormat, UnsignedByteType, sRGBEncoding } from 'three';
|
||||
|
||||
const nodeShaderLib = {
|
||||
LineBasicNodeMaterial: ShaderLib.basic,
|
||||
MeshBasicNodeMaterial: ShaderLib.basic,
|
||||
PointsNodeMaterial: ShaderLib.points,
|
||||
MeshStandardNodeMaterial: ShaderLib.standard
|
||||
};
|
||||
|
||||
function getIncludeSnippet( name ) {
|
||||
|
||||
return `#include <${name}>`;
|
||||
|
||||
}
|
||||
|
||||
function getShaderStageProperty( shaderStage ) {
|
||||
|
||||
return `${shaderStage}Shader`;
|
||||
|
||||
}
|
||||
|
||||
class WebGLNodeBuilder extends NodeBuilder {
|
||||
|
||||
constructor( object, renderer, shader ) {
|
||||
|
||||
super( object, renderer, new GLSLNodeParser() );
|
||||
|
||||
this.shader = shader;
|
||||
this.slots = { vertex: [], fragment: [] };
|
||||
|
||||
this._parseObject();
|
||||
|
||||
}
|
||||
|
||||
addSlot( shaderStage, slotNode ) {
|
||||
|
||||
this.slots[ shaderStage ].push( slotNode );
|
||||
|
||||
return this.addFlow( shaderStage, slotNode );
|
||||
|
||||
}
|
||||
|
||||
addFlowCode( code ) {
|
||||
|
||||
if ( ! /;\s*$/.test( code ) ) {
|
||||
|
||||
code += ';';
|
||||
|
||||
}
|
||||
|
||||
super.addFlowCode( code + '\n\t' );
|
||||
|
||||
}
|
||||
|
||||
_parseObject() {
|
||||
|
||||
const material = this.material;
|
||||
const type = material.type;
|
||||
|
||||
// shader lib
|
||||
|
||||
if ( nodeShaderLib[ type ] !== undefined ) {
|
||||
|
||||
const shaderLib = nodeShaderLib[ type ];
|
||||
const shader = this.shader;
|
||||
|
||||
shader.vertexShader = shaderLib.vertexShader;
|
||||
shader.fragmentShader = shaderLib.fragmentShader;
|
||||
shader.uniforms = UniformsUtils.merge( [ shaderLib.uniforms, UniformsLib.lights ] );
|
||||
|
||||
}
|
||||
|
||||
// parse inputs
|
||||
|
||||
if ( material.colorNode && material.colorNode.isNode ) {
|
||||
|
||||
this.addSlot( 'fragment', new SlotNode( material.colorNode, 'COLOR', 'vec4' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( material.opacityNode && material.opacityNode.isNode ) {
|
||||
|
||||
this.addSlot( 'fragment', new SlotNode( material.opacityNode, 'OPACITY', 'float' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( material.normalNode && material.normalNode.isNode ) {
|
||||
|
||||
this.addSlot( 'fragment', new SlotNode( material.normalNode, 'NORMAL', 'vec3' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( material.emissiveNode && material.emissiveNode.isNode ) {
|
||||
|
||||
this.addSlot( 'fragment', new SlotNode( material.emissiveNode, 'EMISSIVE', 'vec3' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( material.metalnessNode && material.metalnessNode.isNode ) {
|
||||
|
||||
this.addSlot( 'fragment', new SlotNode( material.metalnessNode, 'METALNESS', 'float' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( material.roughnessNode && material.roughnessNode.isNode ) {
|
||||
|
||||
this.addSlot( 'fragment', new SlotNode( material.roughnessNode, 'ROUGHNESS', 'float' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( material.clearcoatNode && material.clearcoatNode.isNode ) {
|
||||
|
||||
this.addSlot( 'fragment', new SlotNode( material.clearcoatNode, 'CLEARCOAT', 'float' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( material.clearcoatRoughnessNode && material.clearcoatRoughnessNode.isNode ) {
|
||||
|
||||
this.addSlot( 'fragment', new SlotNode( material.clearcoatRoughnessNode, 'CLEARCOAT_ROUGHNESS', 'float' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( material.envNode && material.envNode.isNode ) {
|
||||
|
||||
const envRadianceNode = new WebGLPhysicalContextNode( WebGLPhysicalContextNode.RADIANCE, material.envNode );
|
||||
const envIrradianceNode = new WebGLPhysicalContextNode( WebGLPhysicalContextNode.IRRADIANCE, material.envNode );
|
||||
|
||||
this.addSlot( 'fragment', new SlotNode( envRadianceNode, 'RADIANCE', 'vec3' ) );
|
||||
this.addSlot( 'fragment', new SlotNode( envIrradianceNode, 'IRRADIANCE', 'vec3' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( material.positionNode && material.positionNode.isNode ) {
|
||||
|
||||
this.addSlot( 'vertex', new SlotNode( material.positionNode, 'POSITION', 'vec3' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( material.sizeNode && material.sizeNode.isNode ) {
|
||||
|
||||
this.addSlot( 'vertex', new SlotNode( material.sizeNode, 'SIZE', 'float' ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getTexture( textureProperty, uvSnippet, biasSnippet = null ) {
|
||||
|
||||
if ( biasSnippet !== null ) {
|
||||
|
||||
return `texture2D( ${textureProperty}, ${uvSnippet}, ${biasSnippet} )`;
|
||||
|
||||
} else {
|
||||
|
||||
return `texture2D( ${textureProperty}, ${uvSnippet} )`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getCubeTexture( textureProperty, uvSnippet, biasSnippet = null ) {
|
||||
|
||||
const textureCube = 'textureCubeLodEXT'; // textureCubeLodEXT textureLod
|
||||
|
||||
if ( biasSnippet !== null ) {
|
||||
|
||||
return `${textureCube}( ${textureProperty}, ${uvSnippet}, ${biasSnippet} )`;
|
||||
|
||||
} else {
|
||||
|
||||
return `${textureCube}( ${textureProperty}, ${uvSnippet} )`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getUniforms( shaderStage ) {
|
||||
|
||||
const uniforms = this.uniforms[ shaderStage ];
|
||||
|
||||
let snippet = '';
|
||||
|
||||
for ( const uniform of uniforms ) {
|
||||
|
||||
if ( uniform.type === 'texture' ) {
|
||||
|
||||
snippet += `uniform sampler2D ${uniform.name}; `;
|
||||
|
||||
} else if ( uniform.type === 'cubeTexture' ) {
|
||||
|
||||
snippet += `uniform samplerCube ${uniform.name}; `;
|
||||
|
||||
} else {
|
||||
|
||||
const vectorType = this.getVectorType( uniform.type );
|
||||
|
||||
snippet += `uniform ${vectorType} ${uniform.name}; `;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
getAttributes( shaderStage ) {
|
||||
|
||||
let snippet = '';
|
||||
|
||||
if ( shaderStage === 'vertex' ) {
|
||||
|
||||
const attributes = this.attributes;
|
||||
|
||||
for ( let index = 0; index < attributes.length; index ++ ) {
|
||||
|
||||
const attribute = attributes[ index ];
|
||||
|
||||
// ignore common attributes to prevent redefinitions
|
||||
if ( attribute.name === 'uv' || attribute.name === 'position' || attribute.name === 'normal' )
|
||||
continue;
|
||||
|
||||
snippet += `attribute ${attribute.type} ${attribute.name}; `;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
getVarys( /* shaderStage */ ) {
|
||||
|
||||
let snippet = '';
|
||||
|
||||
const varys = this.varys;
|
||||
|
||||
for ( let index = 0; index < varys.length; index ++ ) {
|
||||
|
||||
const vary = varys[ index ];
|
||||
|
||||
snippet += `varying ${vary.type} ${vary.name}; `;
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
addCodeAfterSnippet( shaderStage, snippet, code ) {
|
||||
|
||||
const shaderProperty = getShaderStageProperty( shaderStage );
|
||||
|
||||
let source = this[ shaderProperty ];
|
||||
|
||||
const index = source.indexOf( snippet );
|
||||
|
||||
if ( index !== - 1 ) {
|
||||
|
||||
const start = source.substring( 0, index + snippet.length );
|
||||
const end = source.substring( index + snippet.length );
|
||||
|
||||
source = `${start}\n${code}\n${end}`;
|
||||
|
||||
}
|
||||
|
||||
this[ shaderProperty ] = source;
|
||||
|
||||
}
|
||||
|
||||
addCodeAfterInclude( shaderStage, includeName, code ) {
|
||||
|
||||
const includeSnippet = getIncludeSnippet( includeName );
|
||||
|
||||
this.addCodeAfterSnippet( shaderStage, includeSnippet, code );
|
||||
|
||||
}
|
||||
|
||||
replaceCode( shaderStage, source, target ) {
|
||||
|
||||
const shaderProperty = getShaderStageProperty( shaderStage );
|
||||
|
||||
this.shader[ shaderProperty ] = this.shader[ shaderProperty ].replaceAll( source, target );
|
||||
|
||||
}
|
||||
|
||||
parseInclude( shaderStage, ...includes ) {
|
||||
|
||||
for ( const name of includes ) {
|
||||
|
||||
const includeSnippet = getIncludeSnippet( name );
|
||||
const code = ShaderChunk[ name ];
|
||||
|
||||
this.replaceCode( shaderStage, includeSnippet, code );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getTextureEncodingFromMap( map ) {
|
||||
|
||||
const isWebGL2 = this.renderer.capabilities.isWebGL2;
|
||||
|
||||
if ( isWebGL2 && map && map.isTexture && map.format === RGBAFormat && map.type === UnsignedByteType && map.encoding === sRGBEncoding ) {
|
||||
|
||||
return LinearEncoding; // disable inline decode for sRGB textures in WebGL 2
|
||||
|
||||
}
|
||||
|
||||
return super.getTextureEncodingFromMap( map );
|
||||
|
||||
}
|
||||
|
||||
buildCode() {
|
||||
|
||||
const shaderData = {};
|
||||
|
||||
for ( const shaderStage of shaderStages ) {
|
||||
|
||||
const uniforms = this.getUniforms( shaderStage );
|
||||
const attributes = this.getAttributes( shaderStage );
|
||||
const varys = this.getVarys( shaderStage );
|
||||
const vars = this.getVars( shaderStage );
|
||||
const codes = this.getCodes( shaderStage );
|
||||
|
||||
shaderData[ shaderStage ] = `${this.getSignature()}
|
||||
// <node_builder>
|
||||
|
||||
// uniforms
|
||||
${uniforms}
|
||||
|
||||
// attributes
|
||||
${attributes}
|
||||
|
||||
// varys
|
||||
${varys}
|
||||
|
||||
// vars
|
||||
${vars}
|
||||
|
||||
// codes
|
||||
${codes}
|
||||
|
||||
// </node_builder>
|
||||
|
||||
${this.shader[ getShaderStageProperty( shaderStage ) ]}
|
||||
`;
|
||||
|
||||
}
|
||||
|
||||
this.vertexShader = shaderData.vertex;
|
||||
this.fragmentShader = shaderData.fragment;
|
||||
|
||||
|
||||
}
|
||||
|
||||
build() {
|
||||
|
||||
super.build();
|
||||
|
||||
this._addSnippets();
|
||||
this._addUniforms();
|
||||
|
||||
this.shader.vertexShader = this.vertexShader;
|
||||
this.shader.fragmentShader = this.fragmentShader;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
getSlot( shaderStage, name ) {
|
||||
|
||||
const slots = this.slots[ shaderStage ];
|
||||
|
||||
for ( const node of slots ) {
|
||||
|
||||
if ( node.name === name ) {
|
||||
|
||||
return this.getFlowData( shaderStage, node );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_addSnippets() {
|
||||
|
||||
this.parseInclude( 'fragment', 'lights_physical_fragment' );
|
||||
|
||||
const colorSlot = this.getSlot( 'fragment', 'COLOR' );
|
||||
const opacityNode = this.getSlot( 'fragment', 'OPACITY' );
|
||||
const normalSlot = this.getSlot( 'fragment', 'NORMAL' );
|
||||
const emissiveNode = this.getSlot( 'fragment', 'EMISSIVE' );
|
||||
const roughnessNode = this.getSlot( 'fragment', 'ROUGHNESS' );
|
||||
const metalnessNode = this.getSlot( 'fragment', 'METALNESS' );
|
||||
const clearcoatNode = this.getSlot( 'fragment', 'CLEARCOAT' );
|
||||
const clearcoatRoughnessNode = this.getSlot( 'fragment', 'CLEARCOAT_ROUGHNESS' );
|
||||
|
||||
const positionNode = this.getSlot( 'vertex', 'POSITION' );
|
||||
const sizeNode = this.getSlot( 'vertex', 'SIZE' );
|
||||
|
||||
if ( colorSlot !== undefined ) {
|
||||
|
||||
this.addCodeAfterInclude(
|
||||
'fragment',
|
||||
'color_fragment',
|
||||
`${colorSlot.code}\n\tdiffuseColor = ${colorSlot.result};`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ( opacityNode !== undefined ) {
|
||||
|
||||
this.addCodeAfterInclude(
|
||||
'fragment',
|
||||
'alphatest_fragment',
|
||||
`${opacityNode.code}\n\tdiffuseColor.a = ${opacityNode.result};`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ( normalSlot !== undefined ) {
|
||||
|
||||
this.addCodeAfterInclude(
|
||||
'fragment',
|
||||
'normal_fragment_begin',
|
||||
`${normalSlot.code}\n\tnormal = ${normalSlot.result};`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ( emissiveNode !== undefined ) {
|
||||
|
||||
this.addCodeAfterInclude(
|
||||
'fragment',
|
||||
'emissivemap_fragment',
|
||||
`${emissiveNode.code}\n\ttotalEmissiveRadiance = ${emissiveNode.result};`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ( roughnessNode !== undefined ) {
|
||||
|
||||
this.addCodeAfterInclude(
|
||||
'fragment',
|
||||
'roughnessmap_fragment',
|
||||
`${roughnessNode.code}\n\troughnessFactor = ${roughnessNode.result};`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ( metalnessNode !== undefined ) {
|
||||
|
||||
this.addCodeAfterInclude(
|
||||
'fragment',
|
||||
'metalnessmap_fragment',
|
||||
`${metalnessNode.code}\n\tmetalnessFactor = ${metalnessNode.result};`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ( clearcoatNode !== undefined ) {
|
||||
|
||||
this.addCodeAfterSnippet(
|
||||
'fragment',
|
||||
'material.clearcoatRoughness = clearcoatRoughness;',
|
||||
`${clearcoatNode.code}\n\tmaterial.clearcoat = ${clearcoatNode.result};`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ( clearcoatRoughnessNode !== undefined ) {
|
||||
|
||||
this.addCodeAfterSnippet(
|
||||
'fragment',
|
||||
'material.clearcoatRoughness = clearcoatRoughness;',
|
||||
`${clearcoatRoughnessNode.code}\n\tmaterial.clearcoatRoughness = ${clearcoatRoughnessNode.result};`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ( positionNode !== undefined ) {
|
||||
|
||||
this.addCodeAfterInclude(
|
||||
'vertex',
|
||||
'begin_vertex',
|
||||
`${positionNode.code}\n\ttransformed = ${positionNode.result};`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ( sizeNode !== undefined ) {
|
||||
|
||||
this.addCodeAfterSnippet(
|
||||
'vertex',
|
||||
'gl_PointSize = size;',
|
||||
`${sizeNode.code}\n\tgl_PointSize = ${sizeNode.result};`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
for ( const shaderStage of shaderStages ) {
|
||||
|
||||
this.addCodeAfterSnippet(
|
||||
shaderStage,
|
||||
'main() {',
|
||||
this.flowCode[ shaderStage ]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_addUniforms() {
|
||||
|
||||
for ( const shaderStage of shaderStages ) {
|
||||
|
||||
// uniforms
|
||||
|
||||
for ( const uniform of this.uniforms[ shaderStage ] ) {
|
||||
|
||||
this.shader.uniforms[ uniform.name ] = uniform;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { WebGLNodeBuilder };
|
||||
34
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgl/nodes/WebGLNodes.js
generated
vendored
Normal file
34
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgl/nodes/WebGLNodes.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
import { WebGLNodeBuilder } from './WebGLNodeBuilder.js';
|
||||
import NodeFrame from 'three-nodes/core/NodeFrame.js';
|
||||
|
||||
import { Material } from 'three';
|
||||
|
||||
const builders = new WeakMap();
|
||||
export const nodeFrame = new NodeFrame();
|
||||
|
||||
Material.prototype.onBuild = function ( object, parameters, renderer ) {
|
||||
|
||||
builders.set( this, new WebGLNodeBuilder( object, renderer, parameters ).build() );
|
||||
|
||||
};
|
||||
|
||||
Material.prototype.onBeforeRender = function ( renderer, scene, camera, geometry, object ) {
|
||||
|
||||
const nodeBuilder = builders.get( this );
|
||||
|
||||
if ( nodeBuilder !== undefined ) {
|
||||
|
||||
nodeFrame.material = this;
|
||||
nodeFrame.camera = camera;
|
||||
nodeFrame.object = object;
|
||||
nodeFrame.renderer = renderer;
|
||||
|
||||
for ( const node of nodeBuilder.updateNodes ) {
|
||||
|
||||
nodeFrame.updateNode( node );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
45
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgl/nodes/WebGLPhysicalContextNode.js
generated
vendored
Normal file
45
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgl/nodes/WebGLPhysicalContextNode.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
import ContextNode from 'three-nodes/core/ContextNode.js';
|
||||
import NormalNode from 'three-nodes/accessors/NormalNode.js';
|
||||
import ExpressionNode from 'three-nodes/core/ExpressionNode.js';
|
||||
import FloatNode from 'three-nodes/inputs/FloatNode.js';
|
||||
|
||||
class WebGLPhysicalContextNode extends ContextNode {
|
||||
|
||||
static RADIANCE = 'radiance';
|
||||
static IRRADIANCE = 'irradiance';
|
||||
|
||||
constructor( scope, node ) {
|
||||
|
||||
super( node, 'vec3' );
|
||||
|
||||
this.scope = scope;
|
||||
|
||||
}
|
||||
|
||||
generate( builder, output ) {
|
||||
|
||||
const scope = this.scope;
|
||||
|
||||
let roughness = null;
|
||||
|
||||
if ( scope === WebGLPhysicalContextNode.RADIANCE ) {
|
||||
|
||||
roughness = new ExpressionNode( 'roughnessFactor', 'float' );
|
||||
|
||||
} else if ( scope === WebGLPhysicalContextNode.IRRADIANCE ) {
|
||||
|
||||
roughness = new FloatNode( 1.0 ).setConst( true );
|
||||
|
||||
this.context.uv = new NormalNode( NormalNode.WORLD );
|
||||
|
||||
}
|
||||
|
||||
this.context.roughness = roughness;
|
||||
|
||||
return super.generate( builder, output );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGLPhysicalContextNode;
|
||||
129
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUAttributes.js
generated
vendored
Normal file
129
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUAttributes.js
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
class WebGPUAttributes {
|
||||
|
||||
constructor( device ) {
|
||||
|
||||
this.buffers = new WeakMap();
|
||||
this.device = device;
|
||||
|
||||
}
|
||||
|
||||
get( attribute ) {
|
||||
|
||||
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
|
||||
|
||||
return this.buffers.get( attribute );
|
||||
|
||||
}
|
||||
|
||||
remove( attribute ) {
|
||||
|
||||
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
|
||||
|
||||
const data = this.buffers.get( attribute );
|
||||
|
||||
if ( data ) {
|
||||
|
||||
data.buffer.destroy();
|
||||
|
||||
this.buffers.delete( attribute );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
update( attribute, isIndex = false, usage = null ) {
|
||||
|
||||
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
|
||||
|
||||
let data = this.buffers.get( attribute );
|
||||
|
||||
if ( data === undefined ) {
|
||||
|
||||
if ( usage === null ) {
|
||||
|
||||
usage = ( isIndex === true ) ? GPUBufferUsage.INDEX : GPUBufferUsage.VERTEX;
|
||||
|
||||
}
|
||||
|
||||
data = this._createBuffer( attribute, usage );
|
||||
|
||||
this.buffers.set( attribute, data );
|
||||
|
||||
} else if ( usage && usage !== data.usage ) {
|
||||
|
||||
data.buffer.destroy();
|
||||
|
||||
data = this._createBuffer( attribute, usage );
|
||||
|
||||
this.buffers.set( attribute, data );
|
||||
|
||||
} else if ( data.version < attribute.version ) {
|
||||
|
||||
this._writeBuffer( data.buffer, attribute );
|
||||
|
||||
data.version = attribute.version;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_createBuffer( attribute, usage ) {
|
||||
|
||||
const array = attribute.array;
|
||||
const size = array.byteLength + ( ( 4 - ( array.byteLength % 4 ) ) % 4 ); // ensure 4 byte alignment, see #20441
|
||||
|
||||
const buffer = this.device.createBuffer( {
|
||||
size: size,
|
||||
usage: usage | GPUBufferUsage.COPY_DST,
|
||||
mappedAtCreation: true,
|
||||
} );
|
||||
|
||||
new array.constructor( buffer.getMappedRange() ).set( array );
|
||||
|
||||
buffer.unmap();
|
||||
|
||||
attribute.onUploadCallback();
|
||||
|
||||
return {
|
||||
version: attribute.version,
|
||||
buffer: buffer,
|
||||
usage: usage
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
_writeBuffer( buffer, attribute ) {
|
||||
|
||||
const array = attribute.array;
|
||||
const updateRange = attribute.updateRange;
|
||||
|
||||
if ( updateRange.count === - 1 ) {
|
||||
|
||||
// Not using update ranges
|
||||
|
||||
this.device.queue.writeBuffer(
|
||||
buffer,
|
||||
0,
|
||||
array,
|
||||
0
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
this.device.queue.writeBuffer(
|
||||
buffer,
|
||||
0,
|
||||
array,
|
||||
updateRange.offset * array.BYTES_PER_ELEMENT,
|
||||
updateRange.count * array.BYTES_PER_ELEMENT
|
||||
);
|
||||
|
||||
updateRange.count = - 1; // reset range
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUAttributes;
|
||||
106
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUBackground.js
generated
vendored
Normal file
106
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUBackground.js
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
import { GPULoadOp, GPUStoreOp } from './constants.js';
|
||||
import { Color } from 'three';
|
||||
|
||||
let _clearAlpha;
|
||||
const _clearColor = new Color();
|
||||
|
||||
class WebGPUBackground {
|
||||
|
||||
constructor( renderer ) {
|
||||
|
||||
this.renderer = renderer;
|
||||
|
||||
this.forceClear = false;
|
||||
|
||||
}
|
||||
|
||||
clear() {
|
||||
|
||||
this.forceClear = true;
|
||||
|
||||
}
|
||||
|
||||
update( scene ) {
|
||||
|
||||
const renderer = this.renderer;
|
||||
const background = ( scene.isScene === true ) ? scene.background : null;
|
||||
let forceClear = this.forceClear;
|
||||
|
||||
if ( background === null ) {
|
||||
|
||||
// no background settings, use clear color configuration from the renderer
|
||||
|
||||
_clearColor.copy( renderer._clearColor );
|
||||
_clearAlpha = renderer._clearAlpha;
|
||||
|
||||
} else if ( background.isColor === true ) {
|
||||
|
||||
// background is an opaque color
|
||||
|
||||
_clearColor.copy( background );
|
||||
_clearAlpha = 1;
|
||||
forceClear = true;
|
||||
|
||||
} else {
|
||||
|
||||
console.error( 'THREE.WebGPURenderer: Unsupported background configuration.', background );
|
||||
|
||||
}
|
||||
|
||||
// configure render pass descriptor
|
||||
|
||||
const renderPassDescriptor = renderer._renderPassDescriptor;
|
||||
const colorAttachment = renderPassDescriptor.colorAttachments[ 0 ];
|
||||
const depthStencilAttachment = renderPassDescriptor.depthStencilAttachment;
|
||||
|
||||
if ( renderer.autoClear === true || forceClear === true ) {
|
||||
|
||||
if ( renderer.autoClearColor === true ) {
|
||||
|
||||
colorAttachment.clearValue = { r: _clearColor.r, g: _clearColor.g, b: _clearColor.b, a: _clearAlpha };
|
||||
colorAttachment.loadOp = GPULoadOp.Clear;
|
||||
colorAttachment.storeOp = GPUStoreOp.Store;
|
||||
|
||||
} else {
|
||||
|
||||
colorAttachment.loadOp = GPULoadOp.Load;
|
||||
|
||||
}
|
||||
|
||||
if ( renderer.autoClearDepth === true ) {
|
||||
|
||||
depthStencilAttachment.depthClearValue = renderer._clearDepth;
|
||||
depthStencilAttachment.depthLoadOp = GPULoadOp.Clear;
|
||||
|
||||
} else {
|
||||
|
||||
depthStencilAttachment.depthLoadOp = GPULoadOp.Load;
|
||||
|
||||
}
|
||||
|
||||
if ( renderer.autoClearStencil === true ) {
|
||||
|
||||
depthStencilAttachment.stencilClearValue = renderer._clearStencil;
|
||||
depthStencilAttachment.stencilLoadOp = GPULoadOp.Clear;
|
||||
|
||||
} else {
|
||||
|
||||
depthStencilAttachment.stencilLoadOp = GPULoadOp.Load;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
colorAttachment.loadOp = GPULoadOp.Load;
|
||||
depthStencilAttachment.depthLoadOp = GPULoadOp.Load;
|
||||
depthStencilAttachment.stencilLoadOp = GPULoadOp.Load;
|
||||
|
||||
}
|
||||
|
||||
this.forceClear = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUBackground;
|
||||
22
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUBinding.js
generated
vendored
Normal file
22
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUBinding.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
class WebGPUBinding {
|
||||
|
||||
constructor( name = '' ) {
|
||||
|
||||
this.name = name;
|
||||
this.visibility = null;
|
||||
|
||||
this.type = null; // read-only
|
||||
|
||||
this.isShared = false;
|
||||
|
||||
}
|
||||
|
||||
setVisibility( visibility ) {
|
||||
|
||||
this.visibility = visibility;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUBinding;
|
||||
254
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUBindings.js
generated
vendored
Normal file
254
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUBindings.js
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
class WebGPUBindings {
|
||||
|
||||
constructor( device, info, properties, textures, renderPipelines, computePipelines, attributes, nodes ) {
|
||||
|
||||
this.device = device;
|
||||
this.info = info;
|
||||
this.properties = properties;
|
||||
this.textures = textures;
|
||||
this.renderPipelines = renderPipelines;
|
||||
this.computePipelines = computePipelines;
|
||||
this.attributes = attributes;
|
||||
this.nodes = nodes;
|
||||
|
||||
this.uniformsData = new WeakMap();
|
||||
|
||||
this.updateMap = new WeakMap();
|
||||
|
||||
}
|
||||
|
||||
get( object ) {
|
||||
|
||||
let data = this.uniformsData.get( object );
|
||||
|
||||
if ( data === undefined ) {
|
||||
|
||||
// each object defines an array of bindings (ubos, textures, samplers etc.)
|
||||
|
||||
const nodeBuilder = this.nodes.get( object );
|
||||
const bindings = nodeBuilder.getBindings();
|
||||
|
||||
// setup (static) binding layout and (dynamic) binding group
|
||||
|
||||
const renderPipeline = this.renderPipelines.get( object );
|
||||
|
||||
const bindLayout = renderPipeline.pipeline.getBindGroupLayout( 0 );
|
||||
const bindGroup = this._createBindGroup( bindings, bindLayout );
|
||||
|
||||
data = {
|
||||
layout: bindLayout,
|
||||
group: bindGroup,
|
||||
bindings: bindings
|
||||
};
|
||||
|
||||
this.uniformsData.set( object, data );
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
remove( object ) {
|
||||
|
||||
this.uniformsData.delete( object );
|
||||
|
||||
}
|
||||
|
||||
getForCompute( param ) {
|
||||
|
||||
let data = this.uniformsData.get( param );
|
||||
|
||||
if ( data === undefined ) {
|
||||
|
||||
// bindings are not yet retrieved via node material
|
||||
|
||||
const bindings = param.bindings !== undefined ? param.bindings.slice() : [];
|
||||
|
||||
const computePipeline = this.computePipelines.get( param );
|
||||
|
||||
const bindLayout = computePipeline.getBindGroupLayout( 0 );
|
||||
const bindGroup = this._createBindGroup( bindings, bindLayout );
|
||||
|
||||
data = {
|
||||
layout: bindLayout,
|
||||
group: bindGroup,
|
||||
bindings: bindings
|
||||
};
|
||||
|
||||
this.uniformsData.set( param, data );
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
update( object ) {
|
||||
|
||||
const textures = this.textures;
|
||||
|
||||
const data = this.get( object );
|
||||
const bindings = data.bindings;
|
||||
|
||||
const updateMap = this.updateMap;
|
||||
const frame = this.info.render.frame;
|
||||
|
||||
let needsBindGroupRefresh = false;
|
||||
|
||||
// iterate over all bindings and check if buffer updates or a new binding group is required
|
||||
|
||||
for ( const binding of bindings ) {
|
||||
|
||||
const isShared = binding.isShared;
|
||||
const isUpdated = updateMap.get( binding ) === frame;
|
||||
|
||||
if ( isShared && isUpdated ) continue;
|
||||
|
||||
if ( binding.isUniformBuffer ) {
|
||||
|
||||
const buffer = binding.getBuffer();
|
||||
const bufferGPU = binding.bufferGPU;
|
||||
|
||||
const needsBufferWrite = binding.update();
|
||||
|
||||
if ( needsBufferWrite === true ) {
|
||||
|
||||
this.device.queue.writeBuffer( bufferGPU, 0, buffer, 0 );
|
||||
|
||||
}
|
||||
|
||||
} else if ( binding.isStorageBuffer ) {
|
||||
|
||||
const attribute = binding.attribute;
|
||||
this.attributes.update( attribute, false, binding.usage );
|
||||
|
||||
} else if ( binding.isSampler ) {
|
||||
|
||||
const texture = binding.getTexture();
|
||||
|
||||
textures.updateSampler( texture );
|
||||
|
||||
const samplerGPU = textures.getSampler( texture );
|
||||
|
||||
if ( binding.samplerGPU !== samplerGPU ) {
|
||||
|
||||
binding.samplerGPU = samplerGPU;
|
||||
needsBindGroupRefresh = true;
|
||||
|
||||
}
|
||||
|
||||
} else if ( binding.isSampledTexture ) {
|
||||
|
||||
const texture = binding.getTexture();
|
||||
|
||||
const needsTextureRefresh = textures.updateTexture( texture );
|
||||
const textureGPU = textures.getTextureGPU( texture );
|
||||
|
||||
if ( textureGPU !== undefined && binding.textureGPU !== textureGPU || needsTextureRefresh === true ) {
|
||||
|
||||
binding.textureGPU = textureGPU;
|
||||
needsBindGroupRefresh = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
updateMap.set( binding, frame );
|
||||
|
||||
}
|
||||
|
||||
if ( needsBindGroupRefresh === true ) {
|
||||
|
||||
data.group = this._createBindGroup( bindings, data.layout );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
this.uniformsData = new WeakMap();
|
||||
this.updateMap = new WeakMap();
|
||||
|
||||
}
|
||||
|
||||
_createBindGroup( bindings, layout ) {
|
||||
|
||||
let bindingPoint = 0;
|
||||
const entries = [];
|
||||
|
||||
for ( const binding of bindings ) {
|
||||
|
||||
if ( binding.isUniformBuffer ) {
|
||||
|
||||
if ( binding.bufferGPU === null ) {
|
||||
|
||||
const byteLength = binding.getByteLength();
|
||||
|
||||
binding.bufferGPU = this.device.createBuffer( {
|
||||
size: byteLength,
|
||||
usage: binding.usage,
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
entries.push( { binding: bindingPoint, resource: { buffer: binding.bufferGPU } } );
|
||||
|
||||
} else if ( binding.isStorageBuffer ) {
|
||||
|
||||
if ( binding.bufferGPU === null ) {
|
||||
|
||||
const attribute = binding.attribute;
|
||||
|
||||
this.attributes.update( attribute, false, binding.usage );
|
||||
binding.bufferGPU = this.attributes.get( attribute ).buffer;
|
||||
|
||||
}
|
||||
|
||||
entries.push( { binding: bindingPoint, resource: { buffer: binding.bufferGPU } } );
|
||||
|
||||
} else if ( binding.isSampler ) {
|
||||
|
||||
if ( binding.samplerGPU === null ) {
|
||||
|
||||
binding.samplerGPU = this.textures.getDefaultSampler();
|
||||
|
||||
}
|
||||
|
||||
entries.push( { binding: bindingPoint, resource: binding.samplerGPU } );
|
||||
|
||||
} else if ( binding.isSampledTexture ) {
|
||||
|
||||
if ( binding.textureGPU === null ) {
|
||||
|
||||
if ( binding.isSampledCubeTexture ) {
|
||||
|
||||
binding.textureGPU = this.textures.getDefaultCubeTexture();
|
||||
|
||||
} else {
|
||||
|
||||
binding.textureGPU = this.textures.getDefaultTexture();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
entries.push( { binding: bindingPoint, resource: binding.textureGPU.createView( { dimension: binding.dimension } ) } );
|
||||
|
||||
}
|
||||
|
||||
bindingPoint ++;
|
||||
|
||||
}
|
||||
|
||||
return this.device.createBindGroup( {
|
||||
layout: layout,
|
||||
entries: entries
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUBindings;
|
||||
33
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUBufferUtils.js
generated
vendored
Normal file
33
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUBufferUtils.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { GPUChunkSize } from './constants.js';
|
||||
|
||||
function getFloatLength( floatLength ) {
|
||||
|
||||
// ensure chunk size alignment (STD140 layout)
|
||||
|
||||
return floatLength + ( ( GPUChunkSize - ( floatLength % GPUChunkSize ) ) % GPUChunkSize );
|
||||
|
||||
}
|
||||
|
||||
function getVectorLength( count, vectorLength = 4 ) {
|
||||
|
||||
const strideLength = getStrideLength( vectorLength );
|
||||
|
||||
const floatLength = strideLength * count;
|
||||
|
||||
return getFloatLength( floatLength );
|
||||
|
||||
}
|
||||
|
||||
function getStrideLength( vectorLength ) {
|
||||
|
||||
const strideLength = 4;
|
||||
|
||||
return vectorLength + ( ( strideLength - ( vectorLength % strideLength ) ) % strideLength );
|
||||
|
||||
}
|
||||
|
||||
export {
|
||||
getFloatLength,
|
||||
getVectorLength,
|
||||
getStrideLength
|
||||
};
|
||||
65
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUComputePipelines.js
generated
vendored
Normal file
65
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUComputePipelines.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
import WebGPUProgrammableStage from './WebGPUProgrammableStage.js';
|
||||
|
||||
class WebGPUComputePipelines {
|
||||
|
||||
constructor( device ) {
|
||||
|
||||
this.device = device;
|
||||
|
||||
this.pipelines = new WeakMap();
|
||||
this.stages = {
|
||||
compute: new WeakMap()
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
get( param ) {
|
||||
|
||||
let pipeline = this.pipelines.get( param );
|
||||
|
||||
// @TODO: Reuse compute pipeline if possible, introduce WebGPUComputePipeline
|
||||
|
||||
if ( pipeline === undefined ) {
|
||||
|
||||
const device = this.device;
|
||||
|
||||
const shader = {
|
||||
computeShader: param.shader
|
||||
};
|
||||
|
||||
// programmable stage
|
||||
|
||||
let stageCompute = this.stages.compute.get( shader );
|
||||
|
||||
if ( stageCompute === undefined ) {
|
||||
|
||||
stageCompute = new WebGPUProgrammableStage( device, shader.computeShader, 'compute' );
|
||||
|
||||
this.stages.compute.set( shader, stageCompute );
|
||||
|
||||
}
|
||||
|
||||
pipeline = device.createComputePipeline( {
|
||||
compute: stageCompute.stage
|
||||
} );
|
||||
|
||||
this.pipelines.set( param, pipeline );
|
||||
|
||||
}
|
||||
|
||||
return pipeline;
|
||||
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
this.pipelines = new WeakMap();
|
||||
this.stages = {
|
||||
compute: new WeakMap()
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUComputePipelines;
|
||||
76
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUGeometries.js
generated
vendored
Normal file
76
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUGeometries.js
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
class WebGPUGeometries {
|
||||
|
||||
constructor( attributes, info ) {
|
||||
|
||||
this.attributes = attributes;
|
||||
this.info = info;
|
||||
|
||||
this.geometries = new WeakMap();
|
||||
|
||||
}
|
||||
|
||||
update( geometry ) {
|
||||
|
||||
if ( this.geometries.has( geometry ) === false ) {
|
||||
|
||||
const disposeCallback = onGeometryDispose.bind( this );
|
||||
|
||||
this.geometries.set( geometry, disposeCallback );
|
||||
|
||||
this.info.memory.geometries ++;
|
||||
|
||||
geometry.addEventListener( 'dispose', disposeCallback );
|
||||
|
||||
}
|
||||
|
||||
const geometryAttributes = geometry.attributes;
|
||||
|
||||
for ( const name in geometryAttributes ) {
|
||||
|
||||
this.attributes.update( geometryAttributes[ name ] );
|
||||
|
||||
}
|
||||
|
||||
const index = geometry.index;
|
||||
|
||||
if ( index !== null ) {
|
||||
|
||||
this.attributes.update( index, true );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onGeometryDispose( event ) {
|
||||
|
||||
const geometry = event.target;
|
||||
const disposeCallback = this.geometries.get( geometry );
|
||||
|
||||
this.geometries.delete( geometry );
|
||||
|
||||
this.info.memory.geometries --;
|
||||
|
||||
geometry.removeEventListener( 'dispose', disposeCallback );
|
||||
|
||||
//
|
||||
|
||||
const index = geometry.index;
|
||||
const geometryAttributes = geometry.attributes;
|
||||
|
||||
if ( index !== null ) {
|
||||
|
||||
this.attributes.remove( index );
|
||||
|
||||
}
|
||||
|
||||
for ( const name in geometryAttributes ) {
|
||||
|
||||
this.attributes.remove( geometryAttributes[ name ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUGeometries;
|
||||
74
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUInfo.js
generated
vendored
Normal file
74
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUInfo.js
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
class WebGPUInfo {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.autoReset = true;
|
||||
|
||||
this.render = {
|
||||
frame: 0,
|
||||
drawCalls: 0,
|
||||
triangles: 0,
|
||||
points: 0,
|
||||
lines: 0
|
||||
};
|
||||
|
||||
this.memory = {
|
||||
geometries: 0,
|
||||
textures: 0
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
update( object, count, instanceCount ) {
|
||||
|
||||
this.render.drawCalls ++;
|
||||
|
||||
if ( object.isMesh ) {
|
||||
|
||||
this.render.triangles += instanceCount * ( count / 3 );
|
||||
|
||||
} else if ( object.isPoints ) {
|
||||
|
||||
this.render.points += instanceCount * count;
|
||||
|
||||
} else if ( object.isLineSegments ) {
|
||||
|
||||
this.render.lines += instanceCount * ( count / 2 );
|
||||
|
||||
} else if ( object.isLine ) {
|
||||
|
||||
this.render.lines += instanceCount * ( count - 1 );
|
||||
|
||||
} else {
|
||||
|
||||
console.error( 'THREE.WebGPUInfo: Unknown object type.' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
reset() {
|
||||
|
||||
this.render.frame ++;
|
||||
this.render.drawCalls = 0;
|
||||
this.render.triangles = 0;
|
||||
this.render.points = 0;
|
||||
this.render.lines = 0;
|
||||
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
this.reset();
|
||||
|
||||
this.render.frame = 0;
|
||||
|
||||
this.memory.geometries = 0;
|
||||
this.memory.textures = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export default WebGPUInfo;
|
||||
42
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUObjects.js
generated
vendored
Normal file
42
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUObjects.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
class WebGPUObjects {
|
||||
|
||||
constructor( geometries, info ) {
|
||||
|
||||
this.geometries = geometries;
|
||||
this.info = info;
|
||||
|
||||
this.updateMap = new WeakMap();
|
||||
|
||||
}
|
||||
|
||||
update( object ) {
|
||||
|
||||
const geometry = object.geometry;
|
||||
const updateMap = this.updateMap;
|
||||
const frame = this.info.render.frame;
|
||||
|
||||
if ( geometry.isBufferGeometry !== true ) {
|
||||
|
||||
throw new Error( 'THREE.WebGPURenderer: This renderer only supports THREE.BufferGeometry for geometries.' );
|
||||
|
||||
}
|
||||
|
||||
if ( updateMap.get( geometry ) !== frame ) {
|
||||
|
||||
this.geometries.update( geometry );
|
||||
|
||||
updateMap.set( geometry, frame );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
this.updateMap = new WeakMap();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUObjects;
|
||||
22
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUProgrammableStage.js
generated
vendored
Normal file
22
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUProgrammableStage.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
let _id = 0;
|
||||
|
||||
class WebGPUProgrammableStage {
|
||||
|
||||
constructor( device, code, type ) {
|
||||
|
||||
this.id = _id ++;
|
||||
|
||||
this.code = code;
|
||||
this.type = type;
|
||||
this.usedTimes = 0;
|
||||
|
||||
this.stage = {
|
||||
module: device.createShaderModule( { code } ),
|
||||
entryPoint: 'main'
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUProgrammableStage;
|
||||
38
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUProperties.js
generated
vendored
Normal file
38
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUProperties.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
class WebGPUProperties {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.properties = new WeakMap();
|
||||
|
||||
}
|
||||
|
||||
get( object ) {
|
||||
|
||||
let map = this.properties.get( object );
|
||||
|
||||
if ( map === undefined ) {
|
||||
|
||||
map = {};
|
||||
this.properties.set( object, map );
|
||||
|
||||
}
|
||||
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
remove( object ) {
|
||||
|
||||
this.properties.delete( object );
|
||||
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
this.properties = new WeakMap();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUProperties;
|
||||
199
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPURenderLists.js
generated
vendored
Normal file
199
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPURenderLists.js
generated
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
function painterSortStable( a, b ) {
|
||||
|
||||
if ( a.groupOrder !== b.groupOrder ) {
|
||||
|
||||
return a.groupOrder - b.groupOrder;
|
||||
|
||||
} else if ( a.renderOrder !== b.renderOrder ) {
|
||||
|
||||
return a.renderOrder - b.renderOrder;
|
||||
|
||||
} else if ( a.material.id !== b.material.id ) {
|
||||
|
||||
return a.material.id - b.material.id;
|
||||
|
||||
} else if ( a.z !== b.z ) {
|
||||
|
||||
return a.z - b.z;
|
||||
|
||||
} else {
|
||||
|
||||
return a.id - b.id;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function reversePainterSortStable( a, b ) {
|
||||
|
||||
if ( a.groupOrder !== b.groupOrder ) {
|
||||
|
||||
return a.groupOrder - b.groupOrder;
|
||||
|
||||
} else if ( a.renderOrder !== b.renderOrder ) {
|
||||
|
||||
return a.renderOrder - b.renderOrder;
|
||||
|
||||
} else if ( a.z !== b.z ) {
|
||||
|
||||
return b.z - a.z;
|
||||
|
||||
} else {
|
||||
|
||||
return a.id - b.id;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class WebGPURenderList {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.renderItems = [];
|
||||
this.renderItemsIndex = 0;
|
||||
|
||||
this.opaque = [];
|
||||
this.transparent = [];
|
||||
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
this.renderItemsIndex = 0;
|
||||
|
||||
this.opaque.length = 0;
|
||||
this.transparent.length = 0;
|
||||
|
||||
}
|
||||
|
||||
getNextRenderItem( object, geometry, material, groupOrder, z, group ) {
|
||||
|
||||
let renderItem = this.renderItems[ this.renderItemsIndex ];
|
||||
|
||||
if ( renderItem === undefined ) {
|
||||
|
||||
renderItem = {
|
||||
id: object.id,
|
||||
object: object,
|
||||
geometry: geometry,
|
||||
material: material,
|
||||
groupOrder: groupOrder,
|
||||
renderOrder: object.renderOrder,
|
||||
z: z,
|
||||
group: group
|
||||
};
|
||||
|
||||
this.renderItems[ this.renderItemsIndex ] = renderItem;
|
||||
|
||||
} else {
|
||||
|
||||
renderItem.id = object.id;
|
||||
renderItem.object = object;
|
||||
renderItem.geometry = geometry;
|
||||
renderItem.material = material;
|
||||
renderItem.groupOrder = groupOrder;
|
||||
renderItem.renderOrder = object.renderOrder;
|
||||
renderItem.z = z;
|
||||
renderItem.group = group;
|
||||
|
||||
}
|
||||
|
||||
this.renderItemsIndex ++;
|
||||
|
||||
return renderItem;
|
||||
|
||||
}
|
||||
|
||||
push( object, geometry, material, groupOrder, z, group ) {
|
||||
|
||||
const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group );
|
||||
|
||||
( material.transparent === true ? this.transparent : this.opaque ).push( renderItem );
|
||||
|
||||
}
|
||||
|
||||
unshift( object, geometry, material, groupOrder, z, group ) {
|
||||
|
||||
const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group );
|
||||
|
||||
( material.transparent === true ? this.transparent : this.opaque ).unshift( renderItem );
|
||||
|
||||
}
|
||||
|
||||
sort( customOpaqueSort, customTransparentSort ) {
|
||||
|
||||
if ( this.opaque.length > 1 ) this.opaque.sort( customOpaqueSort || painterSortStable );
|
||||
if ( this.transparent.length > 1 ) this.transparent.sort( customTransparentSort || reversePainterSortStable );
|
||||
|
||||
}
|
||||
|
||||
finish() {
|
||||
|
||||
// Clear references from inactive renderItems in the list
|
||||
|
||||
for ( let i = this.renderItemsIndex, il = this.renderItems.length; i < il; i ++ ) {
|
||||
|
||||
const renderItem = this.renderItems[ i ];
|
||||
|
||||
if ( renderItem.id === null ) break;
|
||||
|
||||
renderItem.id = null;
|
||||
renderItem.object = null;
|
||||
renderItem.geometry = null;
|
||||
renderItem.material = null;
|
||||
renderItem.program = null;
|
||||
renderItem.group = null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class WebGPURenderLists {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.lists = new WeakMap();
|
||||
|
||||
}
|
||||
|
||||
get( scene, camera ) {
|
||||
|
||||
const lists = this.lists;
|
||||
|
||||
const cameras = lists.get( scene );
|
||||
let list;
|
||||
|
||||
if ( cameras === undefined ) {
|
||||
|
||||
list = new WebGPURenderList();
|
||||
lists.set( scene, new WeakMap() );
|
||||
lists.get( scene ).set( camera, list );
|
||||
|
||||
} else {
|
||||
|
||||
list = cameras.get( camera );
|
||||
if ( list === undefined ) {
|
||||
|
||||
list = new WebGPURenderList();
|
||||
cameras.set( camera, list );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return list;
|
||||
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
this.lists = new WeakMap();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPURenderLists;
|
||||
737
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPURenderPipeline.js
generated
vendored
Normal file
737
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPURenderPipeline.js
generated
vendored
Normal file
@@ -0,0 +1,737 @@
|
||||
import { GPUPrimitiveTopology, GPUIndexFormat, GPUCompareFunction, GPUFrontFace, GPUCullMode, GPUVertexFormat, GPUBlendFactor, GPUBlendOperation, BlendColorFactor, OneMinusBlendColorFactor, GPUColorWriteFlags, GPUStencilOperation, GPUInputStepMode } from './constants.js';
|
||||
import {
|
||||
FrontSide, BackSide, DoubleSide,
|
||||
NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth,
|
||||
NeverStencilFunc, AlwaysStencilFunc, LessStencilFunc, LessEqualStencilFunc, EqualStencilFunc, GreaterEqualStencilFunc, GreaterStencilFunc, NotEqualStencilFunc,
|
||||
KeepStencilOp, ZeroStencilOp, ReplaceStencilOp, InvertStencilOp, IncrementStencilOp, DecrementStencilOp, IncrementWrapStencilOp, DecrementWrapStencilOp,
|
||||
NoBlending, NormalBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending, CustomBlending,
|
||||
AddEquation, SubtractEquation, ReverseSubtractEquation, MinEquation, MaxEquation,
|
||||
ZeroFactor, OneFactor, SrcColorFactor, OneMinusSrcColorFactor, SrcAlphaFactor, OneMinusSrcAlphaFactor, DstAlphaFactor, OneMinusDstAlphaFactor, DstColorFactor, OneMinusDstColorFactor, SrcAlphaSaturateFactor
|
||||
} from 'three';
|
||||
|
||||
class WebGPURenderPipeline {
|
||||
|
||||
constructor( device, renderer, sampleCount ) {
|
||||
|
||||
this.cacheKey = null;
|
||||
this.shaderAttributes = null;
|
||||
this.stageVertex = null;
|
||||
this.stageFragment = null;
|
||||
this.usedTimes = 0;
|
||||
|
||||
this._device = device;
|
||||
this._renderer = renderer;
|
||||
this._sampleCount = sampleCount;
|
||||
|
||||
}
|
||||
|
||||
init( cacheKey, stageVertex, stageFragment, object, nodeBuilder ) {
|
||||
|
||||
const material = object.material;
|
||||
const geometry = object.geometry;
|
||||
|
||||
// determine shader attributes
|
||||
|
||||
const shaderAttributes = this._getShaderAttributes( nodeBuilder, geometry );
|
||||
|
||||
// vertex buffers
|
||||
|
||||
const vertexBuffers = [];
|
||||
|
||||
for ( const attribute of shaderAttributes ) {
|
||||
|
||||
const name = attribute.name;
|
||||
const geometryAttribute = geometry.getAttribute( name );
|
||||
const stepMode = ( geometryAttribute !== undefined && geometryAttribute.isInstancedBufferAttribute ) ? GPUInputStepMode.Instance : GPUInputStepMode.Vertex;
|
||||
|
||||
vertexBuffers.push( {
|
||||
arrayStride: attribute.arrayStride,
|
||||
attributes: [ { shaderLocation: attribute.slot, offset: 0, format: attribute.format } ],
|
||||
stepMode: stepMode
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
this.cacheKey = cacheKey;
|
||||
this.shaderAttributes = shaderAttributes;
|
||||
this.stageVertex = stageVertex;
|
||||
this.stageFragment = stageFragment;
|
||||
|
||||
// blending
|
||||
|
||||
let alphaBlend = {};
|
||||
let colorBlend = {};
|
||||
|
||||
if ( material.transparent === true && material.blending !== NoBlending ) {
|
||||
|
||||
alphaBlend = this._getAlphaBlend( material );
|
||||
colorBlend = this._getColorBlend( material );
|
||||
|
||||
}
|
||||
|
||||
// stencil
|
||||
|
||||
let stencilFront = {};
|
||||
|
||||
if ( material.stencilWrite === true ) {
|
||||
|
||||
stencilFront = {
|
||||
compare: this._getStencilCompare( material ),
|
||||
failOp: this._getStencilOperation( material.stencilFail ),
|
||||
depthFailOp: this._getStencilOperation( material.stencilZFail ),
|
||||
passOp: this._getStencilOperation( material.stencilZPass )
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const primitiveState = this._getPrimitiveState( object, material );
|
||||
const colorWriteMask = this._getColorWriteMask( material );
|
||||
const depthCompare = this._getDepthCompare( material );
|
||||
const colorFormat = this._renderer.getCurrentColorFormat();
|
||||
const depthStencilFormat = this._renderer.getCurrentDepthStencilFormat();
|
||||
|
||||
this.pipeline = this._device.createRenderPipeline( {
|
||||
vertex: Object.assign( {}, stageVertex.stage, { buffers: vertexBuffers } ),
|
||||
fragment: Object.assign( {}, stageFragment.stage, { targets: [ {
|
||||
format: colorFormat,
|
||||
blend: {
|
||||
alpha: alphaBlend,
|
||||
color: colorBlend
|
||||
},
|
||||
writeMask: colorWriteMask
|
||||
} ] } ),
|
||||
primitive: primitiveState,
|
||||
depthStencil: {
|
||||
format: depthStencilFormat,
|
||||
depthWriteEnabled: material.depthWrite,
|
||||
depthCompare: depthCompare,
|
||||
stencilFront: stencilFront,
|
||||
stencilBack: {}, // three.js does not provide an API to configure the back function (gl.stencilFuncSeparate() was never used)
|
||||
stencilReadMask: material.stencilFuncMask,
|
||||
stencilWriteMask: material.stencilWriteMask
|
||||
},
|
||||
multisample: {
|
||||
count: this._sampleCount
|
||||
}
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
_getArrayStride( type, bytesPerElement ) {
|
||||
|
||||
// @TODO: This code is GLSL specific. We need to update when we switch to WGSL.
|
||||
|
||||
if ( type === 'float' || type === 'int' || type === 'uint' ) return bytesPerElement;
|
||||
if ( type === 'vec2' || type === 'ivec2' || type === 'uvec2' ) return bytesPerElement * 2;
|
||||
if ( type === 'vec3' || type === 'ivec3' || type === 'uvec3' ) return bytesPerElement * 3;
|
||||
if ( type === 'vec4' || type === 'ivec4' || type === 'uvec4' ) return bytesPerElement * 4;
|
||||
|
||||
console.error( 'THREE.WebGPURenderer: Shader variable type not supported yet.', type );
|
||||
|
||||
}
|
||||
|
||||
_getAlphaBlend( material ) {
|
||||
|
||||
const blending = material.blending;
|
||||
const premultipliedAlpha = material.premultipliedAlpha;
|
||||
|
||||
let alphaBlend = undefined;
|
||||
|
||||
switch ( blending ) {
|
||||
|
||||
case NormalBlending:
|
||||
|
||||
if ( premultipliedAlpha === false ) {
|
||||
|
||||
alphaBlend = {
|
||||
srcFactor: GPUBlendFactor.One,
|
||||
dstFactor: GPUBlendFactor.OneMinusSrcAlpha,
|
||||
operation: GPUBlendOperation.Add
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AdditiveBlending:
|
||||
// no alphaBlend settings
|
||||
break;
|
||||
|
||||
case SubtractiveBlending:
|
||||
|
||||
if ( premultipliedAlpha === true ) {
|
||||
|
||||
alphaBlend = {
|
||||
srcFactor: GPUBlendFactor.OneMinusSrcColor,
|
||||
dstFactor: GPUBlendFactor.OneMinusSrcAlpha,
|
||||
operation: GPUBlendOperation.Add
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MultiplyBlending:
|
||||
if ( premultipliedAlpha === true ) {
|
||||
|
||||
alphaBlend = {
|
||||
srcFactor: GPUBlendFactor.Zero,
|
||||
dstFactor: GPUBlendFactor.SrcAlpha,
|
||||
operation: GPUBlendOperation.Add
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CustomBlending:
|
||||
|
||||
const blendSrcAlpha = material.blendSrcAlpha;
|
||||
const blendDstAlpha = material.blendDstAlpha;
|
||||
const blendEquationAlpha = material.blendEquationAlpha;
|
||||
|
||||
if ( blendSrcAlpha !== null && blendDstAlpha !== null && blendEquationAlpha !== null ) {
|
||||
|
||||
alphaBlend = {
|
||||
srcFactor: this._getBlendFactor( blendSrcAlpha ),
|
||||
dstFactor: this._getBlendFactor( blendDstAlpha ),
|
||||
operation: this._getBlendOperation( blendEquationAlpha )
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPURenderer: Blending not supported.', blending );
|
||||
|
||||
}
|
||||
|
||||
return alphaBlend;
|
||||
|
||||
}
|
||||
|
||||
_getBlendFactor( blend ) {
|
||||
|
||||
let blendFactor;
|
||||
|
||||
switch ( blend ) {
|
||||
|
||||
case ZeroFactor:
|
||||
blendFactor = GPUBlendFactor.Zero;
|
||||
break;
|
||||
|
||||
case OneFactor:
|
||||
blendFactor = GPUBlendFactor.One;
|
||||
break;
|
||||
|
||||
case SrcColorFactor:
|
||||
blendFactor = GPUBlendFactor.SrcColor;
|
||||
break;
|
||||
|
||||
case OneMinusSrcColorFactor:
|
||||
blendFactor = GPUBlendFactor.OneMinusSrcColor;
|
||||
break;
|
||||
|
||||
case SrcAlphaFactor:
|
||||
blendFactor = GPUBlendFactor.SrcAlpha;
|
||||
break;
|
||||
|
||||
case OneMinusSrcAlphaFactor:
|
||||
blendFactor = GPUBlendFactor.OneMinusSrcAlpha;
|
||||
break;
|
||||
|
||||
case DstColorFactor:
|
||||
blendFactor = GPUBlendFactor.DstColor;
|
||||
break;
|
||||
|
||||
case OneMinusDstColorFactor:
|
||||
blendFactor = GPUBlendFactor.OneMinusDstColor;
|
||||
break;
|
||||
|
||||
case DstAlphaFactor:
|
||||
blendFactor = GPUBlendFactor.DstAlpha;
|
||||
break;
|
||||
|
||||
case OneMinusDstAlphaFactor:
|
||||
blendFactor = GPUBlendFactor.OneMinusDstAlpha;
|
||||
break;
|
||||
|
||||
case SrcAlphaSaturateFactor:
|
||||
blendFactor = GPUBlendFactor.SrcAlphaSaturated;
|
||||
break;
|
||||
|
||||
case BlendColorFactor:
|
||||
blendFactor = GPUBlendFactor.BlendColor;
|
||||
break;
|
||||
|
||||
case OneMinusBlendColorFactor:
|
||||
blendFactor = GPUBlendFactor.OneMinusBlendColor;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPURenderer: Blend factor not supported.', blend );
|
||||
|
||||
}
|
||||
|
||||
return blendFactor;
|
||||
|
||||
}
|
||||
|
||||
_getBlendOperation( blendEquation ) {
|
||||
|
||||
let blendOperation;
|
||||
|
||||
switch ( blendEquation ) {
|
||||
|
||||
case AddEquation:
|
||||
blendOperation = GPUBlendOperation.Add;
|
||||
break;
|
||||
|
||||
case SubtractEquation:
|
||||
blendOperation = GPUBlendOperation.Subtract;
|
||||
break;
|
||||
|
||||
case ReverseSubtractEquation:
|
||||
blendOperation = GPUBlendOperation.ReverseSubtract;
|
||||
break;
|
||||
|
||||
case MinEquation:
|
||||
blendOperation = GPUBlendOperation.Min;
|
||||
break;
|
||||
|
||||
case MaxEquation:
|
||||
blendOperation = GPUBlendOperation.Max;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPURenderer: Blend equation not supported.', blendEquation );
|
||||
|
||||
}
|
||||
|
||||
return blendOperation;
|
||||
|
||||
}
|
||||
|
||||
_getColorBlend( material ) {
|
||||
|
||||
const blending = material.blending;
|
||||
const premultipliedAlpha = material.premultipliedAlpha;
|
||||
|
||||
const colorBlend = {
|
||||
srcFactor: null,
|
||||
dstFactor: null,
|
||||
operation: null
|
||||
};
|
||||
|
||||
switch ( blending ) {
|
||||
|
||||
case NormalBlending:
|
||||
|
||||
colorBlend.srcFactor = ( premultipliedAlpha === true ) ? GPUBlendFactor.One : GPUBlendFactor.SrcAlpha;
|
||||
colorBlend.dstFactor = GPUBlendFactor.OneMinusSrcAlpha;
|
||||
colorBlend.operation = GPUBlendOperation.Add;
|
||||
break;
|
||||
|
||||
case AdditiveBlending:
|
||||
colorBlend.srcFactor = ( premultipliedAlpha === true ) ? GPUBlendFactor.One : GPUBlendFactor.SrcAlpha;
|
||||
colorBlend.operation = GPUBlendOperation.Add;
|
||||
break;
|
||||
|
||||
case SubtractiveBlending:
|
||||
colorBlend.srcFactor = GPUBlendFactor.Zero;
|
||||
colorBlend.dstFactor = ( premultipliedAlpha === true ) ? GPUBlendFactor.Zero : GPUBlendFactor.OneMinusSrcColor;
|
||||
colorBlend.operation = GPUBlendOperation.Add;
|
||||
break;
|
||||
|
||||
case MultiplyBlending:
|
||||
colorBlend.srcFactor = GPUBlendFactor.Zero;
|
||||
colorBlend.dstFactor = GPUBlendFactor.SrcColor;
|
||||
colorBlend.operation = GPUBlendOperation.Add;
|
||||
break;
|
||||
|
||||
case CustomBlending:
|
||||
colorBlend.srcFactor = this._getBlendFactor( material.blendSrc );
|
||||
colorBlend.dstFactor = this._getBlendFactor( material.blendDst );
|
||||
colorBlend.operation = this._getBlendOperation( material.blendEquation );
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPURenderer: Blending not supported.', blending );
|
||||
|
||||
}
|
||||
|
||||
return colorBlend;
|
||||
|
||||
}
|
||||
|
||||
_getColorWriteMask( material ) {
|
||||
|
||||
return ( material.colorWrite === true ) ? GPUColorWriteFlags.All : GPUColorWriteFlags.None;
|
||||
|
||||
}
|
||||
|
||||
_getDepthCompare( material ) {
|
||||
|
||||
let depthCompare;
|
||||
|
||||
if ( material.depthTest === false ) {
|
||||
|
||||
depthCompare = GPUCompareFunction.Always;
|
||||
|
||||
} else {
|
||||
|
||||
const depthFunc = material.depthFunc;
|
||||
|
||||
switch ( depthFunc ) {
|
||||
|
||||
case NeverDepth:
|
||||
depthCompare = GPUCompareFunction.Never;
|
||||
break;
|
||||
|
||||
case AlwaysDepth:
|
||||
depthCompare = GPUCompareFunction.Always;
|
||||
break;
|
||||
|
||||
case LessDepth:
|
||||
depthCompare = GPUCompareFunction.Less;
|
||||
break;
|
||||
|
||||
case LessEqualDepth:
|
||||
depthCompare = GPUCompareFunction.LessEqual;
|
||||
break;
|
||||
|
||||
case EqualDepth:
|
||||
depthCompare = GPUCompareFunction.Equal;
|
||||
break;
|
||||
|
||||
case GreaterEqualDepth:
|
||||
depthCompare = GPUCompareFunction.GreaterEqual;
|
||||
break;
|
||||
|
||||
case GreaterDepth:
|
||||
depthCompare = GPUCompareFunction.Greater;
|
||||
break;
|
||||
|
||||
case NotEqualDepth:
|
||||
depthCompare = GPUCompareFunction.NotEqual;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPURenderer: Invalid depth function.', depthFunc );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return depthCompare;
|
||||
|
||||
}
|
||||
|
||||
_getPrimitiveState( object, material ) {
|
||||
|
||||
const descriptor = {};
|
||||
|
||||
descriptor.topology = this._getPrimitiveTopology( object );
|
||||
|
||||
if ( object.isLine === true && object.isLineSegments !== true ) {
|
||||
|
||||
const geometry = object.geometry;
|
||||
const count = ( geometry.index ) ? geometry.index.count : geometry.attributes.position.count;
|
||||
descriptor.stripIndexFormat = ( count > 65535 ) ? GPUIndexFormat.Uint32 : GPUIndexFormat.Uint16; // define data type for primitive restart value
|
||||
|
||||
}
|
||||
|
||||
switch ( material.side ) {
|
||||
|
||||
case FrontSide:
|
||||
descriptor.frontFace = GPUFrontFace.CCW;
|
||||
descriptor.cullMode = GPUCullMode.Back;
|
||||
break;
|
||||
|
||||
case BackSide:
|
||||
descriptor.frontFace = GPUFrontFace.CW;
|
||||
descriptor.cullMode = GPUCullMode.Back;
|
||||
break;
|
||||
|
||||
case DoubleSide:
|
||||
descriptor.frontFace = GPUFrontFace.CCW;
|
||||
descriptor.cullMode = GPUCullMode.None;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPURenderer: Unknown Material.side value.', material.side );
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return descriptor;
|
||||
|
||||
}
|
||||
|
||||
_getPrimitiveTopology( object ) {
|
||||
|
||||
if ( object.isMesh ) return GPUPrimitiveTopology.TriangleList;
|
||||
else if ( object.isPoints ) return GPUPrimitiveTopology.PointList;
|
||||
else if ( object.isLineSegments ) return GPUPrimitiveTopology.LineList;
|
||||
else if ( object.isLine ) return GPUPrimitiveTopology.LineStrip;
|
||||
|
||||
}
|
||||
|
||||
_getStencilCompare( material ) {
|
||||
|
||||
let stencilCompare;
|
||||
|
||||
const stencilFunc = material.stencilFunc;
|
||||
|
||||
switch ( stencilFunc ) {
|
||||
|
||||
case NeverStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.Never;
|
||||
break;
|
||||
|
||||
case AlwaysStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.Always;
|
||||
break;
|
||||
|
||||
case LessStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.Less;
|
||||
break;
|
||||
|
||||
case LessEqualStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.LessEqual;
|
||||
break;
|
||||
|
||||
case EqualStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.Equal;
|
||||
break;
|
||||
|
||||
case GreaterEqualStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.GreaterEqual;
|
||||
break;
|
||||
|
||||
case GreaterStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.Greater;
|
||||
break;
|
||||
|
||||
case NotEqualStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.NotEqual;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPURenderer: Invalid stencil function.', stencilFunc );
|
||||
|
||||
}
|
||||
|
||||
return stencilCompare;
|
||||
|
||||
}
|
||||
|
||||
_getStencilOperation( op ) {
|
||||
|
||||
let stencilOperation;
|
||||
|
||||
switch ( op ) {
|
||||
|
||||
case KeepStencilOp:
|
||||
stencilOperation = GPUStencilOperation.Keep;
|
||||
break;
|
||||
|
||||
case ZeroStencilOp:
|
||||
stencilOperation = GPUStencilOperation.Zero;
|
||||
break;
|
||||
|
||||
case ReplaceStencilOp:
|
||||
stencilOperation = GPUStencilOperation.Replace;
|
||||
break;
|
||||
|
||||
case InvertStencilOp:
|
||||
stencilOperation = GPUStencilOperation.Invert;
|
||||
break;
|
||||
|
||||
case IncrementStencilOp:
|
||||
stencilOperation = GPUStencilOperation.IncrementClamp;
|
||||
break;
|
||||
|
||||
case DecrementStencilOp:
|
||||
stencilOperation = GPUStencilOperation.DecrementClamp;
|
||||
break;
|
||||
|
||||
case IncrementWrapStencilOp:
|
||||
stencilOperation = GPUStencilOperation.IncrementWrap;
|
||||
break;
|
||||
|
||||
case DecrementWrapStencilOp:
|
||||
stencilOperation = GPUStencilOperation.DecrementWrap;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPURenderer: Invalid stencil operation.', stencilOperation );
|
||||
|
||||
}
|
||||
|
||||
return stencilOperation;
|
||||
|
||||
}
|
||||
|
||||
_getVertexFormat( type, bytesPerElement ) {
|
||||
|
||||
// float
|
||||
|
||||
if ( type === 'float' ) return GPUVertexFormat.Float32;
|
||||
|
||||
if ( type === 'vec2' ) {
|
||||
|
||||
if ( bytesPerElement === 2 ) {
|
||||
|
||||
return GPUVertexFormat.Float16x2;
|
||||
|
||||
} else {
|
||||
|
||||
return GPUVertexFormat.Float32x2;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( type === 'vec3' ) return GPUVertexFormat.Float32x3;
|
||||
|
||||
if ( type === 'vec4' ) {
|
||||
|
||||
if ( bytesPerElement === 2 ) {
|
||||
|
||||
return GPUVertexFormat.Float16x4;
|
||||
|
||||
} else {
|
||||
|
||||
return GPUVertexFormat.Float32x4;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// int
|
||||
|
||||
if ( type === 'int' ) return GPUVertexFormat.Sint32;
|
||||
|
||||
if ( type === 'ivec2' ) {
|
||||
|
||||
if ( bytesPerElement === 1 ) {
|
||||
|
||||
return GPUVertexFormat.Sint8x2;
|
||||
|
||||
} else if ( bytesPerElement === 2 ) {
|
||||
|
||||
return GPUVertexFormat.Sint16x2;
|
||||
|
||||
} else {
|
||||
|
||||
return GPUVertexFormat.Sint32x2;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( type === 'ivec3' ) return GPUVertexFormat.Sint32x3;
|
||||
|
||||
if ( type === 'ivec4' ) {
|
||||
|
||||
if ( bytesPerElement === 1 ) {
|
||||
|
||||
return GPUVertexFormat.Sint8x4;
|
||||
|
||||
} else if ( bytesPerElement === 2 ) {
|
||||
|
||||
return GPUVertexFormat.Sint16x4;
|
||||
|
||||
} else {
|
||||
|
||||
return GPUVertexFormat.Sint32x4;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// uint
|
||||
|
||||
if ( type === 'uint' ) return GPUVertexFormat.Uint32;
|
||||
|
||||
if ( type === 'uvec2' ) {
|
||||
|
||||
if ( bytesPerElement === 1 ) {
|
||||
|
||||
return GPUVertexFormat.Uint8x2;
|
||||
|
||||
} else if ( bytesPerElement === 2 ) {
|
||||
|
||||
return GPUVertexFormat.Uint16x2;
|
||||
|
||||
} else {
|
||||
|
||||
return GPUVertexFormat.Uint32x2;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( type === 'uvec3' ) return GPUVertexFormat.Uint32x3;
|
||||
|
||||
if ( type === 'uvec4' ) {
|
||||
|
||||
if ( bytesPerElement === 1 ) {
|
||||
|
||||
return GPUVertexFormat.Uint8x4;
|
||||
|
||||
} else if ( bytesPerElement === 2 ) {
|
||||
|
||||
return GPUVertexFormat.Uint16x4;
|
||||
|
||||
} else {
|
||||
|
||||
return GPUVertexFormat.Uint32x4;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
console.error( 'THREE.WebGPURenderer: Shader variable type not supported yet.', type );
|
||||
|
||||
}
|
||||
|
||||
_getShaderAttributes( nodeBuilder, geometry ) {
|
||||
|
||||
const nodeAttributes = nodeBuilder.attributes;
|
||||
const attributes = [];
|
||||
|
||||
for ( let slot = 0; slot < nodeAttributes.length; slot ++ ) {
|
||||
|
||||
const nodeAttribute = nodeAttributes[ slot ];
|
||||
|
||||
const name = nodeAttribute.name;
|
||||
const type = nodeAttribute.type;
|
||||
|
||||
const geometryAttribute = geometry.getAttribute( name );
|
||||
const bytesPerElement = ( geometryAttribute !== undefined ) ? geometryAttribute.array.BYTES_PER_ELEMENT : 4;
|
||||
|
||||
const arrayStride = this._getArrayStride( type, bytesPerElement );
|
||||
const format = this._getVertexFormat( type, bytesPerElement );
|
||||
|
||||
attributes.push( {
|
||||
name,
|
||||
arrayStride,
|
||||
format,
|
||||
slot
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
return attributes;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPURenderPipeline;
|
||||
293
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPURenderPipelines.js
generated
vendored
Normal file
293
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPURenderPipelines.js
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
import WebGPURenderPipeline from './WebGPURenderPipeline.js';
|
||||
import WebGPUProgrammableStage from './WebGPUProgrammableStage.js';
|
||||
|
||||
class WebGPURenderPipelines {
|
||||
|
||||
constructor( renderer, device, sampleCount, nodes, bindings = null ) {
|
||||
|
||||
this.renderer = renderer;
|
||||
this.device = device;
|
||||
this.sampleCount = sampleCount;
|
||||
this.nodes = nodes;
|
||||
this.bindings = bindings;
|
||||
|
||||
this.pipelines = [];
|
||||
this.objectCache = new WeakMap();
|
||||
|
||||
this.stages = {
|
||||
vertex: new Map(),
|
||||
fragment: new Map()
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
get( object ) {
|
||||
|
||||
const device = this.device;
|
||||
const material = object.material;
|
||||
|
||||
const cache = this._getCache( object );
|
||||
|
||||
let currentPipeline;
|
||||
|
||||
if ( this._needsUpdate( object, cache ) ) {
|
||||
|
||||
// release previous cache
|
||||
|
||||
if ( cache.currentPipeline !== undefined ) {
|
||||
|
||||
this._releaseObject( object );
|
||||
|
||||
}
|
||||
|
||||
// get shader
|
||||
|
||||
const nodeBuilder = this.nodes.get( object );
|
||||
|
||||
// programmable stages
|
||||
|
||||
let stageVertex = this.stages.vertex.get( nodeBuilder.vertexShader );
|
||||
|
||||
if ( stageVertex === undefined ) {
|
||||
|
||||
stageVertex = new WebGPUProgrammableStage( device, nodeBuilder.vertexShader, 'vertex' );
|
||||
this.stages.vertex.set( nodeBuilder.vertexShader, stageVertex );
|
||||
|
||||
}
|
||||
|
||||
let stageFragment = this.stages.fragment.get( nodeBuilder.fragmentShader );
|
||||
|
||||
if ( stageFragment === undefined ) {
|
||||
|
||||
stageFragment = new WebGPUProgrammableStage( device, nodeBuilder.fragmentShader, 'fragment' );
|
||||
this.stages.fragment.set( nodeBuilder.fragmentShader, stageFragment );
|
||||
|
||||
}
|
||||
|
||||
// determine render pipeline
|
||||
|
||||
currentPipeline = this._acquirePipeline( stageVertex, stageFragment, object, nodeBuilder );
|
||||
cache.currentPipeline = currentPipeline;
|
||||
|
||||
// keep track of all used times
|
||||
|
||||
currentPipeline.usedTimes ++;
|
||||
stageVertex.usedTimes ++;
|
||||
stageFragment.usedTimes ++;
|
||||
|
||||
// events
|
||||
|
||||
material.addEventListener( 'dispose', cache.dispose );
|
||||
|
||||
} else {
|
||||
|
||||
currentPipeline = cache.currentPipeline;
|
||||
|
||||
}
|
||||
|
||||
return currentPipeline;
|
||||
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
this.pipelines = [];
|
||||
this.objectCache = new WeakMap();
|
||||
this.shaderModules = {
|
||||
vertex: new Map(),
|
||||
fragment: new Map()
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
_acquirePipeline( stageVertex, stageFragment, object, nodeBuilder ) {
|
||||
|
||||
let pipeline;
|
||||
const pipelines = this.pipelines;
|
||||
|
||||
// check for existing pipeline
|
||||
|
||||
const cacheKey = this._computeCacheKey( stageVertex, stageFragment, object );
|
||||
|
||||
for ( let i = 0, il = pipelines.length; i < il; i ++ ) {
|
||||
|
||||
const preexistingPipeline = pipelines[ i ];
|
||||
|
||||
if ( preexistingPipeline.cacheKey === cacheKey ) {
|
||||
|
||||
pipeline = preexistingPipeline;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( pipeline === undefined ) {
|
||||
|
||||
pipeline = new WebGPURenderPipeline( this.device, this.renderer, this.sampleCount );
|
||||
pipeline.init( cacheKey, stageVertex, stageFragment, object, nodeBuilder );
|
||||
|
||||
pipelines.push( pipeline );
|
||||
|
||||
}
|
||||
|
||||
return pipeline;
|
||||
|
||||
}
|
||||
|
||||
_computeCacheKey( stageVertex, stageFragment, object ) {
|
||||
|
||||
const material = object.material;
|
||||
const renderer = this.renderer;
|
||||
|
||||
const parameters = [
|
||||
stageVertex.id, stageFragment.id,
|
||||
material.transparent, material.blending, material.premultipliedAlpha,
|
||||
material.blendSrc, material.blendDst, material.blendEquation,
|
||||
material.blendSrcAlpha, material.blendDstAlpha, material.blendEquationAlpha,
|
||||
material.colorWrite,
|
||||
material.depthWrite, material.depthTest, material.depthFunc,
|
||||
material.stencilWrite, material.stencilFunc,
|
||||
material.stencilFail, material.stencilZFail, material.stencilZPass,
|
||||
material.stencilFuncMask, material.stencilWriteMask,
|
||||
material.side,
|
||||
this.sampleCount,
|
||||
renderer.getCurrentEncoding(), renderer.getCurrentColorFormat(), renderer.getCurrentDepthStencilFormat()
|
||||
];
|
||||
|
||||
return parameters.join();
|
||||
|
||||
}
|
||||
|
||||
_getCache( object ) {
|
||||
|
||||
let cache = this.objectCache.get( object );
|
||||
|
||||
if ( cache === undefined ) {
|
||||
|
||||
cache = {
|
||||
|
||||
dispose: () => {
|
||||
|
||||
this._releaseObject( object );
|
||||
|
||||
this.objectCache.delete( object );
|
||||
|
||||
object.material.removeEventListener( 'dispose', cache.dispose );
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.objectCache.set( object, cache );
|
||||
|
||||
}
|
||||
|
||||
return cache;
|
||||
|
||||
}
|
||||
|
||||
_releaseObject( object ) {
|
||||
|
||||
const cache = this.objectCache.get( object );
|
||||
|
||||
this._releasePipeline( cache.currentPipeline );
|
||||
delete cache.currentPipeline;
|
||||
|
||||
this.nodes.remove( object );
|
||||
this.bindings.remove( object );
|
||||
|
||||
}
|
||||
|
||||
_releasePipeline( pipeline ) {
|
||||
|
||||
if ( -- pipeline.usedTimes === 0 ) {
|
||||
|
||||
const pipelines = this.pipelines;
|
||||
|
||||
const i = pipelines.indexOf( pipeline );
|
||||
pipelines[ i ] = pipelines[ pipelines.length - 1 ];
|
||||
pipelines.pop();
|
||||
|
||||
this._releaseStage( pipeline.stageVertex );
|
||||
this._releaseStage( pipeline.stageFragment );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_releaseStage( stage ) {
|
||||
|
||||
if ( -- stage.usedTimes === 0 ) {
|
||||
|
||||
const code = stage.code;
|
||||
const type = stage.type;
|
||||
|
||||
this.stages[ type ].delete( code );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_needsUpdate( object, cache ) {
|
||||
|
||||
const material = object.material;
|
||||
|
||||
let needsUpdate = false;
|
||||
|
||||
// check material state
|
||||
|
||||
if ( cache.material !== material || cache.materialVersion !== material.version ||
|
||||
cache.transparent !== material.transparent || cache.blending !== material.blending || cache.premultipliedAlpha !== material.premultipliedAlpha ||
|
||||
cache.blendSrc !== material.blendSrc || cache.blendDst !== material.blendDst || cache.blendEquation !== material.blendEquation ||
|
||||
cache.blendSrcAlpha !== material.blendSrcAlpha || cache.blendDstAlpha !== material.blendDstAlpha || cache.blendEquationAlpha !== material.blendEquationAlpha ||
|
||||
cache.colorWrite !== material.colorWrite ||
|
||||
cache.depthWrite !== material.depthWrite || cache.depthTest !== material.depthTest || cache.depthFunc !== material.depthFunc ||
|
||||
cache.stencilWrite !== material.stencilWrite || cache.stencilFunc !== material.stencilFunc ||
|
||||
cache.stencilFail !== material.stencilFail || cache.stencilZFail !== material.stencilZFail || cache.stencilZPass !== material.stencilZPass ||
|
||||
cache.stencilFuncMask !== material.stencilFuncMask || cache.stencilWriteMask !== material.stencilWriteMask ||
|
||||
cache.side !== material.side
|
||||
) {
|
||||
|
||||
cache.material = material; cache.materialVersion = material.version;
|
||||
cache.transparent = material.transparent; cache.blending = material.blending; cache.premultipliedAlpha = material.premultipliedAlpha;
|
||||
cache.blendSrc = material.blendSrc; cache.blendDst = material.blendDst; cache.blendEquation = material.blendEquation;
|
||||
cache.blendSrcAlpha = material.blendSrcAlpha; cache.blendDstAlpha = material.blendDstAlpha; cache.blendEquationAlpha = material.blendEquationAlpha;
|
||||
cache.colorWrite = material.colorWrite;
|
||||
cache.depthWrite = material.depthWrite; cache.depthTest = material.depthTest; cache.depthFunc = material.depthFunc;
|
||||
cache.stencilWrite = material.stencilWrite; cache.stencilFunc = material.stencilFunc;
|
||||
cache.stencilFail = material.stencilFail; cache.stencilZFail = material.stencilZFail; cache.stencilZPass = material.stencilZPass;
|
||||
cache.stencilFuncMask = material.stencilFuncMask; cache.stencilWriteMask = material.stencilWriteMask;
|
||||
cache.side = material.side;
|
||||
|
||||
needsUpdate = true;
|
||||
|
||||
}
|
||||
|
||||
// check renderer state
|
||||
|
||||
const renderer = this.renderer;
|
||||
|
||||
const encoding = renderer.getCurrentEncoding();
|
||||
const colorFormat = renderer.getCurrentColorFormat();
|
||||
const depthStencilFormat = renderer.getCurrentDepthStencilFormat();
|
||||
|
||||
if ( cache.sampleCount !== this.sampleCount || cache.encoding !== encoding ||
|
||||
cache.colorFormat !== colorFormat || cache.depthStencilFormat !== depthStencilFormat ) {
|
||||
|
||||
cache.sampleCount = this.sampleCount;
|
||||
cache.encoding = encoding;
|
||||
cache.colorFormat = colorFormat;
|
||||
cache.depthStencilFormat = depthStencilFormat;
|
||||
|
||||
needsUpdate = true;
|
||||
|
||||
}
|
||||
|
||||
return needsUpdate;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPURenderPipelines;
|
||||
961
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPURenderer.js
generated
vendored
Normal file
961
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPURenderer.js
generated
vendored
Normal file
@@ -0,0 +1,961 @@
|
||||
import { GPUIndexFormat, GPUTextureFormat, GPUStoreOp } from './constants.js';
|
||||
import WebGPUObjects from './WebGPUObjects.js';
|
||||
import WebGPUAttributes from './WebGPUAttributes.js';
|
||||
import WebGPUGeometries from './WebGPUGeometries.js';
|
||||
import WebGPUInfo from './WebGPUInfo.js';
|
||||
import WebGPUProperties from './WebGPUProperties.js';
|
||||
import WebGPURenderPipelines from './WebGPURenderPipelines.js';
|
||||
import WebGPUComputePipelines from './WebGPUComputePipelines.js';
|
||||
import WebGPUBindings from './WebGPUBindings.js';
|
||||
import WebGPURenderLists from './WebGPURenderLists.js';
|
||||
import WebGPUTextures from './WebGPUTextures.js';
|
||||
import WebGPUBackground from './WebGPUBackground.js';
|
||||
import WebGPUNodes from './nodes/WebGPUNodes.js';
|
||||
|
||||
import { Frustum, Matrix4, Vector3, Color, LinearEncoding } from 'three';
|
||||
|
||||
console.info( 'THREE.WebGPURenderer: Modified Matrix4.makePerspective() and Matrix4.makeOrtographic() to work with WebGPU, see https://github.com/mrdoob/three.js/issues/20276.' );
|
||||
|
||||
Matrix4.prototype.makePerspective = function ( left, right, top, bottom, near, far ) {
|
||||
|
||||
const te = this.elements;
|
||||
const x = 2 * near / ( right - left );
|
||||
const y = 2 * near / ( top - bottom );
|
||||
|
||||
const a = ( right + left ) / ( right - left );
|
||||
const b = ( top + bottom ) / ( top - bottom );
|
||||
const c = - far / ( far - near );
|
||||
const d = - far * near / ( far - near );
|
||||
|
||||
te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0;
|
||||
te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0;
|
||||
te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d;
|
||||
te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0;
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
Matrix4.prototype.makeOrthographic = function ( left, right, top, bottom, near, far ) {
|
||||
|
||||
const te = this.elements;
|
||||
const w = 1.0 / ( right - left );
|
||||
const h = 1.0 / ( top - bottom );
|
||||
const p = 1.0 / ( far - near );
|
||||
|
||||
const x = ( right + left ) * w;
|
||||
const y = ( top + bottom ) * h;
|
||||
const z = near * p;
|
||||
|
||||
te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
|
||||
te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y;
|
||||
te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 1 * p; te[ 14 ] = - z;
|
||||
te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
|
||||
const _frustum = new Frustum();
|
||||
const _projScreenMatrix = new Matrix4();
|
||||
const _vector3 = new Vector3();
|
||||
|
||||
class WebGPURenderer {
|
||||
|
||||
constructor( parameters = {} ) {
|
||||
|
||||
// public
|
||||
|
||||
this.domElement = ( parameters.canvas !== undefined ) ? parameters.canvas : this._createCanvasElement();
|
||||
|
||||
this.autoClear = true;
|
||||
this.autoClearColor = true;
|
||||
this.autoClearDepth = true;
|
||||
this.autoClearStencil = true;
|
||||
|
||||
this.outputEncoding = LinearEncoding;
|
||||
|
||||
this.sortObjects = true;
|
||||
|
||||
// internals
|
||||
|
||||
this._parameters = Object.assign( {}, parameters );
|
||||
|
||||
this._pixelRatio = 1;
|
||||
this._width = this.domElement.width;
|
||||
this._height = this.domElement.height;
|
||||
|
||||
this._viewport = null;
|
||||
this._scissor = null;
|
||||
|
||||
this._adapter = null;
|
||||
this._device = null;
|
||||
this._context = null;
|
||||
this._colorBuffer = null;
|
||||
this._depthBuffer = null;
|
||||
|
||||
this._info = null;
|
||||
this._properties = null;
|
||||
this._attributes = null;
|
||||
this._geometries = null;
|
||||
this._nodes = null;
|
||||
this._bindings = null;
|
||||
this._objects = null;
|
||||
this._renderPipelines = null;
|
||||
this._computePipelines = null;
|
||||
this._renderLists = null;
|
||||
this._textures = null;
|
||||
this._background = null;
|
||||
|
||||
this._renderPassDescriptor = null;
|
||||
|
||||
this._currentRenderList = null;
|
||||
this._opaqueSort = null;
|
||||
this._transparentSort = null;
|
||||
|
||||
this._clearAlpha = 1;
|
||||
this._clearColor = new Color( 0x000000 );
|
||||
this._clearDepth = 1;
|
||||
this._clearStencil = 0;
|
||||
|
||||
this._renderTarget = null;
|
||||
|
||||
// some parameters require default values other than "undefined"
|
||||
|
||||
this._parameters.antialias = ( parameters.antialias === true );
|
||||
|
||||
if ( this._parameters.antialias === true ) {
|
||||
|
||||
this._parameters.sampleCount = ( parameters.sampleCount === undefined ) ? 4 : parameters.sampleCount;
|
||||
|
||||
} else {
|
||||
|
||||
this._parameters.sampleCount = 1;
|
||||
|
||||
}
|
||||
|
||||
this._parameters.requiredFeatures = ( parameters.requiredFeatures === undefined ) ? [] : parameters.requiredFeatures;
|
||||
this._parameters.requiredLimits = ( parameters.requiredLimits === undefined ) ? {} : parameters.requiredLimits;
|
||||
|
||||
}
|
||||
|
||||
async init() {
|
||||
|
||||
const parameters = this._parameters;
|
||||
|
||||
const adapterOptions = {
|
||||
powerPreference: parameters.powerPreference
|
||||
};
|
||||
|
||||
const adapter = await navigator.gpu.requestAdapter( adapterOptions );
|
||||
|
||||
if ( adapter === null ) {
|
||||
|
||||
throw new Error( 'WebGPURenderer: Unable to create WebGPU adapter.' );
|
||||
|
||||
}
|
||||
|
||||
const deviceDescriptor = {
|
||||
requiredFeatures: parameters.requiredFeatures,
|
||||
requiredLimits: parameters.requiredLimits
|
||||
};
|
||||
|
||||
const device = await adapter.requestDevice( deviceDescriptor );
|
||||
|
||||
const context = ( parameters.context !== undefined ) ? parameters.context : this.domElement.getContext( 'webgpu' );
|
||||
|
||||
context.configure( {
|
||||
device: device,
|
||||
format: GPUTextureFormat.BGRA8Unorm // this is the only valid context format right now (r121)
|
||||
} );
|
||||
|
||||
this._adapter = adapter;
|
||||
this._device = device;
|
||||
this._context = context;
|
||||
|
||||
this._info = new WebGPUInfo();
|
||||
this._properties = new WebGPUProperties();
|
||||
this._attributes = new WebGPUAttributes( device );
|
||||
this._geometries = new WebGPUGeometries( this._attributes, this._info );
|
||||
this._textures = new WebGPUTextures( device, this._properties, this._info );
|
||||
this._objects = new WebGPUObjects( this._geometries, this._info );
|
||||
this._nodes = new WebGPUNodes( this );
|
||||
this._computePipelines = new WebGPUComputePipelines( device );
|
||||
this._renderPipelines = new WebGPURenderPipelines( this, device, parameters.sampleCount, this._nodes );
|
||||
this._bindings = this._renderPipelines.bindings = new WebGPUBindings( device, this._info, this._properties, this._textures, this._renderPipelines, this._computePipelines, this._attributes, this._nodes );
|
||||
this._renderLists = new WebGPURenderLists();
|
||||
this._background = new WebGPUBackground( this );
|
||||
|
||||
//
|
||||
|
||||
this._renderPassDescriptor = {
|
||||
colorAttachments: [ {
|
||||
view: null
|
||||
} ],
|
||||
depthStencilAttachment: {
|
||||
view: null,
|
||||
depthStoreOp: GPUStoreOp.Store,
|
||||
stencilStoreOp: GPUStoreOp.Store
|
||||
}
|
||||
};
|
||||
|
||||
this._setupColorBuffer();
|
||||
this._setupDepthBuffer();
|
||||
|
||||
}
|
||||
|
||||
render( scene, camera ) {
|
||||
|
||||
// @TODO: move this to animation loop
|
||||
|
||||
this._nodes.updateFrame();
|
||||
|
||||
//
|
||||
|
||||
if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
|
||||
|
||||
if ( camera.parent === null ) camera.updateMatrixWorld();
|
||||
|
||||
if ( this._info.autoReset === true ) this._info.reset();
|
||||
|
||||
_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
|
||||
_frustum.setFromProjectionMatrix( _projScreenMatrix );
|
||||
|
||||
this._currentRenderList = this._renderLists.get( scene, camera );
|
||||
this._currentRenderList.init();
|
||||
|
||||
this._projectObject( scene, camera, 0 );
|
||||
|
||||
this._currentRenderList.finish();
|
||||
|
||||
if ( this.sortObjects === true ) {
|
||||
|
||||
this._currentRenderList.sort( this._opaqueSort, this._transparentSort );
|
||||
|
||||
}
|
||||
|
||||
// prepare render pass descriptor
|
||||
|
||||
const colorAttachment = this._renderPassDescriptor.colorAttachments[ 0 ];
|
||||
const depthStencilAttachment = this._renderPassDescriptor.depthStencilAttachment;
|
||||
|
||||
const renderTarget = this._renderTarget;
|
||||
|
||||
if ( renderTarget !== null ) {
|
||||
|
||||
// @TODO: Support RenderTarget with antialiasing.
|
||||
|
||||
const renderTargetProperties = this._properties.get( renderTarget );
|
||||
|
||||
colorAttachment.view = renderTargetProperties.colorTextureGPU.createView();
|
||||
depthStencilAttachment.view = renderTargetProperties.depthTextureGPU.createView();
|
||||
|
||||
} else {
|
||||
|
||||
if ( this._parameters.antialias === true ) {
|
||||
|
||||
colorAttachment.view = this._colorBuffer.createView();
|
||||
colorAttachment.resolveTarget = this._context.getCurrentTexture().createView();
|
||||
|
||||
} else {
|
||||
|
||||
colorAttachment.view = this._context.getCurrentTexture().createView();
|
||||
colorAttachment.resolveTarget = undefined;
|
||||
|
||||
}
|
||||
|
||||
depthStencilAttachment.view = this._depthBuffer.createView();
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
this._background.update( scene );
|
||||
|
||||
// start render pass
|
||||
|
||||
const device = this._device;
|
||||
const cmdEncoder = device.createCommandEncoder( {} );
|
||||
const passEncoder = cmdEncoder.beginRenderPass( this._renderPassDescriptor );
|
||||
|
||||
// global rasterization settings for all renderable objects
|
||||
|
||||
const vp = this._viewport;
|
||||
|
||||
if ( vp !== null ) {
|
||||
|
||||
const width = Math.floor( vp.width * this._pixelRatio );
|
||||
const height = Math.floor( vp.height * this._pixelRatio );
|
||||
|
||||
passEncoder.setViewport( vp.x, vp.y, width, height, vp.minDepth, vp.maxDepth );
|
||||
|
||||
}
|
||||
|
||||
const sc = this._scissor;
|
||||
|
||||
if ( sc !== null ) {
|
||||
|
||||
const width = Math.floor( sc.width * this._pixelRatio );
|
||||
const height = Math.floor( sc.height * this._pixelRatio );
|
||||
|
||||
passEncoder.setScissorRect( sc.x, sc.y, width, height );
|
||||
|
||||
}
|
||||
|
||||
// process render lists
|
||||
|
||||
const opaqueObjects = this._currentRenderList.opaque;
|
||||
const transparentObjects = this._currentRenderList.transparent;
|
||||
|
||||
if ( opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, passEncoder );
|
||||
if ( transparentObjects.length > 0 ) this._renderObjects( transparentObjects, camera, passEncoder );
|
||||
|
||||
// finish render pass
|
||||
|
||||
passEncoder.end();
|
||||
device.queue.submit( [ cmdEncoder.finish() ] );
|
||||
|
||||
}
|
||||
|
||||
getContext() {
|
||||
|
||||
return this._context;
|
||||
|
||||
}
|
||||
|
||||
getPixelRatio() {
|
||||
|
||||
return this._pixelRatio;
|
||||
|
||||
}
|
||||
|
||||
getDrawingBufferSize( target ) {
|
||||
|
||||
return target.set( this._width * this._pixelRatio, this._height * this._pixelRatio ).floor();
|
||||
|
||||
}
|
||||
|
||||
getSize( target ) {
|
||||
|
||||
return target.set( this._width, this._height );
|
||||
|
||||
}
|
||||
|
||||
setPixelRatio( value = 1 ) {
|
||||
|
||||
this._pixelRatio = value;
|
||||
|
||||
this.setSize( this._width, this._height, false );
|
||||
|
||||
}
|
||||
|
||||
setDrawingBufferSize( width, height, pixelRatio ) {
|
||||
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
|
||||
this._pixelRatio = pixelRatio;
|
||||
|
||||
this.domElement.width = Math.floor( width * pixelRatio );
|
||||
this.domElement.height = Math.floor( height * pixelRatio );
|
||||
|
||||
this._configureContext();
|
||||
this._setupColorBuffer();
|
||||
this._setupDepthBuffer();
|
||||
|
||||
}
|
||||
|
||||
setSize( width, height, updateStyle = true ) {
|
||||
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
|
||||
this.domElement.width = Math.floor( width * this._pixelRatio );
|
||||
this.domElement.height = Math.floor( height * this._pixelRatio );
|
||||
|
||||
if ( updateStyle === true ) {
|
||||
|
||||
this.domElement.style.width = width + 'px';
|
||||
this.domElement.style.height = height + 'px';
|
||||
|
||||
}
|
||||
|
||||
this._configureContext();
|
||||
this._setupColorBuffer();
|
||||
this._setupDepthBuffer();
|
||||
|
||||
}
|
||||
|
||||
setOpaqueSort( method ) {
|
||||
|
||||
this._opaqueSort = method;
|
||||
|
||||
}
|
||||
|
||||
setTransparentSort( method ) {
|
||||
|
||||
this._transparentSort = method;
|
||||
|
||||
}
|
||||
|
||||
getScissor( target ) {
|
||||
|
||||
const scissor = this._scissor;
|
||||
|
||||
target.x = scissor.x;
|
||||
target.y = scissor.y;
|
||||
target.width = scissor.width;
|
||||
target.height = scissor.height;
|
||||
|
||||
return target;
|
||||
|
||||
}
|
||||
|
||||
setScissor( x, y, width, height ) {
|
||||
|
||||
if ( x === null ) {
|
||||
|
||||
this._scissor = null;
|
||||
|
||||
} else {
|
||||
|
||||
this._scissor = {
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getViewport( target ) {
|
||||
|
||||
const viewport = this._viewport;
|
||||
|
||||
target.x = viewport.x;
|
||||
target.y = viewport.y;
|
||||
target.width = viewport.width;
|
||||
target.height = viewport.height;
|
||||
target.minDepth = viewport.minDepth;
|
||||
target.maxDepth = viewport.maxDepth;
|
||||
|
||||
return target;
|
||||
|
||||
}
|
||||
|
||||
setViewport( x, y, width, height, minDepth = 0, maxDepth = 1 ) {
|
||||
|
||||
if ( x === null ) {
|
||||
|
||||
this._viewport = null;
|
||||
|
||||
} else {
|
||||
|
||||
this._viewport = {
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height,
|
||||
minDepth: minDepth,
|
||||
maxDepth: maxDepth
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getCurrentEncoding() {
|
||||
|
||||
const renderTarget = this.getRenderTarget();
|
||||
return ( renderTarget !== null ) ? renderTarget.texture.encoding : this.outputEncoding;
|
||||
|
||||
}
|
||||
|
||||
getCurrentColorFormat() {
|
||||
|
||||
let format;
|
||||
|
||||
const renderTarget = this.getRenderTarget();
|
||||
|
||||
if ( renderTarget !== null ) {
|
||||
|
||||
const renderTargetProperties = this._properties.get( renderTarget );
|
||||
format = renderTargetProperties.colorTextureFormat;
|
||||
|
||||
} else {
|
||||
|
||||
format = GPUTextureFormat.BGRA8Unorm; // default context format
|
||||
|
||||
}
|
||||
|
||||
return format;
|
||||
|
||||
}
|
||||
|
||||
getCurrentDepthStencilFormat() {
|
||||
|
||||
let format;
|
||||
|
||||
const renderTarget = this.getRenderTarget();
|
||||
|
||||
if ( renderTarget !== null ) {
|
||||
|
||||
const renderTargetProperties = this._properties.get( renderTarget );
|
||||
format = renderTargetProperties.depthTextureFormat;
|
||||
|
||||
} else {
|
||||
|
||||
format = GPUTextureFormat.Depth24PlusStencil8;
|
||||
|
||||
}
|
||||
|
||||
return format;
|
||||
|
||||
}
|
||||
|
||||
getClearColor( target ) {
|
||||
|
||||
return target.copy( this._clearColor );
|
||||
|
||||
}
|
||||
|
||||
setClearColor( color, alpha = 1 ) {
|
||||
|
||||
this._clearColor.set( color );
|
||||
this._clearAlpha = alpha;
|
||||
|
||||
}
|
||||
|
||||
getClearAlpha() {
|
||||
|
||||
return this._clearAlpha;
|
||||
|
||||
}
|
||||
|
||||
setClearAlpha( alpha ) {
|
||||
|
||||
this._clearAlpha = alpha;
|
||||
|
||||
}
|
||||
|
||||
getClearDepth() {
|
||||
|
||||
return this._clearDepth;
|
||||
|
||||
}
|
||||
|
||||
setClearDepth( depth ) {
|
||||
|
||||
this._clearDepth = depth;
|
||||
|
||||
}
|
||||
|
||||
getClearStencil() {
|
||||
|
||||
return this._clearStencil;
|
||||
|
||||
}
|
||||
|
||||
setClearStencil( stencil ) {
|
||||
|
||||
this._clearStencil = stencil;
|
||||
|
||||
}
|
||||
|
||||
clear() {
|
||||
|
||||
this._background.clear();
|
||||
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
this._objects.dispose();
|
||||
this._properties.dispose();
|
||||
this._renderPipelines.dispose();
|
||||
this._computePipelines.dispose();
|
||||
this._nodes.dispose();
|
||||
this._bindings.dispose();
|
||||
this._info.dispose();
|
||||
this._renderLists.dispose();
|
||||
this._textures.dispose();
|
||||
|
||||
}
|
||||
|
||||
setRenderTarget( renderTarget ) {
|
||||
|
||||
this._renderTarget = renderTarget;
|
||||
|
||||
if ( renderTarget !== null ) {
|
||||
|
||||
this._textures.initRenderTarget( renderTarget );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
compute( computeParams ) {
|
||||
|
||||
const device = this._device;
|
||||
const cmdEncoder = device.createCommandEncoder( {} );
|
||||
const passEncoder = cmdEncoder.beginComputePass();
|
||||
|
||||
for ( const param of computeParams ) {
|
||||
|
||||
// pipeline
|
||||
|
||||
const pipeline = this._computePipelines.get( param );
|
||||
passEncoder.setPipeline( pipeline );
|
||||
|
||||
// bind group
|
||||
|
||||
const bindGroup = this._bindings.getForCompute( param ).group;
|
||||
this._bindings.update( param );
|
||||
passEncoder.setBindGroup( 0, bindGroup );
|
||||
|
||||
passEncoder.dispatch( param.num );
|
||||
|
||||
}
|
||||
|
||||
passEncoder.end();
|
||||
device.queue.submit( [ cmdEncoder.finish() ] );
|
||||
|
||||
}
|
||||
|
||||
getRenderTarget() {
|
||||
|
||||
return this._renderTarget;
|
||||
|
||||
}
|
||||
|
||||
_projectObject( object, camera, groupOrder ) {
|
||||
|
||||
const currentRenderList = this._currentRenderList;
|
||||
|
||||
if ( object.visible === false ) return;
|
||||
|
||||
const visible = object.layers.test( camera.layers );
|
||||
|
||||
if ( visible ) {
|
||||
|
||||
if ( object.isGroup ) {
|
||||
|
||||
groupOrder = object.renderOrder;
|
||||
|
||||
} else if ( object.isLOD ) {
|
||||
|
||||
if ( object.autoUpdate === true ) object.update( camera );
|
||||
|
||||
} else if ( object.isLight ) {
|
||||
|
||||
//currentRenderState.pushLight( object );
|
||||
|
||||
if ( object.castShadow ) {
|
||||
|
||||
//currentRenderState.pushShadow( object );
|
||||
|
||||
}
|
||||
|
||||
} else if ( object.isSprite ) {
|
||||
|
||||
if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
|
||||
|
||||
if ( this.sortObjects === true ) {
|
||||
|
||||
_vector3.setFromMatrixPosition( object.matrixWorld ).applyMatrix4( _projScreenMatrix );
|
||||
|
||||
}
|
||||
|
||||
const geometry = object.geometry;
|
||||
const material = object.material;
|
||||
|
||||
if ( material.visible ) {
|
||||
|
||||
currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if ( object.isLineLoop ) {
|
||||
|
||||
console.error( 'THREE.WebGPURenderer: Objects of type THREE.LineLoop are not supported. Please use THREE.Line or THREE.LineSegments.' );
|
||||
|
||||
} else if ( object.isMesh || object.isLine || object.isPoints ) {
|
||||
|
||||
if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
|
||||
|
||||
if ( this.sortObjects === true ) {
|
||||
|
||||
_vector3.setFromMatrixPosition( object.matrixWorld ).applyMatrix4( _projScreenMatrix );
|
||||
|
||||
}
|
||||
|
||||
const geometry = object.geometry;
|
||||
const material = object.material;
|
||||
|
||||
if ( Array.isArray( material ) ) {
|
||||
|
||||
const groups = geometry.groups;
|
||||
|
||||
for ( let i = 0, l = groups.length; i < l; i ++ ) {
|
||||
|
||||
const group = groups[ i ];
|
||||
const groupMaterial = material[ group.materialIndex ];
|
||||
|
||||
if ( groupMaterial && groupMaterial.visible ) {
|
||||
|
||||
currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if ( material.visible ) {
|
||||
|
||||
currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const children = object.children;
|
||||
|
||||
for ( let i = 0, l = children.length; i < l; i ++ ) {
|
||||
|
||||
this._projectObject( children[ i ], camera, groupOrder );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_renderObjects( renderList, camera, passEncoder ) {
|
||||
|
||||
// process renderable objects
|
||||
|
||||
for ( let i = 0, il = renderList.length; i < il; i ++ ) {
|
||||
|
||||
const renderItem = renderList[ i ];
|
||||
|
||||
// @TODO: Add support for multiple materials per object. This will require to extract
|
||||
// the material from the renderItem object and pass it with its group data to _renderObject().
|
||||
|
||||
const object = renderItem.object;
|
||||
|
||||
object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
|
||||
object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
|
||||
|
||||
this._objects.update( object );
|
||||
|
||||
if ( camera.isArrayCamera ) {
|
||||
|
||||
const cameras = camera.cameras;
|
||||
|
||||
for ( let j = 0, jl = cameras.length; j < jl; j ++ ) {
|
||||
|
||||
const camera2 = cameras[ j ];
|
||||
|
||||
if ( object.layers.test( camera2.layers ) ) {
|
||||
|
||||
const vp = camera2.viewport;
|
||||
const minDepth = ( vp.minDepth === undefined ) ? 0 : vp.minDepth;
|
||||
const maxDepth = ( vp.maxDepth === undefined ) ? 1 : vp.maxDepth;
|
||||
|
||||
passEncoder.setViewport( vp.x, vp.y, vp.width, vp.height, minDepth, maxDepth );
|
||||
|
||||
this._nodes.update( object, camera2 );
|
||||
this._bindings.update( object );
|
||||
this._renderObject( object, passEncoder );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
this._nodes.update( object, camera );
|
||||
this._bindings.update( object );
|
||||
this._renderObject( object, passEncoder );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_renderObject( object, passEncoder ) {
|
||||
|
||||
const info = this._info;
|
||||
|
||||
// pipeline
|
||||
|
||||
const renderPipeline = this._renderPipelines.get( object );
|
||||
passEncoder.setPipeline( renderPipeline.pipeline );
|
||||
|
||||
// bind group
|
||||
|
||||
const bindGroup = this._bindings.get( object ).group;
|
||||
passEncoder.setBindGroup( 0, bindGroup );
|
||||
|
||||
// index
|
||||
|
||||
const geometry = object.geometry;
|
||||
const index = geometry.index;
|
||||
|
||||
const hasIndex = ( index !== null );
|
||||
|
||||
if ( hasIndex === true ) {
|
||||
|
||||
this._setupIndexBuffer( index, passEncoder );
|
||||
|
||||
}
|
||||
|
||||
// vertex buffers
|
||||
|
||||
this._setupVertexBuffers( geometry.attributes, passEncoder, renderPipeline );
|
||||
|
||||
// draw
|
||||
|
||||
const drawRange = geometry.drawRange;
|
||||
const firstVertex = drawRange.start;
|
||||
const instanceCount = ( geometry.isInstancedBufferGeometry ) ? geometry.instanceCount : 1;
|
||||
|
||||
if ( hasIndex === true ) {
|
||||
|
||||
const indexCount = ( drawRange.count !== Infinity ) ? drawRange.count : index.count;
|
||||
|
||||
passEncoder.drawIndexed( indexCount, instanceCount, firstVertex, 0, 0 );
|
||||
|
||||
info.update( object, indexCount, instanceCount );
|
||||
|
||||
} else {
|
||||
|
||||
const positionAttribute = geometry.attributes.position;
|
||||
const vertexCount = ( drawRange.count !== Infinity ) ? drawRange.count : positionAttribute.count;
|
||||
|
||||
passEncoder.draw( vertexCount, instanceCount, firstVertex, 0 );
|
||||
|
||||
info.update( object, vertexCount, instanceCount );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_setupIndexBuffer( index, encoder ) {
|
||||
|
||||
const buffer = this._attributes.get( index ).buffer;
|
||||
const indexFormat = ( index.array instanceof Uint16Array ) ? GPUIndexFormat.Uint16 : GPUIndexFormat.Uint32;
|
||||
|
||||
encoder.setIndexBuffer( buffer, indexFormat );
|
||||
|
||||
}
|
||||
|
||||
_setupVertexBuffers( geometryAttributes, encoder, renderPipeline ) {
|
||||
|
||||
const shaderAttributes = renderPipeline.shaderAttributes;
|
||||
|
||||
for ( const shaderAttribute of shaderAttributes ) {
|
||||
|
||||
const name = shaderAttribute.name;
|
||||
const slot = shaderAttribute.slot;
|
||||
|
||||
const attribute = geometryAttributes[ name ];
|
||||
|
||||
if ( attribute !== undefined ) {
|
||||
|
||||
const buffer = this._attributes.get( attribute ).buffer;
|
||||
encoder.setVertexBuffer( slot, buffer );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_setupColorBuffer() {
|
||||
|
||||
const device = this._device;
|
||||
|
||||
if ( device ) {
|
||||
|
||||
if ( this._colorBuffer ) this._colorBuffer.destroy();
|
||||
|
||||
this._colorBuffer = this._device.createTexture( {
|
||||
size: {
|
||||
width: Math.floor( this._width * this._pixelRatio ),
|
||||
height: Math.floor( this._height * this._pixelRatio ),
|
||||
depthOrArrayLayers: 1
|
||||
},
|
||||
sampleCount: this._parameters.sampleCount,
|
||||
format: GPUTextureFormat.BGRA8Unorm,
|
||||
usage: GPUTextureUsage.RENDER_ATTACHMENT
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_setupDepthBuffer() {
|
||||
|
||||
const device = this._device;
|
||||
|
||||
if ( device ) {
|
||||
|
||||
if ( this._depthBuffer ) this._depthBuffer.destroy();
|
||||
|
||||
this._depthBuffer = this._device.createTexture( {
|
||||
size: {
|
||||
width: Math.floor( this._width * this._pixelRatio ),
|
||||
height: Math.floor( this._height * this._pixelRatio ),
|
||||
depthOrArrayLayers: 1
|
||||
},
|
||||
sampleCount: this._parameters.sampleCount,
|
||||
format: GPUTextureFormat.Depth24PlusStencil8,
|
||||
usage: GPUTextureUsage.RENDER_ATTACHMENT
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_configureContext() {
|
||||
|
||||
const device = this._device;
|
||||
|
||||
if ( device ) {
|
||||
|
||||
this._context.configure( {
|
||||
device: device,
|
||||
format: GPUTextureFormat.BGRA8Unorm,
|
||||
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
||||
size: {
|
||||
width: Math.floor( this._width * this._pixelRatio ),
|
||||
height: Math.floor( this._height * this._pixelRatio ),
|
||||
depthOrArrayLayers: 1
|
||||
},
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_createCanvasElement() {
|
||||
|
||||
const canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
|
||||
canvas.style.display = 'block';
|
||||
return canvas;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WebGPURenderer.prototype.isWebGPURenderer = true;
|
||||
|
||||
export default WebGPURenderer;
|
||||
73
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUSampledTexture.js
generated
vendored
Normal file
73
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUSampledTexture.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
import WebGPUBinding from './WebGPUBinding.js';
|
||||
import { GPUBindingType, GPUTextureViewDimension } from './constants.js';
|
||||
|
||||
class WebGPUSampledTexture extends WebGPUBinding {
|
||||
|
||||
constructor( name, texture ) {
|
||||
|
||||
super( name );
|
||||
|
||||
this.texture = texture;
|
||||
|
||||
this.dimension = GPUTextureViewDimension.TwoD;
|
||||
|
||||
this.type = GPUBindingType.SampledTexture;
|
||||
this.visibility = GPUShaderStage.FRAGMENT;
|
||||
|
||||
this.textureGPU = null; // set by the renderer
|
||||
|
||||
}
|
||||
|
||||
getTexture() {
|
||||
|
||||
return this.texture;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WebGPUSampledTexture.prototype.isSampledTexture = true;
|
||||
|
||||
class WebGPUSampledArrayTexture extends WebGPUSampledTexture {
|
||||
|
||||
constructor( name ) {
|
||||
|
||||
super( name );
|
||||
|
||||
this.dimension = GPUTextureViewDimension.TwoDArray;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WebGPUSampledArrayTexture.prototype.isSampledArrayTexture = true;
|
||||
|
||||
class WebGPUSampled3DTexture extends WebGPUSampledTexture {
|
||||
|
||||
constructor( name ) {
|
||||
|
||||
super( name );
|
||||
|
||||
this.dimension = GPUTextureViewDimension.ThreeD;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WebGPUSampled3DTexture.prototype.isSampled3DTexture = true;
|
||||
|
||||
class WebGPUSampledCubeTexture extends WebGPUSampledTexture {
|
||||
|
||||
constructor( name ) {
|
||||
|
||||
super( name );
|
||||
|
||||
this.dimension = GPUTextureViewDimension.Cube;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WebGPUSampledCubeTexture.prototype.isSampledCubeTexture = true;
|
||||
|
||||
export { WebGPUSampledTexture, WebGPUSampledArrayTexture, WebGPUSampled3DTexture, WebGPUSampledCubeTexture };
|
||||
29
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUSampler.js
generated
vendored
Normal file
29
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUSampler.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
import WebGPUBinding from './WebGPUBinding.js';
|
||||
import { GPUBindingType } from './constants.js';
|
||||
|
||||
class WebGPUSampler extends WebGPUBinding {
|
||||
|
||||
constructor( name, texture ) {
|
||||
|
||||
super( name );
|
||||
|
||||
this.texture = texture;
|
||||
|
||||
this.type = GPUBindingType.Sampler;
|
||||
this.visibility = GPUShaderStage.FRAGMENT;
|
||||
|
||||
this.samplerGPU = null; // set by the renderer
|
||||
|
||||
}
|
||||
|
||||
getTexture() {
|
||||
|
||||
return this.texture;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WebGPUSampler.prototype.isSampler = true;
|
||||
|
||||
export default WebGPUSampler;
|
||||
23
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUStorageBuffer.js
generated
vendored
Normal file
23
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUStorageBuffer.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import WebGPUBinding from './WebGPUBinding.js';
|
||||
import { GPUBindingType } from './constants.js';
|
||||
|
||||
class WebGPUStorageBuffer extends WebGPUBinding {
|
||||
|
||||
constructor( name, attribute ) {
|
||||
|
||||
super( name );
|
||||
|
||||
this.type = GPUBindingType.StorageBuffer;
|
||||
|
||||
this.usage = GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;
|
||||
|
||||
this.attribute = attribute;
|
||||
this.bufferGPU = null; // set by the renderer
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WebGPUStorageBuffer.prototype.isStorageBuffer = true;
|
||||
|
||||
export default WebGPUStorageBuffer;
|
||||
40
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUTextureRenderer.js
generated
vendored
Normal file
40
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUTextureRenderer.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
import { WebGLRenderTarget } from 'three';
|
||||
|
||||
class WebGPUTextureRenderer {
|
||||
|
||||
constructor( renderer, options = {} ) {
|
||||
|
||||
this.renderer = renderer;
|
||||
|
||||
// @TODO: Consider to introduce WebGPURenderTarget or rename WebGLRenderTarget to just RenderTarget
|
||||
|
||||
this.renderTarget = new WebGLRenderTarget( options );
|
||||
|
||||
}
|
||||
|
||||
getTexture() {
|
||||
|
||||
return this.renderTarget.texture;
|
||||
|
||||
}
|
||||
|
||||
setSize( width, height ) {
|
||||
|
||||
this.renderTarget.setSize( width, height );
|
||||
|
||||
}
|
||||
|
||||
render( scene, camera ) {
|
||||
|
||||
const renderer = this.renderer;
|
||||
const renderTarget = this.renderTarget;
|
||||
|
||||
renderer.setRenderTarget( renderTarget );
|
||||
renderer.render( scene, camera );
|
||||
renderer.setRenderTarget( null );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUTextureRenderer;
|
||||
180
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUTextureUtils.js
generated
vendored
Normal file
180
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUTextureUtils.js
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
// Copyright 2020 Brandon Jones
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import { GPUIndexFormat, GPUFilterMode, GPUPrimitiveTopology, GPULoadOp, GPUStoreOp } from './constants.js';
|
||||
|
||||
// ported from https://github.com/toji/web-texture-tool/blob/master/src/webgpu-mipmap-generator.js
|
||||
|
||||
class WebGPUTextureUtils {
|
||||
|
||||
constructor( device ) {
|
||||
|
||||
this.device = device;
|
||||
|
||||
const mipmapVertexSource = `
|
||||
struct VarysStruct {
|
||||
|
||||
@builtin( position ) Position: vec4<f32>;
|
||||
@location( 0 ) vTex : vec2<f32>;
|
||||
|
||||
};
|
||||
|
||||
@stage( vertex )
|
||||
fn main( @builtin( vertex_index ) vertexIndex : u32 ) -> VarysStruct {
|
||||
|
||||
var Varys: VarysStruct;
|
||||
|
||||
var pos = array< vec2<f32>, 4 >(
|
||||
vec2<f32>( -1.0, 1.0 ),
|
||||
vec2<f32>( 1.0, 1.0 ),
|
||||
vec2<f32>( -1.0, -1.0 ),
|
||||
vec2<f32>( 1.0, -1.0 )
|
||||
);
|
||||
|
||||
var tex = array< vec2<f32>, 4 >(
|
||||
vec2<f32>( 0.0, 0.0 ),
|
||||
vec2<f32>( 1.0, 0.0 ),
|
||||
vec2<f32>( 0.0, 1.0 ),
|
||||
vec2<f32>( 1.0, 1.0 )
|
||||
);
|
||||
|
||||
Varys.vTex = tex[ vertexIndex ];
|
||||
Varys.Position = vec4<f32>( pos[ vertexIndex ], 0.0, 1.0 );
|
||||
|
||||
return Varys;
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
const mipmapFragmentSource = `
|
||||
@group( 0 ) @binding( 0 )
|
||||
var imgSampler : sampler;
|
||||
|
||||
@group( 0 ) @binding( 1 )
|
||||
var img : texture_2d<f32>;
|
||||
|
||||
@stage( fragment )
|
||||
fn main( @location( 0 ) vTex : vec2<f32> ) -> @location( 0 ) vec4<f32> {
|
||||
|
||||
return textureSample( img, imgSampler, vTex );
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
this.sampler = device.createSampler( { minFilter: GPUFilterMode.Linear } );
|
||||
|
||||
// We'll need a new pipeline for every texture format used.
|
||||
this.pipelines = {};
|
||||
|
||||
this.mipmapVertexShaderModule = device.createShaderModule( {
|
||||
code: mipmapVertexSource
|
||||
} );
|
||||
|
||||
this.mipmapFragmentShaderModule = device.createShaderModule( {
|
||||
code: mipmapFragmentSource
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
getMipmapPipeline( format ) {
|
||||
|
||||
let pipeline = this.pipelines[ format ];
|
||||
|
||||
if ( pipeline === undefined ) {
|
||||
|
||||
pipeline = this.device.createRenderPipeline( {
|
||||
vertex: {
|
||||
module: this.mipmapVertexShaderModule,
|
||||
entryPoint: 'main',
|
||||
},
|
||||
fragment: {
|
||||
module: this.mipmapFragmentShaderModule,
|
||||
entryPoint: 'main',
|
||||
targets: [ { format } ],
|
||||
},
|
||||
primitive: {
|
||||
topology: GPUPrimitiveTopology.TriangleStrip,
|
||||
stripIndexFormat: GPUIndexFormat.Uint32
|
||||
}
|
||||
} );
|
||||
|
||||
this.pipelines[ format ] = pipeline;
|
||||
|
||||
}
|
||||
|
||||
return pipeline;
|
||||
|
||||
}
|
||||
|
||||
generateMipmaps( textureGPU, textureGPUDescriptor ) {
|
||||
|
||||
const pipeline = this.getMipmapPipeline( textureGPUDescriptor.format );
|
||||
|
||||
const commandEncoder = this.device.createCommandEncoder( {} );
|
||||
const bindGroupLayout = pipeline.getBindGroupLayout( 0 ); // @TODO: Consider making this static.
|
||||
|
||||
let srcView = textureGPU.createView( {
|
||||
baseMipLevel: 0,
|
||||
mipLevelCount: 1
|
||||
} );
|
||||
|
||||
for ( let i = 1; i < textureGPUDescriptor.mipLevelCount; i ++ ) {
|
||||
|
||||
const dstView = textureGPU.createView( {
|
||||
baseMipLevel: i,
|
||||
mipLevelCount: 1
|
||||
} );
|
||||
|
||||
const passEncoder = commandEncoder.beginRenderPass( {
|
||||
colorAttachments: [ {
|
||||
view: dstView,
|
||||
loadOp: GPULoadOp.Clear,
|
||||
storeOp: GPUStoreOp.Store,
|
||||
clearValue: [ 0, 0, 0, 0 ]
|
||||
} ]
|
||||
} );
|
||||
|
||||
const bindGroup = this.device.createBindGroup( {
|
||||
layout: bindGroupLayout,
|
||||
entries: [ {
|
||||
binding: 0,
|
||||
resource: this.sampler
|
||||
}, {
|
||||
binding: 1,
|
||||
resource: srcView
|
||||
} ]
|
||||
} );
|
||||
|
||||
passEncoder.setPipeline( pipeline );
|
||||
passEncoder.setBindGroup( 0, bindGroup );
|
||||
passEncoder.draw( 4, 1, 0, 0 );
|
||||
passEncoder.end();
|
||||
|
||||
srcView = dstView;
|
||||
|
||||
}
|
||||
|
||||
this.device.queue.submit( [ commandEncoder.finish() ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUTextureUtils;
|
||||
775
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUTextures.js
generated
vendored
Normal file
775
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUTextures.js
generated
vendored
Normal file
@@ -0,0 +1,775 @@
|
||||
import { GPUTextureFormat, GPUAddressMode, GPUFilterMode, GPUTextureDimension } from './constants.js';
|
||||
import { CubeTexture, Texture, NearestFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter, LinearFilter, RepeatWrapping, MirroredRepeatWrapping,
|
||||
RGBAFormat, RedFormat, RGFormat, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, UnsignedByteType, FloatType, HalfFloatType, sRGBEncoding
|
||||
} from 'three';
|
||||
import WebGPUTextureUtils from './WebGPUTextureUtils.js';
|
||||
|
||||
class WebGPUTextures {
|
||||
|
||||
constructor( device, properties, info ) {
|
||||
|
||||
this.device = device;
|
||||
this.properties = properties;
|
||||
this.info = info;
|
||||
|
||||
this.defaultTexture = null;
|
||||
this.defaultCubeTexture = null;
|
||||
this.defaultSampler = null;
|
||||
|
||||
this.samplerCache = new Map();
|
||||
this.utils = null;
|
||||
|
||||
}
|
||||
|
||||
getDefaultSampler() {
|
||||
|
||||
if ( this.defaultSampler === null ) {
|
||||
|
||||
this.defaultSampler = this.device.createSampler( {} );
|
||||
|
||||
}
|
||||
|
||||
return this.defaultSampler;
|
||||
|
||||
}
|
||||
|
||||
getDefaultTexture() {
|
||||
|
||||
if ( this.defaultTexture === null ) {
|
||||
|
||||
const texture = new Texture();
|
||||
texture.minFilter = NearestFilter;
|
||||
texture.magFilter = NearestFilter;
|
||||
|
||||
this._uploadTexture( texture );
|
||||
|
||||
this.defaultTexture = this.getTextureGPU( texture );
|
||||
|
||||
}
|
||||
|
||||
return this.defaultTexture;
|
||||
|
||||
}
|
||||
|
||||
getDefaultCubeTexture() {
|
||||
|
||||
if ( this.defaultCubeTexture === null ) {
|
||||
|
||||
const texture = new CubeTexture();
|
||||
texture.minFilter = NearestFilter;
|
||||
texture.magFilter = NearestFilter;
|
||||
|
||||
this._uploadTexture( texture );
|
||||
|
||||
this.defaultCubeTexture = this.getTextureGPU( texture );
|
||||
|
||||
}
|
||||
|
||||
return this.defaultCubeTexture;
|
||||
|
||||
}
|
||||
|
||||
getTextureGPU( texture ) {
|
||||
|
||||
const textureProperties = this.properties.get( texture );
|
||||
|
||||
return textureProperties.textureGPU;
|
||||
|
||||
}
|
||||
|
||||
getSampler( texture ) {
|
||||
|
||||
const textureProperties = this.properties.get( texture );
|
||||
|
||||
return textureProperties.samplerGPU;
|
||||
|
||||
}
|
||||
|
||||
updateTexture( texture ) {
|
||||
|
||||
let needsUpdate = false;
|
||||
|
||||
const textureProperties = this.properties.get( texture );
|
||||
|
||||
if ( texture.version > 0 && textureProperties.version !== texture.version ) {
|
||||
|
||||
const image = texture.image;
|
||||
|
||||
if ( image === undefined ) {
|
||||
|
||||
console.warn( 'THREE.WebGPURenderer: Texture marked for update but image is undefined.' );
|
||||
|
||||
} else if ( image.complete === false ) {
|
||||
|
||||
console.warn( 'THREE.WebGPURenderer: Texture marked for update but image is incomplete.' );
|
||||
|
||||
} else {
|
||||
|
||||
// texture init
|
||||
|
||||
if ( textureProperties.initialized === undefined ) {
|
||||
|
||||
textureProperties.initialized = true;
|
||||
|
||||
const disposeCallback = onTextureDispose.bind( this );
|
||||
textureProperties.disposeCallback = disposeCallback;
|
||||
|
||||
texture.addEventListener( 'dispose', disposeCallback );
|
||||
|
||||
this.info.memory.textures ++;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
needsUpdate = this._uploadTexture( texture );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if the texture is used for RTT, it's necessary to init it once so the binding
|
||||
// group's resource definition points to the respective GPUTexture
|
||||
|
||||
if ( textureProperties.initializedRTT === false ) {
|
||||
|
||||
textureProperties.initializedRTT = true;
|
||||
needsUpdate = true;
|
||||
|
||||
}
|
||||
|
||||
return needsUpdate;
|
||||
|
||||
}
|
||||
|
||||
updateSampler( texture ) {
|
||||
|
||||
const array = [];
|
||||
|
||||
array.push( texture.wrapS );
|
||||
array.push( texture.wrapT );
|
||||
array.push( texture.wrapR );
|
||||
array.push( texture.magFilter );
|
||||
array.push( texture.minFilter );
|
||||
array.push( texture.anisotropy );
|
||||
|
||||
const key = array.join();
|
||||
let samplerGPU = this.samplerCache.get( key );
|
||||
|
||||
if ( samplerGPU === undefined ) {
|
||||
|
||||
samplerGPU = this.device.createSampler( {
|
||||
addressModeU: this._convertAddressMode( texture.wrapS ),
|
||||
addressModeV: this._convertAddressMode( texture.wrapT ),
|
||||
addressModeW: this._convertAddressMode( texture.wrapR ),
|
||||
magFilter: this._convertFilterMode( texture.magFilter ),
|
||||
minFilter: this._convertFilterMode( texture.minFilter ),
|
||||
mipmapFilter: this._convertFilterMode( texture.minFilter ),
|
||||
maxAnisotropy: texture.anisotropy
|
||||
} );
|
||||
|
||||
this.samplerCache.set( key, samplerGPU );
|
||||
|
||||
}
|
||||
|
||||
const textureProperties = this.properties.get( texture );
|
||||
textureProperties.samplerGPU = samplerGPU;
|
||||
|
||||
}
|
||||
|
||||
initRenderTarget( renderTarget ) {
|
||||
|
||||
const properties = this.properties;
|
||||
const renderTargetProperties = properties.get( renderTarget );
|
||||
|
||||
if ( renderTargetProperties.initialized === undefined ) {
|
||||
|
||||
const device = this.device;
|
||||
|
||||
const width = renderTarget.width;
|
||||
const height = renderTarget.height;
|
||||
const colorTextureFormat = this._getFormat( renderTarget.texture );
|
||||
|
||||
const colorTextureGPU = device.createTexture( {
|
||||
size: {
|
||||
width: width,
|
||||
height: height,
|
||||
depthOrArrayLayers: 1
|
||||
},
|
||||
format: colorTextureFormat,
|
||||
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
|
||||
} );
|
||||
|
||||
this.info.memory.textures ++;
|
||||
|
||||
renderTargetProperties.colorTextureGPU = colorTextureGPU;
|
||||
renderTargetProperties.colorTextureFormat = colorTextureFormat;
|
||||
|
||||
// When the ".texture" or ".depthTexture" property of a render target is used as a map,
|
||||
// the renderer has to find the respective GPUTexture objects to setup the bind groups.
|
||||
// Since it's not possible to see just from a texture object whether it belongs to a render
|
||||
// target or not, we need the initializedRTT flag.
|
||||
|
||||
const textureProperties = properties.get( renderTarget.texture );
|
||||
textureProperties.textureGPU = colorTextureGPU;
|
||||
textureProperties.initializedRTT = false;
|
||||
|
||||
if ( renderTarget.depthBuffer === true ) {
|
||||
|
||||
const depthTextureFormat = GPUTextureFormat.Depth24PlusStencil8; // @TODO: Make configurable
|
||||
|
||||
const depthTextureGPU = device.createTexture( {
|
||||
size: {
|
||||
width: width,
|
||||
height: height,
|
||||
depthOrArrayLayers: 1
|
||||
},
|
||||
format: depthTextureFormat,
|
||||
usage: GPUTextureUsage.RENDER_ATTACHMENT
|
||||
} );
|
||||
|
||||
this.info.memory.textures ++;
|
||||
|
||||
renderTargetProperties.depthTextureGPU = depthTextureGPU;
|
||||
renderTargetProperties.depthTextureFormat = depthTextureFormat;
|
||||
|
||||
if ( renderTarget.depthTexture !== null ) {
|
||||
|
||||
const depthTextureProperties = properties.get( renderTarget.depthTexture );
|
||||
depthTextureProperties.textureGPU = depthTextureGPU;
|
||||
depthTextureProperties.initializedRTT = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const disposeCallback = onRenderTargetDispose.bind( this );
|
||||
renderTargetProperties.disposeCallback = disposeCallback;
|
||||
|
||||
renderTarget.addEventListener( 'dispose', disposeCallback );
|
||||
|
||||
//
|
||||
|
||||
renderTargetProperties.initialized = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
this.samplerCache.clear();
|
||||
|
||||
}
|
||||
|
||||
_convertAddressMode( value ) {
|
||||
|
||||
let addressMode = GPUAddressMode.ClampToEdge;
|
||||
|
||||
if ( value === RepeatWrapping ) {
|
||||
|
||||
addressMode = GPUAddressMode.Repeat;
|
||||
|
||||
} else if ( value === MirroredRepeatWrapping ) {
|
||||
|
||||
addressMode = GPUAddressMode.MirrorRepeat;
|
||||
|
||||
}
|
||||
|
||||
return addressMode;
|
||||
|
||||
}
|
||||
|
||||
_convertFilterMode( value ) {
|
||||
|
||||
let filterMode = GPUFilterMode.Linear;
|
||||
|
||||
if ( value === NearestFilter || value === NearestMipmapNearestFilter || value === NearestMipmapLinearFilter ) {
|
||||
|
||||
filterMode = GPUFilterMode.Nearest;
|
||||
|
||||
}
|
||||
|
||||
return filterMode;
|
||||
|
||||
}
|
||||
|
||||
_uploadTexture( texture ) {
|
||||
|
||||
let needsUpdate = false;
|
||||
|
||||
const device = this.device;
|
||||
const image = texture.image;
|
||||
|
||||
const textureProperties = this.properties.get( texture );
|
||||
|
||||
const { width, height, depth } = this._getSize( texture );
|
||||
const needsMipmaps = this._needsMipmaps( texture );
|
||||
const dimension = this._getDimension( texture );
|
||||
const mipLevelCount = this._getMipLevelCount( texture, width, height, needsMipmaps );
|
||||
const format = this._getFormat( texture );
|
||||
|
||||
let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST;
|
||||
|
||||
if ( needsMipmaps === true ) {
|
||||
|
||||
// current mipmap generation requires RENDER_ATTACHMENT
|
||||
|
||||
usage |= GPUTextureUsage.RENDER_ATTACHMENT;
|
||||
|
||||
}
|
||||
|
||||
const textureGPUDescriptor = {
|
||||
size: {
|
||||
width: width,
|
||||
height: height,
|
||||
depthOrArrayLayers: depth,
|
||||
},
|
||||
mipLevelCount: mipLevelCount,
|
||||
sampleCount: 1,
|
||||
dimension: dimension,
|
||||
format: format,
|
||||
usage: usage
|
||||
};
|
||||
|
||||
// texture creation
|
||||
|
||||
let textureGPU = textureProperties.textureGPU;
|
||||
|
||||
if ( textureGPU === undefined ) {
|
||||
|
||||
textureGPU = device.createTexture( textureGPUDescriptor );
|
||||
textureProperties.textureGPU = textureGPU;
|
||||
|
||||
needsUpdate = true;
|
||||
|
||||
}
|
||||
|
||||
// transfer texture data
|
||||
|
||||
if ( texture.isDataTexture || texture.isDataArrayTexture || texture.isData3DTexture ) {
|
||||
|
||||
this._copyBufferToTexture( image, format, textureGPU );
|
||||
|
||||
if ( needsMipmaps === true ) this._generateMipmaps( textureGPU, textureGPUDescriptor );
|
||||
|
||||
} else if ( texture.isCompressedTexture ) {
|
||||
|
||||
this._copyCompressedBufferToTexture( texture.mipmaps, format, textureGPU );
|
||||
|
||||
} else if ( texture.isCubeTexture ) {
|
||||
|
||||
this._copyCubeMapToTexture( image, texture, textureGPU );
|
||||
|
||||
} else {
|
||||
|
||||
if ( image !== null ) {
|
||||
|
||||
// assume HTMLImageElement, HTMLCanvasElement or ImageBitmap
|
||||
|
||||
this._getImageBitmap( image, texture ).then( imageBitmap => {
|
||||
|
||||
this._copyExternalImageToTexture( imageBitmap, textureGPU );
|
||||
|
||||
if ( needsMipmaps === true ) this._generateMipmaps( textureGPU, textureGPUDescriptor );
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
textureProperties.version = texture.version;
|
||||
|
||||
return needsUpdate;
|
||||
|
||||
}
|
||||
|
||||
_copyBufferToTexture( image, format, textureGPU ) {
|
||||
|
||||
// @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture()
|
||||
// @TODO: Consider to support valid buffer layouts with other formats like RGB
|
||||
|
||||
const data = image.data;
|
||||
|
||||
const bytesPerTexel = this._getBytesPerTexel( format );
|
||||
const bytesPerRow = Math.ceil( image.width * bytesPerTexel / 256 ) * 256;
|
||||
|
||||
this.device.queue.writeTexture(
|
||||
{
|
||||
texture: textureGPU,
|
||||
mipLevel: 0
|
||||
},
|
||||
data,
|
||||
{
|
||||
offset: 0,
|
||||
bytesPerRow
|
||||
},
|
||||
{
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
depthOrArrayLayers: ( image.depth !== undefined ) ? image.depth : 1
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
_copyCubeMapToTexture( images, texture, textureGPU ) {
|
||||
|
||||
for ( let i = 0; i < images.length; i ++ ) {
|
||||
|
||||
const image = images[ i ];
|
||||
|
||||
this._getImageBitmap( image, texture ).then( imageBitmap => {
|
||||
|
||||
this._copyExternalImageToTexture( imageBitmap, textureGPU, { x: 0, y: 0, z: i } );
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_copyExternalImageToTexture( image, textureGPU, origin = { x: 0, y: 0, z: 0 } ) {
|
||||
|
||||
this.device.queue.copyExternalImageToTexture(
|
||||
{
|
||||
source: image
|
||||
}, {
|
||||
texture: textureGPU,
|
||||
mipLevel: 0,
|
||||
origin: origin
|
||||
}, {
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
depthOrArrayLayers: 1
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
_copyCompressedBufferToTexture( mipmaps, format, textureGPU ) {
|
||||
|
||||
// @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture()
|
||||
|
||||
const blockData = this._getBlockData( format );
|
||||
|
||||
for ( let i = 0; i < mipmaps.length; i ++ ) {
|
||||
|
||||
const mipmap = mipmaps[ i ];
|
||||
|
||||
const width = mipmap.width;
|
||||
const height = mipmap.height;
|
||||
|
||||
const bytesPerRow = Math.ceil( width / blockData.width ) * blockData.byteLength;
|
||||
|
||||
this.device.queue.writeTexture(
|
||||
{
|
||||
texture: textureGPU,
|
||||
mipLevel: i
|
||||
},
|
||||
mipmap.data,
|
||||
{
|
||||
offset: 0,
|
||||
bytesPerRow
|
||||
},
|
||||
{
|
||||
width: Math.ceil( width / blockData.width ) * blockData.width,
|
||||
height: Math.ceil( height / blockData.width ) * blockData.width,
|
||||
depthOrArrayLayers: 1,
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_generateMipmaps( textureGPU, textureGPUDescriptor ) {
|
||||
|
||||
if ( this.utils === null ) {
|
||||
|
||||
this.utils = new WebGPUTextureUtils( this.device ); // only create this helper if necessary
|
||||
|
||||
}
|
||||
|
||||
this.utils.generateMipmaps( textureGPU, textureGPUDescriptor );
|
||||
|
||||
}
|
||||
|
||||
_getBlockData( format ) {
|
||||
|
||||
// this method is only relevant for compressed texture formats
|
||||
|
||||
if ( format === GPUTextureFormat.BC1RGBAUnorm || format === GPUTextureFormat.BC1RGBAUnormSRGB ) return { byteLength: 8, width: 4, height: 4 }; // DXT1
|
||||
if ( format === GPUTextureFormat.BC2RGBAUnorm || format === GPUTextureFormat.BC2RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // DXT3
|
||||
if ( format === GPUTextureFormat.BC3RGBAUnorm || format === GPUTextureFormat.BC3RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // DXT5
|
||||
if ( format === GPUTextureFormat.BC4RUnorm || format === GPUTextureFormat.BC4RSNorm ) return { byteLength: 8, width: 4, height: 4 }; // RGTC1
|
||||
if ( format === GPUTextureFormat.BC5RGUnorm || format === GPUTextureFormat.BC5RGSnorm ) return { byteLength: 16, width: 4, height: 4 }; // RGTC2
|
||||
if ( format === GPUTextureFormat.BC6HRGBUFloat || format === GPUTextureFormat.BC6HRGBFloat ) return { byteLength: 16, width: 4, height: 4 }; // BPTC (float)
|
||||
if ( format === GPUTextureFormat.BC7RGBAUnorm || format === GPUTextureFormat.BC7RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // BPTC (unorm)
|
||||
|
||||
}
|
||||
|
||||
_getBytesPerTexel( format ) {
|
||||
|
||||
if ( format === GPUTextureFormat.R8Unorm ) return 1;
|
||||
if ( format === GPUTextureFormat.R16Float ) return 2;
|
||||
if ( format === GPUTextureFormat.RG8Unorm ) return 2;
|
||||
if ( format === GPUTextureFormat.RG16Float ) return 4;
|
||||
if ( format === GPUTextureFormat.R32Float ) return 4;
|
||||
if ( format === GPUTextureFormat.RGBA8Unorm || format === GPUTextureFormat.RGBA8UnormSRGB ) return 4;
|
||||
if ( format === GPUTextureFormat.RG32Float ) return 8;
|
||||
if ( format === GPUTextureFormat.RGBA16Float ) return 8;
|
||||
if ( format === GPUTextureFormat.RGBA32Float ) return 16;
|
||||
|
||||
}
|
||||
|
||||
_getDimension( texture ) {
|
||||
|
||||
let dimension;
|
||||
|
||||
if ( texture.isData3DTexture ) {
|
||||
|
||||
dimension = GPUTextureDimension.ThreeD;
|
||||
|
||||
} else {
|
||||
|
||||
dimension = GPUTextureDimension.TwoD;
|
||||
|
||||
}
|
||||
|
||||
return dimension;
|
||||
|
||||
}
|
||||
|
||||
_getFormat( texture ) {
|
||||
|
||||
const format = texture.format;
|
||||
const type = texture.type;
|
||||
const encoding = texture.encoding;
|
||||
|
||||
let formatGPU;
|
||||
|
||||
switch ( format ) {
|
||||
|
||||
case RGBA_S3TC_DXT1_Format:
|
||||
formatGPU = ( encoding === sRGBEncoding ) ? GPUTextureFormat.BC1RGBAUnormSRGB : GPUTextureFormat.BC1RGBAUnorm;
|
||||
break;
|
||||
|
||||
case RGBA_S3TC_DXT3_Format:
|
||||
formatGPU = ( encoding === sRGBEncoding ) ? GPUTextureFormat.BC2RGBAUnormSRGB : GPUTextureFormat.BC2RGBAUnorm;
|
||||
break;
|
||||
|
||||
case RGBA_S3TC_DXT5_Format:
|
||||
formatGPU = ( encoding === sRGBEncoding ) ? GPUTextureFormat.BC3RGBAUnormSRGB : GPUTextureFormat.BC3RGBAUnorm;
|
||||
break;
|
||||
|
||||
case RGBAFormat:
|
||||
|
||||
switch ( type ) {
|
||||
|
||||
case UnsignedByteType:
|
||||
formatGPU = ( encoding === sRGBEncoding ) ? GPUTextureFormat.RGBA8UnormSRGB : GPUTextureFormat.RGBA8Unorm;
|
||||
break;
|
||||
|
||||
case HalfFloatType:
|
||||
formatGPU = GPUTextureFormat.RGBA16Float;
|
||||
break;
|
||||
|
||||
case FloatType:
|
||||
formatGPU = GPUTextureFormat.RGBA32Float;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'WebGPURenderer: Unsupported texture type with RGBAFormat.', type );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RedFormat:
|
||||
|
||||
switch ( type ) {
|
||||
|
||||
case UnsignedByteType:
|
||||
formatGPU = GPUTextureFormat.R8Unorm;
|
||||
break;
|
||||
|
||||
case HalfFloatType:
|
||||
formatGPU = GPUTextureFormat.R16Float;
|
||||
break;
|
||||
|
||||
case FloatType:
|
||||
formatGPU = GPUTextureFormat.R32Float;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'WebGPURenderer: Unsupported texture type with RedFormat.', type );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RGFormat:
|
||||
|
||||
switch ( type ) {
|
||||
|
||||
case UnsignedByteType:
|
||||
formatGPU = GPUTextureFormat.RG8Unorm;
|
||||
break;
|
||||
|
||||
case HalfFloatType:
|
||||
formatGPU = GPUTextureFormat.RG16Float;
|
||||
break;
|
||||
|
||||
case FloatType:
|
||||
formatGPU = GPUTextureFormat.RG32Float;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'WebGPURenderer: Unsupported texture type with RGFormat.', type );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'WebGPURenderer: Unsupported texture format.', format );
|
||||
|
||||
}
|
||||
|
||||
return formatGPU;
|
||||
|
||||
}
|
||||
|
||||
_getImageBitmap( image, texture ) {
|
||||
|
||||
const width = image.width;
|
||||
const height = image.height;
|
||||
|
||||
if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
|
||||
( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ) {
|
||||
|
||||
const options = {};
|
||||
|
||||
options.imageOrientation = ( texture.flipY === true ) ? 'flipY' : 'none';
|
||||
options.premultiplyAlpha = ( texture.premultiplyAlpha === true ) ? 'premultiply' : 'default';
|
||||
|
||||
return createImageBitmap( image, 0, 0, width, height, options );
|
||||
|
||||
} else {
|
||||
|
||||
// assume ImageBitmap
|
||||
|
||||
return Promise.resolve( image );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_getMipLevelCount( texture, width, height, needsMipmaps ) {
|
||||
|
||||
let mipLevelCount;
|
||||
|
||||
if ( texture.isCompressedTexture ) {
|
||||
|
||||
mipLevelCount = texture.mipmaps.length;
|
||||
|
||||
} else if ( needsMipmaps === true ) {
|
||||
|
||||
mipLevelCount = Math.floor( Math.log2( Math.max( width, height ) ) ) + 1;
|
||||
|
||||
} else {
|
||||
|
||||
mipLevelCount = 1; // a texture without mipmaps has a base mip (mipLevel 0)
|
||||
|
||||
}
|
||||
|
||||
return mipLevelCount;
|
||||
|
||||
}
|
||||
|
||||
_getSize( texture ) {
|
||||
|
||||
const image = texture.image;
|
||||
|
||||
let width, height, depth;
|
||||
|
||||
if ( texture.isCubeTexture ) {
|
||||
|
||||
width = ( image.length > 0 ) ? image[ 0 ].width : 1;
|
||||
height = ( image.length > 0 ) ? image[ 0 ].height : 1;
|
||||
depth = 6; // one image for each side of the cube map
|
||||
|
||||
} else if ( image !== null ) {
|
||||
|
||||
width = image.width;
|
||||
height = image.height;
|
||||
depth = ( image.depth !== undefined ) ? image.depth : 1;
|
||||
|
||||
} else {
|
||||
|
||||
width = height = depth = 1;
|
||||
|
||||
}
|
||||
|
||||
return { width, height, depth };
|
||||
|
||||
}
|
||||
|
||||
_needsMipmaps( texture ) {
|
||||
|
||||
return ( texture.isCompressedTexture !== true ) && ( texture.generateMipmaps === true ) && ( texture.minFilter !== NearestFilter ) && ( texture.minFilter !== LinearFilter );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onRenderTargetDispose( event ) {
|
||||
|
||||
const renderTarget = event.target;
|
||||
const properties = this.properties;
|
||||
|
||||
const renderTargetProperties = properties.get( renderTarget );
|
||||
|
||||
renderTarget.removeEventListener( 'dispose', renderTargetProperties.disposeCallback );
|
||||
|
||||
renderTargetProperties.colorTextureGPU.destroy();
|
||||
properties.remove( renderTarget.texture );
|
||||
|
||||
this.info.memory.textures --;
|
||||
|
||||
if ( renderTarget.depthBuffer === true ) {
|
||||
|
||||
renderTargetProperties.depthTextureGPU.destroy();
|
||||
|
||||
this.info.memory.textures --;
|
||||
|
||||
if ( renderTarget.depthTexture !== null ) {
|
||||
|
||||
properties.remove( renderTarget.depthTexture );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
properties.remove( renderTarget );
|
||||
|
||||
}
|
||||
|
||||
function onTextureDispose( event ) {
|
||||
|
||||
const texture = event.target;
|
||||
|
||||
const textureProperties = this.properties.get( texture );
|
||||
textureProperties.textureGPU.destroy();
|
||||
|
||||
texture.removeEventListener( 'dispose', textureProperties.disposeCallback );
|
||||
|
||||
this.properties.remove( texture );
|
||||
|
||||
this.info.memory.textures --;
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUTextures;
|
||||
136
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUUniform.js
generated
vendored
Normal file
136
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUUniform.js
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
import { Color, Matrix3, Matrix4, Vector2, Vector3, Vector4 } from 'three';
|
||||
|
||||
class WebGPUUniform {
|
||||
|
||||
constructor( name, value = null ) {
|
||||
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
|
||||
this.boundary = 0; // used to build the uniform buffer according to the STD140 layout
|
||||
this.itemSize = 0;
|
||||
|
||||
this.offset = 0; // this property is set by WebGPUUniformsGroup and marks the start position in the uniform buffer
|
||||
|
||||
}
|
||||
|
||||
setValue( value ) {
|
||||
|
||||
this.value = value;
|
||||
|
||||
}
|
||||
|
||||
getValue() {
|
||||
|
||||
return this.value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FloatUniform extends WebGPUUniform {
|
||||
|
||||
constructor( name, value = 0 ) {
|
||||
|
||||
super( name, value );
|
||||
|
||||
this.boundary = 4;
|
||||
this.itemSize = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FloatUniform.prototype.isFloatUniform = true;
|
||||
|
||||
class Vector2Uniform extends WebGPUUniform {
|
||||
|
||||
constructor( name, value = new Vector2() ) {
|
||||
|
||||
super( name, value );
|
||||
|
||||
this.boundary = 8;
|
||||
this.itemSize = 2;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vector2Uniform.prototype.isVector2Uniform = true;
|
||||
|
||||
class Vector3Uniform extends WebGPUUniform {
|
||||
|
||||
constructor( name, value = new Vector3() ) {
|
||||
|
||||
super( name, value );
|
||||
|
||||
this.boundary = 16;
|
||||
this.itemSize = 3;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vector3Uniform.prototype.isVector3Uniform = true;
|
||||
|
||||
class Vector4Uniform extends WebGPUUniform {
|
||||
|
||||
constructor( name, value = new Vector4() ) {
|
||||
|
||||
super( name, value );
|
||||
|
||||
this.boundary = 16;
|
||||
this.itemSize = 4;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vector4Uniform.prototype.isVector4Uniform = true;
|
||||
|
||||
class ColorUniform extends WebGPUUniform {
|
||||
|
||||
constructor( name, value = new Color() ) {
|
||||
|
||||
super( name, value );
|
||||
|
||||
this.boundary = 16;
|
||||
this.itemSize = 3;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ColorUniform.prototype.isColorUniform = true;
|
||||
|
||||
class Matrix3Uniform extends WebGPUUniform {
|
||||
|
||||
constructor( name, value = new Matrix3() ) {
|
||||
|
||||
super( name, value );
|
||||
|
||||
this.boundary = 48;
|
||||
this.itemSize = 12;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Matrix3Uniform.prototype.isMatrix3Uniform = true;
|
||||
|
||||
class Matrix4Uniform extends WebGPUUniform {
|
||||
|
||||
constructor( name, value = new Matrix4() ) {
|
||||
|
||||
super( name, value );
|
||||
|
||||
this.boundary = 64;
|
||||
this.itemSize = 16;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Matrix4Uniform.prototype.isMatrix4Uniform = true;
|
||||
|
||||
export { FloatUniform, Vector2Uniform, Vector3Uniform, Vector4Uniform, ColorUniform, Matrix3Uniform, Matrix4Uniform };
|
||||
45
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUUniformBuffer.js
generated
vendored
Normal file
45
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUUniformBuffer.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
import WebGPUBinding from './WebGPUBinding.js';
|
||||
import { getFloatLength } from './WebGPUBufferUtils.js';
|
||||
|
||||
import { GPUBindingType } from './constants.js';
|
||||
|
||||
class WebGPUUniformBuffer extends WebGPUBinding {
|
||||
|
||||
constructor( name, buffer = null ) {
|
||||
|
||||
super( name );
|
||||
|
||||
this.bytesPerElement = Float32Array.BYTES_PER_ELEMENT;
|
||||
this.type = GPUBindingType.UniformBuffer;
|
||||
this.visibility = GPUShaderStage.VERTEX;
|
||||
|
||||
this.usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
|
||||
|
||||
this.buffer = buffer;
|
||||
this.bufferGPU = null; // set by the renderer
|
||||
|
||||
}
|
||||
|
||||
getByteLength() {
|
||||
|
||||
return getFloatLength( this.buffer.byteLength );
|
||||
|
||||
}
|
||||
|
||||
getBuffer() {
|
||||
|
||||
return this.buffer;
|
||||
|
||||
}
|
||||
|
||||
update() {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WebGPUUniformBuffer.prototype.isUniformBuffer = true;
|
||||
|
||||
export default WebGPUUniformBuffer;
|
||||
299
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUUniformsGroup.js
generated
vendored
Normal file
299
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/WebGPUUniformsGroup.js
generated
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
import WebGPUUniformBuffer from './WebGPUUniformBuffer.js';
|
||||
import { GPUChunkSize } from './constants.js';
|
||||
|
||||
class WebGPUUniformsGroup extends WebGPUUniformBuffer {
|
||||
|
||||
constructor( name ) {
|
||||
|
||||
super( name );
|
||||
|
||||
// the order of uniforms in this array must match the order of uniforms in the shader
|
||||
|
||||
this.uniforms = [];
|
||||
|
||||
}
|
||||
|
||||
addUniform( uniform ) {
|
||||
|
||||
this.uniforms.push( uniform );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
removeUniform( uniform ) {
|
||||
|
||||
const index = this.uniforms.indexOf( uniform );
|
||||
|
||||
if ( index !== - 1 ) {
|
||||
|
||||
this.uniforms.splice( index, 1 );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
getBuffer() {
|
||||
|
||||
let buffer = this.buffer;
|
||||
|
||||
if ( buffer === null ) {
|
||||
|
||||
const byteLength = this.getByteLength();
|
||||
|
||||
buffer = new Float32Array( new ArrayBuffer( byteLength ) );
|
||||
|
||||
this.buffer = buffer;
|
||||
|
||||
}
|
||||
|
||||
return buffer;
|
||||
|
||||
}
|
||||
|
||||
getByteLength() {
|
||||
|
||||
let offset = 0; // global buffer offset in bytes
|
||||
|
||||
for ( let i = 0, l = this.uniforms.length; i < l; i ++ ) {
|
||||
|
||||
const uniform = this.uniforms[ i ];
|
||||
|
||||
// offset within a single chunk in bytes
|
||||
|
||||
const chunkOffset = offset % GPUChunkSize;
|
||||
const remainingSizeInChunk = GPUChunkSize - chunkOffset;
|
||||
|
||||
// conformance tests
|
||||
|
||||
if ( chunkOffset !== 0 && ( remainingSizeInChunk - uniform.boundary ) < 0 ) {
|
||||
|
||||
// check for chunk overflow
|
||||
|
||||
offset += ( GPUChunkSize - chunkOffset );
|
||||
|
||||
} else if ( chunkOffset % uniform.boundary !== 0 ) {
|
||||
|
||||
// check for correct alignment
|
||||
|
||||
offset += ( chunkOffset % uniform.boundary );
|
||||
|
||||
}
|
||||
|
||||
uniform.offset = ( offset / this.bytesPerElement );
|
||||
|
||||
offset += ( uniform.itemSize * this.bytesPerElement );
|
||||
|
||||
}
|
||||
|
||||
return offset;
|
||||
|
||||
}
|
||||
|
||||
update() {
|
||||
|
||||
let updated = false;
|
||||
|
||||
for ( const uniform of this.uniforms ) {
|
||||
|
||||
if ( this.updateByType( uniform ) === true ) {
|
||||
|
||||
updated = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return updated;
|
||||
|
||||
}
|
||||
|
||||
updateByType( uniform ) {
|
||||
|
||||
if ( uniform.isFloatUniform ) return this.updateNumber( uniform );
|
||||
if ( uniform.isVector2Uniform ) return this.updateVector2( uniform );
|
||||
if ( uniform.isVector3Uniform ) return this.updateVector3( uniform );
|
||||
if ( uniform.isVector4Uniform ) return this.updateVector4( uniform );
|
||||
if ( uniform.isColorUniform ) return this.updateColor( uniform );
|
||||
if ( uniform.isMatrix3Uniform ) return this.updateMatrix3( uniform );
|
||||
if ( uniform.isMatrix4Uniform ) return this.updateMatrix4( uniform );
|
||||
|
||||
console.error( 'THREE.WebGPUUniformsGroup: Unsupported uniform type.', uniform );
|
||||
|
||||
}
|
||||
|
||||
updateNumber( uniform ) {
|
||||
|
||||
let updated = false;
|
||||
|
||||
const a = this.buffer;
|
||||
const v = uniform.getValue();
|
||||
const offset = uniform.offset;
|
||||
|
||||
if ( a[ offset ] !== v ) {
|
||||
|
||||
a[ offset ] = v;
|
||||
updated = true;
|
||||
|
||||
}
|
||||
|
||||
return updated;
|
||||
|
||||
}
|
||||
|
||||
updateVector2( uniform ) {
|
||||
|
||||
let updated = false;
|
||||
|
||||
const a = this.buffer;
|
||||
const v = uniform.getValue();
|
||||
const offset = uniform.offset;
|
||||
|
||||
if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y ) {
|
||||
|
||||
a[ offset + 0 ] = v.x;
|
||||
a[ offset + 1 ] = v.y;
|
||||
|
||||
updated = true;
|
||||
|
||||
}
|
||||
|
||||
return updated;
|
||||
|
||||
}
|
||||
|
||||
updateVector3( uniform ) {
|
||||
|
||||
let updated = false;
|
||||
|
||||
const a = this.buffer;
|
||||
const v = uniform.getValue();
|
||||
const offset = uniform.offset;
|
||||
|
||||
if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y || a[ offset + 2 ] !== v.z ) {
|
||||
|
||||
a[ offset + 0 ] = v.x;
|
||||
a[ offset + 1 ] = v.y;
|
||||
a[ offset + 2 ] = v.z;
|
||||
|
||||
updated = true;
|
||||
|
||||
}
|
||||
|
||||
return updated;
|
||||
|
||||
}
|
||||
|
||||
updateVector4( uniform ) {
|
||||
|
||||
let updated = false;
|
||||
|
||||
const a = this.buffer;
|
||||
const v = uniform.getValue();
|
||||
const offset = uniform.offset;
|
||||
|
||||
if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y || a[ offset + 2 ] !== v.z || a[ offset + 4 ] !== v.w ) {
|
||||
|
||||
a[ offset + 0 ] = v.x;
|
||||
a[ offset + 1 ] = v.y;
|
||||
a[ offset + 2 ] = v.z;
|
||||
a[ offset + 3 ] = v.w;
|
||||
|
||||
updated = true;
|
||||
|
||||
}
|
||||
|
||||
return updated;
|
||||
|
||||
}
|
||||
|
||||
updateColor( uniform ) {
|
||||
|
||||
let updated = false;
|
||||
|
||||
const a = this.buffer;
|
||||
const c = uniform.getValue();
|
||||
const offset = uniform.offset;
|
||||
|
||||
if ( a[ offset + 0 ] !== c.r || a[ offset + 1 ] !== c.g || a[ offset + 2 ] !== c.b ) {
|
||||
|
||||
a[ offset + 0 ] = c.r;
|
||||
a[ offset + 1 ] = c.g;
|
||||
a[ offset + 2 ] = c.b;
|
||||
|
||||
updated = true;
|
||||
|
||||
}
|
||||
|
||||
return updated;
|
||||
|
||||
}
|
||||
|
||||
updateMatrix3( uniform ) {
|
||||
|
||||
let updated = false;
|
||||
|
||||
const a = this.buffer;
|
||||
const e = uniform.getValue().elements;
|
||||
const offset = uniform.offset;
|
||||
|
||||
if ( a[ offset + 0 ] !== e[ 0 ] || a[ offset + 1 ] !== e[ 1 ] || a[ offset + 2 ] !== e[ 2 ] ||
|
||||
a[ offset + 4 ] !== e[ 3 ] || a[ offset + 5 ] !== e[ 4 ] || a[ offset + 6 ] !== e[ 5 ] ||
|
||||
a[ offset + 8 ] !== e[ 6 ] || a[ offset + 9 ] !== e[ 7 ] || a[ offset + 10 ] !== e[ 8 ] ) {
|
||||
|
||||
a[ offset + 0 ] = e[ 0 ];
|
||||
a[ offset + 1 ] = e[ 1 ];
|
||||
a[ offset + 2 ] = e[ 2 ];
|
||||
a[ offset + 4 ] = e[ 3 ];
|
||||
a[ offset + 5 ] = e[ 4 ];
|
||||
a[ offset + 6 ] = e[ 5 ];
|
||||
a[ offset + 8 ] = e[ 6 ];
|
||||
a[ offset + 9 ] = e[ 7 ];
|
||||
a[ offset + 10 ] = e[ 8 ];
|
||||
|
||||
updated = true;
|
||||
|
||||
}
|
||||
|
||||
return updated;
|
||||
|
||||
}
|
||||
|
||||
updateMatrix4( uniform ) {
|
||||
|
||||
let updated = false;
|
||||
|
||||
const a = this.buffer;
|
||||
const e = uniform.getValue().elements;
|
||||
const offset = uniform.offset;
|
||||
|
||||
if ( arraysEqual( a, e, offset ) === false ) {
|
||||
|
||||
a.set( e, offset );
|
||||
updated = true;
|
||||
|
||||
}
|
||||
|
||||
return updated;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function arraysEqual( a, b, offset ) {
|
||||
|
||||
for ( let i = 0, l = b.length; i < l; i ++ ) {
|
||||
|
||||
if ( a[ offset + i ] !== b[ i ] ) return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
WebGPUUniformsGroup.prototype.isUniformsGroup = true;
|
||||
|
||||
export default WebGPUUniformsGroup;
|
||||
261
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/constants.js
generated
vendored
Normal file
261
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/constants.js
generated
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
export const GPUPrimitiveTopology = {
|
||||
PointList: 'point-list',
|
||||
LineList: 'line-list',
|
||||
LineStrip: 'line-strip',
|
||||
TriangleList: 'triangle-list',
|
||||
TriangleStrip: 'triangle-strip',
|
||||
};
|
||||
|
||||
export const GPUCompareFunction = {
|
||||
Never: 'never',
|
||||
Less: 'less',
|
||||
Equal: 'equal',
|
||||
LessEqual: 'less-equal',
|
||||
Greater: 'greater',
|
||||
NotEqual: 'not-equal',
|
||||
GreaterEqual: 'greater-equal',
|
||||
Always: 'always'
|
||||
};
|
||||
|
||||
export const GPUStoreOp = {
|
||||
Store: 'store',
|
||||
Discard: 'discard'
|
||||
};
|
||||
|
||||
export const GPULoadOp = {
|
||||
Load: 'load',
|
||||
Clear: 'clear'
|
||||
};
|
||||
|
||||
export const GPUFrontFace = {
|
||||
CCW: 'ccw',
|
||||
CW: 'cw'
|
||||
};
|
||||
|
||||
export const GPUCullMode = {
|
||||
None: 'none',
|
||||
Front: 'front',
|
||||
Back: 'back'
|
||||
};
|
||||
|
||||
export const GPUIndexFormat = {
|
||||
Uint16: 'uint16',
|
||||
Uint32: 'uint32'
|
||||
};
|
||||
|
||||
export const GPUVertexFormat = {
|
||||
Uint8x2: 'uint8x2',
|
||||
Uint8x4: 'uint8x4',
|
||||
Sint8x2: 'sint8x2',
|
||||
Sint8x4: 'sint8x4',
|
||||
Unorm8x2: 'unorm8x2',
|
||||
Unorm8x4: 'unorm8x4',
|
||||
Snorm8x2: 'snorm8x2',
|
||||
Snorm8x4: 'snorm8x4',
|
||||
Uint16x2: 'uint16x2',
|
||||
Uint16x4: 'uint16x4',
|
||||
Sint16x2: 'sint16x2',
|
||||
Sint16x4: 'sint16x4',
|
||||
Unorm16x2: 'unorm16x2',
|
||||
Unorm16x4: 'unorm16x4',
|
||||
Snorm16x2: 'snorm16x2',
|
||||
Snorm16x4: 'snorm16x4',
|
||||
Float16x2: 'float16x2',
|
||||
Float16x4: 'float16x4',
|
||||
Float32: 'float32',
|
||||
Float32x2: 'float32x2',
|
||||
Float32x3: 'float32x3',
|
||||
Float32x4: 'float32x4',
|
||||
Uint32: 'uint32',
|
||||
Uint32x2: 'uint32x2',
|
||||
Uint32x3: 'uint32x3',
|
||||
Uint32x4: 'uint32x4',
|
||||
Sint32: 'sint32',
|
||||
Sint32x2: 'sint32x2',
|
||||
Sint32x3: 'sint32x3',
|
||||
Sint32x4: 'sint32x4'
|
||||
};
|
||||
|
||||
export const GPUTextureFormat = {
|
||||
|
||||
// 8-bit formats
|
||||
|
||||
R8Unorm: 'r8unorm',
|
||||
R8Snorm: 'r8snorm',
|
||||
R8Uint: 'r8uint',
|
||||
R8Sint: 'r8sint',
|
||||
|
||||
// 16-bit formats
|
||||
|
||||
R16Uint: 'r16uint',
|
||||
R16Sint: 'r16sint',
|
||||
R16Float: 'r16float',
|
||||
RG8Unorm: 'rg8unorm',
|
||||
RG8Snorm: 'rg8snorm',
|
||||
RG8Uint: 'rg8uint',
|
||||
RG8Sint: 'rg8sint',
|
||||
|
||||
// 32-bit formats
|
||||
|
||||
R32Uint: 'r32uint',
|
||||
R32Sint: 'r32sint',
|
||||
R32Float: 'r32float',
|
||||
RG16Uint: 'rg16uint',
|
||||
RG16Sint: 'rg16sint',
|
||||
RG16Float: 'rg16float',
|
||||
RGBA8Unorm: 'rgba8unorm',
|
||||
RGBA8UnormSRGB: 'rgba8unorm-srgb',
|
||||
RGBA8Snorm: 'rgba8snorm',
|
||||
RGBA8Uint: 'rgba8uint',
|
||||
RGBA8Sint: 'rgba8sint',
|
||||
BGRA8Unorm: 'bgra8unorm',
|
||||
BGRA8UnormSRGB: 'bgra8unorm-srgb',
|
||||
// Packed 32-bit formats
|
||||
RGB9E5UFloat: 'rgb9e5ufloat',
|
||||
RGB10A2Unorm: 'rgb10a2unorm',
|
||||
RG11B10uFloat: 'rgb10a2unorm',
|
||||
|
||||
// 64-bit formats
|
||||
|
||||
RG32Uint: 'rg32uint',
|
||||
RG32Sint: 'rg32sint',
|
||||
RG32Float: 'rg32float',
|
||||
RGBA16Uint: 'rgba16uint',
|
||||
RGBA16Sint: 'rgba16sint',
|
||||
RGBA16Float: 'rgba16float',
|
||||
|
||||
// 128-bit formats
|
||||
|
||||
RGBA32Uint: 'rgba32uint',
|
||||
RGBA32Sint: 'rgba32sint',
|
||||
RGBA32Float: 'rgba32float',
|
||||
|
||||
// Depth and stencil formats
|
||||
|
||||
Stencil8: 'stencil8',
|
||||
Depth16Unorm: 'depth16unorm',
|
||||
Depth24Plus: 'depth24plus',
|
||||
Depth24PlusStencil8: 'depth24plus-stencil8',
|
||||
Depth32Float: 'depth32float',
|
||||
|
||||
// BC compressed formats usable if 'texture-compression-bc' is both
|
||||
// supported by the device/user agent and enabled in requestDevice.
|
||||
|
||||
BC1RGBAUnorm: 'bc1-rgba-unorm',
|
||||
BC1RGBAUnormSRGB: 'bc1-rgba-unorm-srgb',
|
||||
BC2RGBAUnorm: 'bc2-rgba-unorm',
|
||||
BC2RGBAUnormSRGB: 'bc2-rgba-unorm-srgb',
|
||||
BC3RGBAUnorm: 'bc3-rgba-unorm',
|
||||
BC3RGBAUnormSRGB: 'bc3-rgba-unorm-srgb',
|
||||
BC4RUnorm: 'bc4-r-unorm',
|
||||
BC4RSNorm: 'bc4-r-snorm',
|
||||
BC5RGUnorm: 'bc5-rg-unorm',
|
||||
BC5RGSnorm: 'bc5-rg-snorm',
|
||||
BC6HRGBUFloat: 'bc6h-rgb-ufloat',
|
||||
BC6HRGBFloat: 'bc6h-rgb-float',
|
||||
BC7RGBAUnorm: 'bc7-rgba-unorm',
|
||||
BC7RGBAUnormSRGB: 'bc7-rgba-srgb',
|
||||
|
||||
// 'depth24unorm-stencil8' extension
|
||||
|
||||
Depth24UnormStencil8: 'depth24unorm-stencil8',
|
||||
|
||||
// 'depth32float-stencil8' extension
|
||||
|
||||
Depth32FloatStencil8: 'depth32float-stencil8',
|
||||
|
||||
};
|
||||
|
||||
export const GPUAddressMode = {
|
||||
ClampToEdge: 'clamp-to-edge',
|
||||
Repeat: 'repeat',
|
||||
MirrorRepeat: 'mirror-repeat'
|
||||
};
|
||||
|
||||
export const GPUFilterMode = {
|
||||
Linear: 'linear',
|
||||
Nearest: 'nearest'
|
||||
};
|
||||
|
||||
export const GPUBlendFactor = {
|
||||
Zero: 'zero',
|
||||
One: 'one',
|
||||
SrcColor: 'src-color',
|
||||
OneMinusSrcColor: 'one-minus-src-color',
|
||||
SrcAlpha: 'src-alpha',
|
||||
OneMinusSrcAlpha: 'one-minus-src-alpha',
|
||||
DstColor: 'dst-color',
|
||||
OneMinusDstColor: 'one-minus-dst-color',
|
||||
DstAlpha: 'dst-alpha',
|
||||
OneMinusDstAlpha: 'one-minus-dst-alpha',
|
||||
SrcAlphaSaturated: 'src-alpha-saturated',
|
||||
BlendColor: 'blend-color',
|
||||
OneMinusBlendColor: 'one-minus-blend-color'
|
||||
};
|
||||
|
||||
export const GPUBlendOperation = {
|
||||
Add: 'add',
|
||||
Subtract: 'subtract',
|
||||
ReverseSubtract: 'reverse-subtract',
|
||||
Min: 'min',
|
||||
Max: 'max'
|
||||
};
|
||||
|
||||
export const GPUColorWriteFlags = {
|
||||
None: 0,
|
||||
Red: 0x1,
|
||||
Green: 0x2,
|
||||
Blue: 0x4,
|
||||
Alpha: 0x8,
|
||||
All: 0xF
|
||||
};
|
||||
|
||||
export const GPUStencilOperation = {
|
||||
Keep: 'keep',
|
||||
Zero: 'zero',
|
||||
Replace: 'replace',
|
||||
Invert: 'invert',
|
||||
IncrementClamp: 'increment-clamp',
|
||||
DecrementClamp: 'decrement-clamp',
|
||||
IncrementWrap: 'increment-wrap',
|
||||
DecrementWrap: 'decrement-wrap'
|
||||
};
|
||||
|
||||
export const GPUBindingType = {
|
||||
UniformBuffer: 'uniform-buffer',
|
||||
StorageBuffer: 'storage-buffer',
|
||||
ReadonlyStorageBuffer: 'readonly-storage-buffer',
|
||||
Sampler: 'sampler',
|
||||
ComparisonSampler: 'comparison-sampler',
|
||||
SampledTexture: 'sampled-texture',
|
||||
MultisampledTexture: 'multisampled-texture',
|
||||
ReadonlyStorageTexture: 'readonly-storage-texture',
|
||||
WriteonlyStorageTexture: 'writeonly-storage-texture'
|
||||
};
|
||||
|
||||
export const GPUTextureDimension = {
|
||||
OneD: '1d',
|
||||
TwoD: '2d',
|
||||
ThreeD: '3d'
|
||||
};
|
||||
|
||||
export const GPUTextureViewDimension = {
|
||||
OneD: '1d',
|
||||
TwoD: '2d',
|
||||
TwoDArray: '2d-array',
|
||||
Cube: 'cube',
|
||||
CubeArray: 'cube-array',
|
||||
ThreeD: '3d'
|
||||
};
|
||||
|
||||
export const GPUInputStepMode = {
|
||||
Vertex: 'vertex',
|
||||
Instance: 'instance'
|
||||
};
|
||||
|
||||
export const GPUChunkSize = 16; // size of a chunk in bytes (STD140 layout)
|
||||
|
||||
// @TODO: Move to src/constants.js
|
||||
|
||||
export const BlendColorFactor = 211;
|
||||
export const OneMinusBlendColorFactor = 212;
|
||||
822
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js
generated
vendored
Normal file
822
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js
generated
vendored
Normal file
@@ -0,0 +1,822 @@
|
||||
import { LinearEncoding } from 'three';
|
||||
|
||||
import WebGPUNodeUniformsGroup from './WebGPUNodeUniformsGroup.js';
|
||||
import {
|
||||
FloatNodeUniform, Vector2NodeUniform, Vector3NodeUniform, Vector4NodeUniform,
|
||||
ColorNodeUniform, Matrix3NodeUniform, Matrix4NodeUniform
|
||||
} from './WebGPUNodeUniform.js';
|
||||
import WebGPUNodeSampler from './WebGPUNodeSampler.js';
|
||||
import { WebGPUNodeSampledTexture } from './WebGPUNodeSampledTexture.js';
|
||||
|
||||
import WebGPUUniformBuffer from '../WebGPUUniformBuffer.js';
|
||||
import { getVectorLength, getStrideLength } from '../WebGPUBufferUtils.js';
|
||||
|
||||
import VarNode from 'three-nodes/core/VarNode.js';
|
||||
import CodeNode from 'three-nodes/core/CodeNode.js';
|
||||
import BypassNode from 'three-nodes/core/BypassNode.js';
|
||||
import ExpressionNode from 'three-nodes/core/ExpressionNode.js';
|
||||
import NodeBuilder from 'three-nodes/core/NodeBuilder.js';
|
||||
import MaterialNode from 'three-nodes/accessors/MaterialNode.js';
|
||||
import PositionNode from 'three-nodes/accessors/PositionNode.js';
|
||||
import NormalNode from 'three-nodes/accessors/NormalNode.js';
|
||||
import ModelViewProjectionNode from 'three-nodes/accessors/ModelViewProjectionNode.js';
|
||||
import SkinningNode from 'three-nodes/accessors/SkinningNode.js';
|
||||
import ColorSpaceNode from 'three-nodes/display/ColorSpaceNode.js';
|
||||
import LightContextNode from 'three-nodes/lights/LightContextNode.js';
|
||||
import OperatorNode from 'three-nodes/math/OperatorNode.js';
|
||||
import WGSLNodeParser from 'three-nodes/parsers/WGSLNodeParser.js';
|
||||
import { add, join, nodeObject } from 'three-nodes/ShaderNode.js';
|
||||
import { getRoughness } from 'three-nodes/functions/PhysicalMaterialFunctions.js';
|
||||
|
||||
const wgslTypeLib = {
|
||||
float: 'f32',
|
||||
int: 'i32',
|
||||
vec2: 'vec2<f32>',
|
||||
vec3: 'vec3<f32>',
|
||||
vec4: 'vec4<f32>',
|
||||
uvec4: 'vec4<u32>',
|
||||
bvec3: 'vec3<bool>',
|
||||
mat3: 'mat3x3<f32>',
|
||||
mat4: 'mat4x4<f32>'
|
||||
};
|
||||
|
||||
const wgslMethods = {
|
||||
dFdx: 'dpdx',
|
||||
dFdy: 'dpdy'
|
||||
};
|
||||
|
||||
const wgslPolyfill = {
|
||||
lessThanEqual: new CodeNode( `
|
||||
fn lessThanEqual( a : vec3<f32>, b : vec3<f32> ) -> vec3<bool> {
|
||||
|
||||
return vec3<bool>( a.x <= b.x, a.y <= b.y, a.z <= b.z );
|
||||
|
||||
}
|
||||
` ),
|
||||
mod: new CodeNode( `
|
||||
fn mod( x : f32, y : f32 ) -> f32 {
|
||||
|
||||
return x - y * floor( x / y );
|
||||
|
||||
}
|
||||
` ),
|
||||
repeatWrapping: new CodeNode( `
|
||||
fn repeatWrapping( uv : vec2<f32>, dimension : vec2<i32> ) -> vec2<i32> {
|
||||
|
||||
let uvScaled = vec2<i32>( uv * vec2<f32>( dimension ) );
|
||||
|
||||
return ( ( uvScaled % dimension ) + dimension ) % dimension;
|
||||
|
||||
}
|
||||
` ),
|
||||
inversesqrt: new CodeNode( `
|
||||
fn inversesqrt( x : f32 ) -> f32 {
|
||||
|
||||
return 1.0 / sqrt( x );
|
||||
|
||||
}
|
||||
` )
|
||||
};
|
||||
|
||||
class WebGPUNodeBuilder extends NodeBuilder {
|
||||
|
||||
constructor( object, renderer, lightNode = null ) {
|
||||
|
||||
super( object, renderer, new WGSLNodeParser() );
|
||||
|
||||
this.lightNode = lightNode;
|
||||
|
||||
this.bindings = { vertex: [], fragment: [] };
|
||||
this.bindingsOffset = { vertex: 0, fragment: 0 };
|
||||
|
||||
this.uniformsGroup = {};
|
||||
|
||||
this._parseObject();
|
||||
|
||||
}
|
||||
|
||||
_parseObject() {
|
||||
|
||||
const object = this.object;
|
||||
const material = this.material;
|
||||
|
||||
// parse inputs
|
||||
|
||||
if ( material.isMeshStandardMaterial || material.isMeshBasicMaterial || material.isPointsMaterial || material.isLineBasicMaterial ) {
|
||||
|
||||
let lightNode = material.lightNode;
|
||||
|
||||
// VERTEX STAGE
|
||||
|
||||
let vertex = new PositionNode( PositionNode.GEOMETRY );
|
||||
|
||||
if ( lightNode === null && this.lightNode && this.lightNode.hasLights === true ) {
|
||||
|
||||
lightNode = this.lightNode;
|
||||
|
||||
}
|
||||
|
||||
if ( material.positionNode && material.positionNode.isNode ) {
|
||||
|
||||
const assignPositionNode = new OperatorNode( '=', new PositionNode( PositionNode.LOCAL ), material.positionNode );
|
||||
|
||||
vertex = new BypassNode( vertex, assignPositionNode );
|
||||
|
||||
}
|
||||
|
||||
if ( object.isSkinnedMesh === true ) {
|
||||
|
||||
vertex = new BypassNode( vertex, new SkinningNode( object ) );
|
||||
|
||||
}
|
||||
|
||||
this.context.vertex = vertex;
|
||||
|
||||
this.addFlow( 'vertex', new VarNode( new ModelViewProjectionNode(), 'MVP', 'vec4' ) );
|
||||
|
||||
// COLOR
|
||||
|
||||
let colorNode = null;
|
||||
|
||||
if ( material.colorNode && material.colorNode.isNode ) {
|
||||
|
||||
colorNode = material.colorNode;
|
||||
|
||||
} else {
|
||||
|
||||
colorNode = new MaterialNode( MaterialNode.COLOR );
|
||||
|
||||
}
|
||||
|
||||
colorNode = this.addFlow( 'fragment', new VarNode( colorNode, 'Color', 'vec4' ) );
|
||||
|
||||
const diffuseColorNode = this.addFlow( 'fragment', new VarNode( colorNode, 'DiffuseColor', 'vec4' ) );
|
||||
|
||||
// OPACITY
|
||||
|
||||
let opacityNode = null;
|
||||
|
||||
if ( material.opacityNode && material.opacityNode.isNode ) {
|
||||
|
||||
opacityNode = material.opacityNode;
|
||||
|
||||
} else {
|
||||
|
||||
opacityNode = new VarNode( new MaterialNode( MaterialNode.OPACITY ) );
|
||||
|
||||
}
|
||||
|
||||
this.addFlow( 'fragment', new VarNode( opacityNode, 'OPACITY', 'float' ) );
|
||||
|
||||
this.addFlow( 'fragment', new ExpressionNode( 'DiffuseColor.a = DiffuseColor.a * OPACITY;' ) );
|
||||
|
||||
// ALPHA TEST
|
||||
|
||||
let alphaTest = null;
|
||||
|
||||
if ( material.alphaTestNode && material.alphaTestNode.isNode ) {
|
||||
|
||||
alphaTest = material.alphaTestNode;
|
||||
|
||||
} else if ( material.alphaTest > 0 ) {
|
||||
|
||||
alphaTest = new MaterialNode( MaterialNode.ALPHA_TEST );
|
||||
|
||||
}
|
||||
|
||||
if ( alphaTest !== null ) {
|
||||
|
||||
this.addFlow( 'fragment', new VarNode( alphaTest, 'AlphaTest', 'float' ) );
|
||||
|
||||
this.addFlow( 'fragment', new ExpressionNode( 'if ( DiffuseColor.a <= AlphaTest ) { discard; }' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( material.isMeshStandardMaterial ) {
|
||||
|
||||
// METALNESS
|
||||
|
||||
let metalnessNode = null;
|
||||
|
||||
if ( material.metalnessNode && material.metalnessNode.isNode ) {
|
||||
|
||||
metalnessNode = material.metalnessNode;
|
||||
|
||||
} else {
|
||||
|
||||
metalnessNode = new MaterialNode( MaterialNode.METALNESS );
|
||||
|
||||
}
|
||||
|
||||
this.addFlow( 'fragment', new VarNode( metalnessNode, 'Metalness', 'float' ) );
|
||||
|
||||
this.addFlow( 'fragment', new ExpressionNode( 'DiffuseColor = vec4<f32>( DiffuseColor.rgb * ( 1.0 - Metalness ), DiffuseColor.a );' ) );
|
||||
|
||||
// ROUGHNESS
|
||||
|
||||
let roughnessNode = null;
|
||||
|
||||
if ( material.roughnessNode && material.roughnessNode.isNode ) {
|
||||
|
||||
roughnessNode = material.roughnessNode;
|
||||
|
||||
} else {
|
||||
|
||||
roughnessNode = new MaterialNode( MaterialNode.ROUGHNESS );
|
||||
|
||||
}
|
||||
|
||||
roughnessNode = getRoughness( { roughness: roughnessNode } );
|
||||
|
||||
this.addFlow( 'fragment', new VarNode( roughnessNode, 'Roughness', 'float' ) );
|
||||
|
||||
// SPECULAR_TINT
|
||||
|
||||
this.addFlow( 'fragment', new VarNode( new ExpressionNode( 'mix( vec3<f32>( 0.04 ), Color.rgb, Metalness )', 'vec3' ), 'SpecularColor', 'color' ) );
|
||||
|
||||
// NORMAL_VIEW
|
||||
|
||||
let normalNode = null;
|
||||
|
||||
if ( material.normalNode && material.normalNode.isNode ) {
|
||||
|
||||
normalNode = material.normalNode;
|
||||
|
||||
} else {
|
||||
|
||||
normalNode = new NormalNode( NormalNode.VIEW );
|
||||
|
||||
}
|
||||
|
||||
this.addFlow( 'fragment', new VarNode( normalNode, 'TransformedNormalView', 'vec3' ) );
|
||||
|
||||
}
|
||||
|
||||
// LIGHT
|
||||
|
||||
let outputNode = diffuseColorNode;
|
||||
|
||||
if ( lightNode && lightNode.isNode ) {
|
||||
|
||||
const lightContextNode = new LightContextNode( lightNode );
|
||||
|
||||
outputNode = this.addFlow( 'fragment', new VarNode( lightContextNode, 'Light', 'vec3' ) );
|
||||
|
||||
}
|
||||
|
||||
// OUTGOING LIGHT
|
||||
|
||||
let outgoingLightNode = nodeObject( outputNode ).xyz;
|
||||
|
||||
// EMISSIVE
|
||||
|
||||
const emissiveNode = material.emissiveNode;
|
||||
|
||||
if ( emissiveNode && emissiveNode.isNode ) {
|
||||
|
||||
outgoingLightNode = add( emissiveNode, outgoingLightNode );
|
||||
|
||||
}
|
||||
|
||||
outputNode = join( outgoingLightNode.xyz, nodeObject( diffuseColorNode ).w );
|
||||
|
||||
// OUTPUT
|
||||
|
||||
const outputEncoding = this.renderer.outputEncoding;
|
||||
|
||||
if ( outputEncoding !== LinearEncoding ) {
|
||||
|
||||
outputNode = new ColorSpaceNode( ColorSpaceNode.LINEAR_TO_LINEAR, outputNode );
|
||||
outputNode.fromEncoding( outputEncoding );
|
||||
|
||||
}
|
||||
|
||||
this.addFlow( 'fragment', new VarNode( outputNode, 'Output', 'vec4' ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
addFlowCode( code ) {
|
||||
|
||||
if ( ! /;\s*$/.test( code ) ) {
|
||||
|
||||
code += ';';
|
||||
|
||||
}
|
||||
|
||||
super.addFlowCode( code + '\n\t' );
|
||||
|
||||
}
|
||||
|
||||
getTexture( textureProperty, uvSnippet, biasSnippet, shaderStage = this.shaderStage ) {
|
||||
|
||||
if ( shaderStage === 'fragment' ) {
|
||||
|
||||
return `textureSample( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet} )`;
|
||||
|
||||
} else {
|
||||
|
||||
this._include( 'repeatWrapping' );
|
||||
|
||||
const dimension = `textureDimensions( ${textureProperty}, 0 )`;
|
||||
|
||||
return `textureLoad( ${textureProperty}, repeatWrapping( ${uvSnippet}, ${dimension} ), 0 )`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getPropertyName( node, shaderStage = this.shaderStage ) {
|
||||
|
||||
if ( node.isNodeVary === true ) {
|
||||
|
||||
if ( shaderStage === 'vertex' ) {
|
||||
|
||||
return `NodeVarys.${ node.name }`;
|
||||
|
||||
}
|
||||
|
||||
} else if ( node.isNodeUniform === true ) {
|
||||
|
||||
const name = node.name;
|
||||
const type = node.type;
|
||||
|
||||
if ( type === 'texture' ) {
|
||||
|
||||
return name;
|
||||
|
||||
} else if ( type === 'buffer' ) {
|
||||
|
||||
return `NodeBuffer.${name}`;
|
||||
|
||||
} else {
|
||||
|
||||
return `NodeUniforms.${name}`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return super.getPropertyName( node );
|
||||
|
||||
}
|
||||
|
||||
getBindings() {
|
||||
|
||||
const bindings = this.bindings;
|
||||
|
||||
return [ ...bindings.vertex, ...bindings.fragment ];
|
||||
|
||||
}
|
||||
|
||||
getUniformFromNode( node, shaderStage, type ) {
|
||||
|
||||
const uniformNode = super.getUniformFromNode( node, shaderStage, type );
|
||||
const nodeData = this.getDataFromNode( node, shaderStage );
|
||||
|
||||
if ( nodeData.uniformGPU === undefined ) {
|
||||
|
||||
let uniformGPU;
|
||||
|
||||
const bindings = this.bindings[ shaderStage ];
|
||||
|
||||
if ( type === 'texture' ) {
|
||||
|
||||
const sampler = new WebGPUNodeSampler( `${uniformNode.name}_sampler`, uniformNode.node );
|
||||
const texture = new WebGPUNodeSampledTexture( uniformNode.name, uniformNode.node );
|
||||
|
||||
// add first textures in sequence and group for last
|
||||
const lastBinding = bindings[ bindings.length - 1 ];
|
||||
const index = lastBinding && lastBinding.isUniformsGroup ? bindings.length - 1 : bindings.length;
|
||||
|
||||
if ( shaderStage === 'fragment' ) {
|
||||
|
||||
bindings.splice( index, 0, sampler, texture );
|
||||
|
||||
uniformGPU = [ sampler, texture ];
|
||||
|
||||
} else {
|
||||
|
||||
bindings.splice( index, 0, texture );
|
||||
|
||||
uniformGPU = [ texture ];
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else if ( type === 'buffer' ) {
|
||||
|
||||
const buffer = new WebGPUUniformBuffer( 'NodeBuffer', node.value );
|
||||
|
||||
// add first textures in sequence and group for last
|
||||
const lastBinding = bindings[ bindings.length - 1 ];
|
||||
const index = lastBinding && lastBinding.isUniformsGroup ? bindings.length - 1 : bindings.length;
|
||||
|
||||
bindings.splice( index, 0, buffer );
|
||||
|
||||
uniformGPU = buffer;
|
||||
|
||||
} else {
|
||||
|
||||
let uniformsGroup = this.uniformsGroup[ shaderStage ];
|
||||
|
||||
if ( uniformsGroup === undefined ) {
|
||||
|
||||
uniformsGroup = new WebGPUNodeUniformsGroup( shaderStage );
|
||||
|
||||
this.uniformsGroup[ shaderStage ] = uniformsGroup;
|
||||
|
||||
bindings.push( uniformsGroup );
|
||||
|
||||
}
|
||||
|
||||
if ( node.isArrayInputNode === true ) {
|
||||
|
||||
uniformGPU = [];
|
||||
|
||||
for ( const inputNode of node.nodes ) {
|
||||
|
||||
const uniformNodeGPU = this._getNodeUniform( inputNode, type );
|
||||
|
||||
// fit bounds to buffer
|
||||
uniformNodeGPU.boundary = getVectorLength( uniformNodeGPU.itemSize );
|
||||
uniformNodeGPU.itemSize = getStrideLength( uniformNodeGPU.itemSize );
|
||||
|
||||
uniformsGroup.addUniform( uniformNodeGPU );
|
||||
|
||||
uniformGPU.push( uniformNodeGPU );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
uniformGPU = this._getNodeUniform( uniformNode, type );
|
||||
|
||||
uniformsGroup.addUniform( uniformGPU );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nodeData.uniformGPU = uniformGPU;
|
||||
|
||||
if ( shaderStage === 'vertex' ) {
|
||||
|
||||
this.bindingsOffset[ 'fragment' ] = bindings.length;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return uniformNode;
|
||||
|
||||
}
|
||||
|
||||
getAttributes( shaderStage ) {
|
||||
|
||||
let snippet = '';
|
||||
|
||||
if ( shaderStage === 'vertex' ) {
|
||||
|
||||
const attributes = this.attributes;
|
||||
const length = attributes.length;
|
||||
|
||||
snippet += '\n';
|
||||
|
||||
for ( let index = 0; index < length; index ++ ) {
|
||||
|
||||
const attribute = attributes[ index ];
|
||||
const name = attribute.name;
|
||||
const type = this.getType( attribute.type );
|
||||
|
||||
snippet += `\t@location( ${index} ) ${ name } : ${ type }`;
|
||||
|
||||
if ( index + 1 < length ) {
|
||||
|
||||
snippet += ',\n';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
snippet += '\n';
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
getVars( shaderStage ) {
|
||||
|
||||
let snippet = '';
|
||||
|
||||
const vars = this.vars[ shaderStage ];
|
||||
|
||||
for ( let index = 0; index < vars.length; index ++ ) {
|
||||
|
||||
const variable = vars[ index ];
|
||||
|
||||
const name = variable.name;
|
||||
const type = this.getType( variable.type );
|
||||
|
||||
snippet += `var ${name} : ${type}; `;
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
getVarys( shaderStage ) {
|
||||
|
||||
let snippet = '';
|
||||
|
||||
if ( shaderStage === 'vertex' ) {
|
||||
|
||||
snippet += '\t@builtin( position ) Vertex: vec4<f32>;\n';
|
||||
|
||||
const varys = this.varys;
|
||||
|
||||
for ( let index = 0; index < varys.length; index ++ ) {
|
||||
|
||||
const vary = varys[ index ];
|
||||
|
||||
snippet += `\t@location( ${index} ) ${ vary.name } : ${ this.getType( vary.type ) };\n`;
|
||||
|
||||
}
|
||||
|
||||
snippet = this._getWGSLStruct( 'NodeVarysStruct', snippet );
|
||||
|
||||
} else if ( shaderStage === 'fragment' ) {
|
||||
|
||||
const varys = this.varys;
|
||||
|
||||
snippet += '\n';
|
||||
|
||||
for ( let index = 0; index < varys.length; index ++ ) {
|
||||
|
||||
const vary = varys[ index ];
|
||||
|
||||
snippet += `\t@location( ${index} ) ${ vary.name } : ${ this.getType( vary.type ) }`;
|
||||
|
||||
if ( index + 1 < varys.length ) {
|
||||
|
||||
snippet += ',\n';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
snippet += '\n';
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
getUniforms( shaderStage ) {
|
||||
|
||||
const uniforms = this.uniforms[ shaderStage ];
|
||||
|
||||
let snippet = '';
|
||||
let groupSnippet = '';
|
||||
|
||||
let index = this.bindingsOffset[ shaderStage ];
|
||||
|
||||
for ( const uniform of uniforms ) {
|
||||
|
||||
if ( uniform.type === 'texture' ) {
|
||||
|
||||
if ( shaderStage === 'fragment' ) {
|
||||
|
||||
snippet += `@group( 0 ) @binding( ${index ++} ) var ${uniform.name}_sampler : sampler; `;
|
||||
|
||||
}
|
||||
|
||||
snippet += `@group( 0 ) @binding( ${index ++} ) var ${uniform.name} : texture_2d<f32>; `;
|
||||
|
||||
} else if ( uniform.type === 'buffer' ) {
|
||||
|
||||
const bufferNode = uniform.node;
|
||||
const bufferType = this.getType( bufferNode.bufferType );
|
||||
const bufferCount = bufferNode.bufferCount;
|
||||
|
||||
const bufferSnippet = `\t${uniform.name} : array< ${bufferType}, ${bufferCount} >;\n`;
|
||||
|
||||
snippet += this._getWGSLUniforms( 'NodeBuffer', bufferSnippet, index ++ ) + '\n\n';
|
||||
|
||||
} else {
|
||||
|
||||
const vectorType = this.getType( this.getVectorType( uniform.type ) );
|
||||
|
||||
if ( Array.isArray( uniform.value ) === true ) {
|
||||
|
||||
const length = uniform.value.length;
|
||||
|
||||
groupSnippet += `uniform ${vectorType}[ ${length} ] ${uniform.name}; `;
|
||||
|
||||
} else {
|
||||
|
||||
groupSnippet += `\t${uniform.name} : ${ vectorType};\n`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( groupSnippet ) {
|
||||
|
||||
snippet += this._getWGSLUniforms( 'NodeUniforms', groupSnippet, index ++ );
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
buildCode() {
|
||||
|
||||
const shadersData = { fragment: {}, vertex: {} };
|
||||
|
||||
for ( const shaderStage in shadersData ) {
|
||||
|
||||
let flow = '// code\n';
|
||||
flow += `\t${ this.flowCode[ shaderStage ] }`;
|
||||
flow += '\n';
|
||||
|
||||
const flowNodes = this.flowNodes[ shaderStage ];
|
||||
const mainNode = flowNodes[ flowNodes.length - 1 ];
|
||||
|
||||
for ( const node of flowNodes ) {
|
||||
|
||||
const flowSlotData = this.getFlowData( shaderStage, node );
|
||||
const slotName = node.name;
|
||||
|
||||
if ( slotName ) {
|
||||
|
||||
if ( flow.length > 0 ) flow += '\n';
|
||||
|
||||
flow += `\t// FLOW -> ${ slotName }\n\t`;
|
||||
|
||||
}
|
||||
|
||||
flow += `${ flowSlotData.code }\n\t`;
|
||||
|
||||
if ( node === mainNode ) {
|
||||
|
||||
flow += '// FLOW RESULT\n\t';
|
||||
|
||||
if ( shaderStage === 'vertex' ) {
|
||||
|
||||
flow += 'NodeVarys.Vertex = ';
|
||||
|
||||
} else if ( shaderStage === 'fragment' ) {
|
||||
|
||||
flow += 'return ';
|
||||
|
||||
}
|
||||
|
||||
flow += `${ flowSlotData.result };`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const stageData = shadersData[ shaderStage ];
|
||||
|
||||
stageData.uniforms = this.getUniforms( shaderStage );
|
||||
stageData.attributes = this.getAttributes( shaderStage );
|
||||
stageData.varys = this.getVarys( shaderStage );
|
||||
stageData.vars = this.getVars( shaderStage );
|
||||
stageData.codes = this.getCodes( shaderStage );
|
||||
stageData.flow = flow;
|
||||
|
||||
}
|
||||
|
||||
this.vertexShader = this._getWGSLVertexCode( shadersData.vertex );
|
||||
this.fragmentShader = this._getWGSLFragmentCode( shadersData.fragment );
|
||||
|
||||
}
|
||||
|
||||
getMethod( method ) {
|
||||
|
||||
if ( wgslPolyfill[ method ] !== undefined ) {
|
||||
|
||||
this._include( method );
|
||||
|
||||
}
|
||||
|
||||
return wgslMethods[ method ] || method;
|
||||
|
||||
}
|
||||
|
||||
getType( type ) {
|
||||
|
||||
return wgslTypeLib[ type ] || type;
|
||||
|
||||
}
|
||||
|
||||
_include( name ) {
|
||||
|
||||
wgslPolyfill[ name ].build( this );
|
||||
|
||||
}
|
||||
|
||||
_getNodeUniform( uniformNode, type ) {
|
||||
|
||||
if ( type === 'float' ) return new FloatNodeUniform( uniformNode );
|
||||
if ( type === 'vec2' ) return new Vector2NodeUniform( uniformNode );
|
||||
if ( type === 'vec3' ) return new Vector3NodeUniform( uniformNode );
|
||||
if ( type === 'vec4' ) return new Vector4NodeUniform( uniformNode );
|
||||
if ( type === 'color' ) return new ColorNodeUniform( uniformNode );
|
||||
if ( type === 'mat3' ) return new Matrix3NodeUniform( uniformNode );
|
||||
if ( type === 'mat4' ) return new Matrix4NodeUniform( uniformNode );
|
||||
|
||||
throw new Error( `Uniform "${type}" not declared.` );
|
||||
|
||||
}
|
||||
|
||||
_getWGSLVertexCode( shaderData ) {
|
||||
|
||||
return `${ this.getSignature() }
|
||||
|
||||
// uniforms
|
||||
${shaderData.uniforms}
|
||||
|
||||
// varys
|
||||
${shaderData.varys}
|
||||
|
||||
// codes
|
||||
${shaderData.codes}
|
||||
|
||||
@stage( vertex )
|
||||
fn main( ${shaderData.attributes} ) -> NodeVarysStruct {
|
||||
|
||||
// system
|
||||
var NodeVarys: NodeVarysStruct;
|
||||
|
||||
// vars
|
||||
${shaderData.vars}
|
||||
|
||||
// flow
|
||||
${shaderData.flow}
|
||||
|
||||
return NodeVarys;
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
}
|
||||
|
||||
_getWGSLFragmentCode( shaderData ) {
|
||||
|
||||
return `${ this.getSignature() }
|
||||
|
||||
// uniforms
|
||||
${shaderData.uniforms}
|
||||
|
||||
// codes
|
||||
${shaderData.codes}
|
||||
|
||||
@stage( fragment )
|
||||
fn main( ${shaderData.varys} ) -> @location( 0 ) vec4<f32> {
|
||||
|
||||
// vars
|
||||
${shaderData.vars}
|
||||
|
||||
// flow
|
||||
${shaderData.flow}
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
}
|
||||
|
||||
_getWGSLStruct( name, vars ) {
|
||||
|
||||
return `
|
||||
struct ${name} {
|
||||
\n${vars}
|
||||
};`;
|
||||
|
||||
}
|
||||
|
||||
_getWGSLUniforms( name, vars, binding = 0, group = 0 ) {
|
||||
|
||||
const structName = name + 'Struct';
|
||||
const structSnippet = this._getWGSLStruct( structName, vars );
|
||||
|
||||
return `${structSnippet}
|
||||
@binding( ${binding} ) @group( ${group} )
|
||||
var<uniform> ${name} : ${structName};`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUNodeBuilder;
|
||||
21
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodeSampledTexture.js
generated
vendored
Normal file
21
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodeSampledTexture.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import { WebGPUSampledTexture } from '../WebGPUSampledTexture.js';
|
||||
|
||||
class WebGPUNodeSampledTexture extends WebGPUSampledTexture {
|
||||
|
||||
constructor( name, textureNode ) {
|
||||
|
||||
super( name, textureNode.value );
|
||||
|
||||
this.textureNode = textureNode;
|
||||
|
||||
}
|
||||
|
||||
getTexture() {
|
||||
|
||||
return this.textureNode.value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { WebGPUNodeSampledTexture };
|
||||
21
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodeSampler.js
generated
vendored
Normal file
21
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodeSampler.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import WebGPUSampler from '../WebGPUSampler.js';
|
||||
|
||||
class WebGPUNodeSampler extends WebGPUSampler {
|
||||
|
||||
constructor( name, textureNode ) {
|
||||
|
||||
super( name, textureNode.value );
|
||||
|
||||
this.textureNode = textureNode;
|
||||
|
||||
}
|
||||
|
||||
getTexture() {
|
||||
|
||||
return this.textureNode.value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUNodeSampler;
|
||||
135
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodeUniform.js
generated
vendored
Normal file
135
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodeUniform.js
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
import {
|
||||
FloatUniform, Vector2Uniform, Vector3Uniform, Vector4Uniform,
|
||||
ColorUniform, Matrix3Uniform, Matrix4Uniform
|
||||
} from '../WebGPUUniform.js';
|
||||
|
||||
class FloatNodeUniform extends FloatUniform {
|
||||
|
||||
constructor( nodeUniform ) {
|
||||
|
||||
super( nodeUniform.name, nodeUniform.value );
|
||||
|
||||
this.nodeUniform = nodeUniform;
|
||||
|
||||
}
|
||||
|
||||
getValue() {
|
||||
|
||||
return this.nodeUniform.value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Vector2NodeUniform extends Vector2Uniform {
|
||||
|
||||
constructor( nodeUniform ) {
|
||||
|
||||
super( nodeUniform.name, nodeUniform.value );
|
||||
|
||||
this.nodeUniform = nodeUniform;
|
||||
|
||||
}
|
||||
|
||||
getValue() {
|
||||
|
||||
return this.nodeUniform.value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Vector3NodeUniform extends Vector3Uniform {
|
||||
|
||||
constructor( nodeUniform ) {
|
||||
|
||||
super( nodeUniform.name, nodeUniform.value );
|
||||
|
||||
this.nodeUniform = nodeUniform;
|
||||
|
||||
}
|
||||
|
||||
getValue() {
|
||||
|
||||
return this.nodeUniform.value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Vector4NodeUniform extends Vector4Uniform {
|
||||
|
||||
constructor( nodeUniform ) {
|
||||
|
||||
super( nodeUniform.name, nodeUniform.value );
|
||||
|
||||
this.nodeUniform = nodeUniform;
|
||||
|
||||
}
|
||||
|
||||
getValue() {
|
||||
|
||||
return this.nodeUniform.value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ColorNodeUniform extends ColorUniform {
|
||||
|
||||
constructor( nodeUniform ) {
|
||||
|
||||
super( nodeUniform.name, nodeUniform.value );
|
||||
|
||||
this.nodeUniform = nodeUniform;
|
||||
|
||||
}
|
||||
|
||||
getValue() {
|
||||
|
||||
return this.nodeUniform.value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Matrix3NodeUniform extends Matrix3Uniform {
|
||||
|
||||
constructor( nodeUniform ) {
|
||||
|
||||
super( nodeUniform.name, nodeUniform.value );
|
||||
|
||||
this.nodeUniform = nodeUniform;
|
||||
|
||||
}
|
||||
|
||||
getValue() {
|
||||
|
||||
return this.nodeUniform.value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Matrix4NodeUniform extends Matrix4Uniform {
|
||||
|
||||
constructor( nodeUniform ) {
|
||||
|
||||
super( nodeUniform.name, nodeUniform.value );
|
||||
|
||||
this.nodeUniform = nodeUniform;
|
||||
|
||||
}
|
||||
|
||||
getValue() {
|
||||
|
||||
return this.nodeUniform.value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export {
|
||||
FloatNodeUniform, Vector2NodeUniform, Vector3NodeUniform, Vector4NodeUniform,
|
||||
ColorNodeUniform, Matrix3NodeUniform, Matrix4NodeUniform
|
||||
};
|
||||
20
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodeUniformsGroup.js
generated
vendored
Normal file
20
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodeUniformsGroup.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import WebGPUUniformsGroup from '../WebGPUUniformsGroup.js';
|
||||
|
||||
class WebGPUNodeUniformsGroup extends WebGPUUniformsGroup {
|
||||
|
||||
constructor( shaderStage ) {
|
||||
|
||||
super( 'nodeUniforms' );
|
||||
|
||||
let shaderStageVisibility;
|
||||
|
||||
if ( shaderStage === 'vertex' ) shaderStageVisibility = GPUShaderStage.VERTEX;
|
||||
else if ( shaderStage === 'fragment' ) shaderStageVisibility = GPUShaderStage.FRAGMENT;
|
||||
|
||||
this.setVisibility( shaderStageVisibility );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUNodeUniformsGroup;
|
||||
73
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodes.js
generated
vendored
Normal file
73
HTML/ThreeJS/node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodes.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
import WebGPUNodeBuilder from './WebGPUNodeBuilder.js';
|
||||
import NodeFrame from 'three-nodes/core/NodeFrame.js';
|
||||
|
||||
class WebGPUNodes {
|
||||
|
||||
constructor( renderer ) {
|
||||
|
||||
this.renderer = renderer;
|
||||
|
||||
this.nodeFrame = new NodeFrame();
|
||||
|
||||
this.builders = new WeakMap();
|
||||
|
||||
}
|
||||
|
||||
get( object, lightNode ) {
|
||||
|
||||
let nodeBuilder = this.builders.get( object );
|
||||
|
||||
if ( nodeBuilder === undefined ) {
|
||||
|
||||
nodeBuilder = new WebGPUNodeBuilder( object, this.renderer, lightNode ).build();
|
||||
|
||||
this.builders.set( object, nodeBuilder );
|
||||
|
||||
}
|
||||
|
||||
return nodeBuilder;
|
||||
|
||||
}
|
||||
|
||||
remove( object ) {
|
||||
|
||||
this.builders.delete( object );
|
||||
|
||||
}
|
||||
|
||||
updateFrame() {
|
||||
|
||||
this.nodeFrame.update();
|
||||
|
||||
}
|
||||
|
||||
update( object, camera, lightNode ) {
|
||||
|
||||
const renderer = this.renderer;
|
||||
const material = object.material;
|
||||
|
||||
const nodeBuilder = this.get( object, lightNode );
|
||||
const nodeFrame = this.nodeFrame;
|
||||
|
||||
nodeFrame.material = material;
|
||||
nodeFrame.camera = camera;
|
||||
nodeFrame.object = object;
|
||||
nodeFrame.renderer = renderer;
|
||||
|
||||
for ( const node of nodeBuilder.updateNodes ) {
|
||||
|
||||
nodeFrame.updateNode( node );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
this.builders = new WeakMap();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUNodes;
|
||||
Reference in New Issue
Block a user