修改静态资源文件夹位置
This commit is contained in:
1492
public/sdk/three/jsm/renderers/webgl/WebGLBackend.js
Normal file
1492
public/sdk/three/jsm/renderers/webgl/WebGLBackend.js
Normal file
File diff suppressed because it is too large
Load Diff
145
public/sdk/three/jsm/renderers/webgl/WebGLBufferRenderer.js
Normal file
145
public/sdk/three/jsm/renderers/webgl/WebGLBufferRenderer.js
Normal file
@ -0,0 +1,145 @@
|
||||
class WebGLBufferRenderer {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.gl = backend.gl;
|
||||
this.extensions = backend.extensions;
|
||||
this.info = backend.renderer.info;
|
||||
this.mode = null;
|
||||
this.index = 0;
|
||||
this.type = null;
|
||||
this.object = null;
|
||||
|
||||
}
|
||||
|
||||
render( start, count ) {
|
||||
|
||||
const { gl, mode, object, type, info, index } = this;
|
||||
|
||||
if ( index !== 0 ) {
|
||||
|
||||
gl.drawElements( mode, count, type, start );
|
||||
|
||||
} else {
|
||||
|
||||
gl.drawArrays( mode, start, count );
|
||||
|
||||
}
|
||||
|
||||
info.update( object, count, mode, 1 );
|
||||
|
||||
}
|
||||
|
||||
renderInstances( start, count, primcount ) {
|
||||
|
||||
const { gl, mode, type, index, object, info } = this;
|
||||
|
||||
if ( primcount === 0 ) return;
|
||||
|
||||
if ( index !== 0 ) {
|
||||
|
||||
gl.drawElementsInstanced( mode, count, type, start, primcount );
|
||||
|
||||
} else {
|
||||
|
||||
gl.drawArraysInstanced( mode, start, count, primcount );
|
||||
|
||||
}
|
||||
|
||||
info.update( object, count, mode, primcount );
|
||||
|
||||
}
|
||||
|
||||
renderMultiDraw( starts, counts, drawCount ) {
|
||||
|
||||
const { extensions, mode, object, info } = this;
|
||||
|
||||
if ( drawCount === 0 ) return;
|
||||
|
||||
const extension = extensions.get( 'WEBGL_multi_draw' );
|
||||
|
||||
if ( extension === null ) {
|
||||
|
||||
for ( let i = 0; i < drawCount; i ++ ) {
|
||||
|
||||
this.render( starts[ i ], counts[ i ] );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ( this.index !== 0 ) {
|
||||
|
||||
extension.multiDrawElementsWEBGL( mode, counts, 0, this.type, starts, 0, drawCount );
|
||||
|
||||
} else {
|
||||
|
||||
extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount );
|
||||
|
||||
}
|
||||
|
||||
let elementCount = 0;
|
||||
for ( let i = 0; i < drawCount; i ++ ) {
|
||||
|
||||
elementCount += counts[ i ];
|
||||
|
||||
}
|
||||
|
||||
info.update( object, elementCount, mode, 1 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
renderMultiDrawInstances( starts, counts, drawCount, primcount ) {
|
||||
|
||||
const { extensions, mode, object, info } = this;
|
||||
|
||||
if ( drawCount === 0 ) return;
|
||||
|
||||
const extension = extensions.get( 'WEBGL_multi_draw' );
|
||||
|
||||
if ( extension === null ) {
|
||||
|
||||
for ( let i = 0; i < drawCount; i ++ ) {
|
||||
|
||||
this.renderInstances( starts[ i ], counts[ i ], primcount[ i ] );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ( this.index !== 0 ) {
|
||||
|
||||
extension.multiDrawElementsInstancedWEBGL( mode, counts, 0, this.type, starts, 0, primcount, 0, drawCount );
|
||||
|
||||
} else {
|
||||
|
||||
extension.multiDrawArraysInstancedWEBGL( mode, starts, 0, counts, 0, primcount, 0, drawCount );
|
||||
|
||||
}
|
||||
|
||||
let elementCount = 0;
|
||||
|
||||
for ( let i = 0; i < drawCount; i ++ ) {
|
||||
|
||||
elementCount += counts[ i ];
|
||||
|
||||
}
|
||||
|
||||
for ( let i = 0; i < primcount.length; i ++ ) {
|
||||
|
||||
info.update( object, elementCount, mode, primcount[ i ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
|
||||
export { WebGLBufferRenderer };
|
810
public/sdk/three/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js
Normal file
810
public/sdk/three/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js
Normal file
@ -0,0 +1,810 @@
|
||||
import { MathNode, GLSLNodeParser, NodeBuilder, UniformNode, vectorComponents } from '../../../nodes/Nodes.js';
|
||||
|
||||
import NodeUniformBuffer from '../../common/nodes/NodeUniformBuffer.js';
|
||||
import NodeUniformsGroup from '../../common/nodes/NodeUniformsGroup.js';
|
||||
|
||||
import { NodeSampledTexture, NodeSampledCubeTexture } from '../../common/nodes/NodeSampledTexture.js';
|
||||
|
||||
import { RedFormat, RGFormat, IntType, DataTexture, RGBFormat, RGBAFormat, FloatType } from 'three';
|
||||
|
||||
const glslMethods = {
|
||||
[ MathNode.ATAN2 ]: 'atan',
|
||||
textureDimensions: 'textureSize',
|
||||
equals: 'equal'
|
||||
};
|
||||
|
||||
const precisionLib = {
|
||||
low: 'lowp',
|
||||
medium: 'mediump',
|
||||
high: 'highp'
|
||||
};
|
||||
|
||||
const supports = {
|
||||
instance: true,
|
||||
swizzleAssign: true
|
||||
};
|
||||
|
||||
const defaultPrecisions = `
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
precision mediump sampler2DArray;
|
||||
precision lowp sampler2DShadow;
|
||||
`;
|
||||
|
||||
class GLSLNodeBuilder extends NodeBuilder {
|
||||
|
||||
constructor( object, renderer, scene = null ) {
|
||||
|
||||
super( object, renderer, new GLSLNodeParser(), scene );
|
||||
|
||||
this.uniformGroups = {};
|
||||
this.transforms = [];
|
||||
|
||||
}
|
||||
|
||||
getMethod( method ) {
|
||||
|
||||
return glslMethods[ method ] || method;
|
||||
|
||||
}
|
||||
|
||||
getPropertyName( node, shaderStage ) {
|
||||
|
||||
if ( node.isOutputStructVar ) return '';
|
||||
|
||||
return super.getPropertyName( node, shaderStage );
|
||||
|
||||
}
|
||||
|
||||
buildFunctionCode( shaderNode ) {
|
||||
|
||||
const layout = shaderNode.layout;
|
||||
const flowData = this.flowShaderNode( shaderNode );
|
||||
|
||||
const parameters = [];
|
||||
|
||||
for ( const input of layout.inputs ) {
|
||||
|
||||
parameters.push( this.getType( input.type ) + ' ' + input.name );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const code = `${ this.getType( layout.type ) } ${ layout.name }( ${ parameters.join( ', ' ) } ) {
|
||||
|
||||
${ flowData.vars }
|
||||
|
||||
${ flowData.code }
|
||||
return ${ flowData.result };
|
||||
|
||||
}`;
|
||||
|
||||
//
|
||||
|
||||
return code;
|
||||
|
||||
}
|
||||
|
||||
setupPBO( storageBufferNode ) {
|
||||
|
||||
const attribute = storageBufferNode.value;
|
||||
|
||||
if ( attribute.pbo === undefined ) {
|
||||
|
||||
const originalArray = attribute.array;
|
||||
const numElements = attribute.count * attribute.itemSize;
|
||||
|
||||
const { itemSize } = attribute;
|
||||
let format = RedFormat;
|
||||
|
||||
if ( itemSize === 2 ) {
|
||||
|
||||
format = RGFormat;
|
||||
|
||||
} else if ( itemSize === 3 ) {
|
||||
|
||||
format = RGBFormat;
|
||||
|
||||
} else if ( itemSize === 4 ) {
|
||||
|
||||
format = RGBAFormat;
|
||||
|
||||
}
|
||||
|
||||
const width = Math.pow( 2, Math.ceil( Math.log2( Math.sqrt( numElements / itemSize ) ) ) );
|
||||
let height = Math.ceil( ( numElements / itemSize ) / width );
|
||||
if ( width * height * itemSize < numElements ) height ++; // Ensure enough space
|
||||
|
||||
const newSize = width * height * itemSize;
|
||||
|
||||
const newArray = new Float32Array( newSize );
|
||||
|
||||
newArray.set( originalArray, 0 );
|
||||
|
||||
attribute.array = newArray;
|
||||
|
||||
const pboTexture = new DataTexture( attribute.array, width, height, format, FloatType );
|
||||
pboTexture.needsUpdate = true;
|
||||
pboTexture.isPBOTexture = true;
|
||||
|
||||
const pbo = new UniformNode( pboTexture );
|
||||
pbo.setPrecision( 'high' );
|
||||
|
||||
attribute.pboNode = pbo;
|
||||
attribute.pbo = pbo.value;
|
||||
|
||||
this.getUniformFromNode( attribute.pboNode, 'texture', this.shaderStage, this.context.label );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
generatePBO( storageArrayElementNode ) {
|
||||
|
||||
const { node, indexNode } = storageArrayElementNode;
|
||||
const attribute = node.value;
|
||||
|
||||
if ( this.renderer.backend.has( attribute ) ) {
|
||||
|
||||
const attributeData = this.renderer.backend.get( attribute );
|
||||
attributeData.pbo = attribute.pbo;
|
||||
|
||||
}
|
||||
|
||||
|
||||
const nodeUniform = this.getUniformFromNode( attribute.pboNode, 'texture', this.shaderStage, this.context.label );
|
||||
const textureName = this.getPropertyName( nodeUniform );
|
||||
|
||||
indexNode.increaseUsage( this ); // force cache generate to be used as index in x,y
|
||||
const indexSnippet = indexNode.build( this, 'uint' );
|
||||
|
||||
const elementNodeData = this.getDataFromNode( storageArrayElementNode );
|
||||
|
||||
let propertyName = elementNodeData.propertyName;
|
||||
|
||||
if ( propertyName === undefined ) {
|
||||
|
||||
// property element
|
||||
|
||||
const nodeVar = this.getVarFromNode( storageArrayElementNode );
|
||||
|
||||
propertyName = this.getPropertyName( nodeVar );
|
||||
|
||||
// property size
|
||||
|
||||
const bufferNodeData = this.getDataFromNode( node );
|
||||
|
||||
let propertySizeName = bufferNodeData.propertySizeName;
|
||||
|
||||
if ( propertySizeName === undefined ) {
|
||||
|
||||
propertySizeName = propertyName + 'Size';
|
||||
|
||||
this.getVarFromNode( node, propertySizeName, 'uint' );
|
||||
|
||||
this.addLineFlowCode( `${ propertySizeName } = uint( textureSize( ${ textureName }, 0 ).x )` );
|
||||
|
||||
bufferNodeData.propertySizeName = propertySizeName;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const { itemSize } = attribute;
|
||||
|
||||
const channel = '.' + vectorComponents.join( '' ).slice( 0, itemSize );
|
||||
const uvSnippet = `ivec2(${indexSnippet} % ${ propertySizeName }, ${indexSnippet} / ${ propertySizeName })`;
|
||||
|
||||
const snippet = this.generateTextureLoad( null, textureName, uvSnippet, null, '0' );
|
||||
|
||||
//
|
||||
|
||||
this.addLineFlowCode( `${ propertyName } = ${ snippet + channel }` );
|
||||
|
||||
elementNodeData.propertyName = propertyName;
|
||||
|
||||
}
|
||||
|
||||
return propertyName;
|
||||
|
||||
}
|
||||
|
||||
generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0' ) {
|
||||
|
||||
if ( depthSnippet ) {
|
||||
|
||||
return `texelFetch( ${ textureProperty }, ivec3( ${ uvIndexSnippet }, ${ depthSnippet } ), ${ levelSnippet } )`;
|
||||
|
||||
} else {
|
||||
|
||||
return `texelFetch( ${ textureProperty }, ${ uvIndexSnippet }, ${ levelSnippet } )`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
generateTexture( texture, textureProperty, uvSnippet, depthSnippet ) {
|
||||
|
||||
if ( texture.isDepthTexture ) {
|
||||
|
||||
return `texture( ${ textureProperty }, ${ uvSnippet } ).x`;
|
||||
|
||||
} else {
|
||||
|
||||
if ( depthSnippet ) uvSnippet = `vec3( ${ uvSnippet }, ${ depthSnippet } )`;
|
||||
|
||||
return `texture( ${ textureProperty }, ${ uvSnippet } )`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet ) {
|
||||
|
||||
return `textureLod( ${ textureProperty }, ${ uvSnippet }, ${ levelSnippet } )`;
|
||||
|
||||
}
|
||||
|
||||
generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet ) {
|
||||
|
||||
return `textureGrad( ${ textureProperty }, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] } )`;
|
||||
|
||||
}
|
||||
|
||||
generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) {
|
||||
|
||||
if ( shaderStage === 'fragment' ) {
|
||||
|
||||
return `texture( ${ textureProperty }, vec3( ${ uvSnippet }, ${ compareSnippet } ) )`;
|
||||
|
||||
} else {
|
||||
|
||||
console.error( `WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${ shaderStage } shader.` );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getVars( shaderStage ) {
|
||||
|
||||
const snippets = [];
|
||||
|
||||
const vars = this.vars[ shaderStage ];
|
||||
|
||||
if ( vars !== undefined ) {
|
||||
|
||||
for ( const variable of vars ) {
|
||||
|
||||
if ( variable.isOutputStructVar ) continue;
|
||||
|
||||
snippets.push( `${ this.getVar( variable.type, variable.name ) };` );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return snippets.join( '\n\t' );
|
||||
|
||||
}
|
||||
|
||||
getUniforms( shaderStage ) {
|
||||
|
||||
const uniforms = this.uniforms[ shaderStage ];
|
||||
|
||||
const bindingSnippets = [];
|
||||
const uniformGroups = {};
|
||||
|
||||
for ( const uniform of uniforms ) {
|
||||
|
||||
let snippet = null;
|
||||
let group = false;
|
||||
|
||||
if ( uniform.type === 'texture' ) {
|
||||
|
||||
const texture = uniform.node.value;
|
||||
|
||||
if ( texture.compareFunction ) {
|
||||
|
||||
snippet = `sampler2DShadow ${ uniform.name };`;
|
||||
|
||||
} else if ( texture.isDataArrayTexture === true ) {
|
||||
|
||||
snippet = `sampler2DArray ${ uniform.name };`;
|
||||
|
||||
} else {
|
||||
|
||||
snippet = `sampler2D ${ uniform.name };`;
|
||||
|
||||
}
|
||||
|
||||
} else if ( uniform.type === 'cubeTexture' ) {
|
||||
|
||||
snippet = `samplerCube ${ uniform.name };`;
|
||||
|
||||
} else if ( uniform.type === 'buffer' ) {
|
||||
|
||||
const bufferNode = uniform.node;
|
||||
const bufferType = this.getType( bufferNode.bufferType );
|
||||
const bufferCount = bufferNode.bufferCount;
|
||||
|
||||
const bufferCountSnippet = bufferCount > 0 ? bufferCount : '';
|
||||
snippet = `${bufferNode.name} {\n\t${ bufferType } ${ uniform.name }[${ bufferCountSnippet }];\n};\n`;
|
||||
|
||||
} else {
|
||||
|
||||
const vectorType = this.getVectorType( uniform.type );
|
||||
|
||||
snippet = `${vectorType} ${uniform.name};`;
|
||||
|
||||
group = true;
|
||||
|
||||
}
|
||||
|
||||
const precision = uniform.node.precision;
|
||||
|
||||
if ( precision !== null ) {
|
||||
|
||||
snippet = precisionLib[ precision ] + ' ' + snippet;
|
||||
|
||||
}
|
||||
|
||||
if ( group ) {
|
||||
|
||||
snippet = '\t' + snippet;
|
||||
|
||||
const groupName = uniform.groupNode.name;
|
||||
const groupSnippets = uniformGroups[ groupName ] || ( uniformGroups[ groupName ] = [] );
|
||||
|
||||
groupSnippets.push( snippet );
|
||||
|
||||
} else {
|
||||
|
||||
snippet = 'uniform ' + snippet;
|
||||
|
||||
bindingSnippets.push( snippet );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let output = '';
|
||||
|
||||
for ( const name in uniformGroups ) {
|
||||
|
||||
const groupSnippets = uniformGroups[ name ];
|
||||
|
||||
output += this._getGLSLUniformStruct( shaderStage + '_' + name, groupSnippets.join( '\n' ) ) + '\n';
|
||||
|
||||
}
|
||||
|
||||
output += bindingSnippets.join( '\n' );
|
||||
|
||||
return output;
|
||||
|
||||
}
|
||||
|
||||
getTypeFromAttribute( attribute ) {
|
||||
|
||||
let nodeType = super.getTypeFromAttribute( attribute );
|
||||
|
||||
if ( /^[iu]/.test( nodeType ) && attribute.gpuType !== IntType ) {
|
||||
|
||||
let dataAttribute = attribute;
|
||||
|
||||
if ( attribute.isInterleavedBufferAttribute ) dataAttribute = attribute.data;
|
||||
|
||||
const array = dataAttribute.array;
|
||||
|
||||
if ( ( array instanceof Uint32Array || array instanceof Int32Array || array instanceof Uint16Array || array instanceof Int16Array ) === false ) {
|
||||
|
||||
nodeType = nodeType.slice( 1 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nodeType;
|
||||
|
||||
}
|
||||
|
||||
getAttributes( shaderStage ) {
|
||||
|
||||
let snippet = '';
|
||||
|
||||
if ( shaderStage === 'vertex' || shaderStage === 'compute' ) {
|
||||
|
||||
const attributes = this.getAttributesArray();
|
||||
|
||||
let location = 0;
|
||||
|
||||
for ( const attribute of attributes ) {
|
||||
|
||||
snippet += `layout( location = ${ location ++ } ) in ${ attribute.type } ${ attribute.name };\n`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
getStructMembers( struct ) {
|
||||
|
||||
const snippets = [];
|
||||
const members = struct.getMemberTypes();
|
||||
|
||||
for ( let i = 0; i < members.length; i ++ ) {
|
||||
|
||||
const member = members[ i ];
|
||||
snippets.push( `layout( location = ${i} ) out ${ member} m${i};` );
|
||||
|
||||
}
|
||||
|
||||
return snippets.join( '\n' );
|
||||
|
||||
}
|
||||
|
||||
getStructs( shaderStage ) {
|
||||
|
||||
const snippets = [];
|
||||
const structs = this.structs[ shaderStage ];
|
||||
|
||||
if ( structs.length === 0 ) {
|
||||
|
||||
return 'layout( location = 0 ) out vec4 fragColor;\n';
|
||||
|
||||
}
|
||||
|
||||
for ( let index = 0, length = structs.length; index < length; index ++ ) {
|
||||
|
||||
const struct = structs[ index ];
|
||||
|
||||
let snippet = '\n';
|
||||
snippet += this.getStructMembers( struct );
|
||||
snippet += '\n';
|
||||
|
||||
snippets.push( snippet );
|
||||
|
||||
}
|
||||
|
||||
return snippets.join( '\n\n' );
|
||||
|
||||
}
|
||||
|
||||
getVaryings( shaderStage ) {
|
||||
|
||||
let snippet = '';
|
||||
|
||||
const varyings = this.varyings;
|
||||
|
||||
if ( shaderStage === 'vertex' || shaderStage === 'compute' ) {
|
||||
|
||||
for ( const varying of varyings ) {
|
||||
|
||||
if ( shaderStage === 'compute' ) varying.needsInterpolation = true;
|
||||
const type = varying.type;
|
||||
const flat = type === 'int' || type === 'uint' ? 'flat ' : '';
|
||||
|
||||
snippet += `${flat}${varying.needsInterpolation ? 'out' : '/*out*/'} ${type} ${varying.name};\n`;
|
||||
|
||||
}
|
||||
|
||||
} else if ( shaderStage === 'fragment' ) {
|
||||
|
||||
for ( const varying of varyings ) {
|
||||
|
||||
if ( varying.needsInterpolation ) {
|
||||
|
||||
const type = varying.type;
|
||||
const flat = type === 'int' || type === 'uint' ? 'flat ' : '';
|
||||
|
||||
snippet += `${flat}in ${type} ${varying.name};\n`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
getVertexIndex() {
|
||||
|
||||
return 'uint( gl_VertexID )';
|
||||
|
||||
}
|
||||
|
||||
getInstanceIndex() {
|
||||
|
||||
return 'uint( gl_InstanceID )';
|
||||
|
||||
}
|
||||
|
||||
getFrontFacing() {
|
||||
|
||||
return 'gl_FrontFacing';
|
||||
|
||||
}
|
||||
|
||||
getFragCoord() {
|
||||
|
||||
return 'gl_FragCoord';
|
||||
|
||||
}
|
||||
|
||||
getFragDepth() {
|
||||
|
||||
return 'gl_FragDepth';
|
||||
|
||||
}
|
||||
|
||||
isAvailable( name ) {
|
||||
|
||||
return supports[ name ] === true;
|
||||
|
||||
}
|
||||
|
||||
isFlipY() {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
registerTransform( varyingName, attributeNode ) {
|
||||
|
||||
this.transforms.push( { varyingName, attributeNode } );
|
||||
|
||||
}
|
||||
|
||||
getTransforms( /* shaderStage */ ) {
|
||||
|
||||
const transforms = this.transforms;
|
||||
|
||||
let snippet = '';
|
||||
|
||||
for ( let i = 0; i < transforms.length; i ++ ) {
|
||||
|
||||
const transform = transforms[ i ];
|
||||
|
||||
const attributeName = this.getPropertyName( transform.attributeNode );
|
||||
|
||||
snippet += `${ transform.varyingName } = ${ attributeName };\n\t`;
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
_getGLSLUniformStruct( name, vars ) {
|
||||
|
||||
return `
|
||||
layout( std140 ) uniform ${name} {
|
||||
${vars}
|
||||
};`;
|
||||
|
||||
}
|
||||
|
||||
_getGLSLVertexCode( shaderData ) {
|
||||
|
||||
return `#version 300 es
|
||||
|
||||
${ this.getSignature() }
|
||||
|
||||
// precision
|
||||
${ defaultPrecisions }
|
||||
|
||||
// uniforms
|
||||
${shaderData.uniforms}
|
||||
|
||||
// varyings
|
||||
${shaderData.varyings}
|
||||
|
||||
// attributes
|
||||
${shaderData.attributes}
|
||||
|
||||
// codes
|
||||
${shaderData.codes}
|
||||
|
||||
void main() {
|
||||
|
||||
// vars
|
||||
${shaderData.vars}
|
||||
|
||||
// transforms
|
||||
${shaderData.transforms}
|
||||
|
||||
// flow
|
||||
${shaderData.flow}
|
||||
|
||||
gl_PointSize = 1.0;
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
}
|
||||
|
||||
_getGLSLFragmentCode( shaderData ) {
|
||||
|
||||
return `#version 300 es
|
||||
|
||||
${ this.getSignature() }
|
||||
|
||||
// precision
|
||||
${ defaultPrecisions }
|
||||
|
||||
// uniforms
|
||||
${shaderData.uniforms}
|
||||
|
||||
// varyings
|
||||
${shaderData.varyings}
|
||||
|
||||
// codes
|
||||
${shaderData.codes}
|
||||
|
||||
${shaderData.structs}
|
||||
|
||||
void main() {
|
||||
|
||||
// vars
|
||||
${shaderData.vars}
|
||||
|
||||
// flow
|
||||
${shaderData.flow}
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
}
|
||||
|
||||
buildCode() {
|
||||
|
||||
const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} };
|
||||
|
||||
for ( const shaderStage in shadersData ) {
|
||||
|
||||
let flow = '// code\n\n';
|
||||
flow += this.flowCode[ shaderStage ];
|
||||
|
||||
const flowNodes = this.flowNodes[ shaderStage ];
|
||||
const mainNode = flowNodes[ flowNodes.length - 1 ];
|
||||
|
||||
for ( const node of flowNodes ) {
|
||||
|
||||
const flowSlotData = this.getFlowData( node/*, shaderStage*/ );
|
||||
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 && shaderStage !== 'compute' ) {
|
||||
|
||||
flow += '// result\n\t';
|
||||
|
||||
if ( shaderStage === 'vertex' ) {
|
||||
|
||||
flow += 'gl_Position = ';
|
||||
flow += `${ flowSlotData.result };`;
|
||||
|
||||
} else if ( shaderStage === 'fragment' ) {
|
||||
|
||||
if ( ! node.outputNode.isOutputStructNode ) {
|
||||
|
||||
flow += 'fragColor = ';
|
||||
flow += `${ flowSlotData.result };`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const stageData = shadersData[ shaderStage ];
|
||||
|
||||
stageData.uniforms = this.getUniforms( shaderStage );
|
||||
stageData.attributes = this.getAttributes( shaderStage );
|
||||
stageData.varyings = this.getVaryings( shaderStage );
|
||||
stageData.vars = this.getVars( shaderStage );
|
||||
stageData.structs = this.getStructs( shaderStage );
|
||||
stageData.codes = this.getCodes( shaderStage );
|
||||
stageData.transforms = this.getTransforms( shaderStage );
|
||||
stageData.flow = flow;
|
||||
|
||||
}
|
||||
|
||||
if ( this.material !== null ) {
|
||||
|
||||
this.vertexShader = this._getGLSLVertexCode( shadersData.vertex );
|
||||
this.fragmentShader = this._getGLSLFragmentCode( shadersData.fragment );
|
||||
|
||||
} else {
|
||||
|
||||
this.computeShader = this._getGLSLVertexCode( shadersData.compute );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getUniformFromNode( node, type, shaderStage, name = null ) {
|
||||
|
||||
const uniformNode = super.getUniformFromNode( node, type, shaderStage, name );
|
||||
const nodeData = this.getDataFromNode( node, shaderStage, this.globalCache );
|
||||
|
||||
let uniformGPU = nodeData.uniformGPU;
|
||||
|
||||
if ( uniformGPU === undefined ) {
|
||||
|
||||
if ( type === 'texture' ) {
|
||||
|
||||
uniformGPU = new NodeSampledTexture( uniformNode.name, uniformNode.node );
|
||||
|
||||
this.bindings[ shaderStage ].push( uniformGPU );
|
||||
|
||||
} else if ( type === 'cubeTexture' ) {
|
||||
|
||||
uniformGPU = new NodeSampledCubeTexture( uniformNode.name, uniformNode.node );
|
||||
|
||||
this.bindings[ shaderStage ].push( uniformGPU );
|
||||
|
||||
} else if ( type === 'buffer' ) {
|
||||
|
||||
node.name = `NodeBuffer_${ node.id }`;
|
||||
uniformNode.name = `buffer${ node.id }`;
|
||||
|
||||
const buffer = new NodeUniformBuffer( node );
|
||||
buffer.name = node.name;
|
||||
|
||||
this.bindings[ shaderStage ].push( buffer );
|
||||
|
||||
uniformGPU = buffer;
|
||||
|
||||
} else {
|
||||
|
||||
const group = node.groupNode;
|
||||
const groupName = group.name;
|
||||
|
||||
const uniformsStage = this.uniformGroups[ shaderStage ] || ( this.uniformGroups[ shaderStage ] = {} );
|
||||
|
||||
let uniformsGroup = uniformsStage[ groupName ];
|
||||
|
||||
if ( uniformsGroup === undefined ) {
|
||||
|
||||
uniformsGroup = new NodeUniformsGroup( shaderStage + '_' + groupName, group );
|
||||
//uniformsGroup.setVisibility( gpuShaderStageLib[ shaderStage ] );
|
||||
|
||||
uniformsStage[ groupName ] = uniformsGroup;
|
||||
|
||||
this.bindings[ shaderStage ].push( uniformsGroup );
|
||||
|
||||
}
|
||||
|
||||
uniformGPU = this.getNodeUniform( uniformNode, type );
|
||||
|
||||
uniformsGroup.addUniform( uniformGPU );
|
||||
|
||||
}
|
||||
|
||||
nodeData.uniformGPU = uniformGPU;
|
||||
|
||||
}
|
||||
|
||||
return uniformNode;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GLSLNodeBuilder;
|
@ -0,0 +1,258 @@
|
||||
import { IntType } from 'three';
|
||||
|
||||
let _id = 0;
|
||||
|
||||
class DualAttributeData {
|
||||
|
||||
constructor( attributeData, dualBuffer ) {
|
||||
|
||||
this.buffers = [ attributeData.bufferGPU, dualBuffer ];
|
||||
this.type = attributeData.type;
|
||||
this.bufferType = attributeData.bufferType;
|
||||
this.pbo = attributeData.pbo;
|
||||
this.byteLength = attributeData.byteLength;
|
||||
this.bytesPerElement = attributeData.BYTES_PER_ELEMENT;
|
||||
this.version = attributeData.version;
|
||||
this.isInteger = attributeData.isInteger;
|
||||
this.activeBufferIndex = 0;
|
||||
this.baseId = attributeData.id;
|
||||
|
||||
}
|
||||
|
||||
|
||||
get id() {
|
||||
|
||||
return `${ this.baseId }|${ this.activeBufferIndex }`;
|
||||
|
||||
}
|
||||
|
||||
get bufferGPU() {
|
||||
|
||||
return this.buffers[ this.activeBufferIndex ];
|
||||
|
||||
}
|
||||
|
||||
get transformBuffer() {
|
||||
|
||||
return this.buffers[ this.activeBufferIndex ^ 1 ];
|
||||
|
||||
}
|
||||
|
||||
switchBuffers() {
|
||||
|
||||
this.activeBufferIndex ^= 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class WebGLAttributeUtils {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.backend = backend;
|
||||
|
||||
}
|
||||
|
||||
createAttribute( attribute, bufferType ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const { gl } = backend;
|
||||
|
||||
const array = attribute.array;
|
||||
const usage = attribute.usage || gl.STATIC_DRAW;
|
||||
|
||||
const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute;
|
||||
const bufferData = backend.get( bufferAttribute );
|
||||
|
||||
let bufferGPU = bufferData.bufferGPU;
|
||||
|
||||
if ( bufferGPU === undefined ) {
|
||||
|
||||
bufferGPU = this._createBuffer( gl, bufferType, array, usage );
|
||||
|
||||
bufferData.bufferGPU = bufferGPU;
|
||||
bufferData.bufferType = bufferType;
|
||||
bufferData.version = bufferAttribute.version;
|
||||
|
||||
}
|
||||
|
||||
//attribute.onUploadCallback();
|
||||
|
||||
let type;
|
||||
|
||||
if ( array instanceof Float32Array ) {
|
||||
|
||||
type = gl.FLOAT;
|
||||
|
||||
} else if ( array instanceof Uint16Array ) {
|
||||
|
||||
if ( attribute.isFloat16BufferAttribute ) {
|
||||
|
||||
type = gl.HALF_FLOAT;
|
||||
|
||||
} else {
|
||||
|
||||
type = gl.UNSIGNED_SHORT;
|
||||
|
||||
}
|
||||
|
||||
} else if ( array instanceof Int16Array ) {
|
||||
|
||||
type = gl.SHORT;
|
||||
|
||||
} else if ( array instanceof Uint32Array ) {
|
||||
|
||||
type = gl.UNSIGNED_INT;
|
||||
|
||||
} else if ( array instanceof Int32Array ) {
|
||||
|
||||
type = gl.INT;
|
||||
|
||||
} else if ( array instanceof Int8Array ) {
|
||||
|
||||
type = gl.BYTE;
|
||||
|
||||
} else if ( array instanceof Uint8Array ) {
|
||||
|
||||
type = gl.UNSIGNED_BYTE;
|
||||
|
||||
} else if ( array instanceof Uint8ClampedArray ) {
|
||||
|
||||
type = gl.UNSIGNED_BYTE;
|
||||
|
||||
} else {
|
||||
|
||||
throw new Error( 'THREE.WebGLBackend: Unsupported buffer data format: ' + array );
|
||||
|
||||
}
|
||||
|
||||
let attributeData = {
|
||||
bufferGPU,
|
||||
bufferType,
|
||||
type,
|
||||
byteLength: array.byteLength,
|
||||
bytesPerElement: array.BYTES_PER_ELEMENT,
|
||||
version: attribute.version,
|
||||
pbo: attribute.pbo,
|
||||
isInteger: type === gl.INT || type === gl.UNSIGNED_INT || type === gl.UNSIGNED_SHORT || attribute.gpuType === IntType,
|
||||
id: _id ++
|
||||
};
|
||||
|
||||
if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) {
|
||||
|
||||
// create buffer for tranform feedback use
|
||||
const bufferGPUDual = this._createBuffer( gl, bufferType, array, usage );
|
||||
attributeData = new DualAttributeData( attributeData, bufferGPUDual );
|
||||
|
||||
}
|
||||
|
||||
backend.set( attribute, attributeData );
|
||||
|
||||
}
|
||||
|
||||
updateAttribute( attribute ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const { gl } = backend;
|
||||
|
||||
const array = attribute.array;
|
||||
const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute;
|
||||
const bufferData = backend.get( bufferAttribute );
|
||||
const bufferType = bufferData.bufferType;
|
||||
const updateRanges = attribute.isInterleavedBufferAttribute ? attribute.data.updateRanges : attribute.updateRanges;
|
||||
|
||||
gl.bindBuffer( bufferType, bufferData.bufferGPU );
|
||||
|
||||
if ( updateRanges.length === 0 ) {
|
||||
|
||||
// Not using update ranges
|
||||
|
||||
gl.bufferSubData( bufferType, 0, array );
|
||||
|
||||
} else {
|
||||
|
||||
for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
|
||||
|
||||
const range = updateRanges[ i ];
|
||||
gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
|
||||
array, range.start, range.count );
|
||||
|
||||
}
|
||||
|
||||
bufferAttribute.clearUpdateRanges();
|
||||
|
||||
}
|
||||
|
||||
gl.bindBuffer( bufferType, null );
|
||||
|
||||
bufferData.version = bufferAttribute.version;
|
||||
|
||||
}
|
||||
|
||||
destroyAttribute( attribute ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const { gl } = backend;
|
||||
|
||||
if ( attribute.isInterleavedBufferAttribute ) {
|
||||
|
||||
backend.delete( attribute.data );
|
||||
|
||||
}
|
||||
|
||||
const attributeData = backend.get( attribute );
|
||||
|
||||
gl.deleteBuffer( attributeData.bufferGPU );
|
||||
|
||||
backend.delete( attribute );
|
||||
|
||||
}
|
||||
|
||||
async getArrayBufferAsync( attribute ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const { gl } = backend;
|
||||
|
||||
const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute;
|
||||
const { bufferGPU } = backend.get( bufferAttribute );
|
||||
|
||||
const array = attribute.array;
|
||||
const byteLength = array.byteLength;
|
||||
|
||||
gl.bindBuffer( gl.COPY_READ_BUFFER, bufferGPU );
|
||||
|
||||
const writeBuffer = gl.createBuffer();
|
||||
|
||||
gl.bindBuffer( gl.COPY_WRITE_BUFFER, writeBuffer );
|
||||
gl.bufferData( gl.COPY_WRITE_BUFFER, byteLength, gl.STREAM_READ );
|
||||
|
||||
gl.copyBufferSubData( gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, byteLength );
|
||||
|
||||
await backend.utils._clientWaitAsync();
|
||||
|
||||
const dstBuffer = new attribute.array.constructor( array.length );
|
||||
|
||||
gl.getBufferSubData( gl.COPY_WRITE_BUFFER, 0, dstBuffer );
|
||||
|
||||
gl.deleteBuffer( writeBuffer );
|
||||
|
||||
return dstBuffer.buffer;
|
||||
|
||||
}
|
||||
|
||||
_createBuffer( gl, bufferType, array, usage ) {
|
||||
|
||||
const bufferGPU = gl.createBuffer();
|
||||
|
||||
gl.bindBuffer( bufferType, bufferGPU );
|
||||
gl.bufferData( bufferType, array, usage );
|
||||
gl.bindBuffer( bufferType, null );
|
||||
|
||||
return bufferGPU;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGLAttributeUtils;
|
@ -0,0 +1,36 @@
|
||||
class WebGLCapabilities {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.backend = backend;
|
||||
|
||||
this.maxAnisotropy = null;
|
||||
|
||||
}
|
||||
|
||||
getMaxAnisotropy() {
|
||||
|
||||
if ( this.maxAnisotropy !== null ) return this.maxAnisotropy;
|
||||
|
||||
const gl = this.backend.gl;
|
||||
const extensions = this.backend.extensions;
|
||||
|
||||
if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
|
||||
|
||||
const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
|
||||
|
||||
this.maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
|
||||
|
||||
} else {
|
||||
|
||||
this.maxAnisotropy = 0;
|
||||
|
||||
}
|
||||
|
||||
return this.maxAnisotropy;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGLCapabilities;
|
12
public/sdk/three/jsm/renderers/webgl/utils/WebGLConstants.js
Normal file
12
public/sdk/three/jsm/renderers/webgl/utils/WebGLConstants.js
Normal file
@ -0,0 +1,12 @@
|
||||
export const GLFeatureName = {
|
||||
|
||||
'WEBGL_compressed_texture_astc': 'texture-compression-astc',
|
||||
'WEBGL_compressed_texture_etc': 'texture-compression-etc2',
|
||||
'WEBGL_compressed_texture_etc1': 'texture-compression-etc1',
|
||||
'WEBGL_compressed_texture_pvrtc': 'texture-compression-pvrtc',
|
||||
'WEBKIT_WEBGL_compressed_texture_pvrtc': 'texture-compression-pvrtc',
|
||||
'WEBGL_compressed_texture_s3tc': 'texture-compression-bc',
|
||||
'EXT_texture_compression_bptc': 'texture-compression-bptc',
|
||||
'EXT_disjoint_timer_query_webgl2': 'timestamp-query',
|
||||
|
||||
};
|
@ -0,0 +1,36 @@
|
||||
class WebGLExtensions {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.backend = backend;
|
||||
|
||||
this.gl = this.backend.gl;
|
||||
this.availableExtensions = this.gl.getSupportedExtensions();
|
||||
|
||||
this.extensions = {};
|
||||
|
||||
}
|
||||
|
||||
get( name ) {
|
||||
|
||||
let extension = this.extensions[ name ];
|
||||
|
||||
if ( extension === undefined ) {
|
||||
|
||||
extension = this.gl.getExtension( name );
|
||||
|
||||
}
|
||||
|
||||
return extension;
|
||||
|
||||
}
|
||||
|
||||
has( name ) {
|
||||
|
||||
return this.availableExtensions.includes( name );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGLExtensions;
|
738
public/sdk/three/jsm/renderers/webgl/utils/WebGLState.js
Normal file
738
public/sdk/three/jsm/renderers/webgl/utils/WebGLState.js
Normal file
@ -0,0 +1,738 @@
|
||||
import {
|
||||
CullFaceNone, CullFaceBack, CullFaceFront, DoubleSide, BackSide,
|
||||
NormalBlending, NoBlending, CustomBlending, AddEquation,
|
||||
AdditiveBlending, SubtractiveBlending, MultiplyBlending, SubtractEquation, ReverseSubtractEquation,
|
||||
ZeroFactor, OneFactor, SrcColorFactor, SrcAlphaFactor, SrcAlphaSaturateFactor, DstColorFactor, DstAlphaFactor,
|
||||
OneMinusSrcColorFactor, OneMinusSrcAlphaFactor, OneMinusDstColorFactor, OneMinusDstAlphaFactor,
|
||||
NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth
|
||||
} from 'three';
|
||||
|
||||
let initialized = false, equationToGL, factorToGL;
|
||||
|
||||
class WebGLState {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.backend = backend;
|
||||
|
||||
this.gl = this.backend.gl;
|
||||
|
||||
this.enabled = {};
|
||||
this.currentFlipSided = null;
|
||||
this.currentCullFace = null;
|
||||
this.currentProgram = null;
|
||||
this.currentBlendingEnabled = false;
|
||||
this.currentBlending = null;
|
||||
this.currentBlendSrc = null;
|
||||
this.currentBlendDst = null;
|
||||
this.currentBlendSrcAlpha = null;
|
||||
this.currentBlendDstAlpha = null;
|
||||
this.currentPremultipledAlpha = null;
|
||||
this.currentPolygonOffsetFactor = null;
|
||||
this.currentPolygonOffsetUnits = null;
|
||||
this.currentColorMask = null;
|
||||
this.currentDepthFunc = null;
|
||||
this.currentDepthMask = null;
|
||||
this.currentStencilFunc = null;
|
||||
this.currentStencilRef = null;
|
||||
this.currentStencilFuncMask = null;
|
||||
this.currentStencilFail = null;
|
||||
this.currentStencilZFail = null;
|
||||
this.currentStencilZPass = null;
|
||||
this.currentStencilMask = null;
|
||||
this.currentLineWidth = null;
|
||||
|
||||
this.currentBoundFramebuffers = {};
|
||||
this.currentDrawbuffers = new WeakMap();
|
||||
|
||||
this.maxTextures = this.gl.getParameter( this.gl.MAX_TEXTURE_IMAGE_UNITS );
|
||||
this.currentTextureSlot = null;
|
||||
this.currentBoundTextures = {};
|
||||
|
||||
if ( initialized === false ) {
|
||||
|
||||
this._init( this.gl );
|
||||
|
||||
initialized = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_init( gl ) {
|
||||
|
||||
// Store only WebGL constants here.
|
||||
|
||||
equationToGL = {
|
||||
[ AddEquation ]: gl.FUNC_ADD,
|
||||
[ SubtractEquation ]: gl.FUNC_SUBTRACT,
|
||||
[ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT
|
||||
};
|
||||
|
||||
factorToGL = {
|
||||
[ ZeroFactor ]: gl.ZERO,
|
||||
[ OneFactor ]: gl.ONE,
|
||||
[ SrcColorFactor ]: gl.SRC_COLOR,
|
||||
[ SrcAlphaFactor ]: gl.SRC_ALPHA,
|
||||
[ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE,
|
||||
[ DstColorFactor ]: gl.DST_COLOR,
|
||||
[ DstAlphaFactor ]: gl.DST_ALPHA,
|
||||
[ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR,
|
||||
[ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA,
|
||||
[ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR,
|
||||
[ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
enable( id ) {
|
||||
|
||||
const { enabled } = this;
|
||||
|
||||
if ( enabled[ id ] !== true ) {
|
||||
|
||||
this.gl.enable( id );
|
||||
enabled[ id ] = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
disable( id ) {
|
||||
|
||||
const { enabled } = this;
|
||||
|
||||
if ( enabled[ id ] !== false ) {
|
||||
|
||||
this.gl.disable( id );
|
||||
enabled[ id ] = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setFlipSided( flipSided ) {
|
||||
|
||||
if ( this.currentFlipSided !== flipSided ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
if ( flipSided ) {
|
||||
|
||||
gl.frontFace( gl.CW );
|
||||
|
||||
} else {
|
||||
|
||||
gl.frontFace( gl.CCW );
|
||||
|
||||
}
|
||||
|
||||
this.currentFlipSided = flipSided;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setCullFace( cullFace ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
if ( cullFace !== CullFaceNone ) {
|
||||
|
||||
this.enable( gl.CULL_FACE );
|
||||
|
||||
if ( cullFace !== this.currentCullFace ) {
|
||||
|
||||
if ( cullFace === CullFaceBack ) {
|
||||
|
||||
gl.cullFace( gl.BACK );
|
||||
|
||||
} else if ( cullFace === CullFaceFront ) {
|
||||
|
||||
gl.cullFace( gl.FRONT );
|
||||
|
||||
} else {
|
||||
|
||||
gl.cullFace( gl.FRONT_AND_BACK );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
this.disable( gl.CULL_FACE );
|
||||
|
||||
}
|
||||
|
||||
this.currentCullFace = cullFace;
|
||||
|
||||
}
|
||||
|
||||
setLineWidth( width ) {
|
||||
|
||||
const { currentLineWidth, gl } = this;
|
||||
|
||||
if ( width !== currentLineWidth ) {
|
||||
|
||||
gl.lineWidth( width );
|
||||
|
||||
this.currentLineWidth = width;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
if ( blending === NoBlending ) {
|
||||
|
||||
if ( this.currentBlendingEnabled === true ) {
|
||||
|
||||
this.disable( gl.BLEND );
|
||||
this.currentBlendingEnabled = false;
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if ( this.currentBlendingEnabled === false ) {
|
||||
|
||||
this.enable( gl.BLEND );
|
||||
this.currentBlendingEnabled = true;
|
||||
|
||||
}
|
||||
|
||||
if ( blending !== CustomBlending ) {
|
||||
|
||||
if ( blending !== this.currentBlending || premultipliedAlpha !== this.currentPremultipledAlpha ) {
|
||||
|
||||
if ( this.currentBlendEquation !== AddEquation || this.currentBlendEquationAlpha !== AddEquation ) {
|
||||
|
||||
gl.blendEquation( gl.FUNC_ADD );
|
||||
|
||||
this.currentBlendEquation = AddEquation;
|
||||
this.currentBlendEquationAlpha = AddEquation;
|
||||
|
||||
}
|
||||
|
||||
if ( premultipliedAlpha ) {
|
||||
|
||||
switch ( blending ) {
|
||||
|
||||
case NormalBlending:
|
||||
gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
|
||||
break;
|
||||
|
||||
case AdditiveBlending:
|
||||
gl.blendFunc( gl.ONE, gl.ONE );
|
||||
break;
|
||||
|
||||
case SubtractiveBlending:
|
||||
gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
|
||||
break;
|
||||
|
||||
case MultiplyBlending:
|
||||
gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGLState: Invalid blending: ', blending );
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
switch ( blending ) {
|
||||
|
||||
case NormalBlending:
|
||||
gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
|
||||
break;
|
||||
|
||||
case AdditiveBlending:
|
||||
gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
|
||||
break;
|
||||
|
||||
case SubtractiveBlending:
|
||||
gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
|
||||
break;
|
||||
|
||||
case MultiplyBlending:
|
||||
gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGLState: Invalid blending: ', blending );
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.currentBlendSrc = null;
|
||||
this.currentBlendDst = null;
|
||||
this.currentBlendSrcAlpha = null;
|
||||
this.currentBlendDstAlpha = null;
|
||||
|
||||
this.currentBlending = blending;
|
||||
this.currentPremultipledAlpha = premultipliedAlpha;
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// custom blending
|
||||
|
||||
blendEquationAlpha = blendEquationAlpha || blendEquation;
|
||||
blendSrcAlpha = blendSrcAlpha || blendSrc;
|
||||
blendDstAlpha = blendDstAlpha || blendDst;
|
||||
|
||||
if ( blendEquation !== this.currentBlendEquation || blendEquationAlpha !== this.currentBlendEquationAlpha ) {
|
||||
|
||||
gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
|
||||
|
||||
this.currentBlendEquation = blendEquation;
|
||||
this.currentBlendEquationAlpha = blendEquationAlpha;
|
||||
|
||||
}
|
||||
|
||||
if ( blendSrc !== this.currentBlendSrc || blendDst !== this.currentBlendDst || blendSrcAlpha !== this.currentBlendSrcAlpha || blendDstAlpha !== this.currentBlendDstAlpha ) {
|
||||
|
||||
gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
|
||||
|
||||
this.currentBlendSrc = blendSrc;
|
||||
this.currentBlendDst = blendDst;
|
||||
this.currentBlendSrcAlpha = blendSrcAlpha;
|
||||
this.currentBlendDstAlpha = blendDstAlpha;
|
||||
|
||||
}
|
||||
|
||||
this.currentBlending = blending;
|
||||
this.currentPremultipledAlpha = false;
|
||||
|
||||
}
|
||||
|
||||
setColorMask( colorMask ) {
|
||||
|
||||
if ( this.currentColorMask !== colorMask ) {
|
||||
|
||||
this.gl.colorMask( colorMask, colorMask, colorMask, colorMask );
|
||||
this.currentColorMask = colorMask;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setDepthTest( depthTest ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
if ( depthTest ) {
|
||||
|
||||
this.enable( gl.DEPTH_TEST );
|
||||
|
||||
} else {
|
||||
|
||||
this.disable( gl.DEPTH_TEST );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setDepthMask( depthMask ) {
|
||||
|
||||
if ( this.currentDepthMask !== depthMask ) {
|
||||
|
||||
this.gl.depthMask( depthMask );
|
||||
this.currentDepthMask = depthMask;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setDepthFunc( depthFunc ) {
|
||||
|
||||
if ( this.currentDepthFunc !== depthFunc ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
switch ( depthFunc ) {
|
||||
|
||||
case NeverDepth:
|
||||
|
||||
gl.depthFunc( gl.NEVER );
|
||||
break;
|
||||
|
||||
case AlwaysDepth:
|
||||
|
||||
gl.depthFunc( gl.ALWAYS );
|
||||
break;
|
||||
|
||||
case LessDepth:
|
||||
|
||||
gl.depthFunc( gl.LESS );
|
||||
break;
|
||||
|
||||
case LessEqualDepth:
|
||||
|
||||
gl.depthFunc( gl.LEQUAL );
|
||||
break;
|
||||
|
||||
case EqualDepth:
|
||||
|
||||
gl.depthFunc( gl.EQUAL );
|
||||
break;
|
||||
|
||||
case GreaterEqualDepth:
|
||||
|
||||
gl.depthFunc( gl.GEQUAL );
|
||||
break;
|
||||
|
||||
case GreaterDepth:
|
||||
|
||||
gl.depthFunc( gl.GREATER );
|
||||
break;
|
||||
|
||||
case NotEqualDepth:
|
||||
|
||||
gl.depthFunc( gl.NOTEQUAL );
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
gl.depthFunc( gl.LEQUAL );
|
||||
|
||||
}
|
||||
|
||||
this.currentDepthFunc = depthFunc;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setStencilTest( stencilTest ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
if ( stencilTest ) {
|
||||
|
||||
this.enable( gl.STENCIL_TEST );
|
||||
|
||||
} else {
|
||||
|
||||
this.disable( gl.STENCIL_TEST );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setStencilMask( stencilMask ) {
|
||||
|
||||
if ( this.currentStencilMask !== stencilMask ) {
|
||||
|
||||
this.gl.stencilMask( stencilMask );
|
||||
this.currentStencilMask = stencilMask;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setStencilFunc( stencilFunc, stencilRef, stencilMask ) {
|
||||
|
||||
if ( this.currentStencilFunc !== stencilFunc ||
|
||||
this.currentStencilRef !== stencilRef ||
|
||||
this.currentStencilFuncMask !== stencilMask ) {
|
||||
|
||||
this.gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
|
||||
|
||||
this.currentStencilFunc = stencilFunc;
|
||||
this.currentStencilRef = stencilRef;
|
||||
this.currentStencilFuncMask = stencilMask;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setStencilOp( stencilFail, stencilZFail, stencilZPass ) {
|
||||
|
||||
if ( this.currentStencilFail !== stencilFail ||
|
||||
this.currentStencilZFail !== stencilZFail ||
|
||||
this.currentStencilZPass !== stencilZPass ) {
|
||||
|
||||
this.gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
|
||||
|
||||
this.currentStencilFail = stencilFail;
|
||||
this.currentStencilZFail = stencilZFail;
|
||||
this.currentStencilZPass = stencilZPass;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setMaterial( material, frontFaceCW ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
material.side === DoubleSide
|
||||
? this.disable( gl.CULL_FACE )
|
||||
: this.enable( gl.CULL_FACE );
|
||||
|
||||
let flipSided = ( material.side === BackSide );
|
||||
if ( frontFaceCW ) flipSided = ! flipSided;
|
||||
|
||||
this.setFlipSided( flipSided );
|
||||
|
||||
( material.blending === NormalBlending && material.transparent === false )
|
||||
? this.setBlending( NoBlending )
|
||||
: this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
|
||||
|
||||
this.setDepthFunc( material.depthFunc );
|
||||
this.setDepthTest( material.depthTest );
|
||||
this.setDepthMask( material.depthWrite );
|
||||
this.setColorMask( material.colorWrite );
|
||||
|
||||
const stencilWrite = material.stencilWrite;
|
||||
this.setStencilTest( stencilWrite );
|
||||
if ( stencilWrite ) {
|
||||
|
||||
this.setStencilMask( material.stencilWriteMask );
|
||||
this.setStencilFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
|
||||
this.setStencilOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
|
||||
|
||||
}
|
||||
|
||||
this.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
|
||||
|
||||
material.alphaToCoverage === true
|
||||
? this.enable( gl.SAMPLE_ALPHA_TO_COVERAGE )
|
||||
: this.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );
|
||||
|
||||
}
|
||||
|
||||
setPolygonOffset( polygonOffset, factor, units ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
if ( polygonOffset ) {
|
||||
|
||||
this.enable( gl.POLYGON_OFFSET_FILL );
|
||||
|
||||
if ( this.currentPolygonOffsetFactor !== factor || this.currentPolygonOffsetUnits !== units ) {
|
||||
|
||||
gl.polygonOffset( factor, units );
|
||||
|
||||
this.currentPolygonOffsetFactor = factor;
|
||||
this.currentPolygonOffsetUnits = units;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
this.disable( gl.POLYGON_OFFSET_FILL );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
useProgram( program ) {
|
||||
|
||||
if ( this.currentProgram !== program ) {
|
||||
|
||||
this.gl.useProgram( program );
|
||||
|
||||
this.currentProgram = program;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// framebuffer
|
||||
|
||||
|
||||
bindFramebuffer( target, framebuffer ) {
|
||||
|
||||
const { gl, currentBoundFramebuffers } = this;
|
||||
|
||||
if ( currentBoundFramebuffers[ target ] !== framebuffer ) {
|
||||
|
||||
gl.bindFramebuffer( target, framebuffer );
|
||||
|
||||
currentBoundFramebuffers[ target ] = framebuffer;
|
||||
|
||||
// gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER
|
||||
|
||||
if ( target === gl.DRAW_FRAMEBUFFER ) {
|
||||
|
||||
currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer;
|
||||
|
||||
}
|
||||
|
||||
if ( target === gl.FRAMEBUFFER ) {
|
||||
|
||||
currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
drawBuffers( renderContext, framebuffer ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
let drawBuffers = [];
|
||||
|
||||
let needsUpdate = false;
|
||||
|
||||
if ( renderContext.textures !== null ) {
|
||||
|
||||
drawBuffers = this.currentDrawbuffers.get( framebuffer );
|
||||
|
||||
if ( drawBuffers === undefined ) {
|
||||
|
||||
drawBuffers = [];
|
||||
this.currentDrawbuffers.set( framebuffer, drawBuffers );
|
||||
|
||||
}
|
||||
|
||||
|
||||
const textures = renderContext.textures;
|
||||
|
||||
if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {
|
||||
|
||||
for ( let i = 0, il = textures.length; i < il; i ++ ) {
|
||||
|
||||
drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i;
|
||||
|
||||
}
|
||||
|
||||
drawBuffers.length = textures.length;
|
||||
|
||||
needsUpdate = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
if ( drawBuffers[ 0 ] !== gl.BACK ) {
|
||||
|
||||
drawBuffers[ 0 ] = gl.BACK;
|
||||
|
||||
needsUpdate = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( needsUpdate ) {
|
||||
|
||||
gl.drawBuffers( drawBuffers );
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// texture
|
||||
|
||||
activeTexture( webglSlot ) {
|
||||
|
||||
const { gl, currentTextureSlot, maxTextures } = this;
|
||||
|
||||
if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;
|
||||
|
||||
if ( currentTextureSlot !== webglSlot ) {
|
||||
|
||||
gl.activeTexture( webglSlot );
|
||||
this.currentTextureSlot = webglSlot;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bindTexture( webglType, webglTexture, webglSlot ) {
|
||||
|
||||
const { gl, currentTextureSlot, currentBoundTextures, maxTextures } = this;
|
||||
|
||||
if ( webglSlot === undefined ) {
|
||||
|
||||
if ( currentTextureSlot === null ) {
|
||||
|
||||
webglSlot = gl.TEXTURE0 + maxTextures - 1;
|
||||
|
||||
} else {
|
||||
|
||||
webglSlot = currentTextureSlot;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let boundTexture = currentBoundTextures[ webglSlot ];
|
||||
|
||||
if ( boundTexture === undefined ) {
|
||||
|
||||
boundTexture = { type: undefined, texture: undefined };
|
||||
currentBoundTextures[ webglSlot ] = boundTexture;
|
||||
|
||||
}
|
||||
|
||||
if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
|
||||
|
||||
if ( currentTextureSlot !== webglSlot ) {
|
||||
|
||||
gl.activeTexture( webglSlot );
|
||||
this.currentTextureSlot = webglSlot;
|
||||
|
||||
}
|
||||
|
||||
gl.bindTexture( webglType, webglTexture );
|
||||
|
||||
boundTexture.type = webglType;
|
||||
boundTexture.texture = webglTexture;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
unbindTexture() {
|
||||
|
||||
const { gl, currentTextureSlot, currentBoundTextures } = this;
|
||||
|
||||
const boundTexture = currentBoundTextures[ currentTextureSlot ];
|
||||
|
||||
if ( boundTexture !== undefined && boundTexture.type !== undefined ) {
|
||||
|
||||
gl.bindTexture( boundTexture.type, null );
|
||||
|
||||
boundTexture.type = undefined;
|
||||
boundTexture.texture = undefined;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGLState;
|
751
public/sdk/three/jsm/renderers/webgl/utils/WebGLTextureUtils.js
Normal file
751
public/sdk/three/jsm/renderers/webgl/utils/WebGLTextureUtils.js
Normal file
@ -0,0 +1,751 @@
|
||||
import { LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, FloatType, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, SRGBColorSpace, NeverCompare, AlwaysCompare, LessCompare, LessEqualCompare, EqualCompare, GreaterEqualCompare, GreaterCompare, NotEqualCompare } from 'three';
|
||||
|
||||
let initialized = false, wrappingToGL, filterToGL, compareToGL;
|
||||
|
||||
class WebGLTextureUtils {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.backend = backend;
|
||||
|
||||
this.gl = backend.gl;
|
||||
this.extensions = backend.extensions;
|
||||
this.defaultTextures = {};
|
||||
|
||||
if ( initialized === false ) {
|
||||
|
||||
this._init( this.gl );
|
||||
|
||||
initialized = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_init( gl ) {
|
||||
|
||||
// Store only WebGL constants here.
|
||||
|
||||
wrappingToGL = {
|
||||
[ RepeatWrapping ]: gl.REPEAT,
|
||||
[ ClampToEdgeWrapping ]: gl.CLAMP_TO_EDGE,
|
||||
[ MirroredRepeatWrapping ]: gl.MIRRORED_REPEAT
|
||||
};
|
||||
|
||||
filterToGL = {
|
||||
[ NearestFilter ]: gl.NEAREST,
|
||||
[ NearestMipmapNearestFilter ]: gl.NEAREST_MIPMAP_NEAREST,
|
||||
[ NearestMipmapLinearFilter ]: gl.NEAREST_MIPMAP_LINEAR,
|
||||
|
||||
[ LinearFilter ]: gl.LINEAR,
|
||||
[ LinearMipmapNearestFilter ]: gl.LINEAR_MIPMAP_NEAREST,
|
||||
[ LinearMipmapLinearFilter ]: gl.LINEAR_MIPMAP_LINEAR
|
||||
};
|
||||
|
||||
compareToGL = {
|
||||
[ NeverCompare ]: gl.NEVER,
|
||||
[ AlwaysCompare ]: gl.ALWAYS,
|
||||
[ LessCompare ]: gl.LESS,
|
||||
[ LessEqualCompare ]: gl.LEQUAL,
|
||||
[ EqualCompare ]: gl.EQUAL,
|
||||
[ GreaterEqualCompare ]: gl.GEQUAL,
|
||||
[ GreaterCompare ]: gl.GREATER,
|
||||
[ NotEqualCompare ]: gl.NOTEQUAL
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
filterFallback( f ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) {
|
||||
|
||||
return gl.NEAREST;
|
||||
|
||||
}
|
||||
|
||||
return gl.LINEAR;
|
||||
|
||||
}
|
||||
|
||||
getGLTextureType( texture ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
let glTextureType;
|
||||
|
||||
if ( texture.isCubeTexture === true ) {
|
||||
|
||||
glTextureType = gl.TEXTURE_CUBE_MAP;
|
||||
|
||||
} else if ( texture.isDataArrayTexture === true ) {
|
||||
|
||||
glTextureType = gl.TEXTURE_2D_ARRAY;
|
||||
|
||||
} else {
|
||||
|
||||
glTextureType = gl.TEXTURE_2D;
|
||||
|
||||
|
||||
}
|
||||
|
||||
return glTextureType;
|
||||
|
||||
}
|
||||
|
||||
getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) {
|
||||
|
||||
const { gl, extensions } = this;
|
||||
|
||||
if ( internalFormatName !== null ) {
|
||||
|
||||
if ( gl[ internalFormatName ] !== undefined ) return gl[ internalFormatName ];
|
||||
|
||||
console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );
|
||||
|
||||
}
|
||||
|
||||
let internalFormat = glFormat;
|
||||
|
||||
if ( glFormat === gl.RED ) {
|
||||
|
||||
if ( glType === gl.FLOAT ) internalFormat = gl.R32F;
|
||||
if ( glType === gl.HALF_FLOAT ) internalFormat = gl.R16F;
|
||||
if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.R8;
|
||||
|
||||
}
|
||||
|
||||
if ( glFormat === gl.RED_INTEGER ) {
|
||||
|
||||
if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.R8UI;
|
||||
if ( glType === gl.UNSIGNED_SHORT ) internalFormat = gl.R16UI;
|
||||
if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.R32UI;
|
||||
if ( glType === gl.BYTE ) internalFormat = gl.R8I;
|
||||
if ( glType === gl.SHORT ) internalFormat = gl.R16I;
|
||||
if ( glType === gl.INT ) internalFormat = gl.R32I;
|
||||
|
||||
}
|
||||
|
||||
if ( glFormat === gl.RG ) {
|
||||
|
||||
if ( glType === gl.FLOAT ) internalFormat = gl.RG32F;
|
||||
if ( glType === gl.HALF_FLOAT ) internalFormat = gl.RG16F;
|
||||
if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.RG8;
|
||||
|
||||
}
|
||||
|
||||
if ( glFormat === gl.RGB ) {
|
||||
|
||||
if ( glType === gl.FLOAT ) internalFormat = gl.RGB32F;
|
||||
if ( glType === gl.HALF_FLOAT ) internalFormat = gl.RGB16F;
|
||||
if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.RGB8;
|
||||
if ( glType === gl.UNSIGNED_SHORT_5_6_5 ) internalFormat = gl.RGB565;
|
||||
if ( glType === gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = gl.RGB5_A1;
|
||||
if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = gl.RGB4;
|
||||
if ( glType === gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = gl.RGB9_E5;
|
||||
|
||||
}
|
||||
|
||||
if ( glFormat === gl.RGBA ) {
|
||||
|
||||
if ( glType === gl.FLOAT ) internalFormat = gl.RGBA32F;
|
||||
if ( glType === gl.HALF_FLOAT ) internalFormat = gl.RGBA16F;
|
||||
if ( glType === gl.UNSIGNED_BYTE ) internalFormat = ( colorSpace === SRGBColorSpace && forceLinearTransfer === false ) ? gl.SRGB8_ALPHA8 : gl.RGBA8;
|
||||
if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = gl.RGBA4;
|
||||
if ( glType === gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = gl.RGB5_A1;
|
||||
|
||||
}
|
||||
|
||||
if ( glFormat === gl.DEPTH_COMPONENT ) {
|
||||
|
||||
if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.DEPTH24_STENCIL8;
|
||||
if ( glType === gl.FLOAT ) internalFormat = gl.DEPTH_COMPONENT32F;
|
||||
|
||||
}
|
||||
|
||||
if ( glFormat === gl.DEPTH_STENCIL ) {
|
||||
|
||||
if ( glType === gl.UNSIGNED_INT_24_8 ) internalFormat = gl.DEPTH24_STENCIL8;
|
||||
|
||||
}
|
||||
|
||||
if ( internalFormat === gl.R16F || internalFormat === gl.R32F ||
|
||||
internalFormat === gl.RG16F || internalFormat === gl.RG32F ||
|
||||
internalFormat === gl.RGBA16F || internalFormat === gl.RGBA32F ) {
|
||||
|
||||
extensions.get( 'EXT_color_buffer_float' );
|
||||
|
||||
}
|
||||
|
||||
return internalFormat;
|
||||
|
||||
}
|
||||
|
||||
setTextureParameters( textureType, texture ) {
|
||||
|
||||
const { gl, extensions, backend } = this;
|
||||
|
||||
const { currentAnisotropy } = backend.get( texture );
|
||||
|
||||
gl.texParameteri( textureType, gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] );
|
||||
gl.texParameteri( textureType, gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] );
|
||||
|
||||
if ( textureType === gl.TEXTURE_3D || textureType === gl.TEXTURE_2D_ARRAY ) {
|
||||
|
||||
gl.texParameteri( textureType, gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] );
|
||||
|
||||
}
|
||||
|
||||
gl.texParameteri( textureType, gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] );
|
||||
|
||||
|
||||
// follow WebGPU backend mapping for texture filtering
|
||||
const minFilter = ! texture.isVideoTexture && texture.minFilter === LinearFilter ? LinearMipmapLinearFilter : texture.minFilter;
|
||||
|
||||
gl.texParameteri( textureType, gl.TEXTURE_MIN_FILTER, filterToGL[ minFilter ] );
|
||||
|
||||
if ( texture.compareFunction ) {
|
||||
|
||||
gl.texParameteri( textureType, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE );
|
||||
gl.texParameteri( textureType, gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] );
|
||||
|
||||
}
|
||||
|
||||
if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
|
||||
|
||||
if ( texture.magFilter === NearestFilter ) return;
|
||||
if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return;
|
||||
if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2
|
||||
|
||||
if ( texture.anisotropy > 1 || currentAnisotropy !== texture.anisotropy ) {
|
||||
|
||||
const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
|
||||
gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, backend.getMaxAnisotropy() ) );
|
||||
backend.get( texture ).currentAnisotropy = texture.anisotropy;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
createDefaultTexture( texture ) {
|
||||
|
||||
const { gl, backend, defaultTextures } = this;
|
||||
|
||||
|
||||
const glTextureType = this.getGLTextureType( texture );
|
||||
|
||||
let textureGPU = defaultTextures[ glTextureType ];
|
||||
|
||||
if ( textureGPU === undefined ) {
|
||||
|
||||
textureGPU = gl.createTexture();
|
||||
|
||||
backend.state.bindTexture( glTextureType, textureGPU );
|
||||
gl.texParameteri( glTextureType, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
|
||||
gl.texParameteri( glTextureType, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
|
||||
|
||||
// gl.texImage2D( glTextureType, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
|
||||
|
||||
defaultTextures[ glTextureType ] = textureGPU;
|
||||
|
||||
}
|
||||
|
||||
backend.set( texture, {
|
||||
textureGPU,
|
||||
glTextureType,
|
||||
isDefault: true
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
createTexture( texture, options ) {
|
||||
|
||||
const { gl, backend } = this;
|
||||
const { levels, width, height, depth } = options;
|
||||
|
||||
const glFormat = backend.utils.convert( texture.format, texture.colorSpace );
|
||||
const glType = backend.utils.convert( texture.type );
|
||||
const glInternalFormat = this.getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture );
|
||||
|
||||
const textureGPU = gl.createTexture();
|
||||
const glTextureType = this.getGLTextureType( texture );
|
||||
|
||||
backend.state.bindTexture( glTextureType, textureGPU );
|
||||
|
||||
gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
|
||||
gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
|
||||
gl.pixelStorei( gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
|
||||
gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE );
|
||||
|
||||
this.setTextureParameters( glTextureType, texture );
|
||||
|
||||
if ( texture.isDataArrayTexture ) {
|
||||
|
||||
gl.texStorage3D( gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, width, height, depth );
|
||||
|
||||
} else if ( ! texture.isVideoTexture ) {
|
||||
|
||||
gl.texStorage2D( glTextureType, levels, glInternalFormat, width, height );
|
||||
|
||||
}
|
||||
|
||||
backend.set( texture, {
|
||||
textureGPU,
|
||||
glTextureType,
|
||||
glFormat,
|
||||
glType,
|
||||
glInternalFormat
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
copyBufferToTexture( buffer, texture ) {
|
||||
|
||||
const { gl, backend } = this;
|
||||
|
||||
const { textureGPU, glTextureType, glFormat, glType } = backend.get( texture );
|
||||
|
||||
const { width, height } = texture.source.data;
|
||||
|
||||
gl.bindBuffer( gl.PIXEL_UNPACK_BUFFER, buffer );
|
||||
|
||||
backend.state.bindTexture( glTextureType, textureGPU );
|
||||
|
||||
gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, false );
|
||||
gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false );
|
||||
gl.texSubImage2D( glTextureType, 0, 0, 0, width, height, glFormat, glType, 0 );
|
||||
|
||||
gl.bindBuffer( gl.PIXEL_UNPACK_BUFFER, null );
|
||||
|
||||
backend.state.unbindTexture();
|
||||
// debug
|
||||
// const framebuffer = gl.createFramebuffer();
|
||||
// gl.bindFramebuffer( gl.FRAMEBUFFER, framebuffer );
|
||||
// gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, glTextureType, textureGPU, 0 );
|
||||
|
||||
// const readout = new Float32Array( width * height * 4 );
|
||||
|
||||
// const altFormat = gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_FORMAT );
|
||||
// const altType = gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_TYPE );
|
||||
|
||||
// gl.readPixels( 0, 0, width, height, altFormat, altType, readout );
|
||||
// gl.bindFramebuffer( gl.FRAMEBUFFER, null );
|
||||
// console.log( readout );
|
||||
|
||||
}
|
||||
|
||||
updateTexture( texture, options ) {
|
||||
|
||||
const { gl } = this;
|
||||
const { width, height } = options;
|
||||
const { textureGPU, glTextureType, glFormat, glType, glInternalFormat } = this.backend.get( texture );
|
||||
|
||||
if ( texture.isRenderTargetTexture || ( textureGPU === undefined /* unsupported texture format */ ) )
|
||||
return;
|
||||
|
||||
const getImage = ( source ) => {
|
||||
|
||||
if ( source.isDataTexture ) {
|
||||
|
||||
return source.image.data;
|
||||
|
||||
} else if ( source instanceof ImageBitmap || source instanceof OffscreenCanvas || source instanceof HTMLImageElement || source instanceof HTMLCanvasElement ) {
|
||||
|
||||
return source;
|
||||
|
||||
}
|
||||
|
||||
return source.data;
|
||||
|
||||
};
|
||||
|
||||
this.backend.state.bindTexture( glTextureType, textureGPU );
|
||||
|
||||
if ( texture.isCompressedTexture ) {
|
||||
|
||||
const mipmaps = texture.mipmaps;
|
||||
|
||||
for ( let i = 0; i < mipmaps.length; i ++ ) {
|
||||
|
||||
const mipmap = mipmaps[ i ];
|
||||
|
||||
if ( texture.isCompressedArrayTexture ) {
|
||||
|
||||
const image = options.image;
|
||||
|
||||
if ( texture.format !== gl.RGBA ) {
|
||||
|
||||
if ( glFormat !== null ) {
|
||||
|
||||
gl.compressedTexSubImage3D( gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 );
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
gl.texSubImage3D( gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ( glFormat !== null ) {
|
||||
|
||||
gl.compressedTexSubImage2D( gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( 'Unsupported compressed texture format' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if ( texture.isCubeTexture ) {
|
||||
|
||||
const images = options.images;
|
||||
|
||||
for ( let i = 0; i < 6; i ++ ) {
|
||||
|
||||
const image = getImage( images[ i ] );
|
||||
|
||||
gl.texSubImage2D( gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, width, height, glFormat, glType, image );
|
||||
|
||||
}
|
||||
|
||||
} else if ( texture.isDataArrayTexture ) {
|
||||
|
||||
const image = options.image;
|
||||
|
||||
gl.texSubImage3D( gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );
|
||||
|
||||
} else if ( texture.isVideoTexture ) {
|
||||
|
||||
texture.update();
|
||||
|
||||
gl.texImage2D( glTextureType, 0, glInternalFormat, glFormat, glType, options.image );
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
const image = getImage( options.image );
|
||||
|
||||
gl.texSubImage2D( glTextureType, 0, 0, 0, width, height, glFormat, glType, image );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
generateMipmaps( texture ) {
|
||||
|
||||
const { gl, backend } = this;
|
||||
const { textureGPU, glTextureType } = backend.get( texture );
|
||||
|
||||
backend.state.bindTexture( glTextureType, textureGPU );
|
||||
gl.generateMipmap( glTextureType );
|
||||
|
||||
}
|
||||
|
||||
deallocateRenderBuffers( renderTarget ) {
|
||||
|
||||
|
||||
const { gl, backend } = this;
|
||||
|
||||
// remove framebuffer reference
|
||||
if ( renderTarget ) {
|
||||
|
||||
const renderContextData = backend.get( renderTarget );
|
||||
|
||||
renderContextData.renderBufferStorageSetup = undefined;
|
||||
|
||||
if ( renderContextData.framebuffer ) {
|
||||
|
||||
gl.deleteFramebuffer( renderContextData.framebuffer );
|
||||
renderContextData.framebuffer = undefined;
|
||||
|
||||
}
|
||||
|
||||
if ( renderContextData.depthRenderbuffer ) {
|
||||
|
||||
gl.deleteRenderbuffer( renderContextData.depthRenderbuffer );
|
||||
renderContextData.depthRenderbuffer = undefined;
|
||||
|
||||
}
|
||||
|
||||
if ( renderContextData.stencilRenderbuffer ) {
|
||||
|
||||
gl.deleteRenderbuffer( renderContextData.stencilRenderbuffer );
|
||||
renderContextData.stencilRenderbuffer = undefined;
|
||||
|
||||
}
|
||||
|
||||
if ( renderContextData.msaaFrameBuffer ) {
|
||||
|
||||
gl.deleteFramebuffer( renderContextData.msaaFrameBuffer );
|
||||
renderContextData.msaaFrameBuffer = undefined;
|
||||
|
||||
}
|
||||
|
||||
if ( renderContextData.msaaRenderbuffers ) {
|
||||
|
||||
for ( let i = 0; i < renderContextData.msaaRenderbuffers.length; i ++ ) {
|
||||
|
||||
gl.deleteRenderbuffer( renderContextData.msaaRenderbuffers[ i ] );
|
||||
|
||||
}
|
||||
|
||||
renderContextData.msaaRenderbuffers = undefined;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
destroyTexture( texture ) {
|
||||
|
||||
const { gl, backend } = this;
|
||||
const { textureGPU, renderTarget } = backend.get( texture );
|
||||
|
||||
this.deallocateRenderBuffers( renderTarget );
|
||||
gl.deleteTexture( textureGPU );
|
||||
|
||||
backend.delete( texture );
|
||||
|
||||
}
|
||||
|
||||
copyTextureToTexture( position, srcTexture, dstTexture, level = 0 ) {
|
||||
|
||||
const { gl, backend } = this;
|
||||
const { state } = this.backend;
|
||||
|
||||
const width = srcTexture.image.width;
|
||||
const height = srcTexture.image.height;
|
||||
const { textureGPU: dstTextureGPU, glTextureType, glType, glFormat } = backend.get( dstTexture );
|
||||
|
||||
state.bindTexture( glTextureType, dstTextureGPU );
|
||||
|
||||
// As another texture upload may have changed pixelStorei
|
||||
// parameters, make sure they are correct for the dstTexture
|
||||
gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
|
||||
gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
|
||||
gl.pixelStorei( gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
|
||||
|
||||
if ( srcTexture.isDataTexture ) {
|
||||
|
||||
gl.texSubImage2D( gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
|
||||
|
||||
} else {
|
||||
|
||||
if ( srcTexture.isCompressedTexture ) {
|
||||
|
||||
gl.compressedTexSubImage2D( gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
|
||||
|
||||
} else {
|
||||
|
||||
gl.texSubImage2D( gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Generate mipmaps only when copying level 0
|
||||
if ( level === 0 && dstTexture.generateMipmaps ) gl.generateMipmap( gl.TEXTURE_2D );
|
||||
|
||||
state.unbindTexture();
|
||||
|
||||
}
|
||||
|
||||
copyFramebufferToTexture( texture, renderContext ) {
|
||||
|
||||
const { gl } = this;
|
||||
const { state } = this.backend;
|
||||
|
||||
const { textureGPU } = this.backend.get( texture );
|
||||
|
||||
const width = texture.image.width;
|
||||
const height = texture.image.height;
|
||||
|
||||
const requireDrawFrameBuffer = texture.isDepthTexture === true || ( renderContext.renderTarget && renderContext.renderTarget.samples > 0 );
|
||||
|
||||
if ( requireDrawFrameBuffer ) {
|
||||
|
||||
let mask;
|
||||
let attachment;
|
||||
|
||||
if ( texture.isDepthTexture === true ) {
|
||||
|
||||
mask = gl.DEPTH_BUFFER_BIT;
|
||||
attachment = gl.DEPTH_ATTACHMENT;
|
||||
|
||||
if ( renderContext.stencil ) {
|
||||
|
||||
mask |= gl.STENCIL_BUFFER_BIT;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
mask = gl.COLOR_BUFFER_BIT;
|
||||
attachment = gl.COLOR_ATTACHMENT0;
|
||||
|
||||
}
|
||||
|
||||
const fb = gl.createFramebuffer();
|
||||
state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb );
|
||||
|
||||
gl.framebufferTexture2D( gl.DRAW_FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureGPU, 0 );
|
||||
|
||||
gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, gl.NEAREST );
|
||||
|
||||
gl.deleteFramebuffer( fb );
|
||||
|
||||
} else {
|
||||
|
||||
state.bindTexture( gl.TEXTURE_2D, textureGPU );
|
||||
gl.copyTexSubImage2D( gl.TEXTURE_2D, 0, 0, 0, 0, 0, width, height );
|
||||
|
||||
state.unbindTexture();
|
||||
|
||||
}
|
||||
|
||||
if ( texture.generateMipmaps ) this.generateMipmaps( texture );
|
||||
|
||||
this.backend._setFramebuffer( renderContext );
|
||||
|
||||
}
|
||||
|
||||
// Setup storage for internal depth/stencil buffers and bind to correct framebuffer
|
||||
setupRenderBufferStorage( renderbuffer, renderContext ) {
|
||||
|
||||
const { gl } = this;
|
||||
const renderTarget = renderContext.renderTarget;
|
||||
|
||||
const { samples, depthTexture, depthBuffer, stencilBuffer, width, height } = renderTarget;
|
||||
|
||||
gl.bindRenderbuffer( gl.RENDERBUFFER, renderbuffer );
|
||||
|
||||
if ( depthBuffer && ! stencilBuffer ) {
|
||||
|
||||
let glInternalFormat = gl.DEPTH_COMPONENT24;
|
||||
|
||||
if ( samples > 0 ) {
|
||||
|
||||
if ( depthTexture && depthTexture.isDepthTexture ) {
|
||||
|
||||
if ( depthTexture.type === gl.FLOAT ) {
|
||||
|
||||
glInternalFormat = gl.DEPTH_COMPONENT32F;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gl.renderbufferStorageMultisample( gl.RENDERBUFFER, samples, glInternalFormat, width, height );
|
||||
|
||||
} else {
|
||||
|
||||
gl.renderbufferStorage( gl.RENDERBUFFER, glInternalFormat, width, height );
|
||||
|
||||
}
|
||||
|
||||
gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer );
|
||||
|
||||
} else if ( depthBuffer && stencilBuffer ) {
|
||||
|
||||
if ( samples > 0 ) {
|
||||
|
||||
gl.renderbufferStorageMultisample( gl.RENDERBUFFER, samples, gl.DEPTH24_STENCIL8, width, height );
|
||||
|
||||
} else {
|
||||
|
||||
gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height );
|
||||
|
||||
}
|
||||
|
||||
|
||||
gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderbuffer );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async copyTextureToBuffer( texture, x, y, width, height ) {
|
||||
|
||||
const { backend, gl } = this;
|
||||
|
||||
const { textureGPU, glFormat, glType } = this.backend.get( texture );
|
||||
|
||||
const fb = gl.createFramebuffer();
|
||||
|
||||
gl.bindFramebuffer( gl.READ_FRAMEBUFFER, fb );
|
||||
gl.framebufferTexture2D( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textureGPU, 0 );
|
||||
|
||||
const typedArrayType = this._getTypedArrayType( glType );
|
||||
const bytesPerTexel = this._getBytesPerTexel( glFormat );
|
||||
|
||||
const elementCount = width * height;
|
||||
const byteLength = elementCount * bytesPerTexel;
|
||||
|
||||
const buffer = gl.createBuffer();
|
||||
|
||||
gl.bindBuffer( gl.PIXEL_PACK_BUFFER, buffer );
|
||||
gl.bufferData( gl.PIXEL_PACK_BUFFER, byteLength, gl.STREAM_READ );
|
||||
gl.readPixels( x, y, width, height, glFormat, glType, 0 );
|
||||
gl.bindBuffer( gl.PIXEL_PACK_BUFFER, null );
|
||||
|
||||
await backend.utils._clientWaitAsync();
|
||||
|
||||
const dstBuffer = new typedArrayType( byteLength / typedArrayType.BYTES_PER_ELEMENT );
|
||||
|
||||
gl.bindBuffer( gl.PIXEL_PACK_BUFFER, buffer );
|
||||
gl.getBufferSubData( gl.PIXEL_PACK_BUFFER, 0, dstBuffer );
|
||||
gl.bindBuffer( gl.PIXEL_PACK_BUFFER, null );
|
||||
|
||||
gl.deleteFramebuffer( fb );
|
||||
|
||||
return dstBuffer;
|
||||
|
||||
}
|
||||
|
||||
_getTypedArrayType( glType ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
if ( glType === gl.UNSIGNED_BYTE ) return Uint8Array;
|
||||
|
||||
if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 ) return Uint16Array;
|
||||
if ( glType === gl.UNSIGNED_SHORT_5_5_5_1 ) return Uint16Array;
|
||||
if ( glType === gl.UNSIGNED_SHORT_5_6_5 ) return Uint16Array;
|
||||
if ( glType === gl.UNSIGNED_SHORT ) return Uint16Array;
|
||||
if ( glType === gl.UNSIGNED_INT ) return Uint32Array;
|
||||
|
||||
if ( glType === gl.FLOAT ) return Float32Array;
|
||||
|
||||
throw new Error( `Unsupported WebGL type: ${glType}` );
|
||||
|
||||
}
|
||||
|
||||
_getBytesPerTexel( glFormat ) {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
if ( glFormat === gl.RGBA ) return 4;
|
||||
if ( glFormat === gl.RGB ) return 3;
|
||||
if ( glFormat === gl.ALPHA ) return 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGLTextureUtils;
|
268
public/sdk/three/jsm/renderers/webgl/utils/WebGLUtils.js
Normal file
268
public/sdk/three/jsm/renderers/webgl/utils/WebGLUtils.js
Normal file
@ -0,0 +1,268 @@
|
||||
import { RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT1_Format, RGB_S3TC_DXT1_Format, DepthFormat, DepthStencilFormat, LuminanceAlphaFormat, LuminanceFormat, RedFormat, RGBFormat, RGBAFormat, AlphaFormat, RedIntegerFormat, RGFormat, RGIntegerFormat, RGBAIntegerFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, RGBA_BPTC_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, RED_GREEN_RGTC2_Format, SIGNED_RED_GREEN_RGTC2_Format, SRGBColorSpace, NoColorSpace } from 'three';
|
||||
|
||||
class WebGLUtils {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.backend = backend;
|
||||
|
||||
this.gl = this.backend.gl;
|
||||
this.extensions = backend.extensions;
|
||||
|
||||
}
|
||||
|
||||
convert( p, colorSpace = NoColorSpace ) {
|
||||
|
||||
const { gl, extensions } = this;
|
||||
|
||||
let extension;
|
||||
|
||||
if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;
|
||||
if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;
|
||||
if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;
|
||||
if ( p === UnsignedInt5999Type ) return gl.UNSIGNED_INT_5_9_9_9_REV;
|
||||
|
||||
if ( p === ByteType ) return gl.BYTE;
|
||||
if ( p === ShortType ) return gl.SHORT;
|
||||
if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT;
|
||||
if ( p === IntType ) return gl.INT;
|
||||
if ( p === UnsignedIntType ) return gl.UNSIGNED_INT;
|
||||
if ( p === FloatType ) return gl.FLOAT;
|
||||
|
||||
if ( p === HalfFloatType ) {
|
||||
|
||||
return gl.HALF_FLOAT;
|
||||
|
||||
}
|
||||
|
||||
if ( p === AlphaFormat ) return gl.ALPHA;
|
||||
if ( p === RGBFormat ) return gl.RGB;
|
||||
if ( p === RGBAFormat ) return gl.RGBA;
|
||||
if ( p === LuminanceFormat ) return gl.LUMINANCE;
|
||||
if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA;
|
||||
if ( p === DepthFormat ) return gl.DEPTH_COMPONENT;
|
||||
if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;
|
||||
|
||||
// WebGL2 formats.
|
||||
|
||||
if ( p === RedFormat ) return gl.RED;
|
||||
if ( p === RedIntegerFormat ) return gl.RED_INTEGER;
|
||||
if ( p === RGFormat ) return gl.RG;
|
||||
if ( p === RGIntegerFormat ) return gl.RG_INTEGER;
|
||||
if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER;
|
||||
|
||||
// S3TC
|
||||
|
||||
if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
|
||||
|
||||
if ( colorSpace === SRGBColorSpace ) {
|
||||
|
||||
extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' );
|
||||
|
||||
if ( extension !== null ) {
|
||||
|
||||
if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT;
|
||||
if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
|
||||
if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
|
||||
if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
|
||||
|
||||
} else {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
|
||||
|
||||
if ( extension !== null ) {
|
||||
|
||||
if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||||
if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||
if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
|
||||
} else {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// PVRTC
|
||||
|
||||
if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
|
||||
|
||||
extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
|
||||
|
||||
if ( extension !== null ) {
|
||||
|
||||
if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
|
||||
if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
|
||||
if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
|
||||
if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
|
||||
|
||||
} else {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ETC
|
||||
|
||||
if ( p === RGB_ETC1_Format || p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {
|
||||
|
||||
extension = extensions.get( 'WEBGL_compressed_texture_etc' );
|
||||
|
||||
if ( extension !== null ) {
|
||||
|
||||
if ( p === RGB_ETC1_Format || p === RGB_ETC2_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2;
|
||||
if ( p === RGBA_ETC2_EAC_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC;
|
||||
|
||||
} else {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ASTC
|
||||
|
||||
if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
|
||||
p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
|
||||
p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
|
||||
p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
|
||||
p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) {
|
||||
|
||||
extension = extensions.get( 'WEBGL_compressed_texture_astc' );
|
||||
|
||||
if ( extension !== null ) {
|
||||
|
||||
if ( p === RGBA_ASTC_4x4_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR;
|
||||
if ( p === RGBA_ASTC_5x4_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR;
|
||||
if ( p === RGBA_ASTC_5x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR;
|
||||
if ( p === RGBA_ASTC_6x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR;
|
||||
if ( p === RGBA_ASTC_6x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR;
|
||||
if ( p === RGBA_ASTC_8x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR;
|
||||
if ( p === RGBA_ASTC_8x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR;
|
||||
if ( p === RGBA_ASTC_8x8_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR;
|
||||
if ( p === RGBA_ASTC_10x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR;
|
||||
if ( p === RGBA_ASTC_10x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR;
|
||||
if ( p === RGBA_ASTC_10x8_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR;
|
||||
if ( p === RGBA_ASTC_10x10_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR;
|
||||
if ( p === RGBA_ASTC_12x10_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR;
|
||||
if ( p === RGBA_ASTC_12x12_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR;
|
||||
|
||||
} else {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// BPTC
|
||||
|
||||
if ( p === RGBA_BPTC_Format ) {
|
||||
|
||||
extension = extensions.get( 'EXT_texture_compression_bptc' );
|
||||
|
||||
if ( extension !== null ) {
|
||||
|
||||
if ( p === RGBA_BPTC_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;
|
||||
|
||||
} else {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// RGTC
|
||||
|
||||
if ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) {
|
||||
|
||||
extension = extensions.get( 'EXT_texture_compression_rgtc' );
|
||||
|
||||
if ( extension !== null ) {
|
||||
|
||||
if ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT;
|
||||
if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT;
|
||||
if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT;
|
||||
if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;
|
||||
|
||||
} else {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
if ( p === UnsignedInt248Type ) {
|
||||
|
||||
return gl.UNSIGNED_INT_24_8;
|
||||
|
||||
}
|
||||
|
||||
// if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats)
|
||||
|
||||
return ( gl[ p ] !== undefined ) ? gl[ p ] : null;
|
||||
|
||||
}
|
||||
|
||||
_clientWaitAsync() {
|
||||
|
||||
const { gl } = this;
|
||||
|
||||
const sync = gl.fenceSync( gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
|
||||
|
||||
gl.flush();
|
||||
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
|
||||
function test() {
|
||||
|
||||
const res = gl.clientWaitSync( sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0 );
|
||||
|
||||
if ( res === gl.WAIT_FAILED ) {
|
||||
|
||||
gl.deleteSync( sync );
|
||||
|
||||
reject();
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if ( res === gl.TIMEOUT_EXPIRED ) {
|
||||
|
||||
requestAnimationFrame( test );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
gl.deleteSync( sync );
|
||||
|
||||
resolve();
|
||||
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGLUtils;
|
Reference in New Issue
Block a user