playcanvas
Version:
PlayCanvas WebGL game engine
239 lines (236 loc) • 9.36 kB
JavaScript
import { math } from '../../core/math/math.js';
import { Color } from '../../core/math/color.js';
import { RenderPassShaderQuad } from '../../scene/graphics/render-pass-shader-quad.js';
import { TONEMAP_LINEAR, GAMMA_SRGB, GAMMA_NONE, gammaNames, tonemapNames } from '../../scene/constants.js';
import { ShaderChunks } from '../../scene/shader-lib/shader-chunks.js';
import { SHADERLANGUAGE_GLSL, SHADERLANGUAGE_WGSL, SEMANTIC_POSITION } from '../../platform/graphics/constants.js';
import { ShaderUtils } from '../../scene/shader-lib/shader-utils.js';
import { composeChunksGLSL } from '../../scene/shader-lib/glsl/collections/compose-chunks-glsl.js';
import { composeChunksWGSL } from '../../scene/shader-lib/wgsl/collections/compose-chunks-wgsl.js';
class RenderPassCompose extends RenderPassShaderQuad {
constructor(graphicsDevice){
super(graphicsDevice), this.sceneTexture = null, this.bloomIntensity = 0.01, this._bloomTexture = null, this._cocTexture = null, this.blurTexture = null, this.blurTextureUpscale = false, this._ssaoTexture = null, this._toneMapping = TONEMAP_LINEAR, this._gradingEnabled = false, this.gradingSaturation = 1, this.gradingContrast = 1, this.gradingBrightness = 1, this.gradingTint = new Color(1, 1, 1, 1), this._shaderDirty = true, this._vignetteEnabled = false, this.vignetteInner = 0.5, this.vignetteOuter = 1.0, this.vignetteCurvature = 0.5, this.vignetteIntensity = 0.3, this._fringingEnabled = false, this.fringingIntensity = 10, this._taaEnabled = false, this._sharpness = 0.5, this._gammaCorrection = GAMMA_SRGB, this._colorLUT = null, this.colorLUTIntensity = 1, this._key = '', this._debug = null;
ShaderChunks.get(graphicsDevice, SHADERLANGUAGE_GLSL).add(composeChunksGLSL);
ShaderChunks.get(graphicsDevice, SHADERLANGUAGE_WGSL).add(composeChunksWGSL);
const { scope } = graphicsDevice;
this.sceneTextureId = scope.resolve('sceneTexture');
this.bloomTextureId = scope.resolve('bloomTexture');
this.cocTextureId = scope.resolve('cocTexture');
this.ssaoTextureId = scope.resolve('ssaoTexture');
this.blurTextureId = scope.resolve('blurTexture');
this.bloomIntensityId = scope.resolve('bloomIntensity');
this.bcsId = scope.resolve('brightnessContrastSaturation');
this.tintId = scope.resolve('tint');
this.vignetterParamsId = scope.resolve('vignetterParams');
this.fringingIntensityId = scope.resolve('fringingIntensity');
this.sceneTextureInvResId = scope.resolve('sceneTextureInvRes');
this.sceneTextureInvResValue = new Float32Array(2);
this.sharpnessId = scope.resolve('sharpness');
this.colorLUTId = scope.resolve('colorLUT');
this.colorLUTParams = new Float32Array(4);
this.colorLUTParamsId = scope.resolve('colorLUTParams');
}
set debug(value) {
if (this._debug !== value) {
this._debug = value;
this._shaderDirty = true;
}
}
get debug() {
return this._debug;
}
set colorLUT(value) {
if (this._colorLUT !== value) {
this._colorLUT = value;
this._shaderDirty = true;
}
}
get colorLUT() {
return this._colorLUT;
}
set bloomTexture(value) {
if (this._bloomTexture !== value) {
this._bloomTexture = value;
this._shaderDirty = true;
}
}
get bloomTexture() {
return this._bloomTexture;
}
set cocTexture(value) {
if (this._cocTexture !== value) {
this._cocTexture = value;
this._shaderDirty = true;
}
}
get cocTexture() {
return this._cocTexture;
}
set ssaoTexture(value) {
if (this._ssaoTexture !== value) {
this._ssaoTexture = value;
this._shaderDirty = true;
}
}
get ssaoTexture() {
return this._ssaoTexture;
}
set taaEnabled(value) {
if (this._taaEnabled !== value) {
this._taaEnabled = value;
this._shaderDirty = true;
}
}
get taaEnabled() {
return this._taaEnabled;
}
set gradingEnabled(value) {
if (this._gradingEnabled !== value) {
this._gradingEnabled = value;
this._shaderDirty = true;
}
}
get gradingEnabled() {
return this._gradingEnabled;
}
set vignetteEnabled(value) {
if (this._vignetteEnabled !== value) {
this._vignetteEnabled = value;
this._shaderDirty = true;
}
}
get vignetteEnabled() {
return this._vignetteEnabled;
}
set fringingEnabled(value) {
if (this._fringingEnabled !== value) {
this._fringingEnabled = value;
this._shaderDirty = true;
}
}
get fringingEnabled() {
return this._fringingEnabled;
}
set toneMapping(value) {
if (this._toneMapping !== value) {
this._toneMapping = value;
this._shaderDirty = true;
}
}
get toneMapping() {
return this._toneMapping;
}
set sharpness(value) {
if (this._sharpness !== value) {
this._sharpness = value;
this._shaderDirty = true;
}
}
get sharpness() {
return this._sharpness;
}
get isSharpnessEnabled() {
return this._sharpness > 0;
}
postInit() {
this.setClearColor(Color.BLACK);
this.setClearDepth(1.0);
this.setClearStencil(0);
}
frameUpdate() {
const rt = this.renderTarget ?? this.device.backBuffer;
const srgb = rt.isColorBufferSrgb(0);
const neededGammaCorrection = srgb ? GAMMA_NONE : GAMMA_SRGB;
if (this._gammaCorrection !== neededGammaCorrection) {
this._gammaCorrection = neededGammaCorrection;
this._shaderDirty = true;
}
if (this._shaderDirty) {
this._shaderDirty = false;
const gammaCorrectionName = gammaNames[this._gammaCorrection];
const key = `${this.toneMapping}` + `-${gammaCorrectionName}` + `-${this.bloomTexture ? 'bloom' : 'nobloom'}` + `-${this.cocTexture ? 'dof' : 'nodof'}` + `-${this.blurTextureUpscale ? 'dofupscale' : ''}` + `-${this.ssaoTexture ? 'ssao' : 'nossao'}` + `-${this.gradingEnabled ? 'grading' : 'nograding'}` + `-${this.colorLUT ? 'colorlut' : 'nocolorlut'}` + `-${this.vignetteEnabled ? 'vignette' : 'novignette'}` + `-${this.fringingEnabled ? 'fringing' : 'nofringing'}` + `-${this.taaEnabled ? 'taa' : 'notaa'}` + `-${this.isSharpnessEnabled ? 'cas' : 'nocas'}` + `-${this._debug ?? ''}`;
if (this._key !== key) {
this._key = key;
const defines = new Map();
defines.set('TONEMAP', tonemapNames[this.toneMapping]);
defines.set('GAMMA', gammaCorrectionName);
if (this.bloomTexture) defines.set('BLOOM', true);
if (this.cocTexture) defines.set('DOF', true);
if (this.blurTextureUpscale) defines.set('DOF_UPSCALE', true);
if (this.ssaoTexture) defines.set('SSAO', true);
if (this.gradingEnabled) defines.set('GRADING', true);
if (this.colorLUT) defines.set('COLOR_LUT', true);
if (this.vignetteEnabled) defines.set('VIGNETTE', true);
if (this.fringingEnabled) defines.set('FRINGING', true);
if (this.taaEnabled) defines.set('TAA', true);
if (this.isSharpnessEnabled) defines.set('CAS', true);
if (this._debug) defines.set('DEBUG_COMPOSE', this._debug);
const includes = new Map(ShaderChunks.get(this.device, this.device.isWebGPU ? SHADERLANGUAGE_WGSL : SHADERLANGUAGE_GLSL));
this.shader = ShaderUtils.createShader(this.device, {
uniqueName: `ComposeShader-${key}`,
attributes: {
aPosition: SEMANTIC_POSITION
},
vertexChunk: 'quadVS',
fragmentChunk: 'composePS',
fragmentDefines: defines,
fragmentIncludes: includes
});
}
}
}
execute() {
this.sceneTextureId.setValue(this.sceneTexture);
this.sceneTextureInvResValue[0] = 1.0 / this.sceneTexture.width;
this.sceneTextureInvResValue[1] = 1.0 / this.sceneTexture.height;
this.sceneTextureInvResId.setValue(this.sceneTextureInvResValue);
if (this._bloomTexture) {
this.bloomTextureId.setValue(this._bloomTexture);
this.bloomIntensityId.setValue(this.bloomIntensity);
}
if (this._cocTexture) {
this.cocTextureId.setValue(this._cocTexture);
this.blurTextureId.setValue(this.blurTexture);
}
if (this._ssaoTexture) {
this.ssaoTextureId.setValue(this._ssaoTexture);
}
if (this._gradingEnabled) {
this.bcsId.setValue([
this.gradingBrightness,
this.gradingContrast,
this.gradingSaturation
]);
this.tintId.setValue([
this.gradingTint.r,
this.gradingTint.g,
this.gradingTint.b
]);
}
const lutTexture = this._colorLUT;
if (lutTexture) {
this.colorLUTParams[0] = lutTexture.width;
this.colorLUTParams[1] = lutTexture.height;
this.colorLUTParams[2] = lutTexture.height - 1.0;
this.colorLUTParams[3] = this.colorLUTIntensity;
this.colorLUTParamsId.setValue(this.colorLUTParams);
this.colorLUTId.setValue(lutTexture);
}
if (this._vignetteEnabled) {
this.vignetterParamsId.setValue([
this.vignetteInner,
this.vignetteOuter,
this.vignetteCurvature,
this.vignetteIntensity
]);
}
if (this._fringingEnabled) {
this.fringingIntensityId.setValue(this.fringingIntensity / 1024);
}
if (this.isSharpnessEnabled) {
this.sharpnessId.setValue(math.lerp(-0.125, -0.2, this.sharpness));
}
super.execute();
}
}
export { RenderPassCompose };