Jump to content

NES - Matrix Rotation of a Cube


Recommended Posts

Hello all, 

Working on some demo coding ideas. Naturally some pseudo 3d was something I wanted to do. 

This was my inspiration for making this: https://www.youtube.com/watch?v=p4Iz0XJY-Qk

This rom is early days but I'm happy to have gotten it this far. I'm doing some matrix rotation using signed sine tables and also utilizing the MMC5's multiplication registers. I'm still trying to figure out where I need to refactor to remove the jitter. This is either from rounding to early, or just the limitations from a 256 byte signed sin table. 

These are the transformations I am doing: 

My sin table uses $00 to represent 0, $FF to represent +1, and $80 for -1. 

If you are not familiar with matrix math this is a basic illustration of what is involved: 

In my code I basically do it in a very unrolled manner to help with execution speed.

For an example of the method, lets take the first cos(theta) in the Z rotation. I need to perform x * cos(theta).  I would do the following. 

LDX Theta            ;  load current angle (0-255) 
LDA cos, x            ; Load precalculated cos value for that given angle  
BPL +                    ; check the sign
JSR TwosComp   ; convert negative to positive to get magnitude of number 

STA $5205           ; store in MMC5 multiplication register 

LDA X                   ; Load starting X coordinate 
BPL +                   ; check sign 
JSR TwosComp  ; convert from negative to get magnitude
STA $5206           ; Store in other MMC5 multiplication register

LDA $5206           ; Take high byte of 16-bit multiplication result
STA alpha             ; save it in var for later addition

LDA cos, x            ; check if was negative
LDA alpha
JSR TwosComp   ; Convert back if it was previously negative. 
STA alpha

LDA X                  ; same check as above
BPL +                  ; if X started negative,
LDA alpha
JSR TwosComp  ; we convert back to negative
STA alpha

Then I do the same for Y * -sin(theta) , store that result in a var called 'beta' and at the end I add alpha + beta to complete the first row of the matrix and get the final X value. 
The process is repeated for the second row of the matrix to get the final Y value for that specific rotation. 


Edited by TylerBarnes
  • Like 2
  • Wow! 1
Link to comment
Share on other sites

Coming from a non-Assembler, non-Homebrewing programmer...

I'm having a tough time trying to put into words what's going on and a possible solution.  The issue is that you are using an 8-bit CPU that's strictly capable of integer math and this is a process that fundamentally needs a processor that can properly handle floats, especially for trig functions.

In practice, what this means is that when any given point in the square has to rotate, it is making wide jumps in pixel movement.  It goes from a 0 pixel movement on one axis, to a 1 pixel movement for a frame or two, followed by a 2 pixel movement for a frame and then a 4 pixel movement after that.  This makes sense that it has to do this, but when values get rounded in certain ways, it looks jittery. This mean that at times, for each step in an axis rotation, the jumps will appear either to fast or to slow on a frame-by-frame basis.

So how do you fix that?  I'm honestly not sure.  You can either slow down the rotations of an axis when movements make those wider pixel jumps, or you can, possibly, find a way to check a given axis rotation and when the cos/sin division is complete return a remainder value and set a flag stating which side of a dot should be aliased if the remainders are within a given threshold.  If a side of a dot (top, bottom, left, right) should be shaded, then draw a grey line on that side of the circle.  This simulated aliasing might break up the visual affect and make it look less stuttery, but it's hard to say without experimentation.

Edited by RH
  • Thanks 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Create New...