X Tutup
Skip to content

Avoid singularity during sky filtering#114279

Merged
Repiteo merged 1 commit intogodotengine:masterfrom
clayjohn:sky-singularity
Jan 6, 2026
Merged

Avoid singularity during sky filtering#114279
Repiteo merged 1 commit intogodotengine:masterfrom
clayjohn:sky-singularity

Conversation

@clayjohn
Copy link
Member

@clayjohn clayjohn commented Dec 22, 2025

Fixes part of: #113676

This switches the singularity to be on the y axis instead of the z.

Previously the singularity wasn't a big deal since only one or fewer pixels would have a z value of exactly 0 since the poles were in the center of the cubemap faces where there is the least distortion. But since octahedral mapping warps space different the z-axis poles are directly on seams, which lead to a huge increase in the amount of distortion

This PR switches to using the y-axis because it isn't on a seam and has a low amount of distortion. This removes the obvious stretching artifacts as well as the little circle.

However, it does not fully close the PR since there are other quality differences resulting from using octahedral coordinates. Importantly, I notice a difference in the contrast for fully rough materials. (Actually, that may not be a regression. The difference may actually be more correct see #108273)

@clayjohn clayjohn added this to the 4.6 milestone Dec 22, 2025
@clayjohn clayjohn requested a review from a team as a code owner December 22, 2025 06:36
@BlueCube3310
Copy link
Contributor

Tested locally, it fixes the singularity but also introduces seams on the higher roughness levels:
new_seam

There are also some very slight 'splotchy' artifacts on the rough levels, though that could be a different issue.
new

When viewed in Renderdoc, the seam is X-shaped:
new_X

@clayjohn
Copy link
Member Author

Very interesting, I'm not seeing those artifacts locally. I will have to test on a different device. That "X" artifact is right along certain fold lines in the octahedral map. So it looks like there is an edge case that isn't being handled properly

@BlueCube3310
Copy link
Contributor

The algorithm tends to 'snap' the tangent/bitangent at certain normals:
Normal: ( * 0.5 + 0.5 to avoid negative values in preview)
normal
Tangent:
tangent
Bitangent:
bitangent

@clayjohn
Copy link
Member Author

clayjohn commented Jan 5, 2026

That's right. The algorithm follows a different codepath for the +Z/-Z hemispheres. However, the paper claims that the result should be continuous. So I need to figure out why it isn't

@clayjohn
Copy link
Member Author

clayjohn commented Jan 5, 2026

@BlueCube3310 I'll push a fix momentarily that gets rid of the discontinuity and removes the stretching at the poles. The correct solution turned out to be very simple. But this won't be enough to close #113676 since the appearance is still different

Copy link
Contributor

@BlueCube3310 BlueCube3310 left a comment

Choose a reason for hiding this comment

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

LGTM, while some distortion is visible on the lower hemisphere, it's nowhere near as obvious as it used to be.
singularity
singularity2
roumetal

Some 'splotching' is still visible on the rough materials, though it can be improved later on as it's not really noticeable.

@Repiteo Repiteo merged commit f5c66ba into godotengine:master Jan 6, 2026
20 checks passed
@Repiteo
Copy link
Contributor

Repiteo commented Jan 6, 2026

Thanks!

@clayjohn
Copy link
Member Author

clayjohn commented Jan 6, 2026

@BlueCube3310 Thank you for checking!

Some 'splotching' is still visible on the rough materials, though it can be improved later on as it's not really noticeable.

I think the way to fix this is to use an approach more similar to what we do in the compatibility renderer which is to precompute samples ahead of time and vary the sample count based on roughness level (as described here: https://placeholderart.wordpress.com/2015/07/28/implementation-notes-runtime-environment-map-filtering-for-image-based-lighting/).

The trick is that the first few levels only need a few samples while the rough levels need a lot more. Right now we use a fixed amount that is overkill for the first couple of levels and not enough for the last couple. If we distribute the samples more towards the rougher levels, we will get improved quality at basically no cost.

In the compatibility renderer, we do that on the CPU and pass in the samples through a uniform. But Seb Lagarde (from Frostbite) left an interesting comment on the post I linked above saying that they precompute the samples in the compute shader using group shared memory. Which is probably what we would want to do too.

Is this something you would like to experiment with yourself?

@BlueCube3310
Copy link
Contributor

Is this something you would like to experiment with yourself?

I would like to, but I will most likely not have the time for it during the next month or so.

@clayjohn
Copy link
Member Author

clayjohn commented Jan 9, 2026

Is this something you would like to experiment with yourself?

I would like to, but I will most likely not have the time for it during the next month or so.

Fair enough!

rivie13 pushed a commit to rivie13/Phoenix-Agentic-Engine that referenced this pull request Feb 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

X Tutup