UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

105 lines (102 loc) 4.68 kB
import { Shader } from '../../platform/graphics/shader.js'; import { ShaderDefinitionUtils } from '../../platform/graphics/shader-definition-utils.js'; import { getProgramLibrary } from './get-program-library.js'; import { ShaderGenerator } from './programs/shader-generator.js'; import { ShaderPass } from '../shader-pass.js'; import { SHADERLANGUAGE_WGSL, SHADERLANGUAGE_GLSL } from '../../platform/graphics/constants.js'; import { ShaderChunks } from './shader-chunks.js'; import { MapUtils } from '../../core/map-utils.js'; class ShaderGeneratorPassThrough extends ShaderGenerator { generateKey(options) { return this.key; } createShaderDefinition(device, options) { return this.shaderDefinition; } constructor(key, shaderDefinition){ super(); this.key = key; this.shaderDefinition = shaderDefinition; } } class ShaderUtils { static createShader(device, options) { const programLibrary = getProgramLibrary(device); let shader = programLibrary.getCachedShader(options.uniqueName); if (!shader) { const wgsl = device.isWebGPU && (!!options.vertexWGSL || !!options.vertexChunk) && (!!options.fragmentWGSL || !!options.fragmentChunk); const chunksMap = ShaderChunks.get(device, wgsl ? SHADERLANGUAGE_WGSL : SHADERLANGUAGE_GLSL); const vertexCode = options.vertexChunk ? chunksMap.get(options.vertexChunk) : wgsl ? options.vertexWGSL : options.vertexGLSL; const fragmentCode = options.fragmentChunk ? chunksMap.get(options.fragmentChunk) : wgsl ? options.fragmentWGSL : options.fragmentGLSL; const fragmentIncludes = MapUtils.merge(chunksMap, options.fragmentIncludes); const vertexIncludes = MapUtils.merge(chunksMap, options.vertexIncludes); shader = new Shader(device, ShaderDefinitionUtils.createDefinition(device, { name: options.uniqueName, shaderLanguage: wgsl ? SHADERLANGUAGE_WGSL : SHADERLANGUAGE_GLSL, attributes: options.attributes, vertexCode: vertexCode, fragmentCode: fragmentCode, useTransformFeedback: options.useTransformFeedback, vertexIncludes: vertexIncludes, vertexDefines: options.vertexDefines, fragmentIncludes: fragmentIncludes, fragmentDefines: options.fragmentDefines, fragmentOutputTypes: options.fragmentOutputTypes })); programLibrary.setCachedShader(options.uniqueName, shader); } return shader; } static getCoreDefines(material, params) { const defines = new Map(material.defines); params.cameraShaderParams.defines.forEach((value, key)=>defines.set(key, value)); const shaderPassInfo = ShaderPass.get(params.device).getByIndex(params.pass); shaderPassInfo.defines.forEach((value, key)=>defines.set(key, value)); return defines; } static processShader(shader, processingOptions) { const shaderDefinition = shader.definition; const name = shaderDefinition.name ?? 'shader'; const key = `${name}-id-${shader.id}`; const materialGenerator = new ShaderGeneratorPassThrough(key, shaderDefinition); const libraryModuleName = 'shader'; const library = getProgramLibrary(shader.device); library.register(libraryModuleName, materialGenerator); const variant = library.getProgram(libraryModuleName, {}, processingOptions); library.unregister(libraryModuleName); return variant; } static addScreenDepthChunkDefines(device, cameraShaderParams, defines) { if (cameraShaderParams.sceneDepthMapLinear) { defines.set('SCENE_DEPTHMAP_LINEAR', ''); } if (device.textureFloatRenderable) { defines.set('SCENE_DEPTHMAP_FLOAT', ''); } } } function createShader(device, vsName, fsName, useTransformFeedback = false, shaderDefinitionOptions = {}) {} function createShaderFromCode(device, vsCode, fsCode, uniqueName, attributes, useTransformFeedback = false, shaderDefinitionOptions = {}) { if (typeof useTransformFeedback === 'boolean') { shaderDefinitionOptions.useTransformFeedback = useTransformFeedback; } else if (typeof useTransformFeedback === 'object') { shaderDefinitionOptions = { ...shaderDefinitionOptions, ...useTransformFeedback }; } const programLibrary = getProgramLibrary(device); let shader = programLibrary.getCachedShader(uniqueName); if (!shader) { shader = new Shader(device, ShaderDefinitionUtils.createDefinition(device, { ...shaderDefinitionOptions, name: uniqueName, vertexCode: vsCode, fragmentCode: fsCode, attributes: attributes })); programLibrary.setCachedShader(uniqueName, shader); } return shader; } export { ShaderUtils, createShader, createShaderFromCode };