Spaces:
Running
Running
| 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 }; | |