ソースを参照

MSAA only in ExtendedRenderPass, some fixes.

master
Palash Bansal 1年前
コミット
a797b1590e
コミッターのメールアドレスに関連付けられたアカウントが存在しません

+ 7
- 6
src/plugins/pipeline/DepthBufferPlugin.ts ファイルの表示

@@ -18,7 +18,7 @@ import {
WebGLRenderTarget,
} from 'three'
import {GBufferRenderPass} from '../../postprocessing'
import {ThreeViewer} from '../../viewer'
import {ThreeViewer, ViewerRenderManager} from '../../viewer'
import {MaterialExtension} from '../../materials'
import {PipelinePassPlugin} from '../base/PipelinePassPlugin'
import {uiDropdown, uiFolderContainer, uiImage} from 'uiconfig.js'
@@ -31,7 +31,7 @@ import {IMaterial, PhysicalMaterial} from '../../core'
export type DepthBufferPluginEventTypes = ''
// type DepthBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget
export type DepthBufferPluginTarget = WebGLRenderTarget
export type DepthBufferPluginPass = GBufferRenderPass<'depth', DepthBufferPluginTarget>
export type DepthBufferPluginPass = GBufferRenderPass<'depth', DepthBufferPluginTarget|undefined>

/**
* Depth Buffer Plugin
@@ -102,12 +102,13 @@ export class DepthBufferPlugin
protected _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<DepthBufferPluginTarget>(
{
depthBuffer: true,
samples: this._viewer.renderManager.zPrepass && this.isPrimaryGBuffer ? // requirement for zPrepass
this._viewer.renderManager.composerTarget.samples || 0 : 0,
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,
@@ -118,7 +119,7 @@ export class DepthBufferPlugin
this.texture = this.target.texture
this.texture.name = 'depthBuffer'

if (this._pass) this._pass.target = this.target
// if (this._pass) this._pass.target = this.target

if (this.isPrimaryGBuffer) {
this._viewer.renderManager.gbufferTarget = this.target
@@ -147,7 +148,7 @@ export class DepthBufferPlugin
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 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']

+ 20
- 6
src/plugins/pipeline/GBufferPlugin.ts ファイルの表示

@@ -29,7 +29,7 @@ import {
WebGLRenderTarget,
} from 'three'
import {GBufferRenderPass} from '../../postprocessing'
import {ThreeViewer} from '../../viewer'
import {ThreeViewer, ViewerRenderManager} from '../../viewer'
import {MaterialExtension, updateMaterialDefines} from '../../materials'
import {PipelinePassPlugin} from '../base/PipelinePassPlugin'
import {uiFolderContainer, uiImage} from 'uiconfig.js'
@@ -51,7 +51,7 @@ import {
export type GBufferPluginEventTypes = ''
export type GBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget
// export type GBufferPluginTarget = WebGLRenderTarget
export type GBufferPluginPass = GBufferRenderPass<'gbuffer', GBufferPluginTarget>
export type GBufferPluginPass = GBufferRenderPass<'gbuffer', GBufferPluginTarget|undefined>

export interface GBufferUpdaterContext {
material: IMaterial, renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, object: Object3D
@@ -118,6 +118,19 @@ export class GBufferPlugin
// }

unpackExtension: MaterialExtension = {
/**
* Use this in shader to get the snippet
* ```
* // for gbuffer
* #include <packing>
* #define THREE_PACKING_INCLUDED
* ```
* or if you don't need packing include
* ```
* #include <gbuffer_unpack>
* ```
* @param shader
*/
shaderExtender: (shader)=>{
const includes = ['gbuffer_unpack', 'packing'] as const
const include = includes.find(i=>shader.fragmentShader.includes(`#include <${i}>`))
@@ -149,11 +162,12 @@ export class GBufferPlugin
if (recreateTarget) this._disposeTarget()
const useMultiple = this._viewer?.renderManager.isWebGL2 && this.renderFlagsBuffer
if (!this.target) {
const rm = this._viewer.renderManager
this.target = this._viewer.renderManager.createTarget<GBufferPluginTarget>(
{
depthBuffer: true,
samples: this._viewer.renderManager.zPrepass && this.isPrimaryGBuffer ? // requirement for zPrepass
this._viewer.renderManager.composerTarget.samples || 0 : 0,
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,
textureCount: useMultiple ? 2 : 1,
depthTexture: this.renderDepthTexture,
@@ -189,7 +203,7 @@ export class GBufferPlugin
})
}

if (this._pass) this._pass.target = this.target
// if (this._pass) this._pass.target = this.target

if (this.isPrimaryGBuffer) {
this._viewer.renderManager.gbufferTarget = this.target
@@ -219,7 +233,7 @@ export class GBufferPlugin
if (!this.target) throw new Error('GBufferPlugin: target not created')
if (!this.material) throw new Error('GBufferPlugin: material not created')
this.material.userData.isGBufferMaterial = true
const pass = new GBufferRenderPass(this.passId, this.target, this.material, new Color(1, 1, 1), 1)
const pass = new GBufferRenderPass(this.passId, ()=>this.target, this.material, new Color(1, 1, 1), 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']

+ 5
- 4
src/plugins/pipeline/NormalBufferPlugin.ts ファイルの表示

@@ -26,7 +26,7 @@ import {uiFolderContainer, uiImage} from 'uiconfig.js'
export type NormalBufferPluginEventTypes = ''
// type NormalBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget
export type NormalBufferPluginTarget = WebGLRenderTarget
export type NormalBufferPluginPass = GBufferRenderPass<'normal', NormalBufferPluginTarget>
export type NormalBufferPluginPass = GBufferRenderPass<'normal', NormalBufferPluginTarget|undefined>
/**
* Normal Buffer Plugin
*
@@ -54,10 +54,11 @@ export class NormalBufferPlugin
if (!this._viewer) return
if (recreate) this._disposeTarget()

// const rm = this._viewer.renderManager
if (!this.target) this.target = this._viewer.renderManager.createTarget<NormalBufferPluginTarget>(
{
depthBuffer: true,
// samples: v.renderManager.composerTarget.samples || 0,
// samples: rm.msaa ? typeof rm.msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : rm.msaa : 0,
samples: 0,
type: this.bufferType,
magFilter: NearestFilter,
@@ -68,7 +69,7 @@ export class NormalBufferPlugin
this.texture = this.target.texture
this.texture.name = 'normalBuffer'

if (this._pass) this._pass.target = this.target
// if (this._pass) this._pass.target = this.target
}
protected _disposeTarget() {
if (!this._viewer) return
@@ -83,7 +84,7 @@ export class NormalBufferPlugin
this._createTarget(true)
if (!this.target) throw new Error('NormalBufferPlugin: 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 pass = new GBufferRenderPass(this.passId, ()=>this.target, this.material, new Color(0, 0, 0), 1)
const preprocessMaterial = pass.preprocessMaterial
pass.preprocessMaterial = (m) => preprocessMaterial(m, true)
pass.before = ['render']

+ 3
- 4
src/plugins/pipeline/SSAOPlugin.ts ファイルの表示

@@ -74,7 +74,7 @@ export class SSAOPlugin
this.texture = this.target.texture
this.texture.name = 'ssaoBuffer'

if (this._pass) this._pass.target = this.target
// if (this._pass) this._pass.target = this.target
}

protected _disposeTarget() {
@@ -102,8 +102,7 @@ export class SSAOPlugin
if (!this._viewer.renderManager.gbufferTarget || !this._viewer.renderManager.gbufferUnpackExtension)
throw new Error('SSAOPlugin: GBuffer target not created. GBufferPlugin or DepthBufferPlugin is required.')
this._createTarget(true)
// todo: send target as a func, so it works when changed
return new SSAOPluginPass(this.passId, this.target)
return new SSAOPluginPass(this.passId, ()=>this.target)
}

onAdded(viewer: ThreeViewer) {
@@ -299,7 +298,7 @@ export class SSAOPluginPass extends ExtendedShaderPass implements IPipelinePass
#include <simpleCameraHelpers>
`,
computeCacheKey: () => {
return this.enabled ? '1' : '0' + getOrCall(this.target)?.texture?.colorSpace
return (this.enabled ? '1' : '0') + getOrCall(this.target)?.texture?.colorSpace
},
uuid: SSAOPlugin.PluginType,
...uiConfigMaterialExtension(this._getUiConfig.bind(this), SSAOPlugin.PluginType),

+ 74
- 8
src/postprocessing/ExtendedRenderPass.ts ファイルの表示

@@ -33,9 +33,10 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren

get transparentTarget(): IRenderTarget {
if (!this._transparentTarget) {
const msaa = this.renderManager.msaa
this._transparentTarget = this.renderManager.getTempTarget({
sizeMultiplier: 1,
samples: this.renderManager.composerTarget.samples || 0,
samples: msaa ? typeof msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : msaa : 0,
colorSpace: NoColorSpace,
type: this.renderManager.renderer.extensions.has('EXT_color_buffer_half_float') ? HalfFloatType : UnsignedByteType,
format: RGBAFormat,
@@ -46,12 +47,41 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren
}
return this._transparentTarget
}

private _releaseTransparentTarget() {
if (this._transparentTarget)
this.renderManager.releaseTempTarget(this._transparentTarget)
this._transparentTarget = undefined
}

readonly preserveOpaqueTarget = false
private _opaqueTarget?: WebGLRenderTarget

get opaqueTarget(): WebGLRenderTarget {
if (!this._opaqueTarget) {
const composerTarget = this.renderManager.composerTarget as WebGLRenderTarget
const msaa = this.renderManager.msaa
this._opaqueTarget = this.renderManager.getTempTarget({
sizeMultiplier: 1,
samples: msaa ? typeof msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : msaa : 0,
colorSpace: composerTarget.texture.colorSpace,
type: this.renderManager.rgbm ? UnsignedByteType : HalfFloatType,
format: composerTarget.texture.format,
minFilter: composerTarget.texture.minFilter,
magFilter: composerTarget.texture.magFilter,
depthBuffer: composerTarget.depthBuffer,
generateMipmaps: composerTarget.texture.generateMipmaps,
})
// console.log(this._opaqueTarget.samples)
}
return this._opaqueTarget
}
private _releaseOpaqueTarget() {
if (this._opaqueTarget)
this.renderManager.releaseTempTarget(this._opaqueTarget)
this._opaqueTarget = undefined
}

constructor(renderManager: ViewerRenderManager, overrideMaterial?: Material, clearColor = new Color(0, 0, 0), clearAlpha = 0) {
super(undefined, undefined, overrideMaterial, clearColor, clearAlpha)
this.renderManager = renderManager
@@ -59,6 +89,7 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren
this.setDirty = this.setDirty.bind(this)
}

// names are incorrect. We read from `writeBuffer` and write to `readBuffer`. same in super class
render(renderer: IWebGLRenderer, writeBuffer?: WebGLMultipleRenderTargets|WebGLRenderTarget|null, readBuffer?: WebGLMultipleRenderTargets|WebGLRenderTarget, deltaTime?: number, maskActive?: boolean) {
if (!this.enabled) return
let needsSwap = false
@@ -72,7 +103,7 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren
}

const ud = renderer.userData
if (!ud) console.error('threejs is not patched?')
if (!ud) console.error('threejs is not patched. Use the @repalash/three.js-modded to this functionality.')

const useGBufferDepth = (this.renderManager.zPrepass || !this.renderManager.depthBuffer) && this.renderManager.gbufferTarget
let depthRenderBuffer: WebGLRenderbuffer | undefined = undefined
@@ -90,6 +121,16 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren

}

const lastReadBuffer = readBuffer

// if msaa we need to create a new multi sampled target to render to

// todo
readBuffer = this.renderManager.msaa ? this.opaqueTarget : readBuffer
// readBuffer = this.opaqueTarget
// if(readBuffer?.samples !== gbuffer?.samples)
// console.error('ExtendedRenderPass - readBuffer and gbuffer samples are not same', readBuffer?.samples, gbuffer?.samples)

let renderFn = ()=> {
super.render(renderer, null, readBuffer, deltaTime, maskActive, depthRenderBuffer) // read is write in super.render (RenderPass)
}
@@ -133,7 +174,7 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren
// renderer.autoClearDepth = false

ud.transmissionRenderTarget = writeBuffer
ud.blurTransmissionTarget = this.blurTransmissionTarget && ud.transmissionRenderTarget.samples === 0 // todo: not working with msaa
ud.blurTransmissionTarget = this.blurTransmissionTarget && ud.transmissionRenderTarget.samples === 0 // todo: not working with msaa target. its fine now because writeBuffer is never multi sampled

renderer.renderWithModes({
shadowMapRender: false,
@@ -178,7 +219,7 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren
opaqueRender: true,
transparentRender: false,
transmissionRender: false,
}, renderFn)
}, renderFn) // render to readBuffer

renderer.autoClearDepth = curClearDepth

@@ -188,6 +229,9 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren
const renderBufferProps2 = renderer.properties.get(readBuffer)
depthRenderBuffer = renderBufferProps2.__webglDepthRenderbuffer || renderBufferProps2.__webglDepthbuffer
}

// readBuffer has data

renderFn = ()=> {
super.render(renderer, null, this.transparentTarget as any, deltaTime, maskActive, depthRenderBuffer)
}
@@ -205,7 +249,7 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren
opaqueRender: false,
transparentRender: true,
transmissionRender: false,
}, renderFn)
}, renderFn) // render to transparentTarget

this.clear = curClear
renderer.autoClearDepth = curClearDepth
@@ -213,12 +257,15 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren

if (!renderer.info || renderer.info.render.calls > 0) {

// writeBuffer = transparentTarget + readBuffer
this._blendPass.uniforms.tDiffuse2.value = this.transparentTarget.texture
this._blendPass.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive)
needsSwap = true
needsSwap = true // writeBuffer has the data now.

}

// if needsSwap, writeBuffer has data, else readBuffer

// Transmission
{
const curClear = this.clear
@@ -227,6 +274,7 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren
// const curClearDepth = renderer.autoClearDepth
// renderer.autoClearDepth = false

// if needsSwap, writeBuffer has current data, else readBuffer
ud.transmissionRenderTarget = needsSwap ? writeBuffer : readBuffer
ud.blurTransmissionTarget = this.blurTransmissionTarget && ud.transmissionRenderTarget.samples === 0 // todo: not working with msaa

@@ -236,7 +284,7 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren
opaqueRender: false,
transparentRender: false,
transmissionRender: true,
}, renderFn)
}, renderFn) // render to transparentTarget

ud.blurTransmissionTarget = undefined
ud.transmissionRenderTarget = undefined
@@ -250,12 +298,16 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren
if (!renderer.info || renderer.info.render.calls > 0) {

// console.log('missive blit', renderer.info.render.frame)

// writeBuffer = transparentTarget + readBuffer. opaque will overwrite opaque pixels again
this._blendPass.uniforms.tDiffuse2.value = this.transparentTarget.texture
this._blendPass.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive)
needsSwap = true
needsSwap = true // writeBuffer has the data now.

}

// if needsSwap, writeBuffer has data, else readBuffer

if (renderToScreen) {
this.renderToScreen = true
const tex = needsSwap ? writeBuffer?.texture : readBuffer?.texture
@@ -268,8 +320,22 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren

}

// todo no need to do this if renderToScreen is true
// resolve msaa
if (!needsSwap && lastReadBuffer !== readBuffer && readBuffer) {
// copy from readBuffer to lastReadBuffer
const source = Array.isArray(readBuffer.texture) ? readBuffer.texture[0] : readBuffer.texture
source && this.renderManager.blit(lastReadBuffer, {
source: source, clear: true,
})
readBuffer = lastReadBuffer
}

if (!this.preserveTransparentTarget)
this._releaseTransparentTarget()
if (!this.preserveOpaqueTarget)
this._releaseOpaqueTarget()

this.needsSwap = needsSwap
renderer.userData.mainRenderPass = undefined
}

+ 7
- 11
src/viewer/ViewerRenderManager.ts ファイルの表示

@@ -1,12 +1,5 @@
import {IRenderTarget, RenderManager} from '../rendering'
import {
HalfFloatType,
LinearFilter,
LinearMipMapLinearFilter,
NoColorSpace,
RGBM16ColorSpace,
UnsignedByteType,
} from 'three'
import {HalfFloatType, LinearFilter, NoColorSpace, RGBM16ColorSpace, UnsignedByteType} from 'three'
import {IRenderManagerEvent, IRenderManagerOptions, IScene} from '../core'
import {ExtendedRenderPass, ScreenPass, TViewerScreenShader} from '../postprocessing'
import {uiFolderContainer, UiObjectConfig} from 'uiconfig.js'
@@ -33,16 +26,19 @@ export class ViewerRenderManager extends RenderManager<IRenderManagerEvent, 'gbu
readonly screenPass: ScreenPass
declare uiConfig: UiObjectConfig

static DEFAULT_MSAA_SAMPLES = 4

constructor({rgbm = true, msaa = false, depthBuffer = false, ...options}: ViewerRenderManagerOptions) {
super({
...options,
targetOptions: {
samples: msaa ? typeof msaa !== 'number' ? 4 : msaa : 0,
samples: 0,
// samples: msaa ? typeof msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : msaa : 0,
colorSpace: rgbm ? RGBM16ColorSpace : NoColorSpace,
type: rgbm ? UnsignedByteType : HalfFloatType,
depthBuffer: depthBuffer,
generateMipmaps: msaa ? true : false, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass
minFilter: msaa ? LinearMipMapLinearFilter : LinearFilter, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass
generateMipmaps: /* msaa ? true : */false, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass
minFilter: /* msaa ? LinearMipMapLinearFilter : */LinearFilter, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass
},
})
this.rgbm = rgbm

読み込み中…
キャンセル
保存