- 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
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
> 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/
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/
> 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/
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/
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
> 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/
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/
> 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/
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
> 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/
- 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
> 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.