Просмотр исходного кода

Add pluginsDisabled and ssaoCastDisabled to disable SSAO.

master
Palash Bansal 2 лет назад
Родитель
Сommit
cabe7ab22f
Аккаунт пользователя с таким Email не найден

+ 6
- 1
src/core/IMaterial.ts Просмотреть файл

@@ -80,7 +80,12 @@ export interface IMaterialUserData extends IImportResultUserData{
* Force a depth value in GBuffer.
* This is useful to force center values like 0 to the depth.
*/
forcedLinearDepth?: number
forcedLinearDepth?: number // todo uiconfig for this in imaterial?

/**
* General flag to disable multiple plugins on the material at once, like SSAO, SSR, Bloom etc.
*/
pluginsDisabled?: boolean // todo uiconfig for this in imaterial?

// todo: move these to respective plugins


+ 1
- 1
src/plugins/pipeline/GBufferPlugin.ts Просмотреть файл

@@ -383,7 +383,7 @@ export class GBufferMaterial extends ShaderMaterial2 {
x : Empty
y : first 3 bits lut index, second 5 bits bevel radius
z : material id (userData.gBufferData?.materialId, userData.matId)
w : this field is for setting bits - lutEnable-0, tonemap-1, bloom-2
w : this field is for setting bits - lutEnable-0, tonemap-1, bloom-2, ssao(cast)-3
*/

this.uniforms.flags.value.set(255, 255, 255, 255)

+ 63
- 20
src/plugins/pipeline/SSAOPlugin.ts Просмотреть файл

@@ -1,17 +1,17 @@
import {Matrix4, Texture, TextureDataType, UnsignedByteType, Vector2, Vector3, Vector4, WebGLRenderTarget} from 'three'
import {ExtendedShaderPass, IPassID, IPipelinePass} from '../../postprocessing'
import {ThreeViewer} from '../../viewer'
import {type IViewerEvent, ThreeViewer} from '../../viewer'
import {PipelinePassPlugin} from '../base/PipelinePassPlugin'
import {uiConfig, uiFolderContainer, uiImage, uiSlider} from 'uiconfig.js'
import {ICamera, IMaterial, IRenderManager, IScene, IWebGLRenderer, PhysicalMaterial} from '../../core'
import {getOrCall, glsl, onChange2, serialize, ValOrFunc} from 'ts-browser-helpers'
import {getOrCall, glsl, onChange2, serialize, updateBit, ValOrFunc} from 'ts-browser-helpers'
import {MaterialExtension} from '../../materials'
import {shaderReplaceString, shaderUtils} from '../../utils'
import {getTexelDecoding, matDefine} from '../../three'
import {getTexelDecoding, matDefine, matDefineBool} from '../../three'
import ssaoPass from './shaders/SSAOPlugin.pass.glsl'
import ssaoPatch from './shaders/SSAOPlugin.patch.glsl'
import {uiConfigMaterialExtension} from '../../materials/MaterialExtender'
import {GBufferPlugin} from './GBufferPlugin'
import {GBufferPlugin, GBufferUpdaterContext} from './GBufferPlugin'

export type SSAOPluginEventTypes = ''
export type SSAOPluginTarget = WebGLRenderTarget
@@ -19,8 +19,8 @@ export type SSAOPluginTarget = WebGLRenderTarget
/**
* SSAO Plugin
*
* Adds a post-render pass to blend the last frame with the current frame.
* This can be used to create a progressive rendering effect which is useful for progressive shadows, gi, denoising, baking, anti-aliasing, and many other effects.
* Adds Screen Space Ambient Occlusion (SSAO) to the scene.
* Adds a pass to calculate AO, which is then read by materials in the render pass.
* @category Plugins
*/
@uiFolderContainer('SSAO Plugin')
@@ -102,24 +102,40 @@ 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)
const pass = new SSAOPluginPass(this.passId, this.target)
pass.before = ['render']
pass.after = ['gbuffer', 'depth']
pass.required = ['render'] // gbuffer required check above.
return pass
// todo: send target as a func, so it works when changed
return new SSAOPluginPass(this.passId, this.target)
}

onAdded(viewer: ThreeViewer) {
super.onAdded(viewer)
const gbuffer = viewer.getPlugin(GBufferPlugin)
if (gbuffer) gbuffer.registerGBufferUpdater(this.constructor.PluginType, this.updateGBufferFlags.bind(this))
else viewer.addEventListener('addPlugin', this._onPluginAdd)
this._gbufferUnpackExtensionChanged()
viewer.renderManager.addEventListener('gbufferUnpackExtensionChanged', this._gbufferUnpackExtensionChanged)
}

private _onPluginAdd = (e: IViewerEvent)=>{
if (e.plugin?.constructor?.PluginType !== GBufferPlugin.PluginType) return
const gbuffer = e.plugin as GBufferPlugin
gbuffer.registerGBufferUpdater(this.constructor.PluginType, this.updateGBufferFlags.bind(this))
this._viewer?.removeEventListener('addPlugin', this._onPluginAdd)
}

onRemove(viewer: ThreeViewer): void {
viewer.removeEventListener('addPlugin', this._onPluginAdd)
this._disposeTarget()
return super.onRemove(viewer)
}

updateGBufferFlags(data: Vector4, c: GBufferUpdaterContext): void {
if (!c.material || !c.material.userData) return
const disabled = c.material.userData.ssaoCastDisabled || c.material.userData.pluginsDisabled
const x = disabled ? 0 : 1
data.w = updateBit(data.w, 3, x)

if (disabled && this._pass) this._pass.checkGBufferFlag = true
}
/**
* @deprecated use {@link target} instead
*/
@@ -132,9 +148,9 @@ export class SSAOPlugin

@uiFolderContainer('SSAO Pass')
export class SSAOPluginPass extends ExtendedShaderPass implements IPipelinePass {
before = ['screen']
after = ['render']
required = ['render']
before = ['render']
after = ['gbuffer', 'depth']
required = ['render'] // gbuffer required check done in plugin.

// todo bilateralPass
// @serialize() readonly bilateralPass: BilateralFilterPass
@@ -171,6 +187,13 @@ export class SSAOPluginPass extends ExtendedShaderPass implements IPipelinePass
@matDefine('NUM_SAMPLES', undefined, undefined, SSAOPluginPass.prototype.setDirty)
numSamples = 8

/**
* Whether to check for gbuffer flag or not. This is used to disable SSAO casting by some objects. its enabled automatically by the SSAOPlugin when required.
* This is disabled by default so that we dont read texture for no reason.
*/
@matDefineBool('CHECK_GBUFFER_FLAG')
checkGBufferFlag = false

// todo after bilateralPass is implemented
// @bindToValue({obj: 'bilateralPass', key: 'enabled', onChange: 'setDirty'})
// smoothEnabled = true
@@ -186,6 +209,7 @@ export class SSAOPluginPass extends ExtendedShaderPass implements IPipelinePass
['NUM_SPIRAL_TURNS']: 3,
['SSAO_PACKING']: 1, // 1 is (r: ssao, gba: depth), 2 is (rgb: ssao, a: 1), 3 is (rgba: packed_ssao), 4 is (rgb: packed_ssao, a: 1)
['PERSPECTIVE_CAMERA']: 1, // set in PerspectiveCamera2
['CHECK_GBUFFER_FLAG']: 0,
},
uniforms: {
tLastThis: {value: null},
@@ -201,7 +225,7 @@ export class SSAOPluginPass extends ExtendedShaderPass implements IPipelinePass

fragmentShader: ssaoPass,

}, 'tDiffuse')
}, 'tDiffuse') // why is tLastThis not here. because encoding and size doesnt matter?

this.needsSwap = false
this.clear = true
@@ -218,9 +242,9 @@ export class SSAOPluginPass extends ExtendedShaderPass implements IPipelinePass
return
}
this._updateParameters()
if (!this.material.defines.HAS_GBUFFER) {
console.warn('SSAOPluginPass: DepthNormalBuffer required for ssao')
}
// if (!this.material.defines.HAS_GBUFFER) {
// console.warn('SSAOPluginPass: DepthNormalBuffer required for ssao')
// }
renderer.renderManager.blit(writeBuffer, {
source: target.texture,
})
@@ -264,9 +288,10 @@ export class SSAOPluginPass extends ExtendedShaderPass implements IPipelinePass
shader.fragmentShader = shaderReplaceString(shader.fragmentShader, '#include <aomap_fragment>', ssaoPatch)
},
onObjectRender: (_object, material, renderer: any) => {
const opaque = !material.transparent && (!material.transmission || material.transmission < 0.001)
const x: any = this.enabled && opaque &&
// const opaque = !material.transparent && (!material.transmission || material.transmission < 0.001)
const x: any = this.enabled && // opaque &&
renderer.userData.screenSpaceRendering !== false &&
!material.userData?.pluginsDisabled &&
!material.userData?.ssaoDisabled ? 1 : 0

if (material.defines!.SSAO_ENABLED !== x) {
@@ -313,6 +338,19 @@ export class SSAOPluginPass extends ExtendedShaderPass implements IPipelinePass
},
onChange: this.setDirty,
},
{
type: 'checkbox',
label: 'Cast SSAO',
get value() {
return !(material.userData.ssaoCastDisabled ?? false)
},
set value(v) {
if (v === !(material.userData.ssaoCastDisabled ?? false)) return
material.userData.ssaoCastDisabled = !v
material.setDirty()
},
onChange: this.setDirty,
},
],
}
}
@@ -325,5 +363,10 @@ declare module '../../core/IMaterial' {
* Disable SSAOPlugin for this material.
*/
ssaoDisabled?: boolean
/**
* Cast SSAO on other objects.
* if casting is not working when this is false, ensure render to depth is true, like for transparent objects
*/
ssaoCastDisabled?: boolean
}
}

+ 19
- 24
src/plugins/pipeline/shaders/SSAOPlugin.pass.glsl Просмотреть файл

@@ -15,13 +15,13 @@ uniform vec2 screenSize;

const float INV_NUM_SAMPLES = 1.0 / float(NUM_SAMPLES);

//int getSelectionBit(in int number) {
// #ifdef WebGL2Context
// return (number/4) % 2;
// #else
// return int(mod(floor(float(number)/4.), 2.));
// #endif
//}
int getSelectionBit(in int number) {
#ifdef WebGL2Context
return (number/8) % 2;
#else
return int(mod(floor(float(number)/8.), 2.));
#endif
}

vec3 packFloatToRGB(const in float x) {
const vec3 code = vec3(1.0, 255.0, 65025.0);
@@ -31,11 +31,7 @@ vec3 packFloatToRGB(const in float x) {
return pack;
}

vec3 getPositionFromOffset(const in vec2 uv,
const in vec2 offset,
const in float screenSpaceRadius) {

vec2 uvOffset = uv + floor(screenSpaceRadius * offset) / screenSize;
vec3 getPositionFromOffset(const in vec2 uvOffset) {
#if defined(HAS_DEPTH_BUFFER) || defined(HAS_NORMAL_DEPTH_BUFFER)
float d = getDepth(uvOffset);
#else
@@ -44,10 +40,10 @@ const in float screenSpaceRadius) {

#if LINEAR_DEPTH == 0
float centerViewZ = viewZFromNDCZ(d);
return screenToView(uvOffset, centerViewZ);
return screenToView3(uvOffset, centerViewZ);
#else
d = mix(-cameraNearFar.x, -cameraNearFar.y, d);
return screenToView(uvOffset, d);
return screenToView3(uvOffset, d);
#endif
}

@@ -58,14 +54,13 @@ const in float occlusionSphereRadius,
const in vec3 centerPosition,
const in vec3 centerNormal) {
float screenSpaceRadius = (float(id) + mod(randomAngle, 1.) + 0.5) * INV_NUM_SAMPLES;

float angle = screenSpaceRadius * (float(NUM_SPIRAL_TURNS) * 6.28) + randomAngle;

float angle = screenSpaceRadius * (float(NUM_SPIRAL_TURNS) * 6.28318) + randomAngle;
screenSpaceRadius = (screenSpaceRadius * occlusionSphereRadius);

vec2 offset = vec2(cos(angle), sin(angle));

vec3 samplePosition = getPositionFromOffset(uv, offset, screenSpaceRadius);
vec2 uvOffset = uv + floor(screenSpaceRadius * vec2(cos(angle), sin(angle))) / screenSize;
#if CHECK_GBUFFER_FLAG == 1
if (getSelectionBit(getGBufferFlags(uvOffset.xy).a) < 1) return 0.0;
#endif
vec3 samplePosition = getPositionFromOffset(uvOffset);
vec3 direction = samplePosition - centerPosition;
float d2 = dot(direction, direction);
float ao = max((dot(centerNormal, direction) + centerPosition.z * saoBiasEpsilon.x) / (saoBiasEpsilon.z * d2 + saoBiasEpsilon.y), 0.0);
@@ -102,8 +97,7 @@ void main() {
float centerViewZ = mix(-cameraNearFar.x, -cameraNearFar.y, centerDepth);
#endif

vec3 centerPosition = screenToView(vUv, centerViewZ);

vec3 centerPosition = screenToView3(vUv, centerViewZ);

float occlusionSphereScreenRadius = 200. * saoData.z / (-centerPosition.z);

@@ -149,7 +143,8 @@ void main() {

float aoValue = sum * saoData.y * INV_NUM_SAMPLES;

// bool disableAO = getSelectionBit(getGBufferFlags(vUv).a) > 0 ? true : false;
// this is not needed since ao can be disabled by not adding the material extension or the patch.
// bool disableAO = getSelectionBit(getGBufferFlags(vUv).a) > 0 ? true : false;

aoValue = 1. - clamp(aoValue, 0., 1.);


+ 6
- 4
src/postprocessing/ExtendedShaderPass.ts Просмотреть файл

@@ -3,7 +3,7 @@ import {ShaderPass} from 'three/examples/jsm/postprocessing/ShaderPass.js'
import {ExtendedShaderMaterial, IWebGLRenderer, ShaderMaterial2} from '../core'
import {Shader, ShaderMaterialParameters, WebGLMultipleRenderTargets, WebGLRenderTarget} from 'three'
import {uiToggle} from 'uiconfig.js'
import {serialize} from 'ts-browser-helpers'
import {onChange2, serialize} from 'ts-browser-helpers'
import {IShaderPropertiesUpdater} from '../materials'

export class ExtendedShaderPass extends ShaderPass implements IPass {
@@ -15,7 +15,9 @@ export class ExtendedShaderPass extends ShaderPass implements IPass {
readonly isExtendedShaderPass = true
// private _textureIDs: string[]

@uiToggle('Enabled') @serialize() enabled = true
@uiToggle('Enabled') @serialize()
@onChange2(ExtendedShaderPass.prototype.setDirty)
enabled = true

constructor(shader: ShaderMaterial2|ShaderMaterialParameters, ...textureID: string[]) {
super(
@@ -51,8 +53,8 @@ export class ExtendedShaderPass extends ShaderPass implements IPass {
}

setDirty() {
this.material.needsUpdate = true // do this when material defines etc are changed
this.onDirty.forEach(v=>v())
if (this.material) this.material.needsUpdate = true // do this when material defines etc are changed
this.onDirty?.forEach(v=>v())
}



+ 1
- 1
src/utils/shaders/cameraHelpers.glsl Просмотреть файл

@@ -32,7 +32,7 @@ vec4 viewToScreen3(const in vec3 pos) {
return projected;
}

vec3 screenToView(const in vec2 uv, const in float viewZ) {
vec3 screenToView3(const in vec2 uv, const in float viewZ) {
vec2 uv_ = 2. * uv - 1.;
float xe = -(uv_.x + projection[2][0]) * viewZ / projection[0][0];
float ye = -(uv_.y + projection[2][1]) * viewZ / projection[1][1];

Загрузка…
Отмена
Сохранить