Skip to content
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

Cc/fix dark surfaces #26

Merged
merged 1 commit into from
Apr 14, 2022
Merged

Cc/fix dark surfaces #26

merged 1 commit into from
Apr 14, 2022

Conversation

ChristopherChudzicki
Copy link
Collaborator

@ChristopherChudzicki ChristopherChudzicki commented Apr 11, 2022

What are the relevant tickets? #25

Note that #25 mentions two issues: dark surfaces and black gridlines. This addresses the dark surfaces, NOT the gridlines. I believe I understand how to fix that, too, but want to write some js tests for it.

What does this PR do?

This PR replaces existing usage of gl_FrontFacing with a cross-product workaround; gl_FrontFacing seems not to be behaving how mathbox expected.

How should this be manually tested

  1. On this branch, npm run build
  2. Open examples/test/surface.html. Change the mathbox line to <script type="text/javascript" src="../../build/bundle/mathbox.js"></script> to use local build
  3. Optionally, comment out the lineX and lineY bits at end of surface.html. The affect is more proncounced without the gridlines

Master / This branch
Screen Shot 2022-04-10 at 10 40 46 PM / Screen Shot 2022-04-10 at 10 40 17 PM

@@ -16,7 +18,12 @@ vec4 getShadedColor(vec4 rgba) {
vec3 light = normalize(vLight);
vec3 position = normalize(vPosition);
float side = gl_FrontFacing ? -1.0 : 1.0;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@sritchie If you feel like futzing with this, try using gl_FrontFacing ? +1.0 : - 1.0...you'll see both sides of the surface turn light.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This one seems to bite many folks. I've been reading up on it, and would NOT have found this on my own. Great find on this fix.

gl_FrontFacing seems to be causing an issue with shaded surfaces. Some data:
  - using `side = gl_FrontFacing ? -1.0 : 1.0` worked in mathbox-0.0.5 (Also on znah's fork using r84)
  - using `side = glFrontFacting ? -1.0 : 1.0` appears to be rendering both sides of a DoubleSided surface as "dark" (the back side) on current mathbox.
  - switching to `side = 1.0` renders both sides as light; `side = -1.0` renders both sides as dark.

The workaround in this commit requires a WebGL standard_derivatives extension. This workaround was suggested in https://www.reddit.com/r/glsl/comments/3q8kn2/gl_frontfacing_on_a_mac/

I do not understand why gl_FrontFacing worked on mathbox 0.0.5 but not hte current version. Something to do with threejs upgrades? Unsure.
// Workaround to avoid gl_FrontFacing. See https://github.com/unconed/mathbox/pull/26
vec3 pdx = dFdx(vPosition);
vec3 pdy = dFdy(vPosition);
bool frontFacting = dot(vNormal, cross(pdx, pdy)) > 0.0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

whoops, slight typo with frontFacting vs frontFacing.

Wow, there is some magic going on in glsl. SO, indulge me in trying to understand what this does:

  • dfDx and dfDy must return vectors; are they giving the derivative of the x and y components of vPosition?
  • If that's right, the cross product will always be orthogonal... so we care if the magnitude is positive or negative.
  • and then dot(...) > 0 is telling us, "is vNormal pointing in the same direction"

But I am missing my concepts here, since I would have expected vNormal to be in reference to some plane... ah!!

I would love a one sentence description of the algorithm here for my own edification, and probably for future folks trying to debug.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

To be honest, I am not 100% clear on the coordinate systems involved here. I think the following sentence would be accurate:

"vNormal (calculated in the vertex shader) and cross(pdx, pdy) (calculated in this fragment shader) are both surface normals, but might be in opposite directions depending on which side of the surface the camera is, hence dot product".

My impression is that vNormal is calculated differently for the different objects, that's why there's surface.position.normal, face.position.normal, and strip.position.normal. [(but represents a surface normal in all cases), but represents a surface normal in all three cases.]
If you look at how vNormal in surface.position.normal is calculated, you'll see its also basically a cross product of derivatives. But I suspect the coordinates are slightly different (potentially reversed) hence the two cross products may differ in direction. (Experimentally, they definitely do differ in direction, since both conditions in the frontFacing ? 1.0 : -1.0 are getting triggered.)

Understanding the shader stuff better is definitely a goal :/ I'm hoping not to tinker with it too much.

In terms of posterity... I decided just leave a link to the PR as the code comment. (Though git history does that, too).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In particular, one thing I am confused about is getPosition in the shaders. A lot of the vertex shaders include

// External
vec3 getPosition(vec4 xyzw, float canonical);

and then getPosition is used. But I can't find where the heck this "External" function is coming from...

@sritchie
Copy link
Collaborator

Just a couple of comments. Excellent work!

@sritchie sritchie merged commit e0240a6 into master Apr 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants