[cairo] The right approach to projective transformations

Andrea Canciani ranma42 at gmail.com
Fri Aug 20 11:01:58 PDT 2010

On Fri, Aug 20, 2010 at 7:34 PM, Bill Spitzak <spitzak at gmail.com> wrote:
> On 08/20/2010 03:03 AM, Maarten Bosmans wrote:
>> The patch I send earlier mainly resulted in discussion about how many
>> dimensions cairo should use and how big the transformation matrix
>> should be. To sidestep that I first would like to define the scope of
>> the proposed feature.
>> I want to enable projective transformations in Cairo using a linear
>> transformation of the 2D homogeneous coordinates. This is the same
>> method that is already implemented in Pixman, using a 3x3 matrix.
>> So I specifically do not want to add a z-axis. The feature is meant to
>> enable the mapping of a rectangle to an arbitrary (convex)
>> quadrilateral instead of only the parallelograms that are currently
>> possible.
> I looked at this some more and I do think 3x3 will work. I was confused
> because I have always seen perspective as putting non-zero in the z->w
> location in a 4x4 matrix. This location is ignored when translating 2D
> coordinates to the 2D screen, but if the matrix is multiplied by others then
> it can make the x->w and y->w locations non-zero to get perspective on the
> screen.
> However if you set these locations directly (which you are doing) then you
> can get all possible results without bothering with these columns.
> In addition the existing Cairo 2D transformations, and this transformation,
> will concatenate correctly. Multiplying these 3x3 matrixes will produce the
> same result as multiplying two 4x4 matrixes with the third row and column
> all zero. This means that even transforms such as setting up a projection,
> and setting up another projection inside that, will produce the desired
> result: it will look like the inner projection has been done onto a flat
> plane and that plane projected onto the final output.
> However I think you will need 9 numbers, not 8. It is pretty easy to make
> the lower-right number be zero so that normalization will not work:
>        | 1 0 0 |   | 1 0 1 |
>        | 0 1 0 | x | 0 1 0 |
>        |-1 0 1 |   | 0 0 1 |
> I suspect that the lower-right number will often end up with very tiny
> values and that normalizing the matrix will make all the other values huge,
> resulting in overflow of even floating point after mulitplying several with
> a normalization step after each multiply.

If you want to "normalize" the matrix, you should not divide the whole matrix
by the bottom right element (i.e. keep it always 1), but by the sum of the
elements in the last column (which cannot be 0, otherwise your transformation
would transform all the points in Infinities or NaNs).

More information about the cairo mailing list