threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
116 lines • 5.79 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { ExtendedShaderPass } from './ExtendedShaderPass';
import { FrontSide, NoBlending, SRGBColorSpace, } from 'three';
import { CopyShader } from 'three/examples/jsm/shaders/CopyShader.js';
import { uiDropdown, uiFolderContainer, uiToggle } from 'uiconfig.js';
import { matDefineBool, threeConstMappings } from '../three';
import ScreenPassShader from './ScreenPass.glsl';
import { shaderReplaceString } from '../utils';
/**
* Screen Pass
*
* This pass renders the final scene to the screen.
* It can be extended by Screen Pass Extensions to apply post-processing effects, such as tonemapping, color grading, etc.
*
* It is used by default in {@link ViewerRenderManager} to render the final scene.
* A custom material/shader can be passed to the constructor to use a custom base fragment shader.
*/
let ScreenPass = class ScreenPass extends ExtendedShaderPass {
constructor(shader = '', ...textureID) {
super(shader?.fragmentShader || shader?.isShaderMaterial ? shader :
makeScreenShader(shader), ...textureID.length ? textureID : ['tDiffuse', 'tTransparent']);
this.passId = 'screen';
this.after = ['render'];
this.required = ['render'];
/**
* Output Color Space
* Note: this is ignored when renderToScreen is false (it will take the color space of the render target)
*/
this.outputColorSpace = SRGBColorSpace;
this._needsReRender = false;
/**
* Force clip background. If this is `true` {@link clipBackground} is overridden.
* This happens when scene.background and scene.backgroundColor are both null.
* This is set in {@link ViewerRenderManager.render}.
*/
this.clipBackgroundForce = false;
// todo: this is not serialized anymore? we should serialize this in some plugin...
this.clipBackground = false;
this.material.addEventListener('materialUpdate', this.setDirty);
}
render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) {
const colorSpace = renderer.outputColorSpace;
if (!writeBuffer || this.renderToScreen)
renderer.outputColorSpace = this.outputColorSpace;
// else console.warn('ScreenPass: outputColorSpace is ignored when renderToScreen is false')
super.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive);
this._lastReadBuffer = readBuffer;
renderer.outputColorSpace = colorSpace;
this._needsReRender = false;
}
reRender(renderer, writeBuffer, deltaTime, maskActive) {
if (this._lastReadBuffer)
this.render(renderer, writeBuffer, this._lastReadBuffer, deltaTime, maskActive);
}
onPostFrame(renderManager) {
if (!this._needsReRender)
return;
this._needsReRender = false;
this.reRender(renderManager.renderer);
if (this.clipBackground && !renderManager.gbufferTarget) {
// todo warn only when rgbm
console.warn('ScreenPass: clipBackground set to true but no gbufferTarget set. Try adding GBufferPlugin.');
}
}
dispose() {
this._lastReadBuffer = undefined;
super.dispose();
}
beforeRender(_, _1, renderManager) {
if (this.material.uniforms.tTransparent) {
this.material.uniforms.tTransparent.value = renderManager.renderPass.preserveTransparentTarget ? renderManager.renderPass.transparentTarget?.texture || null : null;
this.material.defines.HAS_TRANSPARENT_TARGET = this.material.uniforms.tTransparent.value ? 1 : undefined;
if (!this.material.defines.HAS_TRANSPARENT_TARGET)
delete this.material.defines.HAS_TRANSPARENT_TARGET;
}
}
setDirty() {
super.setDirty();
this._needsReRender = true;
}
};
__decorate([
uiDropdown('Output Color Space', threeConstMappings.ColorSpace.uiConfig, (t) => ({ onChange: t.setDirty }))
], ScreenPass.prototype, "outputColorSpace", void 0);
__decorate([
matDefineBool('CLIP_BACKGROUND_FORCE', undefined, undefined, ScreenPass.prototype.setDirty, true)
], ScreenPass.prototype, "clipBackgroundForce", void 0);
__decorate([
matDefineBool('CLIP_BACKGROUND', undefined, undefined, ScreenPass.prototype.setDirty),
uiToggle()
], ScreenPass.prototype, "clipBackground", void 0);
ScreenPass = __decorate([
uiFolderContainer('Screen Pass')
], ScreenPass);
export { ScreenPass };
function makeScreenShader(shader) {
const baseShader = shaderReplaceString(ScreenPassShader, 'void main()', (Array.isArray(shader) ? shader[0] : shader?.pars || '') + '\n', { prepend: true });
const finalShader = baseShader.includes('#glMarker') ? shaderReplaceString(baseShader, '#glMarker', (Array.isArray(shader) ? shader[1] : typeof shader === 'string' ? shader : shader?.main || '') + '\n', { prepend: true }) : baseShader;
return {
...CopyShader,
fragmentShader: finalShader,
uniforms: {
tDiffuse: { value: null },
tTransparent: { value: null },
},
transparent: true,
blending: NoBlending,
side: FrontSide,
};
}
//# sourceMappingURL=ScreenPass.js.map