fix: apply Color LUT in correct sRGB color space#8747
Merged
Conversation
LUTs authored in tools like Photoshop and Unreal are encoded in sRGB display space — both their lookup coordinates and stored values are sRGB. The compose pass was indexing the LUT with linear values and treating the sampled sRGB value as linear, producing visibly desaturated and dim output for aggressive LUTs. With gentle LUTs the mismatch was mostly invisible. The compose shader (GLSL and WGSL) now encodes the linear input to sRGB for the LUT lookup coordinate. The LUT texture is expected to be loaded in an sRGB pixel format so the hardware sampler decodes the LUT values to linear on sample, which is then blended with the linear scene directly. RenderPassCompose.set colorLUT runs a debug-build validation that checks the texture srgb, mipmaps, minFilter and magFilter and emits a single Debug.warnOnce listing the settings the LUT needs. Fixed #8527
mvaligursky
added a commit
to playcanvas/developer-site
that referenced
this pull request
May 18, 2026
…964) Adds a Color LUT subsection to the HDR Rendering guide covering how to load and use CameraFrame.colorLUT with the texture-format contract introduced in playcanvas/engine#8747 (sRGB on, mipmaps off, linear filtering). Includes the Unreal-format layout description, required texture settings with rationale, a full asset-loading + assignment code snippet, the authoring workflow, and embedded neutral and cherry example LUTs as visual references. The CameraFrame index page LUT bullet links to the new section. Japanese mirror updated to match. Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes incorrect color output when
CameraFrame.colorLUTis used with non-trivial LUTs.LUTs authored in tools like Photoshop and Unreal are encoded in sRGB display space — both their lookup coordinates and stored values are sRGB. The compose pass was indexing the LUT with linear values and treating the sampled sRGB value as linear, producing visibly desaturated and dim output for aggressive LUTs (#8527). With gentle LUTs the mismatch was mostly invisible; with strong tints it was significant.
Changes:
powper pixel in the LUT path.RenderPassCompose.set colorLUTruns a debug-build validation (wrapped inDebug.call, stripped in release) that checks the texture'ssrgb,mipmaps,minFilterandmagFilterand emits a singleDebug.warnOncelisting exactly which settings the LUT needs.API note:
LUT textures must now be loaded with
srgb: true,mipmaps: false, andFILTER_LINEARfor both min and mag filters. Existing code that loaded LUTs with default options will get a one-time debug warning naming exactly what to change, e.g.:Before:
After:
In the PlayCanvas Editor, tick sRGB, untick Mipmaps, and set the filter dropdown to Linear on the LUT texture asset.
Examples:
graphics/hdrexample to load itslut-blueasset with the required settings.Assets:
examples/assets/cube-luts/lut-neutral.png(identity LUT) andlut-cherry.png(aggressive red LUT) for use in a follow-up dedicated LUT example.Fixed #8527