### Re: [osg-users] Quat * Vec3 proposals - request for comments/help

--- On Tue, 21/4/09, J.P. Delport jpdelp...@csir.co.za wrote: From: J.P. Delport jpdelp...@csir.co.za Subject: [osg-users] Quat * Vec3 proposals - request for comments/help To: osg users osg-users@lists.openscenegraph.org Date: Tuesday, 21 April, 2009, 1:36 PM Hi all, it's been known for a while [1] that there are inconsistencies with the way OSG handles Quat * Vec3. In short: Quat * Vec3 is written in code as a post-multiply, but the result of the operation is as if a pre-multiply was performed. The attached test app also shows the problem (more on it later). [1] http://thread.gmane.org/gmane.comp.graphics.openscenegraph.user/21003 and http://thread.gmane.org/gmane.comp.graphics.openscenegraph.user/33099 What doesn't work? There are many examples that can be constructed of where a mathematical expression usings quats and vectors would not provide the expected results. See also [1]. The easiest one I could come up with is this: ((q1 * q2) * v) != (q1 * (q2 * v)) Why are there not more complaints? Well I curse this all the time, but not for the same reason. For me it's q1 * q2 that's annoying as I see it as the opposite of what I expect from the mathematics of applying a quaternion to a vector but then therein lies the problem. Using operator* for matrix multiplications is fine as that mirrors precisely what you are doing with the matrices mathematically. Using operator* for quaternion multiplication is a loose analogy since you are actually doing q*v*q' mathematically when applying q to v. If you have two rotations, q1 followed by q2 then you would get q2*q1*v*q1'*q2' mathematically and so I expect the interpretation of operator* to allow me to write q2*q1*v in code. Of course that's just my interpretation and what I'm effectively saying within that interpretation is that it's quat * quat that is wrong but there's no way in the world you can swap that now! :) Alternatively you could drop osg::Vec3::operator*( osg::Quat ) altogether and have osg::Vec3::apply( osg::Quat ) or osg::Vec3::rotate( osg::Quat ). I've used math libraries that do it this way (and where vec::operator*( quat ) is just that i.e. the mathematical multiplication rather than the full blown rotation. I guess it depends on whether you value the brevity of operator* over the underlying mathematics. If operator* is still going to be used for applying a quaternion to a vector then I support the idea of making the multiplication orders consistent between quat/quat and vec/quat as per your proposal. Making it consistent with OSG's row-major matrix multiplication is probably easier for coders who are not concerned with the details of the maths (and as I noted above it's not a workable solution to swap it now anyway). Whatever happens I second the comment of Tanguy Fautre who asked for it to be documented clearly somewhere. :) Anyway I hope you don't mind me chipping in. It certainly is interesting that there hasn't been more discussion. Maybe people just do what works and leave it. ;) Paul Fotheringham. ___ osg-users mailing list osg-users@lists.openscenegraph.org http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

### Re: [osg-users] Quat * Vec3 proposals - request for comments/help

Alternatively you could drop osg::Vec3::operator*( osg::Quat ) altogether and have osg::Vec3::apply( osg::Quat ) or osg::Vec3::rotate( osg::Quat ). Woops. Of course I meant that it was osg::Quat::operator*( osg ::Vec3 ) that could be dropped. Sorry. Paul Fotheringham. ___ osg-users mailing list osg-users@lists.openscenegraph.org http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

### [osg-users] Quat * Vec3 proposals - request for comments/help

Hi all, it's been known for a while [1] that there are inconsistencies with the way OSG handles Quat * Vec3. In short: Quat * Vec3 is written in code as a post-multiply, but the result of the operation is as if a pre-multiply was performed. The attached test app also shows the problem (more on it later). [1] http://thread.gmane.org/gmane.comp.graphics.openscenegraph.user/21003 and http://thread.gmane.org/gmane.comp.graphics.openscenegraph.user/33099 What doesn't work? There are many examples that can be constructed of where a mathematical expression usings quats and vectors would not provide the expected results. See also [1]. The easiest one I could come up with is this: ((q1 * q2) * v) != (q1 * (q2 * v)) Why are there not more complaints? I suppose most people do all the quat multiplications before they multiply with the vector. Since OSG does not have a pre-multiply for quat, the only option is then to post-multiply the resulting quat with the vector. What can be done? As a first step I think we can add the pre-multiply to OSG. The attached header does this. (To fix the post-multiply can be done later.) What will break? I think and hope nothing, since there was no pre-multiply that people could have used. (Fixing the post-multiply would break current code.) Why now? The itch finally got annoying enough. What about the post-multiply? I think we should in some way let developers know that the post-multiply they currently use will change in future and that they should switch their multiply to the pre-version (which will behave the same as current code). I think a compiler warning or error would help more than only documentation. Something like a deprecated warning. I need help with this though, I do not know how to generate a warning in a cross-platform manner. Later we can then fix the post-multiply quat code. Test app details: The test app considers two rotations and a vector. It shows that for Matrix and Vec3 interactions everything is consistent, e.g. ((m1 * m2) * v) == (m1 * (m2 * v)) and (v * (m1 * m2)) == ((v * m1) * m2) It then shows that Quat post-multiply does not behave as Matrix post-multiply does and actually behaves more like Matrix pre-multiply does. It also shows the inconsistency of various expressions. We also know (from the osgunittest example) that m1(q1) * m2(q2) == q1 * q2 so the internal quat * quat is consistent with the matrix multiply order. It is only the quat * vec that is not. Finally it shows that with the added pre-multiply (enable by making the #if 0 a 1), the quat pre-mult behaves the same as the matrix pre-mult. Comments welcome. regards jp -- This message is subject to the CSIR's copyright terms and conditions, e-mail legal notice, and implemented Open Document Format (ODF) standard. The full disclaimer details can be found at http://www.csir.co.za/disclaimer.html. This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. MailScanner thanks Transtec Computers for their support. /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #ifndef OSG_QUAT #define OSG_QUAT 1 #include osg/Export #include osg/Vec3f #include osg/Vec4f #include osg/Vec3d #include osg/Vec4d namespace osg { class Matrixf; class Matrixd; /** A quaternion class. It can be used to represent an orientation in 3D space.*/ class OSG_EXPORT Quat { public: typedef double value_type; value_type _v[4];// a four-vector inline Quat() { _v[0]=0.0; _v[1]=0.0; _v[2]=0.0; _v[3]=1.0; } inline Quat( value_type x, value_type y, value_type z, value_type w ) { _v[0]=x; _v[1]=y; _v[2]=z; _v[3]=w; } inline Quat( const Vec4f v ) { _v[0]=v.x(); _v[1]=v.y(); _v[2]=v.z(); _v[3]=v.w(); } inline Quat( const Vec4d v ) { _v[0]=v.x(); _v[1]=v.y(); _v[2]=v.z(); _v[3]=v.w(); } inline Quat( value_type angle, const Vec3f axis) { makeRotate(angle,axis); } inline Quat( value_type angle, const Vec3d axis) { makeRotate(angle,axis); } inline Quat( value_type angle1, const Vec3f axis1, value_type angle2,