k-l-lambda's picture
feat: add Python ML services (CPU mode) with model download
2b7aae2
import { WebGLUniforms } from './WebGLUniforms.js';
import { WebGLShader } from './WebGLShader.js';
import { ShaderChunk } from '../shaders/ShaderChunk.js';
import {
NoToneMapping,
AddOperation,
MixOperation,
MultiplyOperation,
CubeRefractionMapping,
CubeUVRefractionMapping,
CubeUVReflectionMapping,
CubeReflectionMapping,
PCFSoftShadowMap,
PCFShadowMap,
VSMShadowMap,
ACESFilmicToneMapping,
CineonToneMapping,
CustomToneMapping,
ReinhardToneMapping,
LinearToneMapping,
sRGBEncoding,
LinearEncoding,
GLSL3,
} from '../../constants.js';
let programIdCount = 0;
function addLineNumbers(string) {
const lines = string.split('\n');
for (let i = 0; i < lines.length; i++) {
lines[i] = i + 1 + ': ' + lines[i];
}
return lines.join('\n');
}
function getEncodingComponents(encoding) {
switch (encoding) {
case LinearEncoding:
return ['Linear', '( value )'];
case sRGBEncoding:
return ['sRGB', '( value )'];
default:
console.warn('THREE.WebGLProgram: Unsupported encoding:', encoding);
return ['Linear', '( value )'];
}
}
function getShaderErrors(gl, shader, type) {
const status = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
const errors = gl.getShaderInfoLog(shader).trim();
if (status && errors === '') return '';
// --enable-privileged-webgl-extension
// console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
return type.toUpperCase() + '\n\n' + errors + '\n\n' + addLineNumbers(gl.getShaderSource(shader));
}
function getTexelEncodingFunction(functionName, encoding) {
const components = getEncodingComponents(encoding);
return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[0] + components[1] + '; }';
}
function getToneMappingFunction(functionName, toneMapping) {
let toneMappingName;
switch (toneMapping) {
case LinearToneMapping:
toneMappingName = 'Linear';
break;
case ReinhardToneMapping:
toneMappingName = 'Reinhard';
break;
case CineonToneMapping:
toneMappingName = 'OptimizedCineon';
break;
case ACESFilmicToneMapping:
toneMappingName = 'ACESFilmic';
break;
case CustomToneMapping:
toneMappingName = 'Custom';
break;
default:
console.warn('THREE.WebGLProgram: Unsupported toneMapping:', toneMapping);
toneMappingName = 'Linear';
}
return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
}
function generateExtensions(parameters) {
const chunks = [
parameters.extensionDerivatives ||
parameters.envMapCubeUV ||
parameters.bumpMap ||
parameters.tangentSpaceNormalMap ||
parameters.clearcoatNormalMap ||
parameters.flatShading ||
parameters.shaderID === 'physical'
? '#extension GL_OES_standard_derivatives : enable'
: '',
(parameters.extensionFragDepth || parameters.logarithmicDepthBuffer) && parameters.rendererExtensionFragDepth
? '#extension GL_EXT_frag_depth : enable'
: '',
parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ? '#extension GL_EXT_draw_buffers : require' : '',
(parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission) && parameters.rendererExtensionShaderTextureLod
? '#extension GL_EXT_shader_texture_lod : enable'
: '',
];
return chunks.filter(filterEmptyLine).join('\n');
}
function generateDefines(defines) {
const chunks = [];
for (const name in defines) {
const value = defines[name];
if (value === false) continue;
chunks.push('#define ' + name + ' ' + value);
}
return chunks.join('\n');
}
function fetchAttributeLocations(gl, program) {
const attributes = {};
const n = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
for (let i = 0; i < n; i++) {
const info = gl.getActiveAttrib(program, i);
const name = info.name;
let locationSize = 1;
if (info.type === gl.FLOAT_MAT2) locationSize = 2;
if (info.type === gl.FLOAT_MAT3) locationSize = 3;
if (info.type === gl.FLOAT_MAT4) locationSize = 4;
// console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
attributes[name] = {
type: info.type,
location: gl.getAttribLocation(program, name),
locationSize: locationSize,
};
}
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)
.replace(/NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows)
.replace(/NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows)
.replace(/NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows);
}
function replaceClippingPlaneNums(string, parameters) {
return string
.replace(/NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes)
.replace(/UNION_CLIPPING_PLANES/g, parameters.numClippingPlanes - parameters.numClipIntersection);
}
// Resolve Includes
const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm;
function resolveIncludes(string) {
return string.replace(includePattern, includeReplacer);
}
function includeReplacer(match, include) {
const string = ShaderChunk[include];
if (string === undefined) {
throw new Error('Can not resolve #include <' + include + '>');
}
return resolveIncludes(string);
}
// Unroll Loops
const deprecatedUnrollLoopPattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
const unrollLoopPattern =
/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;
function unrollLoops(string) {
return string.replace(unrollLoopPattern, loopReplacer).replace(deprecatedUnrollLoopPattern, deprecatedLoopReplacer);
}
function deprecatedLoopReplacer(match, start, end, snippet) {
console.warn('WebGLProgram: #pragma unroll_loop shader syntax is deprecated. Please use #pragma unroll_loop_start syntax instead.');
return loopReplacer(match, start, end, snippet);
}
function loopReplacer(match, start, end, snippet) {
let string = '';
for (let i = parseInt(start); i < parseInt(end); i++) {
string += snippet.replace(/\[\s*i\s*\]/g, '[ ' + i + ' ]').replace(/UNROLLED_LOOP_INDEX/g, i);
}
return string;
}
//
function generatePrecision(parameters) {
let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;';
if (parameters.precision === 'highp') {
precisionstring += '\n#define HIGH_PRECISION';
} else if (parameters.precision === 'mediump') {
precisionstring += '\n#define MEDIUM_PRECISION';
} else if (parameters.precision === 'lowp') {
precisionstring += '\n#define LOW_PRECISION';
}
return precisionstring;
}
function generateShadowMapTypeDefine(parameters) {
let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
if (parameters.shadowMapType === PCFShadowMap) {
shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
} else if (parameters.shadowMapType === PCFSoftShadowMap) {
shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
} else if (parameters.shadowMapType === VSMShadowMap) {
shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';
}
return shadowMapTypeDefine;
}
function generateEnvMapTypeDefine(parameters) {
let envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
if (parameters.envMap) {
switch (parameters.envMapMode) {
case CubeReflectionMapping:
case CubeRefractionMapping:
envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
break;
case CubeUVReflectionMapping:
case CubeUVRefractionMapping:
envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
break;
}
}
return envMapTypeDefine;
}
function generateEnvMapModeDefine(parameters) {
let envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
if (parameters.envMap) {
switch (parameters.envMapMode) {
case CubeRefractionMapping:
case CubeUVRefractionMapping:
envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
break;
}
}
return envMapModeDefine;
}
function generateEnvMapBlendingDefine(parameters) {
let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';
if (parameters.envMap) {
switch (parameters.combine) {
case MultiplyOperation:
envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
break;
case MixOperation:
envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
break;
case AddOperation:
envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
break;
}
}
return envMapBlendingDefine;
}
function WebGLProgram(renderer, cacheKey, parameters, bindingStates) {
// TODO Send this event to Three.js DevTools
// console.log( 'WebGLProgram', cacheKey );
const gl = renderer.getContext();
const defines = parameters.defines;
let vertexShader = parameters.vertexShader;
let fragmentShader = parameters.fragmentShader;
const shadowMapTypeDefine = generateShadowMapTypeDefine(parameters);
const envMapTypeDefine = generateEnvMapTypeDefine(parameters);
const envMapModeDefine = generateEnvMapModeDefine(parameters);
const envMapBlendingDefine = generateEnvMapBlendingDefine(parameters);
const customExtensions = parameters.isWebGL2 ? '' : generateExtensions(parameters);
const customDefines = generateDefines(defines);
const program = gl.createProgram();
let prefixVertex, prefixFragment;
let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';
if (parameters.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 = [
generatePrecision(parameters),
'#define SHADER_NAME ' + parameters.shaderName,
customDefines,
parameters.instancing ? '#define USE_INSTANCING' : '',
parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
'#define MAX_BONES ' + parameters.maxBones,
parameters.useFog && parameters.fog ? '#define USE_FOG' : '',
parameters.useFog && parameters.fogExp2 ? '#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.normalMap && parameters.tangentSpaceNormalMap ? '#define TANGENTSPACE_NORMALMAP' : '',
parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
parameters.specularMap ? '#define USE_SPECULARMAP' : '',
parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '',
parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '',
parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
parameters.transmission ? '#define USE_TRANSMISSION' : '',
parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '',
parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '',
parameters.vertexTangents ? '#define USE_TANGENT' : '',
parameters.vertexColors ? '#define USE_COLOR' : '',
parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
parameters.vertexUvs ? '#define USE_UV' : '',
parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
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.morphTargets && parameters.isWebGL2 ? '#define MORPHTARGETS_TEXTURE' : '',
parameters.morphTargets && parameters.isWebGL2 ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',
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 && parameters.rendererExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '',
'uniform mat4 modelMatrix;',
'uniform mat4 modelViewMatrix;',
'uniform mat4 projectionMatrix;',
'uniform mat4 viewMatrix;',
'uniform mat3 normalMatrix;',
'uniform vec3 cameraPosition;',
'uniform bool isOrthographic;',
'#ifdef USE_INSTANCING',
' attribute mat4 instanceMatrix;',
'#endif',
'#ifdef USE_INSTANCING_COLOR',
' attribute vec3 instanceColor;',
'#endif',
'attribute vec3 position;',
'attribute vec3 normal;',
'attribute vec2 uv;',
'#ifdef USE_TANGENT',
' attribute vec4 tangent;',
'#endif',
'#if defined( USE_COLOR_ALPHA )',
' attribute vec4 color;',
'#elif defined( USE_COLOR )',
' attribute vec3 color;',
'#endif',
'#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )',
' 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,
generatePrecision(parameters),
'#define SHADER_NAME ' + parameters.shaderName,
customDefines,
parameters.useFog && parameters.fog ? '#define USE_FOG' : '',
parameters.useFog && parameters.fogExp2 ? '#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.normalMap && parameters.tangentSpaceNormalMap ? '#define TANGENTSPACE_NORMALMAP' : '',
parameters.clearcoat ? '#define USE_CLEARCOAT' : '',
parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
parameters.specularMap ? '#define USE_SPECULARMAP' : '',
parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '',
parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '',
parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
parameters.alphaTest ? '#define USE_ALPHATEST' : '',
parameters.sheen ? '#define USE_SHEEN' : '',
parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '',
parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '',
parameters.transmission ? '#define USE_TRANSMISSION' : '',
parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
parameters.vertexTangents ? '#define USE_TANGENT' : '',
parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
parameters.vertexUvs ? '#define USE_UV' : '',
parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
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 && parameters.rendererExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '',
(parameters.extensionShaderTextureLOD || parameters.envMap) && parameters.rendererExtensionShaderTextureLod ? '#define TEXTURE_LOD_EXT' : '',
'uniform mat4 viewMatrix;',
'uniform vec3 cameraPosition;',
'uniform bool isOrthographic;',
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.alphaWrite ? '' : '#define OPAQUE',
ShaderChunk['encodings_pars_fragment'], // this code is required here because it is used by the various encoding/decoding function defined below
getTexelEncodingFunction('linearToOutputTexel', parameters.outputEncoding),
parameters.depthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',
'\n',
]
.filter(filterEmptyLine)
.join('\n');
}
vertexShader = resolveIncludes(vertexShader);
vertexShader = replaceLightNums(vertexShader, parameters);
vertexShader = replaceClippingPlaneNums(vertexShader, parameters);
fragmentShader = resolveIncludes(fragmentShader);
fragmentShader = replaceLightNums(fragmentShader, parameters);
fragmentShader = replaceClippingPlaneNums(fragmentShader, parameters);
vertexShader = unrollLoops(vertexShader);
fragmentShader = unrollLoops(fragmentShader);
if (parameters.isWebGL2 && parameters.isRawShaderMaterial !== true) {
// GLSL 3.0 conversion for built-in materials and ShaderMaterial
versionString = '#version 300 es\n';
prefixVertex =
['precision mediump sampler2DArray;', '#define attribute in', '#define varying out', '#define texture2D texture'].join('\n') + '\n' + prefixVertex;
prefixFragment =
[
'#define varying in',
parameters.glslVersion === GLSL3 ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;',
parameters.glslVersion === GLSL3 ? '' : '#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;
}
const vertexGlsl = versionString + prefixVertex + vertexShader;
const fragmentGlsl = versionString + prefixFragment + fragmentShader;
// console.log( '*VERTEX*', vertexGlsl );
// console.log( '*FRAGMENT*', fragmentGlsl );
const glVertexShader = WebGLShader(gl, gl.VERTEX_SHADER, vertexGlsl);
const glFragmentShader = WebGLShader(gl, gl.FRAGMENT_SHADER, fragmentGlsl);
gl.attachShader(program, glVertexShader);
gl.attachShader(program, glFragmentShader);
// Force a particular attribute to index 0.
if (parameters.index0AttributeName !== undefined) {
gl.bindAttribLocation(program, 0, parameters.index0AttributeName);
} else if (parameters.morphTargets === true) {
// programs with morphTargets displace position out of attribute 0
gl.bindAttribLocation(program, 0, 'position');
}
gl.linkProgram(program);
// check for link errors
if (renderer.debug.checkShaderErrors) {
const programLog = gl.getProgramInfoLog(program).trim();
const vertexLog = gl.getShaderInfoLog(glVertexShader).trim();
const fragmentLog = gl.getShaderInfoLog(glFragmentShader).trim();
let runnable = true;
let haveDiagnostics = true;
if (gl.getProgramParameter(program, gl.LINK_STATUS) === false) {
runnable = false;
const vertexErrors = getShaderErrors(gl, glVertexShader, 'vertex');
const fragmentErrors = getShaderErrors(gl, glFragmentShader, 'fragment');
console.error(
'THREE.WebGLProgram: Shader Error ' +
gl.getError() +
' - ' +
'VALIDATE_STATUS ' +
gl.getProgramParameter(program, gl.VALIDATE_STATUS) +
'\n\n' +
'Program Info Log: ' +
programLog +
'\n' +
vertexErrors +
'\n' +
fragmentErrors
);
} else if (programLog !== '') {
console.warn('THREE.WebGLProgram: Program Info Log:', programLog);
} else if (vertexLog === '' || fragmentLog === '') {
haveDiagnostics = false;
}
if (haveDiagnostics) {
this.diagnostics = {
runnable: runnable,
programLog: programLog,
vertexShader: {
log: vertexLog,
prefix: prefixVertex,
},
fragmentShader: {
log: fragmentLog,
prefix: prefixFragment,
},
};
}
}
// Clean up
// Crashes in iOS9 and iOS10. #18402
// gl.detachShader( program, glVertexShader );
// gl.detachShader( program, glFragmentShader );
gl.deleteShader(glVertexShader);
gl.deleteShader(glFragmentShader);
// set up caching for uniform locations
let cachedUniforms;
this.getUniforms = function () {
if (cachedUniforms === undefined) {
cachedUniforms = new WebGLUniforms(gl, program);
}
return cachedUniforms;
};
// set up caching for attribute locations
let cachedAttributes;
this.getAttributes = function () {
if (cachedAttributes === undefined) {
cachedAttributes = fetchAttributeLocations(gl, program);
}
return cachedAttributes;
};
// free resource
this.destroy = function () {
bindingStates.releaseStatesOfProgram(this);
gl.deleteProgram(program);
this.program = undefined;
};
//
this.name = parameters.shaderName;
this.id = programIdCount++;
this.cacheKey = cacheKey;
this.usedTimes = 1;
this.program = program;
this.vertexShader = glVertexShader;
this.fragmentShader = glFragmentShader;
return this;
}
export { WebGLProgram };