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.

154 lines (151 loc) 6.85 kB
import { isRenderer } from '../renderers/utils.mjs'; import { RenderPass } from './RenderPass.mjs'; import { Texture } from '../textures/Texture.mjs'; import { generateUUID } from '../../utils/utils.mjs'; var __typeError = (msg) => { throw TypeError(msg); }; var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), member.get(obj)); var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value); var _autoRender; class RenderTarget { /** * RenderTarget constructor * @param renderer - {@link Renderer} object or {@link GPUCurtains} class object used to create this {@link RenderTarget}. * @param parameters - {@link RenderTargetParams | parameters} use to create this {@link RenderTarget}. */ constructor(renderer, parameters = {}) { /** Whether we should add this {@link RenderTarget} to our {@link core/scenes/Scene.Scene | Scene} to let it handle the rendering process automatically. */ __privateAdd(this, _autoRender, true); this.type = "RenderTarget"; renderer = isRenderer(renderer, this.type); this.renderer = renderer; this.uuid = generateUUID(); const { label, colorAttachments, depthTexture, autoRender, renderTextureName, ...renderPassParams } = parameters; const depthTextureToUse = !!depthTexture ? depthTexture : this.renderer.renderPass.options.sampleCount === (parameters.sampleCount ?? 4) && (!renderPassParams.qualityRatio || renderPassParams.qualityRatio === 1) && !renderPassParams.fixedSize && (!parameters.depthFormat || parameters.depthFormat === this.renderer.renderPass.depthTexture.options.format) ? this.renderer.renderPass.depthTexture : null; this.options = { label, ...renderPassParams, ...depthTextureToUse && { depthTexture: depthTextureToUse }, ...colorAttachments && { colorAttachments }, renderTextureName: renderTextureName ?? "renderTexture", autoRender: autoRender === void 0 ? true : autoRender }; if (autoRender !== void 0) { __privateSet(this, _autoRender, autoRender); } this.renderPass = new RenderPass(this.renderer, { label: this.options.label ? `${this.options.label} Render Pass` : "Render Target Render Pass", ...colorAttachments && { colorAttachments }, depthTexture: this.options.depthTexture, ...renderPassParams }); if (renderPassParams.useColorAttachments !== false) { this.renderTexture = new Texture(this.renderer, { label: this.options.label ? `${this.options.label} Render Texture` : "Render Target render texture", name: this.options.renderTextureName, format: colorAttachments && colorAttachments.length && colorAttachments[0].targetFormat ? colorAttachments[0].targetFormat : this.renderer.options.context.format, ...this.options.qualityRatio !== void 0 && { qualityRatio: this.options.qualityRatio }, ...this.options.fixedSize !== void 0 && { fixedSize: this.options.fixedSize }, usage: ["copySrc", "copyDst", "renderAttachment", "textureBinding"] }); } this.addToScene(); } /** * Reset this {@link RenderTarget} {@link RenderTarget.renderer | renderer}. Also set the {@link renderPass} renderer. * @param renderer - New {@link Renderer} or {@link GPUCurtains} instance to use. */ setRenderer(renderer) { if (this.renderer) { this.removeFromScene(); } renderer = isRenderer(renderer, this.type); this.renderer = renderer; if (this.options.depthTexture) { this.options.depthTexture.setRenderer(this.renderer); } this.renderPass.setRenderer(this.renderer); if (this.renderTexture) { this.renderTexture.setRenderer(this.renderer); } this.addToScene(); } /** * Get the textures outputted by the {@link renderPass} if any, which means its {@link RenderPass.viewTextures | viewTextures} if not multisampled, or the {@link RenderPass.resolveTargets | resolveTargets} else. * * Since some {@link RenderPass} might not have any view textures (or in case the first resolve target is `null`), the first element can be the {@link RenderTarget.renderTexture | RenderTarget renderTexture} itself. * * @readonly */ get outputTextures() { return !this.renderPass.outputTextures.length ? !this.renderTexture ? [] : [this.renderTexture] : this.renderPass.outputTextures.map((texture, index) => { return index === 0 && this.renderPass.options.renderToSwapChain ? this.renderTexture : texture; }); } /** * Add the {@link RenderTarget} to the renderer and the {@link core/scenes/Scene.Scene | Scene} */ addToScene() { this.renderer.renderTargets.push(this); if (__privateGet(this, _autoRender)) { this.renderer.scene.addRenderTarget(this); } } /** * Remove the {@link RenderTarget} from the renderer and the {@link core/scenes/Scene.Scene | Scene} */ removeFromScene() { if (__privateGet(this, _autoRender)) { this.renderer.scene.removeRenderTarget(this); } this.renderer.renderTargets = this.renderer.renderTargets.filter((renderTarget) => renderTarget.uuid !== this.uuid); } /** * Update our {@link RenderTarget} {@link renderTexture} and {@link renderPass} quality ratio. * @param qualityRatio - New quality ratio to use. */ setQualityRatio(qualityRatio = 1) { this.options.qualityRatio = qualityRatio; this.renderTexture?.setQualityRatio(qualityRatio); this.renderPass?.setQualityRatio(qualityRatio); } /** * Resize our {@link renderPass}. */ resize() { if (this.options.depthTexture) { this.renderPass.options.depthTexture.texture = this.options.depthTexture.texture; } this.renderPass?.resize(); } /** * Remove our {@link RenderTarget}. Alias of {@link RenderTarget#destroy}. */ remove() { this.destroy(); } /** * Destroy our {@link RenderTarget}. */ destroy() { this.renderer.meshes.forEach((mesh) => { if (mesh.outputTarget && mesh.outputTarget.uuid === this.uuid) { mesh.setOutputTarget(null); } }); this.renderer.shaderPasses.forEach((shaderPass) => { if (shaderPass.outputTarget && shaderPass.outputTarget.uuid === this.uuid) { shaderPass.outputTarget = null; shaderPass.setOutputTarget(null); } }); this.removeFromScene(); this.renderPass?.destroy(); this.renderTexture?.destroy(); } } _autoRender = new WeakMap(); export { RenderTarget };