-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Fix spotlight basis #20272
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
Fix spotlight basis #20272
Conversation
Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke! If it's expected, please add the M-Deliberate-Rendering-Change label. If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this as long as there are no unintended side effects. I’d like if @robtfm could take a look before merging.
one possible reason for the handedness switch might be to make the shadow texture look like a normal view from the light? i guess without the switch it will be mirrored. this isn't very important but might have been useful for debugging when i was originally writing the code. i also can't see any reason why the handedness switch should cause this seam in the lighting example though. i fear that this change is masking the issue rather than fixing it. the only significant change looks to be the shader |
the original code had no handedness switch despite claiming it did: there was a mistranslation where the x and y in the orthonormal basis were flipped. it seems the negation of the x axis was added to correct for this, and it was documented as a handedness flip, but thats a bandage over a mistranslation and not really a handedness flip i tested the copysign stuff separately and it makes no difference, i dont think we have a negative zero in the example |
the original code was copied from glam which seems to still have the same layout so i don't think it's a "mistranslation", just glam's choice of orthonormal basis was different to what i wanted. can you think why else this change might affect the example? annoyingly i don't see the green seam so i can't really investigate. |
Current glam: (
Self::new(1.0 + sign * self.x * self.x * a, sign * b, -sign * self.x),
Self::new(b, sign + self.y * self.y * a, -self.y),
) PR that introduced it: https://github.com/bitshifter/glam-rs/pull/129/files#diff-d0026d63cc96b573d3205664c75e79d503f4602b6d588b79a56d5e100e49ce2bR235 PR that introduced spotlights #4715 : let up_dir = Vec4::new(
1.0 + sign * fwd_dir.x * fwd_dir.x * a,
sign * b,
-sign * fwd_dir.x,
0.0,
);
let right_dir = Vec4::new(-b, -sign - fwd_dir.y * fwd_dir.y * a, fwd_dir.y, 0.0);
Mat4::from_cols(
right_dir,
up_dir,
fwd_dir, Bevy main (after the change i did that broke it, but conforms to glam): let x_basis = Vec3::new(
1.0 + sign * z_basis.x * z_basis.x * a,
sign * b,
-sign * z_basis.x,
);
let y_basis = Vec3::new(b, sign + z_basis.y * z_basis.y * a, -z_basis.y);
Mat3::from_cols(x_basis, y_basis, z_basis.into()) Notice that the original spotlight pr up_dir starts with This is a mistranslation, idk how else to explain it. The other thing to note is that in bevy the |
Also I have a PR open in glam to make the handedness of any_orthonormal_pair explicit: bitshifter/glam-rs#660 The JCGT paper doesn't specify handedness anywhere, but it does specify it is of consistent handedness. I then read Frisvad's paper, which also didnt specify handedness, and then dug into the source accompanying the paper, and found that it was just using a right-handed (standard) cross product to get the third basis vector, after choosing the second one. So its a right handed basis that glam has, assuming you interpret the tuple as (x, y) given a z as input |
I had concerns about for example a light cookie on a spotlight being mirrored, but i don't think thats something that we can even worry about realistically with this code, as consistent rotation of the light cookie would be far more important to get right, and this code cannot specify rotation as it just uses the z direction and reconstructs the rest. I believe the light texture implementation we have just takes a different approach using clustering, which has a different basis. So this basis is only relevant for shadowmap sampling. I believe the reason the handedness flip makes things weird is that the shadow bias factors would be inverted, causing them to be applied in the wrong direction, but thats just conjecture. |
ah i understand ... with the x_axis flip, the the cube is casting shadows from the inside only. this is more-or-less ok for a cube and explains why it looks like the top plane is missing. setting so i'm happy this is the right fix, and that there's no further issue. |
i more am just following what the paper specifies, glam lost the semantic there. It also discarded the semantic of it even being a consistently handed basis. "Any orthonormal pair" could be any handedness, but its not. Its a good point that the API is not explicitly x,y: i should update my PR bitshifter/glam-rs#660 to make that explicit in the return type somehow.
yeah thats what i figured, im not sure it would be correct to automatically "correct" this though, as the semantics of negative scale arent clear. The inside should be the outside if you flip it, no? |
the fix you're doing here stops the spotlight view from ivnerting winding and that's why it fixes this problem. we shouldn't do anything else |
It looks like this also fixed the At least, this changed the example to how it used to render, which looks better to me. |
Objective
bestRanar:
Solution
It turns out, i accidentally unflipped the x and y axis in the basis construction of spotlights to actually match the JCGT paper. This wasn't something i realized at the time, but its just a handedness flip. This means that the handedness flip Aceeri was asking about in #20191 which I just extracted from the orthonormalize implementation was just there to correct for a mistranslation in the original implementation, probably.
So this means we can just yeet it, because two handedness flips means none at all. And indeed, removing the extra flip fixes the regression. So now the code is more straightforward and understandable and it works :D
Most of the diff is updating the comments to reflect this new knowledge.
Testing