Initial commit
This commit is contained in:
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