Lines3d: X/Y co-ordinate too large even with clipping rect?

Started by jaymzjulian, November 05, 2019, 01:28:43 AM

Previous topic - Next topic

jaymzjulian

I had some success with splitting my lines into shorter lines in my code, though i've kind of been avoid that since dual port ram is a precious resource, but I was wondering - if i have a clipping rect on all of my Lines3d sprite objects, I shouldn't be randomly getting these, right?  Alternatly, is there something I can do other than tessellating down objects myself on the basic side?

I end up with a lot of this:


X or Y coordinate was too large in sprite:
Lines3D: visible; pitch 0, roll 0, yaw 0; magnification 1
{{0,-32,0,-32},{1,32,0,-32},{0,-32,0,-24},{1,32,0,-24},{0,-32,0,-16},{1,32,0,-16},{0,-32,0,-8},{1,32,0,-8},{0,-32,0,0},{1,32,0,0},{0,-32,0,8},{1,32,0,8},{0,-32,0,16},{1,32,0,16},{0,-32,0,24},{1,32,0,24}}
Translate: <uninitialized>
Clipping Rect: {{-255,-255},{255,255}}

At line 65, column 14: X or Y coordinate is too large



I was wondering if it's because I'm using quite a bit of MoveTo in there - I noticed it mentioned in the manual that MoveSprites don't count, but Translation does, but my reading was that MoveTo is fine - is this wrong?  I did include my code in case i'm just doing anything super dumb, the meat of this is in the drawscreen function.

(button 1/2 turn left/right.  please excuse my currently incredibly janky camera.... when I try and use better camera code, i get this failure _constantly_, as well as if i touch the scale at all - indeed, if you change "call ScaleSprite(64, 162 / 0.097)"   to "call ScaleSprite(64, 324 / 0.097)", it will happen at startup)

Vectrex32

Hi Jaymz,

I wasn't able to reproduce the crash until I switched to "call ScaleSprite(64, 324 / 0.097)". To be honest, I didn't try very hard; this game goes really fast!

Anyway, when I changed the ScaleSprite, it crashed immediately, as you said it would. So first I called DumpSprites() to get a list of all the sprites. Comparing the error message to the sprites in the dump, I saw that the offending sprite was number 7 in the list.

So I got a handle to the 7th sprite with "s = DrawingListSprite(7)". Then I got the details with "call SpritePrintVectors(s)". That shows the coordinates for each phase of the calculations. I saw this:

Raw data (meters):
mode = MoveTo, x = -32, y = 0, z = -32
mode = DrawTo, x = -32, y = 0, z = 32
mode = DrawTo, x = 32, y = 0, z = 32
mode = DrawTo, x = 32, y = 0, z = -32
mode = DrawTo, x = -32, y = 0, z = -32
View coordinates: (meters)
mode = MoveTo, x = -32.1293, y = -4, z = 7.53032
mode = DrawTo, x = -17.5251, y = -4, z = 69.8418
mode = DrawTo, x = 44.7864, y = -4, z = 55.2375
mode = DrawTo, x = 30.1821, y = -4, z = -7.07393
mode = DrawTo, x = -32.1293, y = -4, z = 7.53032
z-clipped coordinates (meters):
mode = MoveTo, x = -32.1293, y = -4, z = 7.53032
mode = DrawTo, x = -17.5251, y = -4, z = 69.8418
mode = DrawTo, x = 44.7864, y = -4, z = 55.2375
mode = DrawTo, x = 31.8401, y = -4, z = 0
mode = MoveTo, x = 0, y = -4, z = 0
mode = DrawTo, x = -32.1293, y = -4, z = 7.53032
Projected coordinates: (units)
mode = MoveTo, x = -6682.09, y = -831.899
mode = DrawTo, x = -416.093, y = -94.9708
mode = DrawTo, x = 1341.97, y = -119.855
mode = DrawTo, x = 106352, y = -13360.8
mode = MoveTo, x = 0, y = -13360.8
mode = DrawTo, x = -6682.09, y = -831.899
Clipped coordinates (units):
mode = MoveTo, x = -255, y = -97.2509
mode = DrawTo, x = 255, y = -104.47
mode = MoveTo, x = -6682.09, y = -831.899


So when the sprite gets projected from 3D to 2D, the coordinates get huge. That last MoveTo is what's causing the crash. What happened was that the clipping code realized that the last DrawTo in the projected coordinates was completely outside of the clipping rectangle, so it changed the DrawTo to a MoveTo (the line is clipped, so nothing should be drawn, but the pen still needs to be moved to the endpoint so it's in position to draw the next sprite, and that's why the MoveTo isn't eliminated).

The real question, though, is why the coordinates get so big. It's because the object is so close to the camera.  The Z coordinates in the raw data go from -32 to +32. The camera is at {1, 4, -32}, so the object is right up against the camera and it looks "infinitely" large. Thus, the huge X and Y coordinates.

Hope this helps.

- Bob

jaymzjulian

Thank you so much for that detailed analysis - that helps me a lot!  I actually had tried to use SpritePrintVectors, but hadn't quite been able to work it out - I always ended up with an illegal argument error from that - I couldn't tell you why, because when i did it as you described below, it worked just fine :).

I was initially able to mitigate this somewhat by offsetting my camera 0.5, so that they never _quite_ match, since the grid itself is always whole numbers.  this made the issue much more rare, which is obviously nice - though I was still able to trigger it most games, particularly when I change the view perspective - the camera's not equal, but it's fundamentally the same issue of long lines being projected through the "other side" of the screen, and generating insanely large components (this one was camera = {12.5, 4, -4.5}, final-co-ord = {32, 0, 32}), and doing that MoveTo as you said.  As I put back the dynamic camera code, obviously that will get worse...

So then I actually tried adding a MoveTo(0,0,0) at the end of each of these sprites, thinking that might mitigate it - which it did, for a while (I removed the 0.5 offset from the camera, and tested with the "broken" projection), until, hilariously, the MoveTo was also projected to something undisplayable, at which point again it falls in a heap ;)

My next approach was to dynamically updating that last MoveTo to be the near the camera, thinking "that should stop the giant projection, right?".   And, indeed, I got a final co-ordinate of x = 1.41348, y = -4, z = 0.0455957 , which was reasonable... but which still projected to x=4326, y= -12244.  Too close to the camera, I guess.... I tried various calculations on this, but I wasn't yet able to find one which reliably reset the pen to somewhere "on screen".  I _suspect_ to do it this way, I'd have to work with the camera rotation as well, which may well be plausable but also a giant pain.... maybe define a unit vector, rotate it with the camera rotation, then add that to the camera position, might do it - I might try that later tonight if I get a chance, but we're getting into really complicated solutions now, at which point I assume i'm doing it wrong(tm) ;).  But, I suspect that might be an answer which might work, at least... I'm wondering if you have a simpler one though.

(One data point I will throw out there - in both cases, the next drawing operation is a ReturnToOrigin, which should eliminate the need for that MoveTo in any case.  Neither here nor there, since that would be just an optimization ;))

One thing I'd really like to have - I think I mentioned this over in the feature requests forum actually - not for debugging, but for a "finished" game, is an option to say "just stop drawing and accept the corruption" rather than crash the game.  In my case, since all of my objects are preceeded by a ReturnToOriginSprite() anyhow, i might lose the floor for a frame, but no harm would really be done. 

Also: yeah, I need to add an easy mode ;).  I actually plan on adding both a slower mode, and an AI assist mode once I do the AI code. 

Vectrex32

Why not just move the scene further away from the camera? Having it end right at the camera is like putting your eyeball right up to something. The player wouldn't expect to be that close to the lightcycles or playing surface.

- Bob

jaymzjulian

Because the objects in question are the floor, not the cycles/trails, which I draw as single long lines since I found that if i draw them as individual segments, it filled dual port ram - and the floor _is_ expected to extend below the camera

Vectrex32

Well, you want the floor to go to the bottom of the Vectrex screen, but that doesn't mean it has to have a Z offset of zero relative to the camera. Fiddling with the zoom or the tilt of the camera might accomplish the same effect.

- Bob

jaymzjulian

Ahh, my bad, I didn't explain well enough in my last post - because that _is_ easily avoidable.  I know where the lines are, etc.

However, it isn't only happening with zero z-offset - for example, {12.5, 4, -4.5} was failing for the {32, 0, 32} case (with the camera looking backwards), and I just now ran again, and it's now it's failing at camera {-10.5, 4, -21.5} , where the {32,0,32} that's failing to MoveTo is translated to {67, -4, 7.7 }, which then projects to {6847, -403}.   Which is sort of the weird thing - anything ending _behind_ the camera beyond a certain amount seems to get weirdly large.

But, looking at all of the failures, and _what_ fails now, I actually think the reasons are "you're drawing a 64 unit long line, in 3d space, which intersects the screen, and the system just does not handle that condition".  Except it otherwise _does_ handle that, of course, but if you look at the data, you'll see that the actual situation is _all_ the lines that are intersecting the screen are all huge where this happens - that makes sense, it generally happens near the edges of the arena. 


Raw data (meters):
mode = MoveTo, x = -32, y = 0, z = -32
mode = DrawTo, x = -32, y = 0, z = 32
mode = MoveTo, x = -24, y = 0, z = -32
mode = DrawTo, x = -24, y = 0, z = 32
mode = MoveTo, x = -16, y = 0, z = -32
mode = DrawTo, x = -16, y = 0, z = 32
mode = MoveTo, x = -8, y = 0, z = -32
mode = DrawTo, x = -8, y = 0, z = 32
mode = MoveTo, x = 0, y = 0, z = -32
mode = DrawTo, x = 0, y = 0, z = 32
mode = MoveTo, x = 8, y = 0, z = -32
mode = DrawTo, x = 8, y = 0, z = 32
mode = MoveTo, x = 16, y = 0, z = -32
mode = DrawTo, x = 16, y = 0, z = 32
mode = MoveTo, x = 24, y = 0, z = -32
mode = DrawTo, x = 24, y = 0, z = 32
mode = MoveTo, x = 32, y = 0, z = -32
mode = DrawTo, x = 32, y = 0, z = 32
View coordinates: (meters)
mode = MoveTo, x = -22.6274, y = -4, z = 7.77818
mode = DrawTo, x = 22.6274, y = -4, z = 53.033
mode = MoveTo, x = -16.9706, y = -4, z = 2.12133
mode = DrawTo, x = 28.2843, y = -4, z = 47.3761
mode = MoveTo, x = -11.3137, y = -4, z = -3.53553
mode = DrawTo, x = 33.9411, y = -4, z = 41.7193
mode = MoveTo, x = -5.65686, y = -4, z = -9.19239
mode = DrawTo, x = 39.598, y = -4, z = 36.0624
mode = MoveTo, x = -3.8147e-06, y = -4, z = -14.8492
mode = DrawTo, x = 45.2548, y = -4, z = 30.4056
mode = MoveTo, x = 5.65685, y = -4, z = -20.5061
mode = DrawTo, x = 50.9117, y = -4, z = 24.7487
mode = MoveTo, x = 11.3137, y = -4, z = -26.163
mode = DrawTo, x = 56.5686, y = -4, z = 19.0919
mode = MoveTo, x = 16.9706, y = -4, z = -31.8198
mode = DrawTo, x = 62.2254, y = -4, z = 13.435
mode = MoveTo, x = 22.6274, y = -4, z = -37.4767
mode = DrawTo, x = 67.8823, y = -4, z = 7.77816
z-clipped coordinates (meters):
mode = MoveTo, x = -22.6274, y = -4, z = 7.77818
mode = DrawTo, x = 22.6274, y = -4, z = 53.033
mode = MoveTo, x = -16.9706, y = -4, z = 2.12133
mode = DrawTo, x = 28.2843, y = -4, z = 47.3761
mode = MoveTo, x = -7.77818, y = -4, z = 0
mode = DrawTo, x = 33.9411, y = -4, z = 41.7193
mode = MoveTo, x = 3.53553, y = -4, z = 0
mode = DrawTo, x = 39.598, y = -4, z = 36.0624
mode = MoveTo, x = 14.8492, y = -4, z = 0
mode = DrawTo, x = 45.2548, y = -4, z = 30.4056
mode = MoveTo, x = 26.163, y = -4, z = 0
mode = DrawTo, x = 50.9117, y = -4, z = 24.7487
mode = MoveTo, x = 37.4767, y = -4, z = 0
mode = DrawTo, x = 56.5686, y = -4, z = 19.0919
mode = MoveTo, x = 48.7904, y = -4, z = 0
mode = DrawTo, x = 62.2254, y = -4, z = 13.435
mode = MoveTo, x = 60.1041, y = -4, z = 0
mode = DrawTo, x = 67.8823, y = -4, z = 7.77816
Projected coordinates: (units)
mode = MoveTo, x = -2282.51, y = -403.495
mode = DrawTo, x = 352.961, y = -62.3953
mode = MoveTo, x = -5406.16, y = -1274.24
mode = DrawTo, x = 493.332, y = -69.7676
mode = MoveTo, x = -12990.4, y = -6680.41
mode = DrawTo, x = 671.319, y = -79.1156
mode = MoveTo, x = 5904.71, y = -6680.41
mode = DrawTo, x = 904.381, y = -91.3562
mode = MoveTo, x = 24799.8, y = -6680.41
mode = DrawTo, x = 1222.76, y = -108.078
mode = MoveTo, x = 43694.8, y = -6680.41
mode = DrawTo, x = 1683.8, y = -132.292
mode = MoveTo, x = 62589.9, y = -6680.41
mode = DrawTo, x = 2411.08, y = -170.489
mode = MoveTo, x = 81485, y = -6680.41
mode = DrawTo, x = 3728.84, y = -239.699
mode = MoveTo, x = 100380, y = -6680.41
mode = DrawTo, x = 6847.56, y = -403.496
Clipped coordinates (units):
mode = MoveTo, x = -255, y = -141.081
mode = DrawTo, x = 255, y = -75.074
mode = MoveTo, x = -255, y = -222.552
mode = DrawTo, x = 255, y = -118.427
mode = MoveTo, x = 6847.56, y = -403.496


Hence the Moveto{0,0,0} workaround _almost_ working - because teh system CAN draw large lines which intersect the screen just fine, but crashes out because it then tries to move the pen to the end of these undrawable lines. Hence, I now am reasonably confident that camera = camera+rotation_vector will also fix it, and I can probably do that and get on with my life.

I do still wish I could turn off that final MoveTo, or make it non-fatal, though in some software manner. 

jaymzjulian

To follow up, I realised that I can make that final MoveTo point at the target that I'm already generating a lookat matrix for, so I already know is in front of the camera.  Have not been abel to reproduce since :)

jaymzjulian

of course, then I added the computer player, which crashes the game as soon as it gets behind the camera - I guess I'll need to clip that in basic, which is probably good anyhow since I'm reusing the sprite and alternating its position between frames - so only displaying the "visible" bikes makes a lot of sense, given that, but it strikes me that this is something that _should_ have a way to gracefully fail, rather than crash the game :).  still, camera control code is in and otherwise working great, so I think that whole "too far from the behind camera" thing was absolutely my problem.

EDIT: or, you know, just add the MoveTo(target) to the end of my cycle as well, which also totally fxies it because it's totally hte same thing!  it seems just every 3d object i do needs a MoveTo(target) to reset the pointer...

jaymzjulian

I threw a version with AI (so you don't have to play it ;)) and proper camera up at https://github.com/jaymzjulian/vltron (with camera controls on the joystick) so you can kind of see what I'm going for - I may have yet bitten off more than the device really wants to chew on - you'll note that it's currently snake, not tron, and that's because while it contains 2 player code, as soon as I try and place the second player, the system generally falls apart in interesting ways around the prjection stuff again - it seems that, for whatever reason, my MoveTo(target) hack isn't working there, and I didn't figure out why yet.  I may well figure out why, but I may loop back on this later and try something perhaps closer to matching the architecture instead.  It may well be that, to really achieve this on vectrex32, I have to do something like implement the 3d transformations myself in basic - I saw there is vector math commands, though, so that might actually be reasonably doable?  essentially, implement my own version of LinesSprite3d, sort by z-order, and then display only as many lines as we can display.... it might be somewhat of a painful implementation, but doable at least.

That having been said, my remaining stupid question is if there is any way of managing the dual port ram capacity - I wrote a whole blurb in the feature request forum, but really the thing i'd need to make this viable is some way to say "hey, dude, you're close to full" so I can start interleaving objects more aggressivly - things only display half the player trails per frame, maybe some more aggressive z-clipping, or something along those lines.  It's tough to judge when to do this, right now, since obviously it depends on what's actually visible vs not, given that clipped out things don't go there. 

Vectrex32

If the built-in 3D transforms aren't meeting your needs, the solution is for me to upgrade them, not for you to implement your own 3D code in BASIC.

I see that Demo3D also crashes when objects are behind the camera. I think I need to work on this.

- Bob

jaymzjulian

Well I'll definetly loop back to this in any case - I'm certainly not abandoning the project, and I figured the line too long crashes were fixable stuff (and will also affect the other games I want to make, since they're all 3d), it's fitting the trails into ram that's the biggest thing I think, and I'm not sure that's "easily" fixable in the model right now - though I was thinking about it this morning, and if I can come up with a "reasonable" maximum length per trail, I can probably interleave those too.

Also I'm working on updating the object importer to be more aggressive about reducing object complexity, which should also help - the current lightcycle is 172 lines, and it doens't need to be.  If I can get it down to half of that number, I think that might help some too.

One thing I was wondering, is if changing my scale factors might help - I noticed the floor segments are being split into multiple lines (I can see the joins on my display ;)), which makes sense for long lines though of course it'll hurt the accuracy of the 3d - but I'm going to experiment with that as well, and see where I get.

What I'm planning to do with that stuff, is acutally have the timing come not from the vextrex framerate, but instead from the vectrex32 timer, and then set the vectrex side framerate a lot higher than it normally would be - maybe 60fps to start with, but even higher if i can, and manage the interleaving flicker that way - in the current state with two players, it's definitely not _unwatchable_, but the 30hz flicker is not great - if I can reduce that a lot, then I feel like this is reasonably workable.

Vectrex32

I'm working on a fix for the crashes: the final MoveTo in a sprite will be discarded if the next sprite is a ReturnToOrigin. Would you be willing to beta test it?

Since this means coming out with a new version, are there any other features (or bug fixes) you'd like to see?

- Bob

jaymzjulian

Absolutely happy to beta test - it's for my benefit, after all ;)

I do have this one which would be a simple bugfix for you, i suspect: http://forums.vectrex32.com/index.php/topic,98.0.html - "Variable is not an array" error does not display line number

The other two things i've found that I care about are not simple fixes though, and I don't expect them at all, but they're my "this would make my life easier list".  One of which is having Lines3dSprite also take a normal, and eliminate backfaces - http://forums.vectrex32.com/index.php/topic,94.0.html - since my models have these...

The other is, I suspect, hard, but you might have a simple fix for it - http://forums.vectrex32.com/index.php/topic,95.0.html - essentially some kind of catchable error on dual port ram overflow, and/or some kind of "page" type concept where i can have multiple display list buffers and switch between them.  I actually wrote a lot in that post, but to be honest it's all conjecture on my part. 

Vectrex32

Hmm... I never got e-mail notifications of those posts. I don't understand why.

- Bob