akgunter/crt-royale-reshade

Diffusion Interacts Incorrectly With Halation

akgunter opened this issue · 3 comments

Diffusion and Halation are closely related effects that should interact with each other.

I don't think they're interacting correctly, though. When diffusion is set to 1.0, halation is completely disabled.

Adding some notes for myself, since I've been mulling over this.

  • Halation is caused by electrons inside the CRT bouncing around under the phosphors and illuminating them. This results in a Gaussian blur effect. It affects all color channels equally, so it also causes a desaturation effect.
  • Halation happens inside the CRT, so it precedes the phosphor mask, diffusion, and bloom. Due to conservation of energy, increased halation corresponds to reduced intensity of the electron beam.
  • Diffusion happens inside the glass in front of the phosphors, resulting from imperfections in the glass and possibly from refraction. This should also be a Gaussian blur, so it will reduce the intensity of the light emitted by the phosphors.
  • Diffusion will preserve the colors produced by the phosphors, so there will be a blurring effect but no desaturation.
  • Diffusion will inherit the desaturation effect from halation and will further blur the image.
  • Bloom occurs in the player's eyes, or a camera, or any other lens observing the CRT. It corresponds to bright colors bleeding over into dark ones due to lensing and such. There's a wiki page about it. The point is that It sits on top of diffusion. Technically it's subject to a conservation of energy, but we can probably ignore that.

As an observation, diffusion and halation are fundamentally one blurring function composed with itself. The original crt-royale opted to trade accuracy for efficiency and used one instance of that function for both effects, without composition. The consequence of that tradeoff is that diffusion dominates halation as-is. The fix is probably going to be a second round of blur passes. It's unlikely the performance hit will be worth the improvement in correctness.

I figured out an easy fix for the approximation.

Calculate halation as before.
Calculate diffusion by first sampling the blurApprox texture. Then calculate halation of that sample. Then lerp between the two w.r.t. the halation weight to desaturate the diffusion color. Then use the diffusion weight to lerp this desaturated diffusion value as before. The result is that the diffusion color will have the same saturation as the halation color.

The tradeoff is that both halation and diffusion will have the same radius. An accurate implementation would end up with diffusion spreading out further than halation, and both could have their own radii. However in practice, the vast majority of people will choose weights that make this approximation imperceptible. So it's not worth the cost of running two separate blurring passes.

Relased in v2.0.0