KhronosGroup / glTF-Sample-Viewer

Physically-Based Rendering in glTF 2.0 using WebGL
Apache License 2.0
1.27k stars 234 forks source link

Question on perspective divide #451

Closed UX3D-becher closed 1 year ago

UX3D-becher commented 1 year ago

Wasim Abbas asked this question on Slack

Question on the manual perspective divide here IIUC u_ModelMatrix shouldn’t have any perspective correction in it. In what situations would .w be other than 1.0 where one need this division?

https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/9693a0380cd268f18e7523a3e2b961cda58b3c02/source/Renderer/shaders/primitive.vert#L104

abbaswasim commented 1 year ago

For completeness, on the glTF/general slack channel Jeremy Ong replied:

Looking at it, it feels like the division isn't necessary. A model to world transform really just needs a mat3x4 instead of a full mat4, in which case the 4th matrix row is interpreted as (0,0,0,1). Here though, the model matrix is passed as a full mat4.

I am still interested to know if there are situations where the division might be necessary.

ghost commented 1 year ago

I am not sure what exactly you question.

If you ask because of the division in general, vertex positions are constructed as homogenous coordinates. In that space, a 3D location is not a single object, but rather an equivalence class of scalar multiples of a 4D vector. This allows many useful things, like representing all Euclidean isometries of 3D space to be represented as a matrix and the generalization of points and directions. If you still want to work with plain 3D vectors later in the fragment shader, such as for lighting computation, one would project that 4D vector back into the 3D hyper-plane $w = 1$.

On the other hand, if you ask why we need the division in that place, it is because the input vertex might not yet be on the 3D hyper-plane $w = 1$.

Does that answer your question?

abbaswasim commented 1 year ago

@UX3D-eckerlein I do understand why one would use homogenous coordinates. My question is related to the latter.

it is because the input vertex might not yet be on the 3D hyper-plane $w=1$

How is that possible? If you look at the u_ModelMatrix coming in, it should only have translation, scale and rotation. No chance of any perspective-ness i.e. the last row will be 0, 0, 0, 1. The a_position attribute itself can only be 3D vector as per the glTF spec hence its $w=1$ always. The getPosition(); method transforms vertex position if skinning or morphing is present which I believe shouldn't have anything other than TRS either. So I am not sure why would you need the division by w to bring the vertex into the 3D hyper-plane where $w=1$. It's already there.

In other words if I don't do this division. How can I tell the output is wrong (I tried to run the demo locally but haven't managed to run it yet)?

ghost commented 1 year ago

I see your point. The vertex shader still could introduce $w \ne 1$ even though the vertex position input is strictly 3D and the model matrix decomposable into TRS, but this does not seem to be the case, since the spec only allows:

So one could indeed skip the division and still get the same result.

abbaswasim commented 1 year ago

Thanks. Outside the glTF world. I see this seems to be in a few places thats why I was looking for explanation. Like metal gilt viewer and in google filament to name a few.