PDA

View Full Version : Help with a visual effect



SkripT
4th May 2006, 17:33
Hi, I want to know what's the simple way to obain this visual effect: a rectangle (for example) that rotates 180 degrees from the Y axis:

Coordinate system
|Y
|
|
|
|_________________ X
/
/
/
/ Z


All I want is to emulate the effect of a page (of a book) turning around :cool:
I think that I could use openGL but I don't hve much experinece with it, maybe it can be easily achieved with QPainter :confused:
Thanks in advance.

jacek
4th May 2006, 18:23
If you have a point (x, y, z) and you rotate it around Y axis by a degrees, you'll get (x', y', z') where:
x' = x cos a + z sin a,
y' = y,
z' = -x sin a + z cos a.

Second thing you will need is a projection. In this case it probably will be enough if you use:
xp = x - z
yp = y + z
(where xp, and yp are the painter coordinates).

The algorithm:

translate the painter so that the (0, 0) point is in the middle of the top edge of the book,
x1 = width/2, y1 = 0, z1 = 0, (upper corner of the page)
x2 = width/2, y2 = height, z2 = 0, (lower corner of the page)
for a = 0, 1, ..., 180:
calculate new x1, y1, z1, x2, y2 and z2
draw a (0, 0)--(x1-z1, y1-z1)--(x2-z2, y2-z2)--(0, height) rectangle
Note that in fact x1 == x2, z1 == z2 and both y1 and y2 are constant.

SkripT
4th May 2006, 18:35
Thanks a lot jacek, good knowledge of maths ;)

EDIT: taking a look at this alogrithm carefully, I think that it will paint the rectangle with the correct size in each degree, the problem is that I want to paint an image (texture) on this rectangle and I want that it "deforms" with each degree. Is it still possible with QPainter?

jacek
4th May 2006, 19:06
I want that it "deforms" with each degree. Is it still possible with QPainter?
Try QPainter::setMatrix() or QImage::transform().

wysota
4th May 2006, 20:12
Wouldn't it be enough to transform the painter matrix to do it all?

Hmm... Looks like QMatrix is just 2x2 in size...

jacek
4th May 2006, 20:56
Looks like QMatrix is just 2x2 in size...
No, it's 3x3, but the last column is [0;0;1]. Anyway, it will be enough, since you only have to shear and scale the painter (or image).

SkripT
4th May 2006, 23:19
Thanks a lot jacek and wysota for your replies. My question is: so, using QMatrix is enought to do all the rotations/shear/scale that I need applied on the image or the rectangle to simulate the effect that I need? QMatrix seems to work only in 2D and this effect has a 3D component I think....

jacek
5th May 2006, 00:02
QMatrix is enought to do all the rotations/shear/scale that I need applied on the image or the rectangle to simulate the effect that I need?
Theoretically, yes. ;)

QMatrix seems to work only in 2D and this effect has a 3D component I think....
Do you have a 3D monitor?

SkripT
5th May 2006, 00:11
Theoretically, yes. ;)

Do you have a 3D monitor?

Not, but now I know what to request for christmas :p .

I will try with QMatrix it and I comment the results ;)

SkripT
5th May 2006, 09:01
Hi again, I've been reading carefully and testing what the docs explains from QMatrix class and I don't know how could I use it to obtain the effect that I want :( . I know that I should call QMatrix::shear and QMatrix::scale in some way because, as the docs says, "...Rotation is achieved by carefully setting both the shearing factors and the scaling factors" but I don't know how :confused:
It's clear that I'm not a math expert... ;) Could you please guide me a little bit in how could I configure the QMatrix to get the respective "transformated" rectangle for each angle rotated? Thanks again.

wysota
5th May 2006, 09:11
Try those:
http://www.inversereality.org/tutorials/graphics programming/3dwmatrices.html
http://gpwiki.org/index.php/3D:Matrix_Math

SkripT
5th May 2006, 09:28
Thanks a lot wysota. Now I know that to rotate from the Y-axis, I have to use the following matrix:

Matrix:
cosa 0 -sina 0
0 1 0 0
sina 0 cosa 0
0 0 0 1

Now the problem is that QMatrix works with 3x3 matrixs :eek: How can I transfrom this matrix in terms of QMatrix?

wysota
5th May 2006, 09:34
Jacek has always been much better at maths (especially matrices) than me, so he'll probably correct me but I think using ( cosa, -sina, sina, cosa) could do the trick. Try it, maybe it works, but you should wait for Jacek's reply anyway.

SkripT
5th May 2006, 09:37
Ok thanks anyway wysota. I think that, as I comented, QMatrix uses only 3x3 matrix because they work in 2D...

wysota
5th May 2006, 09:40
Yes, but you should be able to achieve the same result with a smaller matrix. The equation will just be more complicated (or use more than one QMatrix).

SkripT
5th May 2006, 10:03
Hi again, I attach the code that I use, trying as wysota comments. The problem is that the rotation is done in 2D, so if I try to rotate an image 90º from the Y axis, the result is not a vertical line or even a null image :confused:

#include <QtGui>
#include <math.h>


int main(int argc, char *argv[])
{
QApplication a(argc, argv);

QImage imatge("../test.jpg");

double radians = 90 * 3.14159265 / 180; //rotation of 90º

imatge = imatge.transformed(QMatrix(cos(radians),-sin(radians),sin(radians),cos(radians),0,0));
imatge.save("../transformated.jpg", "jpg");

return 0;
}

I think that's not as easy as that code :crying:

jacek
5th May 2006, 11:49
Let's see... you need a matrix that for given angle a will transform the (0, 0)--(width/2, 0)--(width/2, height)--(0, heigth) rectangle into (0, 0)--(x1-z1, y1+z1)--(x2-z2, y2+z2)--(0, height).

QMatrix works like this:
x' = m11*x + m21*y + dx
y' = m22*y + m12*x + dy

Since we need to map (0,0) to (0,0), dx = dy = 0.

(0, height) must be mapped to (0, height), so:
0 = m11*0 + m21*height + 0
height = m22*height + m12*0 + 0,
thus:
m21 = 0 and m22 = 1.

(width/2, 0) must be mapped to (x1-z1, y1+z1), where x1, y1, z1 are coordinates of a (width/2,0,0) point rotated around Y axis by a degrees, so:
x1 = width/2 cos a
y1 = 0
z1 = -width/2 sin a

x1 - z1 = width/2 ( sin a + cos a )
y1 + z1 = -width/2 sin a

width/2 (sin a + cos a ) = m11 * width/2
-width/2 sin a = 0 + m12* width/2

which gives us: m11 = sin a + cos a and m12 = - sin a

Whole matrix:
/ sin a + cos a - sin a 0 \
| 0 1 0 |
\ 0 0 1 /

SkripT
5th May 2006, 12:01
Wow jacek, you're a machine in maths :) Now it give better results, but the rotation in 90º is not a "slim" image :confused:. Here's the code:

#include <QtGui>
#include <math.h>


int main(int argc, char *argv[])
{
QApplication a(argc, argv);

QImage imatge("../proba.jpg");

double radians = 90 * 3.14159265 / 180;

imatge = imatge.transformed(QMatrix(sin(radians)+cos(radian s),-sin(radians),0,1,0,0));
imatge.save("../transformada.jpg", "jpg");

return 0;
}

jacek
5th May 2006, 13:04
With this you'll get a better result:
/ 0.5 sin a + cos a - 0.5 sin a 0 \
| 0 1 0 |
\ 0 0 1 /

SkripT
5th May 2006, 14:19
Really good example jacek, thanks a lot :)

SkripT
5th May 2006, 15:55
In honor of jacek, look what I have achieved using his code :cool: I've noticed some strange issues:
1) In my computer it goes very slow. I think that's some issue with QPainter....
2) The movement in the right side is not simetric with the left side :confused: . The matrix should work "equally" with both sides, isn't it?


PD: copy the images where the exe file is
PD2: tune the speed with the value passed to QTimer::start

jacek
5th May 2006, 16:15
1) In my computer it goes very slow. I think that's some issue with QPainter....
You scale a big image very often --- it must cost. You could try OpenGL or you can record that animation and just replay it.


The movement in the right side is not simetric with the left side :confused: . The matrix should work "equally" with both sides, isn't it?
No it shouldn't, it's because of a simple projection that I used here. If you use a bit more complex one it might look better.

nupul
7th May 2006, 16:06
Well SkripT, i have been reading this discussion right from the start...i have a suggestion though, have you tried using OpenGL for achieving the effect you want? it doesn't require much extensive GL knowledge...infact you can use the inbuilt rotate function, put it in a for loop and rotate the image by say 2 degs per loop execution to give you the effect of the moving page!! you as it is know the co-ordinates, just pass them...and opengl will take care of the rest! and ya, it won't slow your system....It'll move as a breeeeeeeeze!!!

;)

Nupul

SkripT
7th May 2006, 18:06
Thanks for the suggestion Nupul. In the beggining, I thought that QPainter was enough to achieve the effect but seems that it's a bit slow :rolleyes: . Next step: OpenGL but that's a new story... ;)

nupul
7th May 2006, 18:30
Thanks for the suggestion Nupul. In the beggining, I thought that QPainter was enough to achieve the effect but seems that it's a bit slow :rolleyes: . Next step: OpenGL but that's a new story... ;)

Let's say a new chapter to your story....so you can keep 'flipping the pages' to see your progress :D

SkripT
7th May 2006, 19:15
Let's say a new chapter to your story....so you can keep 'flipping the pages' to see your progress :D

:D good joke Nupul