playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
108 lines (107 loc) • 4.43 kB
JavaScript
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
};