playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
105 lines (102 loc) • 4.68 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_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 };