Spaces:
Running
Running
/** | |
* @author mrdoob / http://mrdoob.com/ | |
*/ | |
import { WebGLUniforms } from './WebGLUniforms.js'; | |
import { WebGLShader } from './WebGLShader.js'; | |
import { ShaderChunk } from '../shaders/ShaderChunk.js'; | |
import { NoToneMapping, AddOperation, MixOperation, MultiplyOperation, EquirectangularRefractionMapping, CubeRefractionMapping, SphericalReflectionMapping, EquirectangularReflectionMapping, CubeUVRefractionMapping, CubeUVReflectionMapping, CubeReflectionMapping, PCFSoftShadowMap, PCFShadowMap, ACESFilmicToneMapping, CineonToneMapping, Uncharted2ToneMapping, ReinhardToneMapping, LinearToneMapping, GammaEncoding, RGBDEncoding, RGBM16Encoding, RGBM7Encoding, RGBEEncoding, sRGBEncoding, LinearEncoding } from '../../constants.js'; | |
var programIdCount = 0; | |
function getEncodingComponents( encoding ) { | |
switch ( encoding ) { | |
case LinearEncoding: | |
return [ 'Linear', '( value )' ]; | |
case sRGBEncoding: | |
return [ 'sRGB', '( value )' ]; | |
case RGBEEncoding: | |
return [ 'RGBE', '( value )' ]; | |
case RGBM7Encoding: | |
return [ 'RGBM', '( value, 7.0 )' ]; | |
case RGBM16Encoding: | |
return [ 'RGBM', '( value, 16.0 )' ]; | |
case RGBDEncoding: | |
return [ 'RGBD', '( value, 256.0 )' ]; | |
case GammaEncoding: | |
return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ]; | |
default: | |
throw new Error( 'unsupported encoding: ' + encoding ); | |
} | |
} | |
function getTexelDecodingFunction( functionName, encoding ) { | |
var components = getEncodingComponents( encoding ); | |
return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }'; | |
} | |
function getTexelEncodingFunction( functionName, encoding ) { | |
var components = getEncodingComponents( encoding ); | |
return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }'; | |
} | |
function getToneMappingFunction( functionName, toneMapping ) { | |
var toneMappingName; | |
switch ( toneMapping ) { | |
case LinearToneMapping: | |
toneMappingName = 'Linear'; | |
break; | |
case ReinhardToneMapping: | |
toneMappingName = 'Reinhard'; | |
break; | |
case Uncharted2ToneMapping: | |
toneMappingName = 'Uncharted2'; | |
break; | |
case CineonToneMapping: | |
toneMappingName = 'OptimizedCineon'; | |
break; | |
case ACESFilmicToneMapping: | |
toneMappingName = 'ACESFilmic'; | |
break; | |
default: | |
throw new Error( 'unsupported toneMapping: ' + toneMapping ); | |
} | |
return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; | |
} | |
function generateExtensions( extensions, parameters, rendererExtensions ) { | |
extensions = extensions || {}; | |
var chunks = [ | |
( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || ( parameters.normalMap && ! parameters.objectSpaceNormalMap ) || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', | |
( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '', | |
( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '', | |
( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : '' | |
]; | |
return chunks.filter( filterEmptyLine ).join( '\n' ); | |
} | |
function generateDefines( defines ) { | |
var chunks = []; | |
for ( var name in defines ) { | |
var value = defines[ name ]; | |
if ( value === false ) continue; | |
chunks.push( '#define ' + name + ' ' + value ); | |
} | |
return chunks.join( '\n' ); | |
} | |
function fetchAttributeLocations( gl, program ) { | |
var attributes = {}; | |
var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); | |
for ( var i = 0; i < n; i ++ ) { | |
var info = gl.getActiveAttrib( program, i ); | |
var name = info.name; | |
// console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); | |
attributes[ name ] = gl.getAttribLocation( program, name ); | |
} | |
return attributes; | |
} | |
function filterEmptyLine( string ) { | |
return string !== ''; | |
} | |
function replaceLightNums( string, parameters ) { | |
return string | |
.replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) | |
.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) | |
.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) | |
.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) | |
.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ); | |
} | |
function replaceClippingPlaneNums( string, parameters ) { | |
return string | |
.replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes ) | |
.replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) ); | |
} | |
function parseIncludes( string ) { | |
var pattern = /^[ \t]*#include +<([\w\d./]+)>/gm; | |
function replace( match, include ) { | |
var replace = ShaderChunk[ include ]; | |
if ( replace === undefined ) { | |
throw new Error( 'Can not resolve #include <' + include + '>' ); | |
} | |
return parseIncludes( replace ); | |
} | |
return string.replace( pattern, replace ); | |
} | |
function unrollLoops( string ) { | |
var pattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g; | |
function replace( match, start, end, snippet ) { | |
var unroll = ''; | |
for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) { | |
unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' ); | |
} | |
return unroll; | |
} | |
return string.replace( pattern, replace ); | |
} | |
function WebGLProgram( renderer, extensions, code, material, shader, parameters, capabilities, textures ) { | |
var gl = renderer.context; | |
var defines = material.defines; | |
var vertexShader = shader.vertexShader; | |
var fragmentShader = shader.fragmentShader; | |
var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; | |
if ( parameters.shadowMapType === PCFShadowMap ) { | |
shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; | |
} else if ( parameters.shadowMapType === PCFSoftShadowMap ) { | |
shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; | |
} | |
var envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; | |
var envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; | |
var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; | |
if ( parameters.envMap ) { | |
switch ( material.envMap.mapping ) { | |
case CubeReflectionMapping: | |
case CubeRefractionMapping: | |
envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; | |
break; | |
case CubeUVReflectionMapping: | |
case CubeUVRefractionMapping: | |
envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; | |
break; | |
case EquirectangularReflectionMapping: | |
case EquirectangularRefractionMapping: | |
envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; | |
break; | |
case SphericalReflectionMapping: | |
envMapTypeDefine = 'ENVMAP_TYPE_SPHERE'; | |
break; | |
} | |
switch ( material.envMap.mapping ) { | |
case CubeRefractionMapping: | |
case EquirectangularRefractionMapping: | |
envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; | |
break; | |
} | |
switch ( material.combine ) { | |
case MultiplyOperation: | |
envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; | |
break; | |
case MixOperation: | |
envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; | |
break; | |
case AddOperation: | |
envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; | |
break; | |
} | |
} | |
var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; | |
// console.log( 'building new program ' ); | |
// | |
var customExtensions = capabilities.isWebGL2 ? '' : generateExtensions( material.extensions, parameters, extensions ); | |
var customDefines = generateDefines( defines ); | |
// | |
var program = gl.createProgram(); | |
var prefixVertex, prefixFragment; | |
if ( material.isRawShaderMaterial ) { | |
prefixVertex = [ | |
customDefines | |
].filter( filterEmptyLine ).join( '\n' ); | |
if ( prefixVertex.length > 0 ) { | |
prefixVertex += '\n'; | |
} | |
prefixFragment = [ | |
customExtensions, | |
customDefines | |
].filter( filterEmptyLine ).join( '\n' ); | |
if ( prefixFragment.length > 0 ) { | |
prefixFragment += '\n'; | |
} | |
} else { | |
prefixVertex = [ | |
'precision ' + parameters.precision + ' float;', | |
'precision ' + parameters.precision + ' int;', | |
'#define SHADER_NAME ' + shader.name, | |
customDefines, | |
parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', | |
'#define GAMMA_FACTOR ' + gammaFactorDefine, | |
'#define MAX_BONES ' + parameters.maxBones, | |
( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', | |
( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', | |
parameters.map ? '#define USE_MAP' : '', | |
parameters.envMap ? '#define USE_ENVMAP' : '', | |
parameters.envMap ? '#define ' + envMapModeDefine : '', | |
parameters.lightMap ? '#define USE_LIGHTMAP' : '', | |
parameters.aoMap ? '#define USE_AOMAP' : '', | |
parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', | |
parameters.bumpMap ? '#define USE_BUMPMAP' : '', | |
parameters.normalMap ? '#define USE_NORMALMAP' : '', | |
( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', | |
parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', | |
parameters.specularMap ? '#define USE_SPECULARMAP' : '', | |
parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', | |
parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', | |
parameters.alphaMap ? '#define USE_ALPHAMAP' : '', | |
parameters.vertexTangents ? '#define USE_TANGENT' : '', | |
parameters.vertexColors ? '#define USE_COLOR' : '', | |
parameters.flatShading ? '#define FLAT_SHADED' : '', | |
parameters.skinning ? '#define USE_SKINNING' : '', | |
parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', | |
parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', | |
parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', | |
parameters.doubleSided ? '#define DOUBLE_SIDED' : '', | |
parameters.flipSided ? '#define FLIP_SIDED' : '', | |
parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', | |
parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', | |
parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', | |
parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', | |
parameters.logarithmicDepthBuffer && ( capabilities.isWebGL2 || extensions.get( 'EXT_frag_depth' ) ) ? '#define USE_LOGDEPTHBUF_EXT' : '', | |
'uniform mat4 modelMatrix;', | |
'uniform mat4 modelViewMatrix;', | |
'uniform mat4 projectionMatrix;', | |
'uniform mat4 viewMatrix;', | |
'uniform mat3 normalMatrix;', | |
'uniform vec3 cameraPosition;', | |
'attribute vec3 position;', | |
'attribute vec3 normal;', | |
'attribute vec2 uv;', | |
'#ifdef USE_TANGENT', | |
' attribute vec4 tangent;', | |
'#endif', | |
'#ifdef USE_COLOR', | |
' attribute vec3 color;', | |
'#endif', | |
'#ifdef USE_MORPHTARGETS', | |
' attribute vec3 morphTarget0;', | |
' attribute vec3 morphTarget1;', | |
' attribute vec3 morphTarget2;', | |
' attribute vec3 morphTarget3;', | |
' #ifdef USE_MORPHNORMALS', | |
' attribute vec3 morphNormal0;', | |
' attribute vec3 morphNormal1;', | |
' attribute vec3 morphNormal2;', | |
' attribute vec3 morphNormal3;', | |
' #else', | |
' attribute vec3 morphTarget4;', | |
' attribute vec3 morphTarget5;', | |
' attribute vec3 morphTarget6;', | |
' attribute vec3 morphTarget7;', | |
' #endif', | |
'#endif', | |
'#ifdef USE_SKINNING', | |
' attribute vec4 skinIndex;', | |
' attribute vec4 skinWeight;', | |
'#endif', | |
'\n' | |
].filter( filterEmptyLine ).join( '\n' ); | |
prefixFragment = [ | |
customExtensions, | |
'precision ' + parameters.precision + ' float;', | |
'precision ' + parameters.precision + ' int;', | |
'#define SHADER_NAME ' + shader.name, | |
customDefines, | |
parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest + ( parameters.alphaTest % 1 ? '' : '.0' ) : '', // add '.0' if integer | |
'#define GAMMA_FACTOR ' + gammaFactorDefine, | |
( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', | |
( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', | |
parameters.map ? '#define USE_MAP' : '', | |
parameters.matcap ? '#define USE_MATCAP' : '', | |
parameters.envMap ? '#define USE_ENVMAP' : '', | |
parameters.envMap ? '#define ' + envMapTypeDefine : '', | |
parameters.envMap ? '#define ' + envMapModeDefine : '', | |
parameters.envMap ? '#define ' + envMapBlendingDefine : '', | |
parameters.lightMap ? '#define USE_LIGHTMAP' : '', | |
parameters.aoMap ? '#define USE_AOMAP' : '', | |
parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', | |
parameters.bumpMap ? '#define USE_BUMPMAP' : '', | |
parameters.normalMap ? '#define USE_NORMALMAP' : '', | |
( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', | |
parameters.specularMap ? '#define USE_SPECULARMAP' : '', | |
parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', | |
parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', | |
parameters.alphaMap ? '#define USE_ALPHAMAP' : '', | |
parameters.vertexTangents ? '#define USE_TANGENT' : '', | |
parameters.vertexColors ? '#define USE_COLOR' : '', | |
parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', | |
parameters.flatShading ? '#define FLAT_SHADED' : '', | |
parameters.doubleSided ? '#define DOUBLE_SIDED' : '', | |
parameters.flipSided ? '#define FLIP_SIDED' : '', | |
parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', | |
parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', | |
parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', | |
parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '', | |
parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', | |
parameters.logarithmicDepthBuffer && ( capabilities.isWebGL2 || extensions.get( 'EXT_frag_depth' ) ) ? '#define USE_LOGDEPTHBUF_EXT' : '', | |
parameters.envMap && ( capabilities.isWebGL2 || extensions.get( 'EXT_shader_texture_lod' ) ) ? '#define TEXTURE_LOD_EXT' : '', | |
'uniform mat4 viewMatrix;', | |
'uniform vec3 cameraPosition;', | |
( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '', | |
( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below | |
( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '', | |
parameters.dithering ? '#define DITHERING' : '', | |
( parameters.outputEncoding || parameters.mapEncoding || parameters.matcapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? | |
ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below | |
parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '', | |
parameters.matcapEncoding ? getTexelDecodingFunction( 'matcapTexelToLinear', parameters.matcapEncoding ) : '', | |
parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '', | |
parameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '', | |
parameters.outputEncoding ? getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ) : '', | |
parameters.depthPacking ? '#define DEPTH_PACKING ' + material.depthPacking : '', | |
'\n' | |
].filter( filterEmptyLine ).join( '\n' ); | |
} | |
vertexShader = parseIncludes( vertexShader ); | |
vertexShader = replaceLightNums( vertexShader, parameters ); | |
vertexShader = replaceClippingPlaneNums( vertexShader, parameters ); | |
fragmentShader = parseIncludes( fragmentShader ); | |
fragmentShader = replaceLightNums( fragmentShader, parameters ); | |
fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters ); | |
vertexShader = unrollLoops( vertexShader ); | |
fragmentShader = unrollLoops( fragmentShader ); | |
if ( capabilities.isWebGL2 && ! material.isRawShaderMaterial ) { | |
var isGLSL3ShaderMaterial = false; | |
var versionRegex = /^\s*#version\s+300\s+es\s*\n/; | |
if ( material.isShaderMaterial && | |
vertexShader.match( versionRegex ) !== null && | |
fragmentShader.match( versionRegex ) !== null ) { | |
isGLSL3ShaderMaterial = true; | |
vertexShader = vertexShader.replace( versionRegex, '' ); | |
fragmentShader = fragmentShader.replace( versionRegex, '' ); | |
} | |
// GLSL 3.0 conversion | |
prefixVertex = [ | |
'#version 300 es\n', | |
'#define attribute in', | |
'#define varying out', | |
'#define texture2D texture' | |
].join( '\n' ) + '\n' + prefixVertex; | |
prefixFragment = [ | |
'#version 300 es\n', | |
'#define varying in', | |
isGLSL3ShaderMaterial ? '' : 'out highp vec4 pc_fragColor;', | |
isGLSL3ShaderMaterial ? '' : '#define gl_FragColor pc_fragColor', | |
'#define gl_FragDepthEXT gl_FragDepth', | |
'#define texture2D texture', | |
'#define textureCube texture', | |
'#define texture2DProj textureProj', | |
'#define texture2DLodEXT textureLod', | |
'#define texture2DProjLodEXT textureProjLod', | |
'#define textureCubeLodEXT textureLod', | |
'#define texture2DGradEXT textureGrad', | |
'#define texture2DProjGradEXT textureProjGrad', | |
'#define textureCubeGradEXT textureGrad' | |
].join( '\n' ) + '\n' + prefixFragment; | |
} | |
var vertexGlsl = prefixVertex + vertexShader; | |
var fragmentGlsl = prefixFragment + fragmentShader; | |
// console.log( '*VERTEX*', vertexGlsl ); | |
// console.log( '*FRAGMENT*', fragmentGlsl ); | |
var glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); | |
var glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); | |
gl.attachShader( program, glVertexShader ); | |
gl.attachShader( program, glFragmentShader ); | |
// Force a particular attribute to index 0. | |
if ( material.index0AttributeName !== undefined ) { | |
gl.bindAttribLocation( program, 0, material.index0AttributeName ); | |
} else if ( parameters.morphTargets === true ) { | |
// programs with morphTargets displace position out of attribute 0 | |
gl.bindAttribLocation( program, 0, 'position' ); | |
} | |
gl.linkProgram( program ); | |
var programLog = gl.getProgramInfoLog( program ).trim(); | |
var vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); | |
var fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); | |
var runnable = true; | |
var haveDiagnostics = true; | |
// console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); | |
// console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); | |
if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { | |
runnable = false; | |
console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog ); | |
} else if ( programLog !== '' ) { | |
console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog ); | |
} else if ( vertexLog === '' || fragmentLog === '' ) { | |
haveDiagnostics = false; | |
} | |
if ( haveDiagnostics ) { | |
this.diagnostics = { | |
runnable: runnable, | |
material: material, | |
programLog: programLog, | |
vertexShader: { | |
log: vertexLog, | |
prefix: prefixVertex | |
}, | |
fragmentShader: { | |
log: fragmentLog, | |
prefix: prefixFragment | |
} | |
}; | |
} | |
// clean up | |
gl.deleteShader( glVertexShader ); | |
gl.deleteShader( glFragmentShader ); | |
// set up caching for uniform locations | |
var cachedUniforms; | |
this.getUniforms = function () { | |
if ( cachedUniforms === undefined ) { | |
cachedUniforms = new WebGLUniforms( gl, program, textures ); | |
} | |
return cachedUniforms; | |
}; | |
// set up caching for attribute locations | |
var cachedAttributes; | |
this.getAttributes = function () { | |
if ( cachedAttributes === undefined ) { | |
cachedAttributes = fetchAttributeLocations( gl, program ); | |
} | |
return cachedAttributes; | |
}; | |
// free resource | |
this.destroy = function () { | |
gl.deleteProgram( program ); | |
this.program = undefined; | |
}; | |
// DEPRECATED | |
Object.defineProperties( this, { | |
uniforms: { | |
get: function () { | |
console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' ); | |
return this.getUniforms(); | |
} | |
}, | |
attributes: { | |
get: function () { | |
console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' ); | |
return this.getAttributes(); | |
} | |
} | |
} ); | |
// | |
this.name = shader.name; | |
this.id = programIdCount ++; | |
this.code = code; | |
this.usedTimes = 1; | |
this.program = program; | |
this.vertexShader = glVertexShader; | |
this.fragmentShader = glFragmentShader; | |
return this; | |
} | |
export { WebGLProgram }; | |