Discussion:
[Algorithms] Converting raw projection matrices between GL and D3D?
Aras Pranckevicius
2007-02-14 13:06:15 UTC
Permalink
Hi,

Is there a way to convert just the raw projection matrix (i.e. 16
floats, no other data known) between coordinate/projection conventions
of OpenGL and D3D?

What I'm looking for is a function that gets 16 floats on input and
spits out 16 floats in return; handling ortho, perspective and other
(think oblique) projections equally well.

I can't think of a generic method myself (just scale/bias works for
ortho, but not for perspective for example), and my homogeneous math
is in not very good shape...
--
Aras Pranckevicius
work: www.unity3d.com
home: nesnausk.org/nearaz
Jon Watte
2007-02-15 18:20:24 UTC
Permalink
The only difference I can think of is that in OpenGL clip space, the Z
range is -1 to 1, whereas in Direct3D, the Z range is 0 to 1. Thus, you
can scale and offset the Z coordinate (column, if you're row-vector on
left; row, if you're column-vector on right) to adjust for this. Scale
elements 0,1,2 by 0.5, add 0.5 to the 3rd element.

Unless you want to also compensate for left-handed vs right-handed
coordinate interpretation conventions, at which point you need to
involve render state such as face culling in addition to just the matrix.

Cheers,

/ h+
Post by Aras Pranckevicius
Hi,
Is there a way to convert just the raw projection matrix (i.e. 16
floats, no other data known) between coordinate/projection conventions
of OpenGL and D3D?
What I'm looking for is a function that gets 16 floats on input and
spits out 16 floats in return; handling ortho, perspective and other
(think oblique) projections equally well.
I can't think of a generic method myself (just scale/bias works for
ortho, but not for perspective for example), and my homogeneous math
is in not very good shape...
Aras Pranckevicius
2007-02-15 18:49:50 UTC
Permalink
Post by Jon Watte
The only difference I can think of is that in OpenGL clip space, the Z
range is -1 to 1, whereas in Direct3D, the Z range is 0 to 1. Thus, you
can scale and offset the Z coordinate (column, if you're row-vector on
left; row, if you're column-vector on right) to adjust for this. Scale
elements 0,1,2 by 0.5, add 0.5 to the 3rd element.
That was my first idea as well, but somehow it does not seem to work.

Take the canonical GL perspective matrix, third row (assuming no
negative scaling on Z):
0 0 (f+n)/(f-n) -2*f*n/(f-n)
And the canonical D3D perspective matrix:
0 0 f/(f-n) -f*n/(f-n)

Scaling by 0.5 (first 3 elements) and biasing by 0.5 (4th element) on
GL matrix row would not produce the D3D values. But scaling&biasing on
the orthogonal projection matrix would produce the correct result.

Or am I missing something obvious here?
--
Aras Pranckevicius
work: www.unity3d.com
home: nesnausk.org/nearaz
Adrian Stephens
2007-02-15 23:13:07 UTC
Permalink
If you multiply out the matrices, you will get the correct answer. The
magic of homogeneous matrices makes it 'just work' (in this case, because of
the zero in the bottom right corner of the perspective matrix).

i.e. multiply your GL matrix by
| 1 0 0 0 |
| 0 1 0 0 |
| 0 0 .5 .5 |
| 0 0 0 1 |
(which represents the scale and bias of the z component), and you will get
the answer you expect.

-----Original Message-----
From: gdalgorithms-list-***@lists.sourceforge.net
[mailto:gdalgorithms-list-***@lists.sourceforge.net] On Behalf Of Aras
Pranckevicius
Sent: Thursday, February 15, 2007 10:50 AM
To: Game Development Algorithms
Subject: Re: [Algorithms] Converting raw projection matrices between GL
andD3D?
Post by Jon Watte
The only difference I can think of is that in OpenGL clip space, the Z
range is -1 to 1, whereas in Direct3D, the Z range is 0 to 1. Thus, you
can scale and offset the Z coordinate (column, if you're row-vector on
left; row, if you're column-vector on right) to adjust for this. Scale
elements 0,1,2 by 0.5, add 0.5 to the 3rd element.
That was my first idea as well, but somehow it does not seem to work.

Take the canonical GL perspective matrix, third row (assuming no
negative scaling on Z):
0 0 (f+n)/(f-n) -2*f*n/(f-n)
And the canonical D3D perspective matrix:
0 0 f/(f-n) -f*n/(f-n)

Scaling by 0.5 (first 3 elements) and biasing by 0.5 (4th element) on
GL matrix row would not produce the D3D values. But scaling&biasing on
the orthogonal projection matrix would produce the correct result.

Or am I missing something obvious here?
--
Aras Pranckevicius
work: www.unity3d.com
home: nesnausk.org/nearaz

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
GDAlgorithms-list mailing list
GDAlgorithms-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/gdalgorithms-list
Archives:
http://sourceforge.net/mailarchive/forum.php?forum_id=6188
Alen Ladavac
2007-02-15 22:14:42 UTC
Permalink
Post by Aras Pranckevicius
Post by Jon Watte
The only difference I can think of is that in OpenGL clip space, the Z
range is -1 to 1, whereas in Direct3D, the Z range is 0 to 1. Thus, you
can scale and offset the Z coordinate (column, if you're row-vector on
left; row, if you're column-vector on right) to adjust for this. Scale
elements 0,1,2 by 0.5, add 0.5 to the 3rd element.
That was my first idea as well, but somehow it does not seem to work.
Take the canonical GL perspective matrix, third row (assuming no
0 0 (f+n)/(f-n) -2*f*n/(f-n)
0 0 f/(f-n) -f*n/(f-n)
Scaling by 0.5 (first 3 elements) and biasing by 0.5 (4th element) on
GL matrix row would not produce the D3D values. But scaling&biasing on
the orthogonal projection matrix would produce the correct result.
Or am I missing something obvious here?
It's too late in the evening for me now to get into dissecting the
math behind it (to see if this is equivalent to the scale&bias
mentioned), but this formula derived a few years ago for conversion
from OpenGL to D3D matrices still seems to work correctly in our
codebase:

mAdj =
{
1 0 0 0
0 1 0 0
0 0 0.5 0.5
0 0 0 1
}
mAdjustedProjection = mAdj * mProj;

That is for column vector on the right. Note that you can also add
subpixel correction and fake scissor clipping by adding some more
complicated coefficients to the mAdj matrix.

HTH,
Alen
Benjamin Rouveyrol
2007-02-16 08:42:07 UTC
Permalink
IMHO, you can't just scale/bias the z element by 0.5, 0.5 because in
direct3d, z increases as you get away from the camera, while in opengl it
decreases. I guess that instead of doing Zogl = 2*Zd3d-1, you should have
Zogl = 1-2*Zd3d. So the scale bias should be reversed for the 3rd component
of the matrix.
Post by Aras Pranckevicius
Post by Jon Watte
The only difference I can think of is that in OpenGL clip space, the Z
range is -1 to 1, whereas in Direct3D, the Z range is 0 to 1. Thus, you
can scale and offset the Z coordinate (column, if you're row-vector on
left; row, if you're column-vector on right) to adjust for this. Scale
elements 0,1,2 by 0.5, add 0.5 to the 3rd element.
That was my first idea as well, but somehow it does not seem to work.
Take the canonical GL perspective matrix, third row (assuming no
0 0 (f+n)/(f-n) -2*f*n/(f-n)
0 0 f/(f-n) -f*n/(f-n)
Scaling by 0.5 (first 3 elements) and biasing by 0.5 (4th element) on
GL matrix row would not produce the D3D values. But scaling&biasing on
the orthogonal projection matrix would produce the correct result.
Or am I missing something obvious here?
--
Aras Pranckevicius
work: www.unity3d.com
home: nesnausk.org/nearaz
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share
your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
GDAlgorithms-list mailing list
https://lists.sourceforge.net/lists/listinfo/gdalgorithms-list
http://sourceforge.net/mailarchive/forum.php?forum_id=6188
Aras Pranckevicius
2007-02-16 14:42:46 UTC
Permalink
Hi,

Doh, my multiplying-matrices-on-paper skills are really getting rusty!
Of course scaling and biasing just works (also with taking care of
negated Z axis and inverted culling somewhere).

Sorry for the trouble and thanks!
--
Aras Pranckevicius
work: www.unity3d.com
home: nesnausk.org/nearaz
Jon Watte
2007-02-16 19:33:55 UTC
Permalink
Post by Benjamin Rouveyrol
IMHO, you can't just scale/bias the z element by 0.5, 0.5 because in
direct3d, z increases as you get away from the camera, while in opengl
it decreases. I guess that instead of doing Zogl = 2*Zd3d-1, you
should have Zogl = 1-2*Zd3d. So the scale bias should be reversed for
the 3rd component of the matrix.
I believe that OpenGL, once you've done the viewport transform, also
maps the Z buffer from 0 at the near plane to 1 at the far plane (or
whatever else you've set using glDepthRange()).

Cheers,

/ h+

Loading...