Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add engine option for using exact sRGB conversions in the shader. #12750

Merged
17 changes: 17 additions & 0 deletions packages/dev/core/src/Engines/thinEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ export interface EngineOptions extends WebGLContextAttributes {
* This will not influence NativeEngine and WebGPUEngine which set the behavior to true during construction.
*/
forceSRGBBufferSupportState?: boolean;
/**
* True if the more expensive but exact conversions should be used for transforming colors to and from linear space within shaders.
* Otherwise, the default is to use a cheaper approximation.
*/
useExactSrgbConversions?: boolean;
}

/**
Expand Down Expand Up @@ -698,6 +703,14 @@ export class ThinEngine {
this._snapshotRenderingMode = mode;
}

protected _useExactSrgbConversions = false;
/**
* Gets a boolean indicating if the exact sRGB conversions or faster approximations are used for converting to and from linear space.
*/
public get useExactSrgbConversions(): boolean {
return this._useExactSrgbConversions;
}

/**
* Creates a new snapshot at the next frame using the current snapshotRenderingMode
*/
Expand Down Expand Up @@ -815,6 +828,10 @@ export class ThinEngine {
options.xrCompatible = true;
}

if (options.useExactSrgbConversions !== undefined) {
this._useExactSrgbConversions = options.useExactSrgbConversions;
}

this._doNotHandleContextLost = options.doNotHandleContextLost ? true : false;

// Exceptions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ class BackgroundMaterialDefines extends MaterialDefines implements IImageProcess
public SKIPFINALCOLORCLAMP = false;
public EXPOSURE = false;
public MULTIVIEW = false;
public USEEXACTSRGBCONVERSIONS = false;
kircher1 marked this conversation as resolved.
Show resolved Hide resolved

// Reflection.
public REFLECTION = false;
Expand Down Expand Up @@ -832,7 +833,7 @@ export class BackgroundMaterial extends PushMaterial {
return false;
}

this._imageProcessingConfiguration.prepareDefines(defines);
this._imageProcessingConfiguration.prepareDefines(defines, false, engine.useExactSrgbConversions);
}

// Misc.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class ImageProcessingBlock extends NodeMaterialBlock {

public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
if (defines._areImageProcessingDirty && nodeMaterial.imageProcessingConfiguration) {
nodeMaterial.imageProcessingConfiguration.prepareDefines(defines);
nodeMaterial.imageProcessingConfiguration.prepareDefines(defines, false, mesh.getEngine().useExactSrgbConversions);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
}

if (defines._areImageProcessingDirty && nodeMaterial.imageProcessingConfiguration) {
nodeMaterial.imageProcessingConfiguration.prepareDefines(defines);
nodeMaterial.imageProcessingConfiguration.prepareDefines(defines, false, mesh.getEngine().useExactSrgbConversions);
}

if (!defines._areLightsDirty) {
Expand Down
1 change: 1 addition & 0 deletions packages/dev/core/src/Materials/Node/nodeMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export class NodeMaterialDefines extends MaterialDefines implements IImageProces
public SAMPLER3DBGRMAP = false;
public IMAGEPROCESSINGPOSTPROCESS = false;
public SKIPFINALCOLORCLAMP = false;
public USEEXACTSRGBCONVERSIONS = false;

/** MISC. */
public BUMPDIRECTUV = 0;
Expand Down
3 changes: 2 additions & 1 deletion packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ export class PBRMaterialDefines extends MaterialDefines implements IImageProcess
public MULTIVIEW = false;
public ORDER_INDEPENDENT_TRANSPARENCY = false;
public ORDER_INDEPENDENT_TRANSPARENCY_16BITS = false;
public USEEXACTSRGBCONVERSIONS = false;

public USEPHYSICALLIGHTFALLOFF = false;
public USEGLTFLIGHTFALLOFF = false;
Expand Down Expand Up @@ -1800,7 +1801,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
}

if (defines._areImageProcessingDirty && this._imageProcessingConfiguration) {
this._imageProcessingConfiguration.prepareDefines(defines);
this._imageProcessingConfiguration.prepareDefines(defines, false, mesh.getEngine().useExactSrgbConversions);
}

defines.FORCENORMALFORWARD = this._forceNormalForward;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface IImageProcessingConfigurationDefines {
SAMPLER3DBGRMAP: boolean;
IMAGEPROCESSINGPOSTPROCESS: boolean;
SKIPFINALCOLORCLAMP: boolean;
USEEXACTSRGBCONVERSIONS: boolean;
}

/**
Expand All @@ -52,6 +53,7 @@ export class ImageProcessingConfigurationDefines extends MaterialDefines impleme
public IMAGEPROCESSINGPOSTPROCESS = false;
public EXPOSURE = false;
public SKIPFINALCOLORCLAMP = false;
public USEEXACTSRGBCONVERSIONS = false;

constructor() {
super();
Expand Down Expand Up @@ -464,8 +466,9 @@ export class ImageProcessingConfiguration {
* Prepare the list of defines associated to the shader.
* @param defines the list of defines to complete
* @param forPostProcess Define if we are currently in post process mode or not
* @param useExactSrgbConversions true if the engine is using exact srgb conversions
*/
public prepareDefines(defines: IImageProcessingConfigurationDefines, forPostProcess: boolean = false): void {
public prepareDefines(defines: IImageProcessingConfigurationDefines, forPostProcess = false, useExactSrgbConversions = false): void {
if (forPostProcess !== this.applyByPostProcess || !this._isEnabled) {
defines.VIGNETTE = false;
defines.TONEMAPPING = false;
Expand All @@ -476,6 +479,7 @@ export class ImageProcessingConfiguration {
defines.COLORGRADING = false;
defines.COLORGRADING3D = false;
defines.IMAGEPROCESSING = false;
defines.USEEXACTSRGBCONVERSIONS = useExactSrgbConversions;
defines.SKIPFINALCOLORCLAMP = this.skipFinalColorClamp;
defines.IMAGEPROCESSINGPOSTPROCESS = this.applyByPostProcess && this._isEnabled;
return;
Expand All @@ -495,6 +499,8 @@ export class ImageProcessingConfiguration {
break;
}

defines.USEEXACTSRGBCONVERSIONS = useExactSrgbConversions;

defines.CONTRAST = this.contrast !== 1.0;
defines.EXPOSURE = this.exposure !== 1.0;
defines.COLORCURVES = this.colorCurvesEnabled && !!this.colorCurves;
Expand Down
4 changes: 4 additions & 0 deletions packages/dev/core/src/Materials/shaderMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,10 @@ export class ShaderMaterial extends PushMaterial {
}
}

if (engine.useExactSrgbConversions) {
defines.push("#define USEEXACTSRGBCONVERSIONS");
}

if (this.customShaderNameResolve) {
uniforms = uniforms.slice();
uniformBuffers = uniformBuffers.slice();
Expand Down
3 changes: 2 additions & 1 deletion packages/dev/core/src/Materials/standardMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr
public MULTIVIEW = false;
public ORDER_INDEPENDENT_TRANSPARENCY = false;
public ORDER_INDEPENDENT_TRANSPARENCY_16BITS = false;
public USEEXACTSRGBCONVERSIONS = false;

/**
* If the reflection texture on this material is in linear color space
Expand Down Expand Up @@ -1122,7 +1123,7 @@ export class StandardMaterial extends PushMaterial {
return false;
}

this._imageProcessingConfiguration.prepareDefines(defines);
this._imageProcessingConfiguration.prepareDefines(defines, false, engine.useExactSrgbConversions);

defines.IS_REFLECTION_LINEAR = this.reflectionTexture != null && !this.reflectionTexture.gammaSpace;
defines.IS_REFRACTION_LINEAR = this.refractionTexture != null && !this.refractionTexture.gammaSpace;
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/core/src/Particles/gpuParticleSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1339,7 +1339,7 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
}

if (this._imageProcessingConfiguration) {
this._imageProcessingConfiguration.prepareDefines(this._imageProcessingConfigurationDefines);
this._imageProcessingConfiguration.prepareDefines(this._imageProcessingConfigurationDefines, false, this._engine.useExactSrgbConversions);
defines.push("" + this._imageProcessingConfigurationDefines.toString());
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/core/src/Particles/particleSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1805,7 +1805,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
}

if (this._imageProcessingConfiguration) {
this._imageProcessingConfiguration.prepareDefines(this._imageProcessingConfigurationDefines);
this._imageProcessingConfiguration.prepareDefines(this._imageProcessingConfigurationDefines, false, this._engine.useExactSrgbConversions);
defines.push(this._imageProcessingConfigurationDefines.toString());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ export class ImageProcessingPostProcess extends PostProcess {
COLORGRADING: false,
COLORGRADING3D: false,
FROMLINEARSPACE: false,
USEEXACTSRGBCONVERSIONS: false,
SAMPLER3DGREENDEPTH: false,
SAMPLER3DBGRMAP: false,
IMAGEPROCESSINGPOSTPROCESS: false,
Expand Down Expand Up @@ -407,7 +408,7 @@ export class ImageProcessingPostProcess extends PostProcess {
*/
public _updateParameters(): void {
this._defines.FROMLINEARSPACE = this._fromLinearSpace;
this.imageProcessingConfiguration.prepareDefines(this._defines, true);
this.imageProcessingConfiguration.prepareDefines(this._defines, true, this.getEngine().useExactSrgbConversions);
let defines = "";
for (const define in this._defines) {
if ((<any>this._defines)[define]) {
Expand Down
9 changes: 7 additions & 2 deletions packages/dev/core/src/Rendering/geometryBufferRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -571,13 +571,18 @@ export class GeometryBufferRenderer {
defines.push("#define RENDER_TARGET_COUNT " + this._multiRenderTarget.textures.length);
}

const engine = this._scene.getEngine();
if (engine.useExactSrgbConversions) {
defines.push("#define USEEXACTSRGBCONVERSIONS");
}

// Get correct effect
const drawWrapper = subMesh._getDrawWrapper(undefined, true)!;
const cachedDefines = drawWrapper.defines;
const join = defines.join("\n");
if (cachedDefines !== join) {
drawWrapper.setEffect(
this._scene.getEngine().createEffect(
engine.createEffect(
"geometry",
{
attributes: attribs,
Expand Down Expand Up @@ -611,7 +616,7 @@ export class GeometryBufferRenderer {
uniformBuffersNames: ["Scene"],
indexParameters: { buffersCount: this._multiRenderTarget.textures.length - 1, maxSimultaneousMorphTargets: numMorphInfluencers },
},
this._scene.getEngine()
engine
),
join
);
Expand Down
80 changes: 70 additions & 10 deletions packages/dev/core/src/Shaders/ShadersInclude/helperFunctions.fx
Original file line number Diff line number Diff line change
Expand Up @@ -45,34 +45,94 @@ mat3 inverseMat3(mat3 inMatrix) {
b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;
}

#if USEEXACTSRGBCONVERSIONS
vec3 toLinearSpaceExact(vec3 color)
kircher1 marked this conversation as resolved.
Show resolved Hide resolved
{
vec3 nearZeroSection = 0.0773993808 * color;
vec3 remainingSection = pow(0.947867299 * (color + vec3(0.055)), vec3(2.4));
#if defined(WEBGL2) || defined(WEBGPU)
return mix(remainingSection, nearZeroSection, lessThanEqual(color, vec3(0.04045)));
#else
kircher1 marked this conversation as resolved.
Show resolved Hide resolved
return
vec3(
color.r <= 0.04045 ? nearZeroSection.r : remainingSection.r,
color.g <= 0.04045 ? nearZeroSection.g : remainingSection.g,
color.b <= 0.04045 ? nearZeroSection.b : remainingSection.b);
#endif
}

vec3 toGammaSpaceExact(vec3 color)
{
vec3 nearZeroSection = 12.92 * color;
vec3 remainingSection = 1.055 * pow(color, vec3(0.41666)) - vec3(0.055);
#if defined(WEBGL2) || defined(WEBGPU)
return mix(remainingSection, nearZeroSection, lessThanEqual(color, vec3(0.0031308)));
#else
return
vec3(
color.r <= 0.0031308 ? nearZeroSection.r : remainingSection.r,
color.g <= 0.0031308 ? nearZeroSection.g : remainingSection.g,
color.b <= 0.0031308 ? nearZeroSection.b : remainingSection.b);
#endif
}
#endif

float toLinearSpace(float color)
{
return pow(color, LinearEncodePowerApprox);
#if USEEXACTSRGBCONVERSIONS
float nearZeroSection = 0.0773993808 * color;
float remainingSection = pow(0.947867299 * (color + 0.055), 2.4);
return color <= 0.04045 ? nearZeroSection : remainingSection;
#else
return pow(color, LinearEncodePowerApprox);
#endif
}

vec3 toLinearSpace(vec3 color)
{
return pow(color, vec3(LinearEncodePowerApprox));
#if USEEXACTSRGBCONVERSIONS
return toLinearSpaceExact(color);
#else
return pow(color, vec3(LinearEncodePowerApprox));
#endif
}

vec4 toLinearSpace(vec4 color)
{
return vec4(pow(color.rgb, vec3(LinearEncodePowerApprox)), color.a);
#if USEEXACTSRGBCONVERSIONS
return vec4(toLinearSpaceExact(color.rgb), color.a);
#else
return vec4(pow(color.rgb, vec3(LinearEncodePowerApprox)), color.a);
#endif
}

vec3 toGammaSpace(vec3 color)
float toGammaSpace(float color)
{
return pow(color, vec3(GammaEncodePowerApprox));
#if USEEXACTSRGBCONVERSIONS
float nearZeroSection = 12.92 * color;
float remainingSection = 1.055 * pow(color, 0.41666) - 0.055;
return color <= 0.0031308 ? nearZeroSection : remainingSection;
#else
return pow(color, GammaEncodePowerApprox);
#endif
}

vec4 toGammaSpace(vec4 color)
vec3 toGammaSpace(vec3 color)
{
return vec4(pow(color.rgb, vec3(GammaEncodePowerApprox)), color.a);
#if USEEXACTSRGBCONVERSIONS
return toGammaSpaceExact(color);
#else
return pow(color, vec3(GammaEncodePowerApprox));
#endif
}

float toGammaSpace(float color)
vec4 toGammaSpace(vec4 color)
{
return pow(color, GammaEncodePowerApprox);
#if USEEXACTSRGBCONVERSIONS
return vec4(toGammaSpaceExact(color.rgb), color.a);
#else
return vec4(pow(color.rgb, vec3(GammaEncodePowerApprox)), color.a);
#endif
}

float square(float value)
Expand Down Expand Up @@ -117,7 +177,7 @@ vec4 toRGBD(vec3 color) {
D = clamp(floor(D) / 255.0, 0., 1.);
// vec3 rgb = color.rgb * (D * (255.0 / rgbdMaxRange));
vec3 rgb = color.rgb * D;

// Helps with png quantization.
rgb = toGammaSpace(rgb);

Expand Down
Loading