| onBeforeCompile(s: Shader, renderer: WebGLRenderer) { | onBeforeCompile(s: Shader, renderer: WebGLRenderer) { | ||||
| const pars = '\n' + this.textures | const pars = '\n' + this.textures | ||||
| .map(t=>`uniform sampler2D ${t.id}; \n` | .map(t=>`uniform sampler2D ${t.id}; \n` | ||||
| + getTexelDecoding(t.id ?? 'input', t, renderer.capabilities.isWebGL2)).join('\n') | |||||
| + getTexelDecoding(t.id ?? 'input', t.colorSpace)).join('\n') | |||||
| if (s.fragmentShader.includes('#include <encodings_pars_fragment>')) { | if (s.fragmentShader.includes('#include <encodings_pars_fragment>')) { | ||||
| s.fragmentShader = shaderReplaceString(s.fragmentShader, '#include <encodings_pars_fragment>', pars, {append: true}) | s.fragmentShader = shaderReplaceString(s.fragmentShader, '#include <encodings_pars_fragment>', pars, {append: true}) |
| if (!Array.isArray(material.materialExtensions)) material.materialExtensions = [] | if (!Array.isArray(material.materialExtensions)) material.materialExtensions = [] | ||||
| if (customMaterialExtensions) | if (customMaterialExtensions) | ||||
| for (const ext of customMaterialExtensions) { | for (const ext of customMaterialExtensions) { | ||||
| if (!ext.isCompatible || !ext.isCompatible(material) || material.materialExtensions.includes(ext)) continue | |||||
| if (material.materialExtensions.includes(ext)) continue | |||||
| if (ext.isCompatible !== undefined && (!ext.isCompatible || !ext.isCompatible(material))) continue | |||||
| exts.push(ext) | exts.push(ext) | ||||
| if (!ext.uuid) ext.uuid = generateUUID() | if (!ext.uuid) ext.uuid = generateUUID() | ||||
| if (!ext.__setDirty) ext.__setDirty = ()=>{ | if (!ext.__setDirty) ext.__setDirty = ()=>{ |
| * Function to check if this material extension is compatible with the given material. | * Function to check if this material extension is compatible with the given material. | ||||
| * If not compatible, the material extension will not be applied. | * If not compatible, the material extension will not be applied. | ||||
| * This is only checked when the extension is registered. | * This is only checked when the extension is registered. | ||||
| * | |||||
| * The extension is assumed to be compatible if this function is not defined | |||||
| * @param material | * @param material | ||||
| */ | */ | ||||
| isCompatible: (material: IMaterial) => boolean | |||||
| isCompatible?: (material: IMaterial) => boolean|undefined | |||||
| /** | /** | ||||
| * List of shader properties updaters to run on the material. | * List of shader properties updaters to run on the material. |
| material.needsUpdate = true | material.needsUpdate = true | ||||
| } | } | ||||
| }, | }, | ||||
| parsFragmentSnippet: (renderer)=>glsl` | |||||
| parsFragmentSnippet: ()=>glsl` | |||||
| uniform sampler2D tSSAOMap; | uniform sampler2D tSSAOMap; | ||||
| ${getTexelDecoding('tSSAOMap', getOrCall(this.target)?.texture, renderer!.capabilities.isWebGL2)} | |||||
| ${getTexelDecoding('tSSAOMap', getOrCall(this.target)?.texture.colorSpace)} | |||||
| #include <simpleCameraHelpers> | #include <simpleCameraHelpers> | ||||
| `, | `, | ||||
| computeCacheKey: () => { | computeCacheKey: () => { |
| }, | }, | ||||
| } | } | ||||
| addCamera(camera: ICamera) { | |||||
| addCamera(camera: ICamera, target?: IRenderTarget): VirtualCamera { | |||||
| if (!this._viewer) throw 'Plugin not added to viewer' | if (!this._viewer) throw 'Plugin not added to viewer' | ||||
| const target = this._viewer.renderManager.composerTarget.clone(true) | |||||
| target = target ?? this._viewer.renderManager.composerTarget.clone(true) | |||||
| target.name = camera.name + '_virtualCamTarget' | target.name = camera.name + '_virtualCamTarget' | ||||
| const vCam: VirtualCamera = {camera, target, enabled: true} | const vCam: VirtualCamera = {camera, target, enabled: true} | ||||
| this.cameras.push(vCam) | this.cameras.push(vCam) |
| this._renderer = this._initWebGLRenderer(canvas, alpha) | this._renderer = this._initWebGLRenderer(canvas, alpha) | ||||
| this._context = this._renderer.getContext() | this._context = this._renderer.getContext() | ||||
| this._isWebGL2 = this._renderer.capabilities.isWebGL2 | this._isWebGL2 = this._renderer.capabilities.isWebGL2 | ||||
| if (!this._isWebGL2) console.error('RenderManager: WebGL 1 is not officially supported anymore. Some features may not work.') | |||||
| this.resetShadows() | this.resetShadows() | ||||
| const composerTarget = this.createTarget<WebGLRenderTarget>(targetOptions, false) | const composerTarget = this.createTarget<WebGLRenderTarget>(targetOptions, false) | ||||
| }) | }) | ||||
| // renderer.info.autoReset = false // Not supported by ExtendedRenderPass | // renderer.info.autoReset = false // Not supported by ExtendedRenderPass | ||||
| renderer.useLegacyLights = false | |||||
| // renderer.useLegacyLights = false | |||||
| renderer.setAnimationLoop(this._animationLoop) | renderer.setAnimationLoop(this._animationLoop) | ||||
| renderer.onContextLost = (event: WebGLContextEvent) => { | renderer.onContextLost = (event: WebGLContextEvent) => { | ||||
| this.dispatchEvent({type: 'contextLost', event}) | this.dispatchEvent({type: 'contextLost', event}) |
| import { | |||||
| ColorSpace, | |||||
| LinearSRGBColorSpace, | |||||
| NoColorSpace, | |||||
| RGBAFormat, | |||||
| RGBM16ColorSpace, | |||||
| SRGBColorSpace, | |||||
| Texture, | |||||
| UnsignedByteType, | |||||
| WebGLRenderTarget, | |||||
| } from 'three' | |||||
| import {ColorSpace, LinearSRGBColorSpace, NoColorSpace, RGBM16ColorSpace, SRGBColorSpace} from 'three' | |||||
| export function getEncodingComponents(colorSpace: ColorSpace) { | |||||
| // three.js WebGLProgram.js | |||||
| export function getTexelDecodingFunction(functionName: string, colorSpace: ColorSpace) { | |||||
| let fn | |||||
| switch (colorSpace) { | switch (colorSpace) { | ||||
| case NoColorSpace: | case NoColorSpace: | ||||
| case LinearSRGBColorSpace: | case LinearSRGBColorSpace: | ||||
| return ['Linear', '( value )'] | |||||
| fn = '' | |||||
| break | |||||
| case SRGBColorSpace: | case SRGBColorSpace: | ||||
| return ['sRGB', '( value )'] | |||||
| // case RGBEEncoding: | |||||
| // return ['RGBE', '( value )'] | |||||
| // case RGBM7Encoding: | |||||
| // return ['RGBM', '( value, 7.0 )'] | |||||
| // fn = 'sRGBToLinear' // todo required? | |||||
| fn = '' | |||||
| break | |||||
| case RGBM16ColorSpace: | case RGBM16ColorSpace: | ||||
| return ['RGBM', '( value, 16.0 )'] | |||||
| // case RGBDEncoding: | |||||
| // return ['RGBD', '( value, 256.0 )'] | |||||
| // case GammaEncoding: | |||||
| // return ['Gamma', '( value, float( GAMMA_FACTOR ) )'] | |||||
| // case LogLuvEncoding: | |||||
| // return ['LogLuv', '( value )'] | |||||
| fn = 'RGBM16ToLinear' | |||||
| break | |||||
| default: | default: | ||||
| console.warn('utils: Unsupported colorspace:', colorSpace) | |||||
| return ['Linear', '( value )'] | |||||
| } | |||||
| } | |||||
| export function getTextureColorSpaceFromMap(map: Texture | WebGLRenderTarget | null | undefined, isWebGL2: boolean): ColorSpace { | |||||
| let colorSpace | |||||
| if (map && (<Texture>map).colorSpace !== undefined) { | |||||
| colorSpace = (<Texture>map).colorSpace || NoColorSpace | |||||
| } else if (map && (<WebGLRenderTarget>map).isWebGLRenderTarget) { | |||||
| console.warn('THREE.WebGLPrograms.getTextureColorSpaceFromMap: don\'t use render targets as textures. Use their .texture property instead.') | |||||
| colorSpace = (<WebGLRenderTarget>map).texture.colorSpace | |||||
| } else { | |||||
| colorSpace = LinearSRGBColorSpace | |||||
| } | |||||
| // See https://github.com/mrdoob/three.js/pull/22952 | |||||
| // todo: just check if srgb8 is enabled, instead of relying on threejs. | |||||
| if (isWebGL2 && map && (<Texture>map).isTexture && (<Texture>map).format === RGBAFormat && (<Texture>map).type === UnsignedByteType && (<Texture>map).colorSpace === SRGBColorSpace) { | |||||
| colorSpace = LinearSRGBColorSpace // disable inline decode for sRGB textures in WebGL 2 | |||||
| console.warn('THREE.WebGLProgram: Unsupported color space:', colorSpace) | |||||
| fn = '' | |||||
| break | |||||
| } | } | ||||
| return colorSpace | |||||
| } | |||||
| export function getTexelDecodingFunction(functionName: string, colorSpace: ColorSpace) { | |||||
| const components = getEncodingComponents(colorSpace) | |||||
| return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }' | |||||
| } | |||||
| export function getTexelDecoding(mapName: string, map: Texture | WebGLRenderTarget | null | undefined | any, isWebGL2: boolean) { | |||||
| return getTexelDecodingFunction(mapName + 'TexelToLinear', getTextureColorSpaceFromMap(map, isWebGL2)) + '\n' | |||||
| } | |||||
| export function getTexelDecoding2(mapName: string, colorSpace: ColorSpace) { | |||||
| return getTexelDecodingFunction(mapName + 'TexelToLinear', colorSpace) + '\n' | |||||
| } | |||||
| export function getTexelEncodingFunction(functionName: string, colorSpace: ColorSpace) { | |||||
| const components = getEncodingComponents(colorSpace) | |||||
| return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }' | |||||
| // return `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}ToLinear${components[ 1 ]}; }`; | |||||
| // return `vec4 ${functionName}( vec4 value ) { return ${fn} ( value ); }` | |||||
| return `#define ${functionName}( value ) ${fn} ( value )` | |||||
| } | } | ||||
| export function getTexelEncoding(functionName: string, map: Texture | WebGLRenderTarget | null | undefined | any, isWebGL2: boolean) { | |||||
| export function getTexelDecoding(mapName: string, colorSpace?: ColorSpace) { | |||||
| return getTexelEncodingFunction(functionName, getTextureColorSpaceFromMap(map, isWebGL2)) | |||||
| return getTexelDecodingFunction(mapName + 'TexelToLinear', colorSpace ?? LinearSRGBColorSpace) + '\n' | |||||
| } | } |
| export {overrideThreeCache} from './cache' | export {overrideThreeCache} from './cache' | ||||
| export {dataTextureFromColor, dataTextureFromVec4, halfFloatToRgbe} from './conversion' | export {dataTextureFromColor, dataTextureFromVec4, halfFloatToRgbe} from './conversion' | ||||
| export {uniform, matDefine, matDefineBool, bindToValue} from './decorators' | export {uniform, matDefine, matDefineBool, bindToValue} from './decorators' | ||||
| export {getEncodingComponents, getTexelEncoding, getTexelDecoding, getTexelDecoding2, getTexelDecodingFunction, getTexelEncodingFunction, getTextureColorSpaceFromMap} from './encoding' | |||||
| export {getTexelDecoding, getTexelDecodingFunction} from './encoding' | |||||
| export {generateUUID, toIndexedGeometry, isInScene, localToWorldQuaternion, worldToLocalQuaternion} from './misc' | export {generateUUID, toIndexedGeometry, isInScene, localToWorldQuaternion, worldToLocalQuaternion} from './misc' | ||||
| export {getTextureDataType, textureToCanvas, textureDataToImageData, textureToDataUrl, textureToBlob, texImageToCanvas} from './texture' | export {getTextureDataType, textureToCanvas, textureDataToImageData, textureToDataUrl, textureToBlob, texImageToCanvas} from './texture' | ||||
| export {threeConstMappings} from './const-mappings' | export {threeConstMappings} from './const-mappings' |