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.
188 lines • 8.8 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 { BasicDepthPacking, Color, DoubleSide, FrontSide, MeshDepthMaterial, NoBlending, UnsignedByteType, } from 'three';
import { GBufferRenderPass } from '../../postprocessing';
import { ViewerRenderManager } from '../../viewer';
import { PipelinePassPlugin } from '../base/PipelinePassPlugin';
import { uiDropdown, uiFolderContainer, uiImage } from 'uiconfig.js';
import { shaderReplaceString } from '../../utils';
import { onChange } from 'ts-browser-helpers';
import DepthBufferUnpack from './shaders/DepthBufferPlugin.unpack.glsl';
import { threeConstMappings } from '../../three';
/**
* Depth Buffer Plugin
*
* Adds a pre-render pass to render the depth buffer to a render target that can be used as gbuffer or for postprocessing.
* @category Plugins
*/
let DepthBufferPlugin = class DepthBufferPlugin extends PipelinePassPlugin {
_depthPackingChanged() {
this.material.depthPacking = this.depthPacking;
this.material.needsUpdate = true;
if (this.unpackExtension && this.unpackExtension.extraDefines) {
this.unpackExtension.extraDefines.DEPTH_PACKING = this.depthPacking;
this.unpackExtension.setDirty?.();
}
this.setDirty();
}
_createTarget(recreate = true) {
if (!this._viewer)
return;
if (recreate)
this._disposeTarget();
const rm = this._viewer.renderManager;
if (!this.target)
this.target = this._viewer.renderManager.createTarget({
depthBuffer: true,
samples: this._viewer.renderManager.zPrepass && this.isPrimaryGBuffer && rm.msaa ? // requirement for zPrepass
typeof rm.msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : rm.msaa : 0,
type: this.bufferType,
// magFilter: NearestFilter,
// minFilter: NearestFilter,
// generateMipmaps: false,
// encoding: LinearEncoding,
});
this.texture = this.target.texture;
this.texture.name = 'depthBuffer';
// if (this._pass) this._pass.target = this.target
if (this.isPrimaryGBuffer) {
this._viewer.renderManager.gbufferTarget = this.target;
this._viewer.renderManager.gbufferUnpackExtension = this.unpackExtension;
this._viewer.renderManager.screenPass.material.registerMaterialExtensions([this.unpackExtension]);
this._isPrimaryGBufferSet = true;
}
}
_disposeTarget() {
if (!this._viewer)
return;
if (this.target) {
this._viewer.renderManager.disposeTarget(this.target);
this.target = undefined;
}
this.texture = undefined;
if (this._isPrimaryGBufferSet) { // using a separate flag as when isPrimaryGBuffer is changed, we cannot check it.
this._viewer.renderManager.gbufferTarget = undefined;
this._viewer.renderManager.gbufferUnpackExtension = undefined;
// this._viewer.renderManager.screenPass.material.unregisterMaterialExtensions([this.unpackExtension]) // todo this has an issue
this._isPrimaryGBufferSet = false;
}
}
_createPass() {
this._createTarget(true);
if (!this.target)
throw new Error('DepthBufferPlugin: target not created');
this.material.userData.isGBufferMaterial = true;
const pass = new GBufferRenderPass(this.passId, () => this.target, this.material, new Color(0, 0, 0), 1);
const preprocessMaterial = pass.preprocessMaterial;
pass.preprocessMaterial = (m) => preprocessMaterial(m, m.userData.renderToDepth); // if renderToDepth is undefined then renderToGbuffer is taken internally
pass.before = ['render'];
pass.after = [];
pass.required = ['render'];
return pass;
}
constructor(bufferType = UnsignedByteType, isPrimaryGBuffer = false, enabled = true, depthPacking = BasicDepthPacking) {
super();
this.passId = 'depth';
// @uiConfig() // not supported in this material yet
this.material = new MeshDepthMaterialOverride({
depthPacking: BasicDepthPacking,
blending: NoBlending,
transparent: true,
});
this.unpackExtension = {
shaderExtender: (shader) => {
const includes = ['depth_buffer_unpack', 'gbuffer_unpack', 'packing'];
const include = includes.find(i => shader.fragmentShader.includes(`#include <${i}>`));
shader.fragmentShader = shaderReplaceString(shader.fragmentShader, `#include <${include}>`, '\n' + DepthBufferUnpack + '\n', { append: include === 'packing' });
},
extraUniforms: {
tDepthBuffer: () => ({ value: this.target?.texture }),
},
extraDefines: {
['DEPTH_PACKING']: BasicDepthPacking,
['HAS_DEPTH_BUFFER']: () => this.target?.texture ? 1 : undefined,
['HAS_GBUFFER']: () => this.isPrimaryGBuffer && this.target?.texture ? 1 : undefined,
},
priority: 100,
isCompatible: () => true,
};
this._isPrimaryGBufferSet = false;
this.enabled = enabled;
this.depthPacking = depthPacking;
this.bufferType = bufferType;
this.isPrimaryGBuffer = isPrimaryGBuffer;
}
onRemove(viewer) {
this._disposeTarget();
return super.onRemove(viewer);
}
};
DepthBufferPlugin.PluginType = 'DepthBufferPlugin';
__decorate([
uiImage('Depth Buffer', { readOnly: true })
], DepthBufferPlugin.prototype, "texture", void 0);
__decorate([
onChange(DepthBufferPlugin.prototype._depthPackingChanged),
uiDropdown('Depth Packing', threeConstMappings.DepthPackingStrategies.uiConfig)
], DepthBufferPlugin.prototype, "depthPacking", void 0);
DepthBufferPlugin = __decorate([
uiFolderContainer('Depth Buffer Plugin')
], DepthBufferPlugin);
export { DepthBufferPlugin };
class MeshDepthMaterialOverride extends MeshDepthMaterial {
constructor(parameters) {
super(parameters);
this.reset();
}
onBeforeRender(renderer, scene, camera, geometry, object) {
super.onBeforeRender(renderer, scene, camera, geometry, object);
let material = object.material;
if (Array.isArray(material)) { // todo: add support for multi materials.
material = material[0];
}
if (!material)
return;
if (material.map !== undefined)
this.map = material.map; // in case there is alpha in the map.
if (material.side !== undefined)
this.side = material.side ?? FrontSide;
if (material.alphaMap !== undefined)
this.alphaMap = material.alphaMap;
if (material.alphaTest !== undefined)
this.alphaTest = material.alphaTest < 1e-4 ? 1e-4 : material.alphaTest;
if (material.alphaHash !== undefined)
this.alphaHash = material.alphaHash;
if (material.displacementMap !== undefined)
this.displacementMap = material.displacementMap;
if (material.displacementScale !== undefined)
this.displacementScale = material.displacementScale;
if (material.displacementBias !== undefined)
this.displacementBias = material.displacementBias;
if (material.wireframe !== undefined)
this.wireframe = material.wireframe;
if (material.wireframeLinewidth !== undefined)
this.wireframeLinewidth = material.wireframeLinewidth;
this.needsUpdate = true;
}
onAfterRender(renderer, scene, camera, geometry, object) {
super.onAfterRender(renderer, scene, camera, geometry, object);
this.reset();
}
reset() {
this.map = null;
this.side = DoubleSide;
this.alphaMap = null;
this.alphaTest = 0.001;
this.alphaHash = false;
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.wireframe = false;
this.wireframeLinewidth = 1;
}
}
//# sourceMappingURL=DepthBufferPlugin.js.map