Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions apps/typegpu-docs/src/components/hero-effect/hero-effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ const Uniforms = d.struct({
modelMatrix: d.mat4x4f,
});

// Page backgrounds (in sRGB) the canvas is composited onto, matching `bg-white` and `bg-navy-bg`
const lightBackground = d.vec3f(1);
const darkBackground = d.vec3f(35 / 255, 39 / 255, 54 / 255);

function isDarkMode() {
return document.documentElement.dataset.theme === 'dark' ? 1 : 0;
}

export async function initHeroEffect(options: HeroEffectOptions) {
const { root, context } = options;
const canvas = context.canvas as HTMLCanvasElement;
Expand All @@ -32,6 +40,7 @@ export async function initHeroEffect(options: HeroEffectOptions) {
}

const uniforms = root.createUniform(Uniforms);
const darkMode = root.createUniform(d.u32, isDarkMode());
const fsampler = root.createSampler({
minFilter: 'linear',
magFilter: 'linear',
Expand Down Expand Up @@ -140,8 +149,17 @@ export async function initHeroEffect(options: HeroEffectOptions) {
);

const grayscale = d.vec4f(d.vec3f(c2.x + c2.y + c2.z + 0.8) * tint, 1) * 0.5 * c2.w;

return std.mix(grayscale, c2, std.smoothstep(0, 0.2, downSample));
const result = std.saturate(std.mix(grayscale, c2, std.smoothstep(0, 0.2, downSample)));

// The canvas is premultiplied, and the effect relies on color exceeding alpha (additive light).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if this is a good idea that the effect relies on undefined behavior (source).

Clamping against the page background does not guarantee that color <= alpha.
See:

Image

Legend:

  • x -> alpha
  • y -> color
  • b -> arbitrary channel from background color

// The compositor outputs `color + background * (1 - alpha)`, which can go above 1.0 and
// make the display switch to HDR. Clamping against the page background keeps it within range.
let background = d.vec3f(lightBackground);
if (darkMode.$ === 1) {
background = d.vec3f(darkBackground);
}
Comment on lines +157 to +160

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let background = d.vec3f(lightBackground);
if (darkMode.$ === 1) {
background = d.vec3f(darkBackground);
}
const background = darkMode.$ === 1 ? d.vec3f(darkBackground) : d.vec3f(lightBackground);

const maxColor = 1 - background * (1 - result.w);
return d.vec4f(std.min(result.xyz, maxColor), result.w);
});

const postProcessPipeline = root.createRenderPipeline({
Expand All @@ -165,6 +183,7 @@ export async function initHeroEffect(options: HeroEffectOptions) {
}

fluidSim.update(timestamp);
darkMode.write(isDarkMode());

const viewProjection = mat4.perspective(
0.5,
Expand Down Expand Up @@ -236,6 +255,7 @@ export async function initHeroEffect(options: HeroEffectOptions) {
fluidSim.destroy();
screenTextures.destroy();
uniforms.buffer.destroy();
darkMode.buffer.destroy();
model.destroy();
},
};
Expand Down
Loading