I thought I have a decent understanding of graphics pipelines, but apparently do not. I found some code that fairly efficiently renders particles, and I've convinced the code to do a lot of things it didn’t originally do, but I'm missing something. Also, if anyone has ideas of better zones to post this in, please let me know.
First, here's the basic code. Since my problem is in the concepts rather than the programming, I'll leave it as pseudocode:
variables:
fov (field of view),
cx (x value of the center pixel),
cy (y value of the center pixel),
pan (amount to pan the particles),
tilt (amount to tilt the particles),
cameraX (x value of the camera),
cameraY (y value of the camera),
cameraZ (z value of the camera),
screenWidth (the width of the screen to display to)
focalLength = screenWidth / 2 * (cos( fov / 2 ) / sin( fov / 2 ));
matrix.identity();
matrix.appendRotation( pan, Y_AXIS );
matrix.appendRotation( tilt, X_AXIS );
matrix.appendTranslation( cameraX, cameraY, cameraZ );
p00 = matrix.rawData[ 0 ];
p01 = matrix.rawData[ 1 ];
p02 = matrix.rawData[ 2 ];
p10 = matrix.rawData[ 4 ];
p11 = matrix.rawData[ 5 ];
p12 = matrix.rawData[ 6 ];
p20 = matrix.rawData[ 8 ];
p21 = matrix.rawData[ 9 ];
p22 = matrix.rawData[ 10 ];
p30 = matrix.rawData[ 12 ];
p31 = matrix.rawData[ 13 ];
p32 = matrix.rawData[ 14 ];
for each point {x, y, z}:
{
d = focalLength + p32 + x * p02 + y * p12 + z * p22;
if (d < 0)
{
d = -d;
}
w = focalLength / d;
xi = (int)( w * ( x * p00 + y * p10 + z * p20 ) + cx + p30);
if (xi >= screenWidth || xi < 0)
{
continue;
}
yi = (int)( w * ( x * p01 + y * p11 + z * p21 ) + cy + p31);
buffer_index = xi + (yi * screenWidth);
}
This algorithm works perfectly, and looks fantastic. Obviously, the code for the matrix work calls a library. The library's help says that appending a transformation does exactly what it should - it multiplies by putting the new transformation on the left of the existing matrix. I can double check that using the debugger to verify if necessary.
The problem comes about when I try adding in rotation around an arbitrary point. From what I understand, that should be relatively easy - simply change the matrix setup from the above to the following:
matrix.identity();
matrix.appendTranslation( -centerOfRotationX, -centerOfRotationY, -centerOfRotationZ );
matrix.appendRotation( pan, Y_AXIS );
matrix.appendRotation( tilt, X_AXIS );
matrix.appendTranslation( centerOfRotationX, centerOfRotationY, centerOfRotationZ );
matrix.appendTranslation( cameraX, cameraY, cameraZ );
However, this causes problems. As long as I leave the centerOfRotation at the origin, everything is good, as it had been. However, when I set any other center of rotation, my values are off. It seems to be rotating around some other position. The most obvious way that this problem presents itself is that I draw the center of rotation a different color from all the other particles, and as I pan or tilt the particles, the center of rotation moves on the screen. (How much it moves depends on how "zoomed in" to the center I am.) Obviously, the center of rotation should not ever move.
I've tried everything I can think of. I removed the camera translations and added them only into the xi, yi calculations (with an added scale to the matrix manipulations to account for zoom capabilities), and it seemed to be a little bit better, but the problem was still there. I’ve completely removed the camera translations, and the problem still presents itself.
The only thing that seems to help is for me to add a "magic" number to the focalLength. I set my program so I could tweak the number, and see the results, and I can get the movement of the center of rotation to be down to a few pixels in both the x and y direction, but I'm sure that's not right (and I haven't figured out where the "magic" number comes from, other than trial and error). If it helps any, one data point I've had is that when I set the center of rotation to {0, -1, 0}, the only wobble is along the y-axis. When I set to {-1, 0, 0} or {0, 0, -1}, there is wobble in both the x- and y-axis. The wobble seems to be a projection of a circle or occasionally a projection of a figure 8. But maybe none of that matters – it’s effectively altering the zoom, so maybe I’m just zooming out enough to mitigate the issue. (Probably, not, though – that would mean I could simply set the “magic” to a huge number, and the problem would stop evidencing itself, and I haven’t seen that.)
I've been working on this for days and making no progress. Can anyone give me any ideas?
Thanks!
I think the answer is about when you apply the rotation about a point. I guess what your after is rotation and then translation to the point. So the code would be something like this -
matrix.identity();
matrix.appendRotation( pan, Y_AXIS );
matrix.appendRotation( tilt, X_AXIS );
matrix.appendTranslation( centerOfRotationX, centerOfRotationY, centerOfRotationZ );
matrix.appendTranslation( cameraX, cameraY, cameraZ );
The matrix sequence you show would rotate the particles around the point, in the sense of a planet orbiting around the sun. I guess you're trying to rotate them at that position. Though I'm not clear about the use of camera X, Y and Z in this context.
You've called rotation around the Y axis 'pan'. It's normally called 'yaw', as in Yaw, Pitch and Roll. Pan is translation along the view plane. That confused me for a bit. Equally unsure why the code uses screen width and ignores screen height.