UNPKG

playcanvas

Version:

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

108 lines (107 loc) 4.43 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_GLSL, SHADERLANGUAGE_WGSL } from "../../platform/graphics/constants.js"; import { ShaderChunks } from "./shader-chunks.js"; import { MapUtils } from "../../core/map-utils.js"; class ShaderGeneratorPassThrough extends ShaderGenerator { constructor(key, shaderDefinition) { super(); this.key = key; this.shaderDefinition = shaderDefinition; } generateKey(options) { return this.key; } createShaderDefinition(device, options) { return this.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, fragmentCode, useTransformFeedback: options.useTransformFeedback, vertexIncludes, vertexDefines: options.vertexDefines, 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 })); programLibrary.setCachedShader(uniqueName, shader); } return shader; } export { ShaderUtils, createShader, createShaderFromCode };