[osg-users] transpose() and osg_NormalViewMatrix

211 views
Skip to first unread message

Rob Radtke

unread,
Jan 15, 2011, 5:43:08 PM1/15/11
to OpenSceneGraph Users
I am submitting a code patch for possible inclusion into the OSG code
repository. The patch is against the OSG trunk, as updated this
morning. It's just a couple of very small changes but, from reading
some old posts on the message board, I thought that the changes might be
useful to other OSG users as well. The changes are:

- Add a transpose() function to Matrixf and Matrixd
- Add two new osg "global" glsl uniforms: osg_NormalViewMatrix and
osg_NormalViewMatrixInverse

If you prefer that I submit these changes in a different format, I'd be
happy to do that as well. Thanks,

Rob

osgUniformTranspose.patch

Paul Martz

unread,
Jan 15, 2011, 6:00:34 PM1/15/11
to OpenSceneGraph Users
On 1/15/2011 3:43 PM, Rob Radtke wrote:
> - Add a transpose() function to Matrixf and Matrixd

Rather than a transpose() function, I wonder if anyone else would be interested
in seeing support for two different operator*() methods to handle vector/matrix
multiply, namely:

osg::Vec4 v;
osg::Matrix m;

vec4 vprime = v * m; // multiply the row vector by the row-major matrix,
// as currently supported by OSG.
vprime = m * v; // effectively multiply the vector by the matrix transpose.

In the second case, each element of vprime would be computed as:
vprime.x = dot( m.column0, v );
vprime.y = dot( m.column1, v );
vprime.z = dot( m.column2, v );
vprime.w = dot( m.column3, v );

Similarly, GLSL uses order to do essentially the same thing, however, GLSL uses
column major matrices (as per OpenGL spec, math texts, etc), so the ordering is
reversed, that is:
vec4 vprime = m * v; // multiply column vector by column-major matrix
vprime = v * m; // effectively multiply the vector by the matrix transpose.

If we were to do this in OSG, it would make it a bit easier to multiply an
instance of the osg::Plane class by a matrix, we could just define an
operator*() for that, like we would do for Vec4.
-Paul
_______________________________________________
osg-users mailing list
osg-...@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Jean-Sébastien Guay

unread,
Jan 15, 2011, 10:21:33 PM1/15/11
to OpenSceneGraph Users
Hi Paul, Rob,

> Rather than a transpose() function, I wonder if anyone else would be
> interested in seeing support for two different operator*() methods to
> handle vector/matrix multiply, namely:

[...]

Maybe I'm missing something, but aren't M*V and V*M already defined
precisely to help with multiplying by a matrix or its transpose? See the
code for the Matrixf and Matrixd classes, as well as this page:

http://www.openscenegraph.org/projects/osg/wiki/Support/Maths/MatrixTransformations

Quote which is apparently from Robert a while ago:
<begin quote>

V' = V*M and M* V are defined....

the first, as Don points out is the standard one you should use, and the
later is just for special occasions...

And the special occasion is when you'd want to do V' = V* Mtranspose
where you only have M to hand and would have to do a transpose of M.

This can be rewritten V' = M * V;

The particular time when you'll do this would be when transforming
normals and planes by the inverse transpose. This is done all the time
in the cull traversal, where the inverse just happens to be the
accumulated modelview matrix.

This is all a bit crafty, but certainly helps remove all those extra ops
in transposing.

<end quote>

J-S
--
______________________________________________________
Jean-Sebastien Guay jean-seba...@cm-labs.com
http://www.cm-labs.com/
http://whitestar02.webhop.org/

Paul Martz

unread,
Jan 16, 2011, 10:10:47 AM1/16/11
to OpenSceneGraph Users
On 1/15/2011 8:21 PM, Jean-Sébastien Guay wrote:
> Maybe I'm missing something, but aren't M*V and V*M already defined precisely to
> help with multiplying by a matrix or its transpose? See the code for the Matrixf
> and Matrixd classes, as well as this page:

Good...

> The particular time when you'll do this would be when transforming normals and
> planes by the inverse transpose. This is done all the time in the cull
> traversal, where the inverse just happens to be the accumulated modelview matrix.

Well, this doesn't appear to work for Plane:

osg::Plane p;
osg::Matrix4 l2w;
osg::Plane pprime = l2w * p; // compile error

I used this code instead:

p.transform( l2w );

This compiles, runs, and transforms the plane correctly.

Converting the plane to a Vec4 allows me to do this:

osg::Vec4 pv = p.asVec4();
osg::Vec4 pvprime = l2w * pv;

That code compiles and runs, but produces incorrect results when compared to the
(correct) results of osg::Plane::transform().

I'm on 2.8.3, so perhaps there have been improvements on trunk?

--
-Paul Martz Skew Matrix Software
http://www.skew-matrix.com/

Jean-Sébastien Guay

unread,
Jan 16, 2011, 12:10:12 PM1/16/11
to OpenSceneGraph Users
Hi Paul,

> Well, this doesn't appear to work for Plane:

I wouldn't know about planes, I've only ever used the multiply by
transpose to transform direction vectors or normals, never planes.
Perhaps there's just a little extra needed (for example, maybe adding an
implicit conversion constructor from osg::Vec4 to osg::Plane or an
additional Plane operator*(Matrix, Plane) method.

It's just that I had seen that page about the V*M and M*V a long time
ago, and thought it would be good to know there's already part of the
work done.

> Converting the plane to a Vec4 allows me to do this:
>
> osg::Vec4 pv = p.asVec4();
> osg::Vec4 pvprime = l2w * pv;
>
> That code compiles and runs, but produces incorrect results when
> compared to the (correct) results of osg::Plane::transform().

Did you look at the math that this results in? Running it in the
debugger would likely tell you why it doesn't work. Again I'm not much
help, I've never done this myself.

Sorry I can't help more,

J-S
--
______________________________________________________
Jean-Sebastien Guay jean-seba...@cm-labs.com
http://www.cm-labs.com/
http://whitestar02.webhop.org/

Paul Martz

unread,
Jan 19, 2011, 11:54:52 AM1/19/11
to OpenSceneGraph Users
More info -- This is not an issue. "m * v" is equivalent to "v * mTranspose".

I had previously written code that indicated this was broke for vectors, but I
recently rewrote the test case:
{
osg::Vec4 v( 1.0, 0.0, 0.0, 1.0 );
osg::Matrix m( osg::Matrix::translate( 3., 5., 0. ) );

osg::Plane p( v );
p.transform( m ); // multiply by inverse transpose
osg::notify( osg::NOTICE ) << p << std::endl;

osg::Matrix mInv = osg::Matrix::inverse( m );
osg::Vec4 vPrime = mInv * v; // multiply by inverse transpose
osg::notify( osg::NOTICE ) << vPrime << std::endl;
}
and I am now getting the same results for both the Plane and the Vec4 transform.
So my original code must have been flawed.

Back to the original poster, then... Does this eliminate a need for a
transpose() function in the Matrix class?
-Paul


On 1/16/2011 10:10 AM, Jean-Sébastien Guay wrote:
> Hi Paul,
>
>> Well, this doesn't appear to work for Plane:
>
> I wouldn't know about planes, I've only ever used the multiply by transpose to
> transform direction vectors or normals, never planes. Perhaps there's just a
> little extra needed (for example, maybe adding an implicit conversion
> constructor from osg::Vec4 to osg::Plane or an additional Plane
> operator*(Matrix, Plane) method.
>
> It's just that I had seen that page about the V*M and M*V a long time ago, and
> thought it would be good to know there's already part of the work done.
>
>> Converting the plane to a Vec4 allows me to do this:
>>
>> osg::Vec4 pv = p.asVec4();
>> osg::Vec4 pvprime = l2w * pv;
>>
>> That code compiles and runs, but produces incorrect results when
>> compared to the (correct) results of osg::Plane::transform().
>
> Did you look at the math that this results in? Running it in the debugger would
> likely tell you why it doesn't work. Again I'm not much help, I've never done
> this myself.
>
> Sorry I can't help more,
>
> J-S


--

-Paul Martz Skew Matrix Software
http://www.skew-matrix.com/

Rob Radtke

unread,
Jan 19, 2011, 12:13:52 PM1/19/11
to OpenSceneGraph Users

On 1/19/2011 8:54 AM, Paul Martz wrote:
> More info -- This is not an issue. "m * v" is equivalent to "v *
> mTranspose".
>
> I had previously written code that indicated this was broke for
> vectors, but I recently rewrote the test case:
> {
> osg::Vec4 v( 1.0, 0.0, 0.0, 1.0 );
> osg::Matrix m( osg::Matrix::translate( 3., 5., 0. ) );
>
> osg::Plane p( v );
> p.transform( m ); // multiply by inverse transpose
> osg::notify( osg::NOTICE ) << p << std::endl;
>
> osg::Matrix mInv = osg::Matrix::inverse( m );
> osg::Vec4 vPrime = mInv * v; // multiply by inverse transpose
> osg::notify( osg::NOTICE ) << vPrime << std::endl;
> }
> and I am now getting the same results for both the Plane and the Vec4
> transform. So my original code must have been flawed.
>
> Back to the original poster, then... Does this eliminate a need for a
> transpose() function in the Matrix class?

I'm not 100% sure. My primary motivation for the transpose() function
was to compute a normal matrix (so it could be passed to glsl as an osg
uniform: osg_NormalViewMatrix). My understanding is that the way to do
that is to transpose the inverse of the view matrix (and take the upper
right 3x3), like so:

static osg::Matrix3 toNormalMatrix( const osg::Matrix& mat )
{
osg::Matrix normVMat = osg::Matrix::orthoNormal(
osg::Matrix::transpose( osg::Matrix::inverse( mat ) ) );
osg::Matrix3 normalViewMatrix3x3( normVMat(0,0), normVMat(0,1),
normVMat(0,2),
normVMat(1,0), normVMat(1,1),
normVMat(1,2),
normVMat(2,0), normVMat(2,1),
normVMat(2,2) );
return normalViewMatrix3x3;
}

Multiplication by this normal matrix wouldn't happen until you were
inside of a vertex shader. If we really wanted to avoid transposing the
matrix, I suppose we could instead use a uniform named
osg_NormalViewMatrixTransposed and the shaders would be responsible for
reversing the multiplication order. It would save some cpu time, but I
feel like the solution is less clean. It would be even more confusing
for the osg_NormalViewMatrixInverse uniform, which would become
osg_NormalViewMatrixInverseTransposed. What do you all think?

Rob

Jean-Sébastien Guay

unread,
Jan 19, 2011, 12:24:59 PM1/19/11
to OpenSceneGraph Users
Hi Paul,

> So my original code must have been flawed.

Just curious, trying to get to the bottom of this in case it's
important... The code you first posted used Plane::asVec4(), and your
new code doesn't. Could it be that p.asVec4() != v? i.e. there would be
a bug in Plane::asVec4()?

{
osg::Vec4 v( 1.0, 0.0, 0.0, 1.0 );
osg::Matrix m( osg::Matrix::translate( 3., 5., 0. ) );

osg::Plane p( v );
p.transform( m ); // multiply by inverse transpose
osg::notify( osg::NOTICE ) << p << std::endl;

osg::Matrix mInv = osg::Matrix::inverse( m );
osg::Vec4 vPrime = mInv * v; // multiply by inverse transpose
osg::notify( osg::NOTICE ) << vPrime << std::endl;

osg::Vec4 vPrime2 = mInv * p.asVec4(); // multiply by inverse
transpose
osg::notify( osg::NOTICE ) << vPrime2 << std::endl;

assert(v == p.asVec4());
assert(vPrime == vPrime2);
}

J-S
--
______________________________________________________
Jean-Sebastien Guay jean-seba...@cm-labs.com
http://www.cm-labs.com/
http://whitestar02.webhop.org/

Paul Martz

unread,
Jan 19, 2011, 12:50:40 PM1/19/11
to OpenSceneGraph Users
On 1/19/2011 10:24 AM, Jean-Sébastien Guay wrote:
> Hi Paul,
>
>> So my original code must have been flawed.
>
> Just curious, trying to get to the bottom of this in case it's important... The
> code you first posted used Plane::asVec4(), and your new code doesn't. Could it
> be that p.asVec4() != v? i.e. there would be a bug in Plane::asVec4()?

The asVec4() function seems straightforward:
Vec4_type asVec4() const { return Vec4(_fv[0],_fv[1],_fv[2],_fv[3]); }

I see in the code I posted earlier that the matrix is names "l2w" rather than
"w2l", so I think it's more likely that I forget to invert the matrix for the
Vec4 transform, which the Plane transform does automatically.

My project code is still transforming using Plane, so the real test would be to
go back and rewrite that code to (again) use Vec4. I'll try to get to that
today, but have a few other high-priority issues I need to deal with...
-Paul

>
> {
> osg::Vec4 v( 1.0, 0.0, 0.0, 1.0 );
> osg::Matrix m( osg::Matrix::translate( 3., 5., 0. ) );
>
> osg::Plane p( v );
> p.transform( m ); // multiply by inverse transpose
> osg::notify( osg::NOTICE ) << p << std::endl;
>
> osg::Matrix mInv = osg::Matrix::inverse( m );
> osg::Vec4 vPrime = mInv * v; // multiply by inverse transpose
> osg::notify( osg::NOTICE ) << vPrime << std::endl;
>
> osg::Vec4 vPrime2 = mInv * p.asVec4(); // multiply by inverse transpose
> osg::notify( osg::NOTICE ) << vPrime2 << std::endl;
>
> assert(v == p.asVec4());
> assert(vPrime == vPrime2);
> }
>
> J-S


--

-Paul Martz Skew Matrix Software
http://www.skew-matrix.com/

Jean-Sébastien Guay

unread,
Jan 19, 2011, 1:06:48 PM1/19/11
to OpenSceneGraph Users
Hi Paul,

> I'll try
> to get to that today, but have a few other high-priority issues I need
> to deal with...

Yeah, don't sweat it, I'm just curious and I think you've nailed it in
the previous message.

J-S
--
______________________________________________________
Jean-Sebastien Guay jean-seba...@cm-labs.com
http://www.cm-labs.com/
http://whitestar02.webhop.org/

Paul Martz

unread,
Jan 19, 2011, 1:09:32 PM1/19/11
to OpenSceneGraph Users
On 1/19/2011 10:13 AM, Rob Radtke wrote:
>> Back to the original poster, then... Does this eliminate a need for a
>> transpose() function in the Matrix class?
>
> I'm not 100% sure. My primary motivation for the transpose() function was to
> compute a normal matrix (so it could be passed to glsl as an osg uniform:
> osg_NormalViewMatrix).

Ah. I see. You don't want to do the math on the host, you want to do it in the
shader. You could swap the multiplication order to get the transpose, but you'd
still need to invert the model-view matrix, which you probably don't want to do
per vertex.
-Paul

Rob Radtke

unread,
Jan 19, 2011, 6:48:36 PM1/19/11
to OpenSceneGraph Users
On 1/19/2011 10:09 AM, Paul Martz wrote:
> On 1/19/2011 10:13 AM, Rob Radtke wrote:
>>> Back to the original poster, then... Does this eliminate a need for a
>>> transpose() function in the Matrix class?
>>
>> I'm not 100% sure. My primary motivation for the transpose() function
>> was to
>> compute a normal matrix (so it could be passed to glsl as an osg
>> uniform:
>> osg_NormalViewMatrix).
>
> Ah. I see. You don't want to do the math on the host, you want to do
> it in the shader. You could swap the multiplication order to get the
> transpose, but you'd still need to invert the model-view matrix, which
> you probably don't want to do per vertex.
Yes, exactly. It would be nice to make osg_NormalViewMatrix and
osg_NormalViewMatrixInverse available as OSG global uniforms (similar to
existing global uniforms osg_ViewMatrix and osg_ViewMatrixInverse).
That was the primary purpose of my patch, but computing those matrices
involves also computing matrix transposes. Of course, we don't need to
make osg::Matrix::transpose() part of the public API, if we don't want
to. Do others agree that the new osg_NormalViewMatrix and
osg_NormalViewMatrixInverse uniforms would be generally useful? If so,
then I'll put together a different patch that doesn't include a public
Matrix::transpose() function.

Rob

Jean-Sébastien Guay

unread,
Jan 19, 2011, 8:29:33 PM1/19/11
to OpenSceneGraph Users
Hi Rob,

> Of course, we don't need to
> make osg::Matrix::transpose() part of the public API, if we don't want
> to.

I personally think there's nothing *wrong* with having a transpose()
method, it's just that if the existing M*V would have fit your use case
then it would have avoided duplicating functionality and having 2 ways
of doing things, which would potentially confuse new users. Though you
may argue that *not* having a transpose() method and relying on the M*V
might confuse them more, given that it's more obscure and hard to
understand at a glance and we need a wiki page to explain its use.

So I would be open to adding transpose(), and while you're at it,
perhaps the doxygen comment for transpose() can mention that when
transforming normals and planes you can use M*V to avoid extra
operations involved in an explicit transpose, and the doxygen comment
for the M*V operator can also mention the particular cases where this is
useful and not to confuse it with the regular V*M operator...

Thanks,

J-S
--
______________________________________________________
Jean-Sebastien Guay jean-seba...@cm-labs.com
http://www.cm-labs.com/
http://whitestar02.webhop.org/

Rob Radtke

unread,
Jan 20, 2011, 12:53:56 PM1/20/11
to OpenSceneGraph Users
On 1/19/2011 5:29 PM, Jean-Sébastien Guay wrote:
> Hi Rob,
>
>> Of course, we don't need to
>> make osg::Matrix::transpose() part of the public API, if we don't want
>> to.
>
> I personally think there's nothing *wrong* with having a transpose()
> method, it's just that if the existing M*V would have fit your use
> case then it would have avoided duplicating functionality and having 2
> ways of doing things, which would potentially confuse new users.
> Though you may argue that *not* having a transpose() method and
> relying on the M*V might confuse them more, given that it's more
> obscure and hard to understand at a glance and we need a wiki page to
> explain its use.
>
> So I would be open to adding transpose(), and while you're at it,
> perhaps the doxygen comment for transpose() can mention that when
> transforming normals and planes you can use M*V to avoid extra
> operations involved in an explicit transpose, and the doxygen comment
> for the M*V operator can also mention the particular cases where this
> is useful and not to confuse it with the regular V*M operator...
>
Attached is a patch (against trunk) that contains my original changes:

- Add a transpose() function to Matrixf and Matrixd

- Add two new osg "global" glsl uniforms: osg_NormalViewMatrix and
osg_NormalViewMatrixInverse

as well as some doxygen comments that discuss the merits of using
transpose() vs. postMult() etc. The meat of the comments are on the
preMult() and postMult() functions with see also's on the relevant
operator*() functions.

Rob

OsgUniformAndTransposePatch.patch

Jean-Sébastien Guay

unread,
Jan 20, 2011, 1:11:19 PM1/20/11
to OpenSceneGraph Users
Hi Rob,

> Attached is a patch (against trunk)[...]

The changes look good to me. Good work on the comments. You'll want to
send the whole modified files to osg-submissions so Robert can review
and check them in.

Also I should have said that my opinion is not the deciding factor for
whether the changes get integrated or not... Robert has final say of
course. I was giving my opinion in the previous message and I realize it
may have been construed as a final decision, sorry if I misled you.

Reply all
Reply to author
Forward
0 new messages