three
Version:
JavaScript 3D library
543 lines (403 loc) • 17.4 kB
JavaScript
import { BackSide, DoubleSide, CubeUVReflectionMapping, ObjectSpaceNormalMap, TangentSpaceNormalMap, NoToneMapping, LinearEncoding, sRGBEncoding, NormalBlending } from '../../constants.js';
import { Layers } from '../../core/Layers.js';
import { WebGLProgram } from './WebGLProgram.js';
import { WebGLShaderCache } from './WebGLShaderCache.js';
import { ShaderLib } from '../shaders/ShaderLib.js';
import { UniformsUtils } from '../shaders/UniformsUtils.js';
function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) {
const _programLayers = new Layers();
const _customShaders = new WebGLShaderCache();
const programs = [];
const isWebGL2 = capabilities.isWebGL2;
const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
const vertexTextures = capabilities.vertexTextures;
let precision = capabilities.precision;
const shaderIDs = {
MeshDepthMaterial: 'depth',
MeshDistanceMaterial: 'distanceRGBA',
MeshNormalMaterial: 'normal',
MeshBasicMaterial: 'basic',
MeshLambertMaterial: 'lambert',
MeshPhongMaterial: 'phong',
MeshToonMaterial: 'toon',
MeshStandardMaterial: 'physical',
MeshPhysicalMaterial: 'physical',
MeshMatcapMaterial: 'matcap',
LineBasicMaterial: 'basic',
LineDashedMaterial: 'dashed',
PointsMaterial: 'points',
ShadowMaterial: 'shadow',
SpriteMaterial: 'sprite'
};
function getParameters( material, lights, shadows, scene, object ) {
const fog = scene.fog;
const geometry = object.geometry;
const environment = material.isMeshStandardMaterial ? scene.environment : null;
const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null;
const shaderID = shaderIDs[ material.type ];
// heuristics to create shader parameters according to lights in the scene
// (not to blow over maxLights budget)
if ( material.precision !== null ) {
precision = capabilities.getMaxPrecision( material.precision );
if ( precision !== material.precision ) {
console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
}
}
//
const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
let morphTextureStride = 0;
if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1;
if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2;
if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3;
//
let vertexShader, fragmentShader;
let customVertexShaderID, customFragmentShaderID;
if ( shaderID ) {
const shader = ShaderLib[ shaderID ];
vertexShader = shader.vertexShader;
fragmentShader = shader.fragmentShader;
} else {
vertexShader = material.vertexShader;
fragmentShader = material.fragmentShader;
_customShaders.update( material );
customVertexShaderID = _customShaders.getVertexShaderID( material );
customFragmentShaderID = _customShaders.getFragmentShaderID( material );
}
const currentRenderTarget = renderer.getRenderTarget();
const useAlphaTest = material.alphaTest > 0;
const useClearcoat = material.clearcoat > 0;
const useIridescence = material.iridescence > 0;
const parameters = {
isWebGL2: isWebGL2,
shaderID: shaderID,
shaderName: material.type,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
defines: material.defines,
customVertexShaderID: customVertexShaderID,
customFragmentShaderID: customFragmentShaderID,
isRawShaderMaterial: material.isRawShaderMaterial === true,
glslVersion: material.glslVersion,
precision: precision,
instancing: object.isInstancedMesh === true,
instancingColor: object.isInstancedMesh === true && object.instanceColor !== null,
supportsVertexTextures: vertexTextures,
outputEncoding: ( currentRenderTarget === null ) ? renderer.outputEncoding : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.encoding : LinearEncoding ),
map: !! material.map,
matcap: !! material.matcap,
envMap: !! envMap,
envMapMode: envMap && envMap.mapping,
envMapCubeUVHeight: envMapCubeUVHeight,
lightMap: !! material.lightMap,
aoMap: !! material.aoMap,
emissiveMap: !! material.emissiveMap,
bumpMap: !! material.bumpMap,
normalMap: !! material.normalMap,
objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap,
tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap,
decodeVideoTexture: !! material.map && ( material.map.isVideoTexture === true ) && ( material.map.encoding === sRGBEncoding ),
clearcoat: useClearcoat,
clearcoatMap: useClearcoat && !! material.clearcoatMap,
clearcoatRoughnessMap: useClearcoat && !! material.clearcoatRoughnessMap,
clearcoatNormalMap: useClearcoat && !! material.clearcoatNormalMap,
iridescence: useIridescence,
iridescenceMap: useIridescence && !! material.iridescenceMap,
iridescenceThicknessMap: useIridescence && !! material.iridescenceThicknessMap,
displacementMap: !! material.displacementMap,
roughnessMap: !! material.roughnessMap,
metalnessMap: !! material.metalnessMap,
specularMap: !! material.specularMap,
specularIntensityMap: !! material.specularIntensityMap,
specularColorMap: !! material.specularColorMap,
opaque: material.transparent === false && material.blending === NormalBlending,
alphaMap: !! material.alphaMap,
alphaTest: useAlphaTest,
gradientMap: !! material.gradientMap,
sheen: material.sheen > 0,
sheenColorMap: !! material.sheenColorMap,
sheenRoughnessMap: !! material.sheenRoughnessMap,
transmission: material.transmission > 0,
transmissionMap: !! material.transmissionMap,
thicknessMap: !! material.thicknessMap,
combine: material.combine,
vertexTangents: ( !! material.normalMap && !! geometry.attributes.tangent ),
vertexColors: material.vertexColors,
vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4,
vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || !! material.displacementMap || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || !! material.sheenColorMap || !! material.sheenRoughnessMap,
uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || material.transmission > 0 || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || material.sheen > 0 || !! material.sheenColorMap || !! material.sheenRoughnessMap ) && !! material.displacementMap,
fog: !! fog,
useFog: material.fog === true,
fogExp2: ( fog && fog.isFogExp2 ),
flatShading: !! material.flatShading,
sizeAttenuation: material.sizeAttenuation,
logarithmicDepthBuffer: logarithmicDepthBuffer,
skinning: object.isSkinnedMesh === true,
morphTargets: geometry.morphAttributes.position !== undefined,
morphNormals: geometry.morphAttributes.normal !== undefined,
morphColors: geometry.morphAttributes.color !== undefined,
morphTargetsCount: morphTargetsCount,
morphTextureStride: morphTextureStride,
numDirLights: lights.directional.length,
numPointLights: lights.point.length,
numSpotLights: lights.spot.length,
numSpotLightMaps: lights.spotLightMap.length,
numRectAreaLights: lights.rectArea.length,
numHemiLights: lights.hemi.length,
numDirLightShadows: lights.directionalShadowMap.length,
numPointLightShadows: lights.pointShadowMap.length,
numSpotLightShadows: lights.spotShadowMap.length,
numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps,
numClippingPlanes: clipping.numPlanes,
numClipIntersection: clipping.numIntersection,
dithering: material.dithering,
shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,
shadowMapType: renderer.shadowMap.type,
toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping,
physicallyCorrectLights: renderer.physicallyCorrectLights,
premultipliedAlpha: material.premultipliedAlpha,
doubleSided: material.side === DoubleSide,
flipSided: material.side === BackSide,
useDepthPacking: !! material.depthPacking,
depthPacking: material.depthPacking || 0,
index0AttributeName: material.index0AttributeName,
extensionDerivatives: material.extensions && material.extensions.derivatives,
extensionFragDepth: material.extensions && material.extensions.fragDepth,
extensionDrawBuffers: material.extensions && material.extensions.drawBuffers,
extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD,
rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ),
rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ),
rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ),
customProgramCacheKey: material.customProgramCacheKey()
};
return parameters;
}
function getProgramCacheKey( parameters ) {
const array = [];
if ( parameters.shaderID ) {
array.push( parameters.shaderID );
} else {
array.push( parameters.customVertexShaderID );
array.push( parameters.customFragmentShaderID );
}
if ( parameters.defines !== undefined ) {
for ( const name in parameters.defines ) {
array.push( name );
array.push( parameters.defines[ name ] );
}
}
if ( parameters.isRawShaderMaterial === false ) {
getProgramCacheKeyParameters( array, parameters );
getProgramCacheKeyBooleans( array, parameters );
array.push( renderer.outputEncoding );
}
array.push( parameters.customProgramCacheKey );
return array.join();
}
function getProgramCacheKeyParameters( array, parameters ) {
array.push( parameters.precision );
array.push( parameters.outputEncoding );
array.push( parameters.envMapMode );
array.push( parameters.envMapCubeUVHeight );
array.push( parameters.combine );
array.push( parameters.vertexUvs );
array.push( parameters.fogExp2 );
array.push( parameters.sizeAttenuation );
array.push( parameters.morphTargetsCount );
array.push( parameters.morphAttributeCount );
array.push( parameters.numDirLights );
array.push( parameters.numPointLights );
array.push( parameters.numSpotLights );
array.push( parameters.numSpotLightMaps );
array.push( parameters.numHemiLights );
array.push( parameters.numRectAreaLights );
array.push( parameters.numDirLightShadows );
array.push( parameters.numPointLightShadows );
array.push( parameters.numSpotLightShadows );
array.push( parameters.numSpotLightShadowsWithMaps );
array.push( parameters.shadowMapType );
array.push( parameters.toneMapping );
array.push( parameters.numClippingPlanes );
array.push( parameters.numClipIntersection );
array.push( parameters.depthPacking );
}
function getProgramCacheKeyBooleans( array, parameters ) {
_programLayers.disableAll();
if ( parameters.isWebGL2 )
_programLayers.enable( 0 );
if ( parameters.supportsVertexTextures )
_programLayers.enable( 1 );
if ( parameters.instancing )
_programLayers.enable( 2 );
if ( parameters.instancingColor )
_programLayers.enable( 3 );
if ( parameters.map )
_programLayers.enable( 4 );
if ( parameters.matcap )
_programLayers.enable( 5 );
if ( parameters.envMap )
_programLayers.enable( 6 );
if ( parameters.lightMap )
_programLayers.enable( 7 );
if ( parameters.aoMap )
_programLayers.enable( 8 );
if ( parameters.emissiveMap )
_programLayers.enable( 9 );
if ( parameters.bumpMap )
_programLayers.enable( 10 );
if ( parameters.normalMap )
_programLayers.enable( 11 );
if ( parameters.objectSpaceNormalMap )
_programLayers.enable( 12 );
if ( parameters.tangentSpaceNormalMap )
_programLayers.enable( 13 );
if ( parameters.clearcoat )
_programLayers.enable( 14 );
if ( parameters.clearcoatMap )
_programLayers.enable( 15 );
if ( parameters.clearcoatRoughnessMap )
_programLayers.enable( 16 );
if ( parameters.clearcoatNormalMap )
_programLayers.enable( 17 );
if ( parameters.iridescence )
_programLayers.enable( 18 );
if ( parameters.iridescenceMap )
_programLayers.enable( 19 );
if ( parameters.iridescenceThicknessMap )
_programLayers.enable( 20 );
if ( parameters.displacementMap )
_programLayers.enable( 21 );
if ( parameters.specularMap )
_programLayers.enable( 22 );
if ( parameters.roughnessMap )
_programLayers.enable( 23 );
if ( parameters.metalnessMap )
_programLayers.enable( 24 );
if ( parameters.gradientMap )
_programLayers.enable( 25 );
if ( parameters.alphaMap )
_programLayers.enable( 26 );
if ( parameters.alphaTest )
_programLayers.enable( 27 );
if ( parameters.vertexColors )
_programLayers.enable( 28 );
if ( parameters.vertexAlphas )
_programLayers.enable( 29 );
if ( parameters.vertexUvs )
_programLayers.enable( 30 );
if ( parameters.vertexTangents )
_programLayers.enable( 31 );
if ( parameters.uvsVertexOnly )
_programLayers.enable( 32 );
array.push( _programLayers.mask );
_programLayers.disableAll();
if ( parameters.fog )
_programLayers.enable( 0 );
if ( parameters.useFog )
_programLayers.enable( 1 );
if ( parameters.flatShading )
_programLayers.enable( 2 );
if ( parameters.logarithmicDepthBuffer )
_programLayers.enable( 3 );
if ( parameters.skinning )
_programLayers.enable( 4 );
if ( parameters.morphTargets )
_programLayers.enable( 5 );
if ( parameters.morphNormals )
_programLayers.enable( 6 );
if ( parameters.morphColors )
_programLayers.enable( 7 );
if ( parameters.premultipliedAlpha )
_programLayers.enable( 8 );
if ( parameters.shadowMapEnabled )
_programLayers.enable( 9 );
if ( parameters.physicallyCorrectLights )
_programLayers.enable( 10 );
if ( parameters.doubleSided )
_programLayers.enable( 11 );
if ( parameters.flipSided )
_programLayers.enable( 12 );
if ( parameters.useDepthPacking )
_programLayers.enable( 13 );
if ( parameters.dithering )
_programLayers.enable( 14 );
if ( parameters.specularIntensityMap )
_programLayers.enable( 15 );
if ( parameters.specularColorMap )
_programLayers.enable( 16 );
if ( parameters.transmission )
_programLayers.enable( 17 );
if ( parameters.transmissionMap )
_programLayers.enable( 18 );
if ( parameters.thicknessMap )
_programLayers.enable( 19 );
if ( parameters.sheen )
_programLayers.enable( 20 );
if ( parameters.sheenColorMap )
_programLayers.enable( 21 );
if ( parameters.sheenRoughnessMap )
_programLayers.enable( 22 );
if ( parameters.decodeVideoTexture )
_programLayers.enable( 23 );
if ( parameters.opaque )
_programLayers.enable( 24 );
array.push( _programLayers.mask );
}
function getUniforms( material ) {
const shaderID = shaderIDs[ material.type ];
let uniforms;
if ( shaderID ) {
const shader = ShaderLib[ shaderID ];
uniforms = UniformsUtils.clone( shader.uniforms );
} else {
uniforms = material.uniforms;
}
return uniforms;
}
function acquireProgram( parameters, cacheKey ) {
let program;
// Check if code has been already compiled
for ( let p = 0, pl = programs.length; p < pl; p ++ ) {
const preexistingProgram = programs[ p ];
if ( preexistingProgram.cacheKey === cacheKey ) {
program = preexistingProgram;
++ program.usedTimes;
break;
}
}
if ( program === undefined ) {
program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );
programs.push( program );
}
return program;
}
function releaseProgram( program ) {
if ( -- program.usedTimes === 0 ) {
// Remove from unordered set
const i = programs.indexOf( program );
programs[ i ] = programs[ programs.length - 1 ];
programs.pop();
// Free WebGL resources
program.destroy();
}
}
function releaseShaderCache( material ) {
_customShaders.remove( material );
}
function dispose() {
_customShaders.dispose();
}
return {
getParameters: getParameters,
getProgramCacheKey: getProgramCacheKey,
getUniforms: getUniforms,
acquireProgram: acquireProgram,
releaseProgram: releaseProgram,
releaseShaderCache: releaseShaderCache,
// Exposed for resource monitoring & error feedback via renderer.info:
programs: programs,
dispose: dispose
};
}
export { WebGLPrograms };