| @@ -76,6 +76,11 @@ export interface IMaterialUserData extends IImportResultUserData{ | |||
| [key: string]: any | |||
| } | |||
| /** | |||
| * Force a depth value in GBuffer. | |||
| * This is useful to force center values like 0 to the depth. | |||
| */ | |||
| forcedLinearDepth?: number | |||
| // todo: move these to respective plugins | |||
| @@ -111,6 +111,11 @@ export const iMaterialUI = { | |||
| property: [material, 'depthWrite'], | |||
| onChange: (ev)=>material.setDirty({uiChangeEvent: ev}), | |||
| }, | |||
| { | |||
| type: 'checkbox', | |||
| property: [material, 'colorWrite'], | |||
| onChange: (ev)=>material.setDirty({uiChangeEvent: ev}), | |||
| }, | |||
| { | |||
| type: 'slider', | |||
| bounds: [0, 1], | |||
| @@ -55,6 +55,7 @@ export class MaterialExtender { | |||
| static CacheKeyForExtension(material: IMaterial, materialExtension: MaterialExtension): string { | |||
| let r = '' | |||
| if (materialExtension.computeCacheKey) r += getOrCall(materialExtension.computeCacheKey, material) | |||
| else r += materialExtension.uuid | |||
| if (materialExtension.extraDefines) r += Object.values(materialExtension.extraDefines).map(v=>getOrCall(v) ?? '').join('') | |||
| return r | |||
| } | |||
| @@ -65,7 +66,7 @@ export class MaterialExtender { | |||
| if (customMaterialExtensions) | |||
| for (const ext of customMaterialExtensions) { | |||
| if (!ext.isCompatible || !ext.isCompatible(material) || material.materialExtensions.includes(ext)) continue | |||
| else exts.push(ext) | |||
| exts.push(ext) | |||
| if (!ext.uuid) ext.uuid = generateUUID() | |||
| if (!ext.__setDirty) ext.__setDirty = ()=>{ | |||
| if (!ext.updateVersion) ext.updateVersion = 0 | |||
| @@ -74,6 +75,8 @@ export class MaterialExtender { | |||
| if (!ext.setDirty) ext.setDirty = ext.__setDirty | |||
| } | |||
| if (!exts.length) return [] | |||
| material.materialExtensions = [...material.materialExtensions || [], ...exts] | |||
| .sort((a, b)=>(b.priority || 0) - (a.priority || 0)) | |||
| @@ -85,6 +88,8 @@ export class MaterialExtender { | |||
| (material as any).__ext_afterRenderListen = true | |||
| material.addEventListener('afterRender', materialAfterRender) | |||
| } | |||
| material.needsUpdate = true | |||
| return exts | |||
| } | |||
| @@ -45,6 +45,7 @@ export interface MaterialExtension{ | |||
| * Check three.js docs for more info. | |||
| * Value can be a string or a function that returns a string | |||
| * This will only be checked if `material.needsUpdate` is `true`, not on every render. | |||
| * Note: extension might never be registered if an empty string is returned. | |||
| */ | |||
| computeCacheKey?: string | ((material: IMaterial) => string) | |||
| @@ -406,7 +406,7 @@ export class GBufferMaterial extends ShaderMaterial2 { | |||
| ['USE_DISPLACEMENTMAP']: this.uniforms.displacementMap.value ? 1 : undefined, | |||
| ['DISPLACEMENTMAP_UV']: this.uniforms.displacementMap.value ? 'uv' : undefined, // todo use getChannel, see WebGLPrograms.js | |||
| ['ALPHA_I_RGBA_PACKING']: material.userData.ALPHA_I_RGBA_PACKING ? 1 : undefined, | |||
| ['FORCED_LINEAR_DEPTH']: material.userData.forcedLinearDepth ?? undefined, | |||
| ['FORCED_LINEAR_DEPTH']: material.userData.forcedLinearDepth ?? undefined, // todo add to DepthBufferPlugin as well. | |||
| }, material) | |||
| // todo: do the same in DepthBufferPlugin and NormalBufferPlugin | |||
| @@ -229,3 +229,4 @@ export {ShaderPass} from 'three/examples/jsm/postprocessing/ShaderPass.js' | |||
| export {EffectComposer} from 'three/examples/jsm/postprocessing/EffectComposer.js' | |||
| export {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js' | |||
| export * from 'three/examples/jsm/utils/BufferGeometryUtils.js' | |||
| @@ -1,5 +1,5 @@ | |||
| const warnEnabled = true | |||
| const errorStr1 = 'shaderReplaceString: str must be passed if str is a RegExp and append/prepend is true' | |||
| /** | |||
| * Replace a string in a shader function with added options to prepend, append, show warning when not found, and replace all occurrences. | |||
| * @param shader - shader code | |||
| @@ -8,24 +8,30 @@ const warnEnabled = true | |||
| * @param replaceAll - replace all occurrences | |||
| * @param prepend - prepend new string to old string | |||
| * @param append - append new string to old string | |||
| * @param _str - optional string to use for replacement. This must be passed if str is a RegExp and append/prepend is true | |||
| */ | |||
| export function shaderReplaceString(shader: string, str: string|RegExp, newStr: string, { | |||
| replaceAll = false, | |||
| prepend = false, | |||
| append = false, | |||
| str: _str = undefined as string|undefined, | |||
| } = {}) { | |||
| // todo: use safeReplaceString from ts-browser-helpers | |||
| const isStr = typeof str === 'string' | |||
| if (warnEnabled /* && ThreeViewer.ViewerDebugging */) { | |||
| if (typeof str === 'string' ? !shader.includes(str) : !str.test(shader)) { | |||
| if (isStr ? !shader.includes(str) : !str.test(shader)) { | |||
| console.error(`${str} not found in shader`) | |||
| return shader | |||
| } | |||
| } | |||
| let s = newStr | |||
| _str = _str ?? (isStr ? str : undefined) | |||
| if (prepend) { | |||
| s = newStr + str | |||
| if (typeof _str !== 'string') throw new Error(errorStr1) | |||
| s = newStr + _str | |||
| } else if (append) { | |||
| s = str + newStr | |||
| if (typeof _str !== 'string') throw new Error(errorStr1) | |||
| s = _str + newStr | |||
| } | |||
| return replaceAll ? shader.replaceAll(str, s) : shader.replace(str, s) | |||
| } | |||