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.
138 lines (135 loc) • 5.94 kB
JavaScript
import { FullscreenPlane } from '../meshes/FullscreenPlane.mjs';
import { isRenderer } from '../renderers/utils.mjs';
import { getDefaultShaderPassFragmentCode } from '../shaders/full/fragment/get-default-shader-pass-fragment-code.mjs';
import { throwWarning } from '../../utils/utils.mjs';
class ShaderPass 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
};
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: parameters.renderTextureName ?? "renderTexture",
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);
}
}
}
export { ShaderPass };