10
votes

I'm encountering a problem trying to replicate the OpenGL behaviour in an ambient without OpenGL.

Basically I need to create an SVG file from a list of lines my program creates. These lines are created using an othigraphic projection.

I'm sure that these lines are calculated correctly because if I try to use them with a OpenGL context with orthographic projection and save the result into an image, the image is correct.

The problem raises when I use the exactly same lines without OpenGL.

I've replicated the OpenGL projection and view matrices and I process every line point like this:

3D_output_point = projection_matrix * view_matrix * 3D_input_point

and then I calculate it's screen (SVG file) position like this:

2D_point_x = (windowWidth / 2) * 3D_point_x + (windowWidth / 2)
2D_point_y = (windowHeight / 2) * 3D_point_y + (windowHeight / 2)

I calculate the othographic projection matrix like this:

float range = 700.0f;
float l, t, r, b, n, f;

l = -range;
r = range;
b = -range;
t = range;
n = -6000;
f = 8000;

matProj.SetValore(0, 0, 2.0f / (r - l));
matProj.SetValore(0, 1, 0.0f);
matProj.SetValore(0, 2, 0.0f);
matProj.SetValore(0, 3, 0.0f);

matProj.SetValore(1, 0, 0.0f);
matProj.SetValore(1, 1, 2.0f / (t - b));
matProj.SetValore(1, 2, 0.0f);
matProj.SetValore(1, 3, 0.0f);

matProj.SetValore(2, 0, 0.0f);
matProj.SetValore(2, 1, 0.0f);
matProj.SetValore(2, 2, (-1.0f) / (f - n));
matProj.SetValore(2, 3, 0.0f);

matProj.SetValore(3, 0, -(r + l) / (r - l));
matProj.SetValore(3, 1, -(t + b) / (t - b));
matProj.SetValore(3, 2, -n / (f - n));
matProj.SetValore(3, 3, 1.0f);

and the view matrix this way:

CVettore position, lookAt, up;

position.AssegnaCoordinate(rtRay->m_pCam->Vp.x, rtRay->m_pCam->Vp.y, rtRay->m_pCam->Vp.z);
lookAt.AssegnaCoordinate(rtRay->m_pCam->Lp.x, rtRay->m_pCam->Lp.y, rtRay->m_pCam->Lp.z);
up.AssegnaCoordinate(rtRay->m_pCam->Up.x, rtRay->m_pCam->Up.y, rtRay->m_pCam->Up.z);

up[0] = -up[0];
up[1] = -up[1];
up[2] = -up[2];

CVettore zAxis, xAxis, yAxis;
float length, result1, result2, result3;

// zAxis = normal(lookAt - position)
zAxis[0] = lookAt[0] - position[0];
zAxis[1] = lookAt[1] - position[1];
zAxis[2] = lookAt[2] - position[2];
length = sqrt((zAxis[0] * zAxis[0]) + (zAxis[1] * zAxis[1]) + (zAxis[2] * zAxis[2]));
zAxis[0] = zAxis[0] / length;
zAxis[1] = zAxis[1] / length;
zAxis[2] = zAxis[2] / length;

// xAxis = normal(cross(up, zAxis))
xAxis[0] = (up[1] * zAxis[2]) - (up[2] * zAxis[1]);
xAxis[1] = (up[2] * zAxis[0]) - (up[0] * zAxis[2]);
xAxis[2] = (up[0] * zAxis[1]) - (up[1] * zAxis[0]);
length = sqrt((xAxis[0] * xAxis[0]) + (xAxis[1] * xAxis[1]) + (xAxis[2] * xAxis[2]));
xAxis[0] = xAxis[0] / length;
xAxis[1] = xAxis[1] / length;
xAxis[2] = xAxis[2] / length;

// yAxis = cross(zAxis, xAxis)
yAxis[0] = (zAxis[1] * xAxis[2]) - (zAxis[2] * xAxis[1]);
yAxis[1] = (zAxis[2] * xAxis[0]) - (zAxis[0] * xAxis[2]);
yAxis[2] = (zAxis[0] * xAxis[1]) - (zAxis[1] * xAxis[0]);

// -dot(xAxis, position)
result1 = ((xAxis[0] * position[0]) + (xAxis[1] * position[1]) + (xAxis[2] * position[2])) * -1.0f;

// -dot(yaxis, eye)
result2 = ((yAxis[0] * position[0]) + (yAxis[1] * position[1]) + (yAxis[2] * position[2])) * -1.0f;

// -dot(zaxis, eye)
result3 = ((zAxis[0] * position[0]) + (zAxis[1] * position[1]) + (zAxis[2] * position[2])) * -1.0f;

// Set the computed values in the view matrix.
matView.SetValore(0, 0, xAxis[0]);
matView.SetValore(0, 1, yAxis[0]);
matView.SetValore(0, 2, zAxis[0]);
matView.SetValore(0, 3, 0.0f);

matView.SetValore(1, 0, xAxis[1]);
matView.SetValore(1, 1, yAxis[1]);
matView.SetValore(1, 2, zAxis[1]);
matView.SetValore(1, 3, 0.0f);

matView.SetValore(2, 0, xAxis[2]);
matView.SetValore(2, 1, yAxis[2]);
matView.SetValore(2, 2, zAxis[2]);
matView.SetValore(2, 3, 0.0f);

matView.SetValore(3, 0, result1);
matView.SetValore(3, 1, result2);
matView.SetValore(3, 2, result3);
matView.SetValore(3, 3, 1.0f);

The results I get from OpenGL and from the SVG output are quite different, but in two days I couldn't come up with a solution.

This is the OpenGL output enter image description here

And this is my SVG output enter image description here

As you can see, it's rotation isn't corrent.

Any idea why? The line points are the same and the matrices too, hopefully.


Pasing the matrices I was creating didn't work. I mean, the matrices were wrong, I think, because OpenGL didn't show anything. So I tryed doing the opposite, I created the matrices in OpenGL and used them with my code. The result is better, but not perfect yet.

Now I think the I do something wrong mapping the 3D points into 2D screen points because the points I get are inverted in Y and I still have some lines not perfectly matching.

This is what I get using the OpenGL matrices and my previous approach to map 3D points to 2D screen space (this is the SVG, not OpenGL render):

enter image description here


Ok this is the content of the view matrix I get from OpenGL:

enter image description here

This is the projection matrix I get from OpenGL:

enter image description here

And this is the result I get with those matrices and by changing my 2D point Y coordinate calculation like bofjas said:

enter image description here

It looks like some rotations are missing. My camera has a rotation of 30° on both the X and Y axis, and it looks like they're not computed correctly.

Now I'm using the same matrices OpenGL does. So I think that I'm doing some wrong calculations when I map the 3D point into 2D screen coordinates.

4
Just FYI: Your method lacks the homogenous division after the projection transformation. It doesn't matter for an orthographic projection, but is vital for a perspective projection to work. As for the ill rotation in your SVG case, I'll have to look into that yet.datenwolf
BTW: What happens if you load the matrices you created into OpenGL and try rendering the image using those? glMatrixMode(...); glLoadMatrix(...) in case you're using the fixed function pipeline.datenwolf
and btw you could print the content of the matrices.joojaa
In OpenGL the lower-left corner is 0,0. Try switching to: 2D_point_y = (windowHeight / 2) * -3D_point_y + (windowHeight / 2) for the Y-axis. At least then it will be correct when using the OpenGL matrixbofjas
The OpenGL produces exactly vertical lines for lines of constant X, and sloping lines for lines of constant Y, while your code is producing sloping lines for lines of constant X and exactly horizontal lines for lines of constant Y. I would guess that that indicates you have an inadvertent x-y swap in your code.cardiff space man

4 Answers

2
votes

Rather than debugging your own code, you can use transform feedback to compute the projections of your lines using the OpenGL pipeline. Rather than rasterizing them on the screen you can capture them in a memory buffer and save directly to the SVG afterwards. Setting this up is a bit involved and depends on the exact setup of your OpenGL codepath, but it might be a simpler solution.

As per your own code, it looks like you either mixed x and y coordinates somewhere, or row-major and column-major matrices.

0
votes

I've solved this problem in a really simple way. Since when I draw using OpenGL it's working, I've just created the matrices in OpenGL and then retrieved them with glGet(). Using those matrices everything is ok.

0
votes

You're looking for a specialized version of orthographic (oblique) projections called isometric projections. The math is really simple if you want to know what's inside the matrix. Have a look on Wikipedia

0
votes

OpenGL loads matrices in column major(opposite of c++).for example this matrix:

[1 ,2 ,3 ,4 ,
 5 ,6 ,7 ,8 ,
 9 ,10,11,12,
 13,14,15,16]

loads this way in memory:

|_1 _|
|_5 _|
|_9 _|
|_13_|
|_2 _|
.
.
.

so i suppose you should transpose those matrices from openGL(if you`re doing it row major)