LDraw.org Discussion Forums
Problem with normals when building my own LDraw interpreter. - Printable Version

+- LDraw.org Discussion Forums (https://forums.ldraw.org)
+-- Forum: General (https://forums.ldraw.org/forum-12.html)
+--- Forum: Help (https://forums.ldraw.org/forum-13.html)
+--- Thread: Problem with normals when building my own LDraw interpreter. (/thread-23274.html)



Problem with normals when building my own LDraw interpreter. - Lasse Boijens - 2019-03-12

So first of all, as a little announcement, I've started work on a virtual reality lego builder, which I'm really excited for, and a lot of the work's already done, but I've only recently started on the work for actually allowing the LDraw .dat files to be used to load in bricks instead of inefficiently storing the bricks as models. I'm using the game engine unity since I have a reasonable amount of experience with it and integrating VR is easy-peasy, but now I'm having problems getting the normals to display correctly.

I'm aware of BFC and winding, and I've taken an example of little bits and bobs from the old LDrawToObj convertor from Rold Redford (https://github.com/rredford/LdrawToObj) and that got me most of the way there, but now I'm stuck with some issues with faces not having correct normals. I have to admit I think that it's a bit difficult to explain why this is happening since I don't really know what I'm missing, but I hope that when I share some images and examples other people might be able to help me out. I can post the C# code I'm using if anyone thinks it'll help, but it's fairly messy and lacking comments so I don't think it'll be too useful.

On top of that, apologies if this forum already holds the answer to my question, but I wasn't able to find it.

[Image: AM1t2PC.png]
[Image: kPmrWS7.png]


So here we have the standard 2x2 brick. This brick is generated perfectly except that the 4 quads at the bottom of the brick are facing the wrong way. The winding should be correct, and the inversion system should be correct, else how could the rest of the brick generate perfectly? The only real repeating logic I can see with this problem is that (as far as I'm aware) normals never face the right way when primitives are created in the base brick file, only in subparts. But how is that possible? Are there some rules that I'm missing here?

But primitives in the root file aren't the only ones to not work consistently; for instance here in the 2x3 brick:

[Image: Z5Dj9w5.png]

The same four quads at the bototm are inverted, but also one of the faces of the outer box-5. This image has my debug-lines enabled so you can see the shape it's supposed to have more clearly. (Note that the normals on the inside of the brick are correct, since you are supposed to see through them from this angle.)

Lastly, the standard 2x4 brick shows some strange behaviour. This might be an unrelated issue and this is the only brick I've tested where this problem occurs (it's also easily fixable by changing one of the transformations in the 2x4 brick file, but that cant be right.) but I'm posting it here anyways just in case some very clever person can tell me that that's related to the same issue.

[Image: HWD9X98.png]

Thanks so much for anyone willing to help me out here! I've been stuck on this for ages... Heart


RE: Problem with normals when building my own LDraw interpreter. - Roland Melkert - 2019-03-12

Things to check:

Are the type 1 line matrices multiplied correctly?

Not everything is CCW or CW it can differ per .dat, in LDCad I convert everything to CCW (flip tri and quads point order) before using the data.

How do you correct for the neg Y in ldraw? (things seem to be pos Y in your images)

Is unity left or right handed?


RE: Problem with normals when building my own LDraw interpreter. - Lasse Boijens - 2019-03-12

(2019-03-12, 22:11)Roland Melkert Wrote: Things to check:

Are the type 1 line matrices multiplied correctly?

Not everything is CCW or CW it can differ per .dat, in LDCad I convert everything to CCW (flip tri and quads point order) before using the data.

How do you correct for the neg Y in ldraw? (things seem to be pos Y in your images)

Is unity left or right handed?

Thanks for the quick response Roland!

First of all, I copied the matrix multiplication from the convertor and am using built-in unity classes to translate the vertices. I think that all that should be working correctly, but then again the 2x4 suggests otherwise. I can't run any complicated tests now since I'm in bed on my phone but I will try tomorrow morning.

Secondly, unity uses a left-handed coordinate system with clockwise binding. I have handling for CW and CCW but as far as I'm aware all files in these simple brick tests use CCW winding anyways. I am converting those to CW by changing the vertex order. Also, I would suspect that a mistake in that system would cause more problems than just those few quads; that is unless if I'm wrong about the winding, but again I cannot check that right now.

The Y correction is done as a final step in the conversion process, I go through the already established vertices and invert their Y coordinate. This shouldnt cause any problems since removing this inversion gives the same results, just upsidedown in Unity's Y+ system.


RE: Problem with normals when building my own LDraw interpreter. - Lasse Deleuran - 2019-03-12

While I am not 100% sure about the root cause, I believe this problem is caused by inversions due to negative determinants.

Try to treat negative determinants of the rotation matrix as a switch for the winding.


RE: Problem with normals when building my own LDraw interpreter. - Travis Cobbs - 2019-03-12

(2019-03-12, 23:24)Lasse Deleuran Wrote: While I am not 100% sure about the root cause, I believe this problem is caused by inversions due to negative determinants.

Try to treat negative determinants of the rotation matrix as a switch for the winding.

I strongly suspect that this is the cause of his problems.

Having said that, BFC as a whole is fairly complex, and requires quite a bit of work to implement properly. You have to deal with the fact that every file specifies winding separately, the fact that BFC isn't in fact required, and can only be enabled if all the files above the current file in the hierarchy are also BFC certified (up to the part level), the fact that matrices with negative determinants flip the winding, the fact that the winding can be flipped in the parent part before referencing a child part (INVERTNEXT), the fact that NOCLIP can turn of BFC for arbitrary polygons in any file, and possibly other complications. (The INVERTNEXT and the negative matrix determinants also mean that a single file can have both windings.) And in addition to being difficult to make all that work, you still have to support non-BFC geometry (for transparent parts, for non-BFC certified parts, and for sections of BFC certified parts that are in a NOCLIP section.)

I believe that an alternative is to draw every face twice (with opposite windings). This would obviously be slower, but not by as much as you might think. Bear in mind that it is likely that things from the first winding will still be mostly already calculated by the graphics card when it does the second winding, and since only one of the windings will face the camera, only one will actually get drawn. Furthermore, generally speaking, the vertex data won't have to be duplicated, since faces are usually drawn with indexes. (However, the actual surface normals for each winding would be in opposite directions, so depending on how the vertices are specified, it might mean that they have to be fully specified twice.)

If things look good after doing that, then taking the time to properly and fully support BFC would probably be good, but I wouldn't bother to even try in the initial stages of a new project.


RE: Problem with normals when building my own LDraw interpreter. - Lasse Boijens - 2019-03-13

(2019-03-12, 23:51)Travis Cobbs Wrote: I strongly suspect that this is the cause of his problems.

Having said that, BFC as a whole is fairly complex, and requires quite a bit of work to implement properly. You have to deal with the fact that every file specifies winding separately, the fact that BFC isn't in fact required, and can only be enabled if all the files above the current file in the hierarchy are also BFC certified (up to the part level), the fact that matrices with negative determinants flip the winding, the fact that the winding can be flipped in the parent part before referencing a child part (INVERTNEXT), the fact that NOCLIP can turn of BFC for arbitrary polygons in any file, and possibly other complications. (The INVERTNEXT and the negative matrix determinants also mean that a single file can have both windings.) And in addition to being difficult to make all that work, you still have to support non-BFC geometry (for transparent parts, for non-BFC certified parts, and for sections of BFC certified parts that are in a NOCLIP section.)

I believe that an alternative is to draw every face twice (with opposite windings). This would obviously be slower, but not by as much as you might think. Bear in mind that it is likely that things from the first winding will still be mostly already calculated by the graphics card when it does the second winding, and since only one of the windings will face the camera, only one will actually get drawn. Furthermore, generally speaking, the vertex data won't have to be duplicated, since faces are usually drawn with indexes. (However, the actual surface normals for each winding would be in opposite directions, so depending on how the vertices are specified, it might mean that they have to be fully specified twice.)

If things look good after doing that, then taking the time to properly and fully support BFC would probably be good, but I wouldn't bother to even try in the initial stages of a new project.

Yea you're right, BFC is very very complicated, I might be better off just drawing two faces like you said. Unity indeed uses indeces to store the actual triangles (also does not support quads to make things even more difficult) so besides the normals taking up some space it will be efficient enough for now, and I'll see if I can fix the integration later. Thanks for all the help.


RE: Problem with normals when building my own LDraw interpreter. - Lasse Boijens - 2019-03-13

(2019-03-12, 23:24)Lasse Deleuran Wrote: While I am not 100% sure about the root cause, I believe this problem is caused by inversions due to negative determinants.

Try to treat negative determinants of the rotation matrix as a switch for the winding.

Seeing as I didn't know that this was a thing, this could indeed very very likely be the problem. I can check in a few hours. For some reason I figured unity would do that for me, but really all it does is give the coordinates and lets me do the rest. Thanks for everyone on this ancient forum still knowing what they're talking about.

However, as the other commentor said, I think I will leave this for later and just use double sided faces for now.


RE: Problem with normals when building my own LDraw interpreter. - Lasse Boijens - 2019-03-13

(2019-03-12, 23:24)Lasse Deleuran Wrote: While I am not 100% sure about the root cause, I believe this problem is caused by inversions due to negative determinants.

Try to treat negative determinants of the rotation matrix as a switch for the winding.

This was the issue! The normals are all fixed now! I do think that the issue with 3001 is something with my matrix multiplications, since I now see that with more complicated bricks even more things get transformed incorrectly, but that seems unrelated so I won't go into it (at least not here not now). Thanks for the help.