gfxfundamentals / webgl2-fundamentals

WebGL 2 lessons starting from the basics
https://webgl2fundamentals.org
BSD 3-Clause "New" or "Revised" License
1.72k stars 214 forks source link

Bugs with code in WebGL2 3D Perspective Section #168

Open molicaca opened 2 years ago

molicaca commented 2 years ago

Describe the bug It seems some codes are wrong in the first example of 3D Perspective Section.

To Reproduce Steps to reproduce the behavior:

  1. Go to the first example in 3D Perspective Section
  2. Change the x, y position to get the object in the center of canvas
  3. Add the X angle to around 263

Expected behavior Then in the result figure, the model seems to be worn, just like below image

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Additional context Also, the code in that example also gets wrong. In this code "float zToDivideBy = 1.0 + position.z u_fudgeFactor;" it should be "float zToDivideBy = (1.0 + position.z) u_fudgeFactor;".

greggman commented 2 years ago

Thanks for the report and sorry it's confusing

The first example is manually dividing by Z. The problem with manually dividing by Z is the sign is lost. Example (-6 / -3 = 2). -6 and -3 are negative but after dividing the result is positive.

This is one reason why the space the shader returns is called "clip space" because once the sign is lost it's impossible to clip the triangle correctly all the vertices that are z < 0 get flipped to a positive value.

So, what really happens is your shader returns vertices in clip space by setting gl_Position. Every 3 vertices make a triangle in clip space, that triangle is clipped in clip space, and after that step the vertices are divided by W.

You can see if you take the 2nd example on the page where we let WebGL do the division it shows the correct image

Screen Shot 2022-06-01 at 6 23 59 PM

Sorry if that was confusing.

The point of the first example it to show that dividing by Z will give you the illusion of perspective.

The point of the second example it to show that WebGL does

vertex = gl_Position.xyz / gl_Position.z

It divides by Z for you so you don't do the division yourself like the first example, you let WebGL do it.

I should probably put more details to show why you let WebGL do it.

greggman commented 2 years ago

as for

Also, the code in that example also gets wrong. In this code "float zToDivideBy = 1.0 + position.z u_fudgeFactor;" it should be "float zToDivideBy = (1.0 + position.z) u_fudge

You might be right. For me, it didn't really matter. What mattered was that the image looks like it has perspective (things further away are smaller than things that are near).

Once we've established that dividing by Z gives the illusion of perspective we can go to step 3 and show we can achieve this division using matrices

And step 4 is that there is magic math (math that is unexplained) that will compute a matrix that will give us perspective based on field of view, aspect, near, and far inputs.