This forum has been archived. All content is frozen. Please use KDE Discuss instead.

Recommended method for applying a perspective matrix?

Tags: None
(comma "," separated)
davidje13
Registered Member
Posts
13
Karma
0
OS
I need to multiply points by a matrix, divide by the w-component, and convert the result to an int. I can do:

Code: Select all
void applyProjection( Eigen::Matrix<int,2,Eigen::Dynamic>& output, const Eigen::Matrix<double,4,4>& mvp,
                      const Eigen::Matrix<double,4,Eigen::Dynamic>& coordinates,
                      double scaleX, double scaleY, double shiftX, double shiftY ) {
   Eigen::Matrix<double,4,Eigen::Dynamic> projected = mvp * coordinates;
   output.resize( 2, projected.cols( ) );
   output.row( 0 ) = (projected.row( 0 ).array( ) * scaleX / projected.row( 3 ).array( ) + shiftX).cast<int>( );
   output.row( 1 ) = (projected.row( 1 ).array( ) * scaleY / projected.row( 3 ).array( ) + shiftY).cast<int>( );
}


but that uses 3 passes of the data and a temporary. Is there a more efficient way? This seems like the sort of thing which would come up a lot.
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
The recommended way is to use a Projective3d (typedef for Transform<double,3,Projective>). See http://eigen.tuxfamily.org/dox/classEig ... sform.html and http://eigen.tuxfamily.org/dox/group__T ... metry.html for details.

For instance:
Projective3d P(mvp);
coordinates = mvp * coordinates;
davidje13
Registered Member
Posts
13
Karma
0
OS
I don't understand; Projective3d seems to be a plain wrapper around the matrix object (it isn't dividing by the w component). I don't know much of the terminology for this, but it seems that homogeneous vectors are what I'm looking for (maybe). But using "P * coordinates.homogeneous();" or "P * coordinates.colwise().homogeneous();" cause compile errors: YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX and INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION.
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
ah, it seems we don't allow implicit normalization so you can do:
Code: Select all
(mvp * coordinates.colwise().homogeneous()).colwise().hnormalized()
davidje13
Registered Member
Posts
13
Karma
0
OS
OK, that makes sense. I haven't checked if it works yet but it sounds right.

For anyone else, something which tripped me up is that hnormalized returns a 3-component vector not a 4-component one. So you need to do:
Code: Select all
Eigen::Matrix<double,3,Eigen::Dynamic> projected;
projected.noalias( ) = (mvp * coordinates).colwise( ).hnormalized( );

otherwise it will complain about mixing different sizes. (incidentally, is this optimised? If it's returning 3-component vectors it can't be working in-place, and won't be 16-byte aligned… I'm sure it's faster than my old code but it seems there could be room for improvement)


Bookmarks



Who is online

Registered users: Bing [Bot], Google [Bot], Sogou [Bot], Yahoo [Bot]