<div dir="ltr">Although only a 3x3 matrix is needed to specify an perspective transform, if you want to use 3D rotations you need to use 4x4 matrix. This is because the result of a rotation depends on the position of the camera from the rotation origin and also the projection (ie fov) being used, and describing that requires more than 9 numbers. I feel supporting 4x4 matrix is not a good idea and thus supporting perspective using rotation is also not a good idea.<div><div><br></div><div>It looks like a "perspective" operation that takes two numbers which I will call px and py will work and kind of match cairo's current transformation concatenation. What this does is premultiply the CTM by the matrix [[1 0 0] [0 1 0] [px py 1]] (in an arrangement where cairo_matrix_t is described as [[xx xy x0] [yx yy y0] [0 0 1]].</div><div><br></div><div>px is 1/x where x is the location of the vanishing point along the x axis. py is 1/y where y is the location of the vanishing point along the y axis.</div><div><br></div><div>The attached images show a 512x512 image where there first is a translate by 256,256, then a perspective operation, then a translate by -256,-256 (the effect of these transformations is to put the origin in the middle of the image). In the first sample the perspective is 1/256,0. In the second it is 0,1/256. In the third it is 1/256,1/256. If you look carefully you can see the lines converge in each of them at the center of the edges, ie 256 units away from the origin.</div></div><div><br></div><div><img src="cid:ii_jcqlxx3o0_1611f5a829d91ddf" width="512" height="512"><br><img src="cid:ii_jcqlxx3v1_1611f5a829d91ddf" width="512" height="512"><br><img src="cid:ii_jcqlxx3z2_1611f5a829d91ddf" width="512" height="512"><br><br></div><div>If the translation is non-zero then the perspective will produce a w (the lower-right corner of the matrix) that is not 1.0. I think this needs to be preserved, rather than attempting to normalize the matrix. This is because it could be zero, but further transforms can restore a non-zero value. The normalization can be applied when the matrix is used to make projections.</div><div><br></div><div>If a client has figured out a projection matrix it wants, it is possible but really difficult to decompose this into a perspective and cairo_matrix_t. So you almost certainly want to add an equivalent of cairo_transform and cairo_set_matrix that take a 3x3 matrix directly. To make it easy to call with matrixes computed by modern 3d libraries, it would be best to also take a 4x4 matrix in *column major order* and ignore the 3rd row and column. In such a matrix a cairo_matrix_t and perspective would be the following 16 numbers in this order: [xx yx ? px xy yy ? py ? ? ? ? x0 y0 ? 1], ? are ignored numbers.</div><div><br></div><div>Perspective also brings up questions about what to do about the line width, dash patterns, and the font. IMHO applying perspective to these would break all kinds of optimizations. The only useful thing to support is perspective transforms of images. It may also be useful to transform path points by it. For the same reason rotations don't work, it is useless for the client to provide a 'z' value, you can only draw paths in the projected plane. To logically support this you certainly need "line width locking" so changing the CTM does not change the lines.</div><div><br></div><div>Another approach that may be more useful is to simply add three xy->uv pairs to the source image, as an enhancement of the origin-setting code. These specify that the location uv in the source will end up at xy in the CTM. Actually the more I think about it, the better this sounds. This gets the only useful part of 3D that anybody expects Cairo to support, and allows a program doing it's own 3D projections to easily texture-map a triangle that has uv coordinates.</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Jan 19, 2018 at 3:36 PM, Bryce Harrington <span dir="ltr"><<a href="mailto:bryce@osg.samsung.com" target="_blank">bryce@osg.samsung.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Wed, Jan 10, 2018 at 02:13:39PM -0500, <a href="mailto:cecashon@aol.com">cecashon@aol.com</a> wrote:<br>
><br>
><br>
> Hi Bryce,<br>
><br>
> A 3x3 matrix should might work for quaternion rotations. In the sample<br>
> code this is reduced to a 2x2 matrix, or four variables for each<br>
> circle rotation, by using initial reference points but that wouldn't<br>
> work in general to preserve rotations. There would be a need to keep<br>
> the z component of a plane to make the rotations additive. If you<br>
> assumed z=0 then a first rotation would work but not a second or it<br>
> wouldn't work as expected.<br>
><br>
<br>
The code I've been hacking on adds to Cairo a 3x3 matrix with the 9th<br>
element fixed to 1 (so effectively is an 8-element matrix). If that<br>
last element is needed, it shouldn't be too hard to add in subsequently;<br>
I've hidden the matrix definition internally so it'd be no API break to<br>
change, just making sure all the math accounts for the transformation.<br>
<br>
> This probably is something difficult to add to Cairo. There are a lot<br>
> of places that the cairo_matrix_t touches in the code. Also I think<br>
> there would be a need for a new matrix for quaternion rotations and if<br>
> that is done then you run into further difficulties such as the order<br>
> of matrix multiplication. A lot of speculation at this point.<br>
<br>
Yes, it is proving to be rather difficult. Actually, just expanding the<br>
cairo_matrix_t definition to include projection wasn't too bad, but<br>
keeping the cairo_matrix_t API intact and adding projection as a new<br>
matrix type is rather invasive - everywhere that uses cairo_matrix_t<br>
needs updated to handle a cairo_matrix3_t.<br>
<br>
But, I'm working my way through it, and I think once that's in place<br>
then I think the quaternion rotation is doable. Since internally Cairo<br>
assumes a 2D surface (Z=0), perhaps some flattening operation would<br>
allow using 9-elements externally and avoid a lot of logical mess by<br>
using 8 internally.<br>
<br>
> I got going on this to figure out 3d rotations using Cairo's api. I<br>
> could get some special case rotations in 3d but not something that<br>
> would work for a gyro. Working on putting together a little gyro<br>
> widget with Cairo and GTK.<br>
><br>
> I am not familiar with the internals of Cairo. I have looked around a<br>
> little but I don't have a test setup with the current version. Do you<br>
> have any suggestions for putting together a test setup? I would be<br>
> interested in getting a test build set up that I could experiment<br>
> with. Also to take a look at what you have going with projections.<br>
<br>
Depends on what operating system you're on.<br>
<br>
If you're on Linux it's just `apt-get build-dep libcairo2-dev` or the<br>
equivalent for your distro to install the build dependencies, checkout<br>
the code from git, and build it. See INSTALL and README.<br>
<br>
There's more tips on the download page and elsewhere, although can't<br>
vouch for how current the directions are:<br>
<br>
<a href="https://cairographics.org/download/" rel="noreferrer" target="_blank">https://cairographics.org/<wbr>download/</a><br>
<a href="https://cairographics.org/end_to_end_build_for_win32/" rel="noreferrer" target="_blank">https://cairographics.org/end_<wbr>to_end_build_for_win32/</a><br>
<br>
For experimenting with the matrix code, the good thing is that even just<br>
the image backend will be suitable, so don't have to worry about driver<br>
issues at least. :-)<br>
<div class="HOEnZb"><div class="h5"><br>
Bryce<br>
--<br>
cairo mailing list<br>
<a href="mailto:cairo@cairographics.org">cairo@cairographics.org</a><br>
<a href="https://lists.cairographics.org/mailman/listinfo/cairo" rel="noreferrer" target="_blank">https://lists.cairographics.<wbr>org/mailman/listinfo/cairo</a></div></div></blockquote></div><br></div>