Feature Request: Normals+Backface culling on sprite3d?

Started by jaymzjulian, October 27, 2019, 03:18:20 AM

Previous topic - Next topic

jaymzjulian

Apologies if i've misread the documenation, and this already exists!

You may ask "Why, Mr. JJ, would you want this?" - the answer is, hidden line culling - i'm importing objects which have normals (I have a script to import OBJ format objects and optimize them for vectrex a bit, whcih I really should post to the code forum!), and I'd like to save vectors by only displaying the front facing surfaces.  If my DrawTo commands would take a normal vector as well, then we could ignore any backsurfaces (i.e. dotproduct < 0)

Perhaps this already exists - I saw in 1.20, you added functions around calculating and transforming normals, so theoretically i could do the heavy lifting in basic and draw my objects piece by piece, BUT it seems like a bad move to do... but I could be completly on crack!

Vectrex32

I'm not sure how I'd pull this off. 3D sprites aren't defined as polygons, they're just defined as lines.

I guess I'd have to introduce a new type of sprite that uses polygons.

- Bob

jaymzjulian

Quote from: Vectrex32 on November 06, 2019, 07:15:17 PM
I'm not sure how I'd pull this off. 3D sprites aren't defined as polygons, they're just defined as lines.

I guess I'd have to introduce a new type of sprite that uses polygons.

- Bob

I actually meant on each line - I was going to generate a normal per line (an average of the two point normals), and then have it be line-culled rather than poly-culled, sinc ethe vectrex don't play with polys :)

Vectrex32

I took a course in 3D graphics back in college, but that was 36 years ago, so be patient with me.

How can you take the normal of a line? The normal would be perpendicular, right? But in 3D space, there would be an infinite number of lines perpendicular to your vector.

You could find a normal of two joined vectors, but programmers would have to be really careful of which direction their vectors are going to make sure the normal is pointing the right way and indicating whether this is a back face or a front face.

Or am I missing something?

- Bob

jaymzjulian

Technically what you say is acutally true, however it depends on how you visualise what a "line" actually represents in this case.   My visualisation - I apologise if I'm being over verbose here, btw:

Technical method of visualising this - probably less helpful than the later paragraphs: While in _simple_ 3d graphics, obviously a surface has one norma, once you start talking smooth shading, you have a normal per point instead - this is what my inputs _actually_ have, and then the poly is culled if no _point_ is visible.  From this perspective, there's no reason this can't apply to lines either - after all, the only thing actually seperating a line from a triangle is that it has two points instead of three.   

This would, of course, require _two_ normals, which I am not proposing.

The way I visualize it, is to consider the line surface which is the thickness of the line - you can imagine a line really as a quad that has a very small width - so in traditional 3d parlance, really the Lines3dSprite is actually a series of very small quads with gaps in between them for the empty space.  Because that surface "part" of a 3d object, that surface still has a front facing direction - and this is represented in the input objects by the actual point normals that are attached to it. 

If you were to synthsise it without that information, for an _entirely convex_ object, you could actually consider the normal to be a vector which traverses from the center point of the object through the centerpoint of the line - again, giving you what is the "front" of the object from the viewers perspective.  This would be an imperfect algorythm. of course, and if you have surface information, it would actually be better to give each line the normal of the surface it's connected to - but, in a pinch, it could be synthisised this way if someone handed you a line-only model.

That having been said, the statement "programmers would have to be really careful of which direction their vectors are going to make sure the normal is pointing the right way and indicating whether this is a back face or a front face." is absolutely correct, but is also correct in any 3d graphics!  I would expect this to be something the programmer would have to explicitly opt in for, rather than being the "default" - because, yes, if you get your normals wrong, then "interesting" things happen, but this is true outside of this space as well (back when I was doing gamedev for a living, you'd be shocked how often I was given models where the polygon winding was wrong, breaking the engine.... we actually ended up writing a tool to correct it, which sadly I don't have anymore, based ironically on the normal maps which generally _were_ right, since they were coming out of 3dsmax...)

Vectrex32

I'm a little concerned about the direction of the lines being so important. If you're drawing a triangle, but all the lines need to go left to right, then you can't do three DrawTos; you need to do a DrawTo, MoveTo, DrawTo, MoveTo, DrawTo. It won't end up looking good.

I think I'd need to add polygon-based sprites.

- Bob

jaymzjulian

#6
To be honest, I think doing polygon sprites is overcomplicating things, and I'm not convinced this wouldn't end up looking good, but as they say great claims require great evidence, so here's my proposal - I'll do a prototype of this on the PC, probably tomorrow, and then we can see if it ends up looking good or not - I should be able to write a small python program later tonight that proves whether the simple version looks good one way or the other.  Because my inclination is that you're not right, but without proof i'm just pissing in the wind.

You're absolutely on track about the implementation of course - you would still need to moveto that missing vertex - but i think you are incorrect about whether it would end up looking good... but since I have objects to test this with, it should be pretty easy to clear up one way or the other!

EDIT: not that a polysprite wouldn't be cool, and i'd totally support that, BUT it's complicated to get right - if you did go down that path, i'd strongly encourage you to at least make it take a points/lines set, rather than direct geometry, since that will make processing much easier, and also aligns to what 3d programs output - so you end up with an array of points, and array polys connecting them, and then you can do your transforms on the points once, and then process all of the polys throwing out what you don't need at that point. 

Vectrex32

Do the test on the V32. My concern is that the Vectrex's analog hardware is not precise enough to move to the starting point of a previously drawn line.

- Bob

jaymzjulian

yeah, funny thing is i realised that i needed to do the test on the v32 right after posting that, so that's what i'll do :)

jaymzjulian

As promised.... my opinion is that this has worked out actually quite well.  your opinion is, of course, able to vary ;).

Both of these come from the same lightcycle model that's in the obj converter (and vltron) with some different settings - specifically, there is a window material in the original which I've been generally turning off, but i actually like more on with the culling.  However, I have _disabled_ simplifying triangles into quads for this demo - this is entirely because i didn't port that code in my converter yet, obviously I will at some point (this reduces the line count a lot, but this was about worst case not best!)

defualt is backface culling on, but you can hold button 1 to turn the backfaces back on - interestingly, the drawing is actually worse with them on due to pen drift ;).

also, this is obviously totally unoptimized - in particular, i started doing code to consildate the MoveTo operations, but i realised i had to juggle arrays at that point and decided it was annoying, and beacuse it was generally working out okay...

jaymzjulian

Quote from: jaymzjulian on November 07, 2019, 02:37:31 AM
As promised.... my opinion is that this has worked out actually quite well.  your opinion is, of course, able to vary ;).

Both of these come from the same lightcycle model that's in the obj converter (and vltron) with some different settings - specifically, there is a window material in the original which I've been generally turning off, but i actually like more on with the culling.  However, I have _disabled_ simplifying triangles into quads for this demo - this is entirely because i didn't port that code in my converter yet, obviously I will at some point (this reduces the line count a lot, but this was about worst case not best!)

defualt is backface culling on, but you can hold button 1 to turn the backfaces back on - interestingly, the drawing is actually worse with them on due to pen drift ;).

also, this is obviously totally unoptimized - in particular, i started doing code to consildate the MoveTo operations, but i realised i had to juggle arrays at that point and decided it was annoying, and beacuse it was generally working out okay...

EDIT: where the wheel surfaces dissapear on the "no-window" version, btw?  that's where there was semi-transparent polys on the original, and i culled them on vectrex - so there is literally no poly there ;).  hence the "window" version not having that glitch - doens't bother me, to be honest, but in case you were wondering why ;)

Vectrex32

Let me see if I understand your code.

mySprite is an array where each element has a MoveTo or DrawTo, the (x, y, z) coords of the point we're moving/drawing to, and the (x, y, z) vector of the line's normal. You rotate the line and the normal, and cull the lines whose normals have z < 0. Is that right?

The tricky part is that you've hard coded the normal. That's a big burden on the programmer (assuming he doesn't have a program that's converting OBJs, like you do). On the plus side, if you hard code the normal, it doesn't matter anymore which direction your line is going; you can draw your lines in the order that will make it look best on the screen, rather than in the direction that the code would require for calculating normals.

I'm still confused about the wheel surfaces disappearing. What I'm seeing is that as the cycle rotates, an edge of the wheel appears and disappears. Is that what you're referring to? You say they were semi-transparent so you "culled them on vectrex". You mean you removed them from the mySprite array? Then why do they ever appear?

- Bob