Spaces:
Running
Running
/** | |
* @author mrdoob / http://mrdoob.com/ | |
*/ | |
import { BackSide, DoubleSide, CubeUVRefractionMapping, CubeUVReflectionMapping, GammaEncoding, LinearEncoding, ObjectSpaceNormalMap } from '../../constants.js'; | |
import { WebGLProgram } from './WebGLProgram.js'; | |
function WebGLPrograms( renderer, extensions, capabilities, textures ) { | |
var programs = []; | |
var shaderIDs = { | |
MeshDepthMaterial: 'depth', | |
MeshDistanceMaterial: 'distanceRGBA', | |
MeshNormalMaterial: 'normal', | |
MeshBasicMaterial: 'basic', | |
MeshLambertMaterial: 'lambert', | |
MeshPhongMaterial: 'phong', | |
MeshToonMaterial: 'phong', | |
MeshStandardMaterial: 'physical', | |
MeshPhysicalMaterial: 'physical', | |
MeshMatcapMaterial: 'matcap', | |
LineBasicMaterial: 'basic', | |
LineDashedMaterial: 'dashed', | |
PointsMaterial: 'points', | |
ShadowMaterial: 'shadow', | |
SpriteMaterial: 'sprite' | |
}; | |
var parameterNames = [ | |
"precision", "supportsVertexTextures", "map", "mapEncoding", "matcap", "matcapEncoding", "envMap", "envMapMode", "envMapEncoding", | |
"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "displacementMap", "specularMap", | |
"roughnessMap", "metalnessMap", "gradientMap", | |
"alphaMap", "combine", "vertexColors", "vertexTangents", "fog", "useFog", "fogExp", | |
"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning", | |
"maxBones", "useVertexTexture", "morphTargets", "morphNormals", | |
"maxMorphTargets", "maxMorphNormals", "premultipliedAlpha", | |
"numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights", | |
"shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights', | |
"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering" | |
]; | |
function allocateBones( object ) { | |
var skeleton = object.skeleton; | |
var bones = skeleton.bones; | |
if ( capabilities.floatVertexTextures ) { | |
return 1024; | |
} else { | |
// default for when object is not specified | |
// ( for example when prebuilding shader to be used with multiple objects ) | |
// | |
// - leave some extra space for other uniforms | |
// - limit here is ANGLE's 254 max uniform vectors | |
// (up to 54 should be safe) | |
var nVertexUniforms = capabilities.maxVertexUniforms; | |
var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); | |
var maxBones = Math.min( nVertexMatrices, bones.length ); | |
if ( maxBones < bones.length ) { | |
console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' ); | |
return 0; | |
} | |
return maxBones; | |
} | |
} | |
function getTextureEncodingFromMap( map, gammaOverrideLinear ) { | |
var encoding; | |
if ( ! map ) { | |
encoding = LinearEncoding; | |
} else if ( map.isTexture ) { | |
encoding = map.encoding; | |
} else if ( map.isWebGLRenderTarget ) { | |
console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." ); | |
encoding = map.texture.encoding; | |
} | |
// add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point. | |
if ( encoding === LinearEncoding && gammaOverrideLinear ) { | |
encoding = GammaEncoding; | |
} | |
return encoding; | |
} | |
this.getParameters = function ( material, lights, shadows, fog, nClipPlanes, nClipIntersection, object ) { | |
var shaderID = shaderIDs[ material.type ]; | |
// heuristics to create shader parameters according to lights in the scene | |
// (not to blow over maxLights budget) | |
var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0; | |
var precision = capabilities.precision; | |
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.' ); | |
} | |
} | |
var currentRenderTarget = renderer.getRenderTarget(); | |
var parameters = { | |
shaderID: shaderID, | |
precision: precision, | |
supportsVertexTextures: capabilities.vertexTextures, | |
outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ), | |
map: !! material.map, | |
mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ), | |
matcap: !! material.matcap, | |
matcapEncoding: getTextureEncodingFromMap( material.matcap, renderer.gammaInput ), | |
envMap: !! material.envMap, | |
envMapMode: material.envMap && material.envMap.mapping, | |
envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ), | |
envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ), | |
lightMap: !! material.lightMap, | |
aoMap: !! material.aoMap, | |
emissiveMap: !! material.emissiveMap, | |
emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ), | |
bumpMap: !! material.bumpMap, | |
normalMap: !! material.normalMap, | |
objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap, | |
displacementMap: !! material.displacementMap, | |
roughnessMap: !! material.roughnessMap, | |
metalnessMap: !! material.metalnessMap, | |
specularMap: !! material.specularMap, | |
alphaMap: !! material.alphaMap, | |
gradientMap: !! material.gradientMap, | |
combine: material.combine, | |
vertexTangents: ( material.normalMap && material.vertexTangents ), | |
vertexColors: material.vertexColors, | |
fog: !! fog, | |
useFog: material.fog, | |
fogExp: ( fog && fog.isFogExp2 ), | |
flatShading: material.flatShading, | |
sizeAttenuation: material.sizeAttenuation, | |
logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer, | |
skinning: material.skinning && maxBones > 0, | |
maxBones: maxBones, | |
useVertexTexture: capabilities.floatVertexTextures, | |
morphTargets: material.morphTargets, | |
morphNormals: material.morphNormals, | |
maxMorphTargets: renderer.maxMorphTargets, | |
maxMorphNormals: renderer.maxMorphNormals, | |
numDirLights: lights.directional.length, | |
numPointLights: lights.point.length, | |
numSpotLights: lights.spot.length, | |
numRectAreaLights: lights.rectArea.length, | |
numHemiLights: lights.hemi.length, | |
numClippingPlanes: nClipPlanes, | |
numClipIntersection: nClipIntersection, | |
dithering: material.dithering, | |
shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && shadows.length > 0, | |
shadowMapType: renderer.shadowMap.type, | |
toneMapping: renderer.toneMapping, | |
physicallyCorrectLights: renderer.physicallyCorrectLights, | |
premultipliedAlpha: material.premultipliedAlpha, | |
alphaTest: material.alphaTest, | |
doubleSided: material.side === DoubleSide, | |
flipSided: material.side === BackSide, | |
depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false | |
}; | |
return parameters; | |
}; | |
this.getProgramCode = function ( material, parameters ) { | |
var array = []; | |
if ( parameters.shaderID ) { | |
array.push( parameters.shaderID ); | |
} else { | |
array.push( material.fragmentShader ); | |
array.push( material.vertexShader ); | |
} | |
if ( material.defines !== undefined ) { | |
for ( var name in material.defines ) { | |
array.push( name ); | |
array.push( material.defines[ name ] ); | |
} | |
} | |
for ( var i = 0; i < parameterNames.length; i ++ ) { | |
array.push( parameters[ parameterNames[ i ] ] ); | |
} | |
array.push( material.onBeforeCompile.toString() ); | |
array.push( renderer.gammaOutput ); | |
array.push( renderer.gammaFactor ); | |
return array.join(); | |
}; | |
this.acquireProgram = function ( material, shader, parameters, code ) { | |
var program; | |
// Check if code has been already compiled | |
for ( var p = 0, pl = programs.length; p < pl; p ++ ) { | |
var programInfo = programs[ p ]; | |
if ( programInfo.code === code ) { | |
program = programInfo; | |
++ program.usedTimes; | |
break; | |
} | |
} | |
if ( program === undefined ) { | |
program = new WebGLProgram( renderer, extensions, code, material, shader, parameters, capabilities, textures ); | |
programs.push( program ); | |
} | |
return program; | |
}; | |
this.releaseProgram = function ( program ) { | |
if ( -- program.usedTimes === 0 ) { | |
// Remove from unordered set | |
var i = programs.indexOf( program ); | |
programs[ i ] = programs[ programs.length - 1 ]; | |
programs.pop(); | |
// Free WebGL resources | |
program.destroy(); | |
} | |
}; | |
// Exposed for resource monitoring & error feedback via renderer.info: | |
this.programs = programs; | |
} | |
export { WebGLPrograms }; | |