I have a 2D transformation problem in OpenGL. My program draws two letters on screen and, by pressing assigned keys, letters have to move up (GLUT_KEY_UP) down (GLUT_KEY_DOWN) left (GLUT_KEY_LEFT) right (GLUT_KEY_RIGHT) and rotate CW (GLUT_KEY_HOME) and CCW (GLUT_KEY_END). (On keys GLUT_KEY_PAGE_UP and GLUT_KEY_PAGE_DOWN both letters rotate around their own centers simultaniously in oposite directions, pressing e.g. GLUT_KEY_UP after GLUT_KEY_PAGE_UP moves both letters in a correct direction).
I can't make the letters do the correct movement (up, down, left or right) after the objects had been rotated with GLUT_KEY_HOME or GLUT_KEY_END:
case GLUT_KEY_HOME: //rotate clockwise around the center of the model
glMatrixMode(GL_MODELVIEW);
setRotationMatrix(-angle, modelSizeX, modelSizeY);
glMultMatrixf(rotationMatrix); // multiply current Modelview Matrix by rotate-and-translate matrix
display();
break;
Function that 'sets' the rotation matrix inserts angle and rotation point into Identity matrix [4x4]:
void setRotationMatrix(float theta, float x0, float y0)
{
theta = theta * (2 * acos(0.0)) / 180; // convert theta from degrees to radian
rotationMatrix[0] = cos(theta);
rotationMatrix[1] = sin(theta);
rotationMatrix[4] = -sin(theta);
rotationMatrix[5] = cos(theta);
rotationMatrix[12] = ((x0 * 0.5f) * (1 - cos(theta)) + (y0 * 0.5f) * sin(theta));
rotationMatrix[13] = ((y0 * 0.5f) * (1 - cos(theta)) - (x0 * 0.5f) * sin(theta));
}
After the objects have been rotated, if I press KEY_UP, they move not 'up' (in normal direction against x axis ) but in the direction normal to the horizontal plane of the object after rotation (slightly sideways).
case GLUT_KEY_UP:
glMatrixMode(GL_MODELVIEW);
glTranslated(0, delta, 0);
display();
break;
how do I make it move straightly to the 'north', meaning, not the 'north' of the object but the 'north' of my coordinate system?
#include <Windows.h>
#include <GL/glut.h>
#include <vector>
#include <fstream>
#include <cmath>
using namespace std;
#define EscKey 27
#define PlusKey 43
#define MinusKey 45
struct Point
{
int x, y;
};
double pi = 2 * acos(0.0);
void reshape(int w, int h);
void display();
void drawInitials();
void processNormalKeys(unsigned char key, int x, int y);
void processSpecialKeys(int key, int x, int y);
void setRotationMatrix(float theta, float x0, float y0);
void readFromFile();
void lineto(Point p);
void moveto(Point p);
void drawM();
void drawJ();
vector <Point> point;
vector <int> code;
Point currentPoint;
int modelSizeX = 202; int modelSizeY = 89;
int letterMSizeX = 107; int letterJSizeX = 78;
int delta = 5; // movement size
float zoomRate = 0.1; // scale-and-translate rate: 0.1 = resize by 10%
float angle = 1, rotaterR = 1 * pi / 180, rotater, angleCount = 0.0; // saved rotation angle
GLfloat modelviewStateMatrix[16];
int windowSizeX, windowSizeY;
boolean separate = false;
float rotationMatrix[16] = { 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
float plusKeyMatrix[16] = { 1.0f + zoomRate, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f + zoomRate, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
-(modelSizeX * zoomRate * 0.5f), -(modelSizeY * zoomRate * 0.5f), 0.0f, 1.0f };
float minusKeyMatrix[16] = { 1.0f - zoomRate, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f - zoomRate, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
modelSizeX * zoomRate * 0.5f, modelSizeY * zoomRate * 0.5f, 0.0f, 1.0f };
void readFromFile()
{
fstream f("initials_points_2.txt", ios::in);
int pointNumber;
Point p;
f >> pointNumber;
for (int i = 0; i < pointNumber;i++)
{
f >> p.x >> p.y;
point.push_back(p);
}
int movesNumber, m;
f >> movesNumber;
for (int i = 0; i < movesNumber; i++)
{
f >> m; code.push_back(m);
}
f.close();
}
void moveto(Point p)
{
currentPoint.x = p.x; currentPoint.y = p.y;
}
void lineto(Point p)
{
glBegin(GL_LINES);
glVertex2i(currentPoint.x, currentPoint.y);
glVertex2i(p.x, p.y);
glEnd();
currentPoint.x = p.x; currentPoint.y = p.y;
}
void setRotationMatrix(float theta, float x0, float y0)
{
theta = theta * (2 * acos(0.0)) / 180; // convert theta from degrees to radian
rotationMatrix[0] = cos(theta);
rotationMatrix[1] = sin(theta);
rotationMatrix[4] = -sin(theta);
rotationMatrix[5] = cos(theta);
rotationMatrix[12] = ((x0 * 0.5f) * (1 - cos(theta)) + (y0 * 0.5f) * sin(theta));
rotationMatrix[13] = ((y0 * 0.5f) * (1 - cos(theta)) - (x0 * 0.5f) * sin(theta));
}
void drawM()
{
int i = 1;
moveto(point[0]);
while (code[i] > 0 && i < code.size())
{
lineto(point[code[i] - 1]);
i++;
}
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(letterMSizeX, 0.0, 0.0);
glVertex3f(letterMSizeX, 0.0, 0.0);
glVertex3f(letterMSizeX, modelSizeY, 0.0);
glVertex3f(letterMSizeX, modelSizeY, 0.0);
glVertex3f(0.0, modelSizeY, 0.0);
glVertex3f(0.0, modelSizeY, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_LINES);
glVertex2i(0, 0); glVertex2i(letterMSizeX, modelSizeY);
glVertex2i(letterMSizeX, 0); glVertex2i(0, modelSizeY);
glEnd();
}
void drawJ()
{
glColor3f(1.0, 0.0, 0.0);
int i = 14;
moveto(point[-1 * (code[i]) - 1]);
i++;
while (i < code.size())
{
lineto(point[code[i] - 1]);
i++;
}
glBegin(GL_LINES);
glVertex3f((modelSizeX - letterJSizeX), 0.0, 0.0);
glVertex3f((modelSizeX - letterJSizeX), modelSizeY, 0.0);
glVertex3f((modelSizeX - letterJSizeX), modelSizeY, 0.0);
glVertex3f(modelSizeX, modelSizeY, 0.0);
glVertex3f(modelSizeX, modelSizeY, 0.0);
glVertex3f(modelSizeX, 0.0, 0.0);
glVertex3f(modelSizeX, 0.0, 0.0);
glVertex3f((modelSizeX - letterJSizeX), 0.0, 0.0);
glEnd();
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_LINES);
glVertex2i(letterMSizeX + 17, 0); glVertex2i(modelSizeX, modelSizeY);
glVertex2i(letterMSizeX + 17, modelSizeY); glVertex2i(modelSizeX, 0);
glEnd();
}
void drawInitials()
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
setRotationMatrix(-rotater, letterMSizeX, modelSizeY);
glMultMatrixf(rotationMatrix); // multiply current Modelview Matrix by rotate-and-translate matrix
drawM();
glTranslatef(-letterMSizeX * 0.5, -modelSizeY * 0.5, 0);
glPopMatrix();
glPushMatrix();
glTranslatef((modelSizeX - letterJSizeX), 0, 0);
setRotationMatrix(rotater, letterJSizeX, modelSizeY);
glMultMatrixf(rotationMatrix); // multiply current Modelview Matrix by rotate-and-translate matrix
glTranslatef(-(modelSizeX - letterJSizeX), 0, 0);
drawJ();
glPopMatrix();
}
void processNormalKeys(unsigned char key, int x, int y)
{
switch (key)
{
case EscKey:
exit(0);
break;
case PlusKey: // "zoom in"
glMatrixMode(GL_MODELVIEW);
glMultMatrixf(plusKeyMatrix); // multiply current Modelview Matrix by scale-and-translate matrix
display();
break;
case MinusKey: // "zoom out"
glMatrixMode(GL_MODELVIEW);
glMultMatrixf(minusKeyMatrix); // multiply current Modelview Matrix by scale-and-translate matrix
display();
break;
}
}
void processSpecialKeys(int key, int x, int y) {
switch (key) {
case GLUT_KEY_UP:
glMatrixMode(GL_MODELVIEW);
glTranslated(0, delta, 0);
display();
break;
case GLUT_KEY_DOWN:
glMatrixMode(GL_MODELVIEW);
glTranslated(0, -delta, 0);
display();
break;
case GLUT_KEY_LEFT:
glMatrixMode(GL_MODELVIEW);
glTranslated(-delta, 0, 0);
display();
break;
case GLUT_KEY_RIGHT:
glMatrixMode(GL_MODELVIEW);
glTranslated(delta, 0, 0);
display();
break;
case GLUT_KEY_HOME: //rotate clockwise around the center of the model
glMatrixMode(GL_MODELVIEW);
setRotationMatrix(-angle, modelSizeX, modelSizeY);
glMultMatrixf(rotationMatrix); // multiply current Modelview Matrix by rotate-and-translate matrix
display();
break;
case GLUT_KEY_END: //rotate counterclockwise around the center of the model
glMatrixMode(GL_MODELVIEW);
setRotationMatrix(angle, modelSizeX, modelSizeY);
glMultMatrixf(rotationMatrix); // multiply current Modelview Matrix by rotate-and-translate matrix
display();
break;
case GLUT_KEY_PAGE_UP:
rotater -= rotaterR;
if (rotater <= -2 * pi)
rotater += 2 * pi;
display();
break;
case GLUT_KEY_PAGE_DOWN:
rotater += rotaterR;
if (rotater >= 2 * pi)
rotater -= 2 * pi;
display();
break;
}
}
int main(int argc, char* argv[])
{
currentPoint.x = 0; currentPoint.y = 0;
readFromFile();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(800, 600);
glutInitWindowPosition(100, 150);
glutCreateWindow("OpenGL lab");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(processNormalKeys);
glutSpecialFunc(processSpecialKeys);
glutMainLoop();
return 0;
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
windowSizeX = w;
windowSizeY = h;
gluOrtho2D(-modelSizeX, modelSizeX * 2, -modelSizeY, modelSizeY * 2); // World size
}
void display()
{
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glColor3f(0.0, 0.0, 1.0);
glBegin(GL_LINES);
glVertex2i(-windowSizeX, 0); glVertex2i(windowSizeX, 0);
glVertex2i(0, -windowSizeY); glVertex2i(0, windowSizeY);
glEnd();
glPopMatrix();
glColor3d(1, 0, 0);
drawInitials();
glPointSize(5);
glBegin(GL_POINTS);
glVertex3f(modelSizeX * 0.5, modelSizeY * 0.5, 0.0);
glVertex3f(letterMSizeX * 0.5, modelSizeY * 0.5, 0.0);
glVertex3f(letterJSizeX * 0.5 + letterMSizeX + 17, modelSizeY * 0.5, 0.0);
glEnd();
glFlush();
}
vertices file: initials_points_2.txt
I was trying to:
none of them had worked as I intended
I found out what I was doing wrong: buttons GLUT_KEY_HOME/GLUT_KEY_END should be performing rotations similar to those of GLUT_KEY_PAGE_UP/GLUT_KEY_PAGE_DOWN:
Then, inside display() method:
Code on keys:
case GLUT_KEY_HOME: //rotate clockwise around the center of the model
glMatrixMode(GL_MODELVIEW);
angle -= rotationRate;
if (angle <= -2 * pi)
angle += 2 * pi;
display();
break;
case GLUT_KEY_END: //rotate counterclockwise around the center of the model
glMatrixMode(GL_MODELVIEW);
angle += rotationRate;
if (angle >= 2 * pi)
angle -= 2 * pi;
display();
break;
edited drawInitials() method (called from display() method):
void drawInitials()
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
setRotationMatrix(angle, modelSizeX, modelSizeY); //set rotation matrix to rotate around the center of the model by current angle
glMultMatrixf(rotationMatrix); // multiply current Modelview Matrix by rotate-and-translate matrix
glPushMatrix();
setRotationMatrix(-rotater, letterMSizeX, modelSizeY); //set to rotate around the center of the letter M by current rotater Clockwise
glMultMatrixf(rotationMatrix); // multiply current Modelview Matrix by rotate-and-translate matrix
drawM();
glPopMatrix();
glPushMatrix();
glTranslatef((modelSizeX - letterJSizeX), 0, 0); // move OX axis by the size of letter M + space between the letters
setRotationMatrix(rotater, letterJSizeX, modelSizeY);//set to rotate around the center of the letter J by current rotater Counter Clockwise
glMultMatrixf(rotationMatrix); // multiply current Modelview Matrix by rotate-and-translate matrix
glTranslatef(-(modelSizeX - letterJSizeX), 0, 0); // return OX axis to its previous place
drawJ();
glPopMatrix();
glPopMatrix();
}
In setRotationMatrix() remove conversion into radian;
Add new variable rotationRate to use it as an incriment for both rotations:
float angle;
// saved rotation angle around center of the model (radian)
float rotater;
// rotater - saved rotation angle around center of the letter (radian)
float rotationRate = 1 * pi / 180; // rotation rate (radian), ex rotaterR