UNPKG

gpu-curtains

Version:

gpu-curtains is a 3D WebGPU rendering engine. It can be used as a standalone 3D engine, but also includes extra classes focused on mapping 3d objects to DOM elements; It allows users to synchronize values such as position, sizing, or scale between them.

140 lines (139 loc) 6.4 kB
import { throwWarning } from "../../utils/utils.mjs"; import { isRenderer } from "../renderers/utils.mjs"; import { FullscreenPlane } from "../meshes/FullscreenPlane.mjs"; import { getDefaultShaderPassFragmentCode } from "../shaders/full/fragment/get-default-shader-pass-fragment-code.mjs"; //#region src/core/renderPasses/ShaderPass.ts /** * Used to apply postprocessing, i.e. draw meshes to a {@link Texture} and then draw a {@link FullscreenPlane} using that texture as an input. * * A ShaderPass could either post process the whole scene or just a bunch of meshes using a specific {@link RenderTarget}. * * @example * ```javascript * // set our main GPUCurtains instance * const gpuCurtains = new GPUCurtains({ * container: '#canvas' // selector of our WebGPU canvas container * }) * * // set the GPU device * // note this is asynchronous * await gpuCurtains.setDevice() * * // create a ShaderPass * const shaderPass = new ShaderPass(gpuCurtain, { * label: 'My shader pass', * shaders: { * fragment: { * code: shaderPassCode, // assume it is a valid WGSL fragment shader * }, * }, * }) * ``` */ var ShaderPass = class extends FullscreenPlane { /** * ShaderPass constructor * @param renderer - {@link Renderer} object or {@link GPUCurtains} class object used to create this {@link ShaderPass} * @param parameters - {@link ShaderPassParams | parameters} use to create this {@link ShaderPass} */ constructor(renderer, parameters = {}) { renderer = isRenderer(renderer, parameters.label ? parameters.label + " ShaderPass" : "ShaderPass"); parameters.isPrePass = !!parameters.isPrePass; const defaultBlend = { color: { srcFactor: "one", dstFactor: "one-minus-src-alpha" }, alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha" } }; if (!parameters.isPrePass) { if (!parameters.targets) parameters.targets = [{ blend: defaultBlend }]; else if (parameters.targets && parameters.targets.length && !parameters.targets[0].blend) parameters.targets[0].blend = defaultBlend; } parameters.label = parameters.label ?? "ShaderPass " + renderer.shaderPasses?.length; parameters.sampleCount = !!parameters.sampleCount ? parameters.sampleCount : renderer && renderer.renderPass && parameters.isPrePass ? renderer.renderPass.options.sampleCount : renderer && renderer.postProcessingPass ? renderer && renderer.postProcessingPass.options.sampleCount : 1; if (!parameters.shaders) parameters.shaders = {}; if (!parameters.shaders.fragment) parameters.shaders.fragment = { code: getDefaultShaderPassFragmentCode, entryPoint: "main" }; parameters.depth = parameters.isPrePass; super(renderer, parameters); this.options = { ...this.options, copyOutputToRenderTexture: parameters.copyOutputToRenderTexture, isPrePass: parameters.isPrePass, renderTextureName: parameters.renderTextureName ?? "renderTexture" }; if (parameters.inputTarget) this.setInputTarget(parameters.inputTarget); if (this.outputTarget) this.setRenderingOptionsForRenderPass(this.outputTarget.renderPass); this.type = "ShaderPass"; this.renderTexture = this.createTexture({ label: parameters.label ? `${parameters.label} render texture` : "Shader pass render texture", name: this.options.renderTextureName, fromTexture: this.inputTarget ? this.inputTarget.renderTexture : null, usage: [ "copySrc", "copyDst", "textureBinding" ], ...this.outputTarget && this.outputTarget.options.qualityRatio && { qualityRatio: this.outputTarget.options.qualityRatio } }); } /** * Hook used to clean up parameters before sending them to the material. * @param parameters - parameters to clean before sending them to the {@link core/materials/RenderMaterial.RenderMaterial | RenderMaterial} * @returns - cleaned parameters */ cleanupRenderMaterialParameters(parameters) { delete parameters.copyOutputToRenderTexture; delete parameters.inputTarget; delete parameters.isPrePass; super.cleanupRenderMaterialParameters(parameters); return parameters; } /** * Assign or remove an input {@link RenderTarget} to this {@link ShaderPass}, which can be different from what has just been drawn to the {@link core/renderers/GPURenderer.GPURenderer#context | context} current texture. * * Since this manipulates the {@link core/scenes/Scene.Scene | Scene} stacks, it can be used to remove a RenderTarget as well. * Also copy or remove the {@link RenderTarget#renderTexture | render target render texture} into the {@link ShaderPass} {@link renderTexture} * @param inputTarget - the {@link RenderTarget} to assign or null if we want to remove the current {@link RenderTarget} */ setInputTarget(inputTarget) { if (inputTarget && inputTarget.type !== "RenderTarget") { throwWarning(`${this.options.label ?? this.type}: inputTarget is not a RenderTarget: ${inputTarget}`); return; } this.removeFromScene(); this.inputTarget = inputTarget; this.addToScene(); if (this.renderTexture) if (inputTarget) this.renderTexture.copy(this.inputTarget.renderTexture); else { this.renderTexture.options.fromTexture = null; this.renderTexture.createTexture(); } } /** * Add the {@link ShaderPass} to the {@link core/scenes/Scene.Scene | Scene} and optionally to the renderer as well. * @param addToRenderer - whether to add this {@link ShaderPass} to the {@link Renderer#shaderPasses | Renderer shaderPasses array} */ addToScene(addToRenderer = false) { if (addToRenderer) this.renderer.shaderPasses.push(this); this.setRenderingOptionsForRenderPass(this.outputTarget ? this.outputTarget.renderPass : this.options.isPrePass ? this.renderer.renderPass : this.renderer.postProcessingPass); if (this.autoRender) this.renderer.scene.addShaderPass(this); } /** * Remove the {@link ShaderPass} from the {@link core/scenes/Scene.Scene | Scene} and optionally from the renderer as well. * @param removeFromRenderer - whether to remove this {@link ShaderPass} from the {@link Renderer#shaderPasses | Renderer shaderPasses array} */ removeFromScene(removeFromRenderer = false) { if (this.outputTarget && removeFromRenderer) this.outputTarget.destroy(); if (this.autoRender) this.renderer.scene.removeShaderPass(this); if (removeFromRenderer) this.renderer.shaderPasses = this.renderer.shaderPasses.filter((sP) => sP.uuid !== this.uuid); } }; //#endregion export { ShaderPass };