The Code So Far II
Prev: Moving the Camera III | Next: Popup Menus |
#include <stdlib.h> #include <math.h> #ifdef __APPLE__ #include <GLUT/glut.h> #else #include <GL/glut.h> #endif // angle of rotation for the camera direction float angle = 0.0f; // actual vector representing the camera's direction float lx=0.0f,lz=-1.0f; // XZ position of the camera float x=0.0f, z=5.0f; // the key states. These variables will be zero //when no key is being presses float deltaAngle = 0.0f; float deltaMove = 0; int xOrigin = -1; void changeSize(int w, int h) { // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if (h == 0) h = 1; float ratio = w * 1.0 / h; // Use the Projection Matrix glMatrixMode(GL_PROJECTION); // Reset Matrix glLoadIdentity(); // Set the viewport to be the entire window glViewport(0, 0, w, h); // Set the correct perspective. gluPerspective(45.0f, ratio, 0.1f, 100.0f); // Get Back to the Modelview glMatrixMode(GL_MODELVIEW); } void drawSnowMan() { glColor3f(1.0f, 1.0f, 1.0f); // Draw Body glTranslatef(0.0f ,0.75f, 0.0f); glutSolidSphere(0.75f,20,20); // Draw Head glTranslatef(0.0f, 1.0f, 0.0f); glutSolidSphere(0.25f,20,20); // Draw Eyes glPushMatrix(); glColor3f(0.0f,0.0f,0.0f); glTranslatef(0.05f, 0.10f, 0.18f); glutSolidSphere(0.05f,10,10); glTranslatef(-0.1f, 0.0f, 0.0f); glutSolidSphere(0.05f,10,10); glPopMatrix(); // Draw Nose glColor3f(1.0f, 0.5f , 0.5f); glRotatef(0.0f,1.0f, 0.0f, 0.0f); glutSolidCone(0.08f,0.5f,10,2); } void computePos(float deltaMove) { x += deltaMove * lx * 0.1f; z += deltaMove * lz * 0.1f; } void renderScene(void) { if (deltaMove) computePos(deltaMove); // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Reset transformations glLoadIdentity(); // Set the camera gluLookAt( x, 1.0f, z, x+lx, 1.0f, z+lz, 0.0f, 1.0f, 0.0f); // Draw ground glColor3f(0.9f, 0.9f, 0.9f); glBegin(GL_QUADS); glVertex3f(-100.0f, 0.0f, -100.0f); glVertex3f(-100.0f, 0.0f, 100.0f); glVertex3f( 100.0f, 0.0f, 100.0f); glVertex3f( 100.0f, 0.0f, -100.0f); glEnd(); // Draw 36 SnowMen for(int i = -3; i < 3; i++) for(int j=-3; j < 3; j++) { glPushMatrix(); glTranslatef(i*10.0,0,j * 10.0); drawSnowMan(); glPopMatrix(); } glutSwapBuffers(); } void processNormalKeys(unsigned char key, int xx, int yy) { if (key == 27) exit(0); } void pressKey(int key, int xx, int yy) { switch (key) { case GLUT_KEY_UP : deltaMove = 0.5f; break; case GLUT_KEY_DOWN : deltaMove = -0.5f; break; } } void releaseKey(int key, int x, int y) { switch (key) { case GLUT_KEY_UP : case GLUT_KEY_DOWN : deltaMove = 0;break; } } void mouseMove(int x, int y) { // this will only be true when the left button is down if (xOrigin >= 0) { // update deltaAngle deltaAngle = (x - xOrigin) * 0.001f; // update camera's direction lx = sin(angle + deltaAngle); lz = -cos(angle + deltaAngle); } } void mouseButton(int button, int state, int x, int y) { // only start motion if the left button is pressed if (button == GLUT_LEFT_BUTTON) { // when the button is released if (state == GLUT_UP) { angle += deltaAngle; xOrigin = -1; } else {// state = GLUT_DOWN xOrigin = x; } } } int main(int argc, char **argv) { // init GLUT and create window glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320); glutCreateWindow("Lighthouse3D - GLUT Tutorial"); // register callbacks glutDisplayFunc(renderScene); glutReshapeFunc(changeSize); glutIdleFunc(renderScene); glutIgnoreKeyRepeat(1); glutKeyboardFunc(processNormalKeys); glutSpecialFunc(pressKey); glutSpecialUpFunc(releaseKey); // here are the two new functions glutMouseFunc(mouseButton); glutMotionFunc(mouseMove); // OpenGL init glEnable(GL_DEPTH_TEST); // enter GLUT event processing cycle glutMainLoop(); return 1; }
Check out the source code at GitHub.
Prev: Moving the Camera III | Next: Popup Menus |
16 Responses to “The Code So Far II”
Leave a Reply Cancel reply
This site uses Akismet to reduce spam. Learn how your comment data is processed.
Why is the code:
//if (deltaAngle)
// computeDir(deltaAngle);
removed from this example?
Here is my code. Just some differences. And one problem: I can’t reply on your page by Firefox.
#include
#include
#include
float angle = 0;
float xView = 0, yView = 2, zView = 7;
float lx = 0, ly = 0, lz = -1;
int xOrigin = -1, yOrigin = -1, zOrigin = -1;
float deltaAngle = 0;
//float deltaMove = 0;
void changeSize(int width, int height);
void drawSnowMan();
void display(void);
void processNormalKeys(unsigned char key, int x, int y);
void processSpecialKeys(int key, int x, int y);
void mouseMove(int x, int y);
void mouseButton(int button, int state, int x, int y);
void changeSize(int width, int height)
{
if (height == 0)
{
height = 1;
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, width, height);
float aspect = width / height;
gluPerspective(45, aspect, 0.1, 100);
glMatrixMode(GL_MODELVIEW);
}
void drawSnowMan()
{
glColor3f(1, 1, 1);
glTranslatef(0, 0.75, 0);
glutWireSphere(0.75, 10, 10);
glTranslatef(0, 1, 0);
glutSolidSphere(0.25, 10, 10);
glPushMatrix();
//Draw eyes
glTranslatef(0.1, 0, 0.23);
glColor3f(0, 0, 1);
glutSolidSphere(0.03, 10, 10);
glTranslatef(-0.2, 0, 0);
glutSolidSphere(0.03, 10, 10);
glPopMatrix();
glTranslatef(0, -0.05, 0.25);
glColor3f(1, 0, 0);
glutSolidCone(0.025, 0.25, 4, 4);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(xView, yView, zView,
xView + lx, yView + ly, zView + lz,
0, 1, 0);
glRotatef(angle, 0, 1, 0);
glColor3f(1, 0, 0);
glLineWidth(3);
glBegin(GL_LINES);
glVertex3f(0, 0, 0);
glVertex3f(1.5, 0, 0);
glVertex3f(0, 0, 0);
glVertex3f(0, 3, 0);
glVertex3f(0, 0, 0);
glVertex3f(0, 0, 1.5);
glEnd();
glColor3f(0.5, 0.5, 0.5);
glBegin(GL_QUADS);
glVertex3f(-100, 0, -100);
glVertex3f(-100, 0, 100);
glVertex3f(100, 0, 100);
glVertex3f(100, 0, -100);
glEnd();
drawSnowMan();
glutSwapBuffers();
}
void processNormalKeys(unsigned char key, int x, int y)
{
switch (key)
{
case 27:
exit(0);
break;
}
}
void processSpecialKeys(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_LEFT:
angle -= 0.5;
break;
case GLUT_KEY_RIGHT:
angle += 0.5;
break;
case GLUT_KEY_UP:
zView -= 0.5;
break;
case GLUT_KEY_DOWN:
zView += 0.5;
break;
}
}
void mouseMove(int x, int y)
{
if (xOrigin >= 0 || zOrigin >= 0)
{
deltaAngle = acos(((float)xOrigin * x + yOrigin * y) / (sqrt((float)xOrigin * xOrigin + yOrigin * yOrigin) * sqrt((float)x * x + y * y)));
if (x <= xOrigin)
{
angle -= deltaAngle * 100;
xOrigin = x;
yOrigin = y;
}
else
{
angle += deltaAngle * 100;
xOrigin = x;
yOrigin = y;
}
}
}
void mouseButton(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON)
{
if (state == GLUT_DOWN)
{
xOrigin = x;
yOrigin = y;
}
else
{
xOrigin = -1;
yOrigin = -1;
}
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);
glutInitWindowPosition(0, 0);
glutInitWindowSize(680, 680);
glutCreateWindow("Example 2.4 – Mouse");
glutDisplayFunc(display);
glutReshapeFunc(changeSize);
glutIdleFunc(display);
glutKeyboardFunc(processNormalKeys);
glutSpecialFunc(processSpecialKeys);
//glutIgnoreKeyRepeat(1);
glutMouseFunc(mouseButton);
glutMotionFunc(mouseMove);
glEnable(GL_DEPTH_TEST);
glutMainLoop();
return 0;
}
You have to be careful when you name your variables. I spent like one hour until i figure out that x from expresion (x – xOrigin) is the local x from the function and the same thing at xOrigin = x. Very good tutorial !! I also want to make the camera to move up and down and, as you said, I need another angle variable to move horizontaly
…has been removed from renderScene().
Sorry about that :/
Note that
:
if (deltaAngle)
computeDir(deltaAngle);
I would also like to thank for for this awesome guide. It has helped me immensely. By adopting the same techniques and functions I have been able to create a decent fractal generator. 😀
It seems to me that, in the function mouseButton the line “angle += deltaAngle” is redundant, since nothing happens if I remove it. Is there another not-obvious reason for this?
Also, as it is written in the example the camera continues to rotate when I release the left mouse button at the same “speed” as before I released it. If I change the code under the second if, then I can make it stop rotating when I release the left mouse button:
void mouseButton(int button, int state, int x, int y) {
// only start motion if the left button is pressed
if (button == GLUT_LEFT_BUTTON) {
// when the button is released
if (state == GLUT_UP) {
//angle += deltaAngle;
deltaAngle = 0; // Stops the camera.
xOrigin = -1;
}
else {// state = GLUT_DOWN
xOrigin = x;
}
}
}
Additionally, if you want the camera to only “follow the mouse” (in lack of better expression) instead of letting the difference (x – xOrigin) decide the speed of rotation, you can add one line in the function moveMouse:
void mouseMove(int x, int y) {
// this will only be true when the left button is down
if (xOrigin >= 0) {
// update deltaAngle
deltaAngle = (x – xOrigin) * 0.001f;
xOrigin = x;
// update camera’s direction
lx = sin(angle + deltaAngle);
lz = -cos(angle + deltaAngle);
}
}
Hi Morten,
Let me see if I reply properly to your comment.
1. The speed of rotation is determined only by the multiplication factor 0.001f. Changing this number changes the speed of rotation.
2. The code in the page is almost equivalent to yours if instead of deltaAngle = (x – xOrigin) * 0.001f; you write angle += (x – xOrigin) * 0.001f;. However it is not strictly equivalent due to resolution issues. What i mean is that if you move the mouse 10 pixels to the right you’re going to sum 10 times the step, whereas the site’s solution sums only once (ten times the step). This is not equivalent due to floating point resolution issues, i.e. step+step+…+step (n times) is different from n * step. Although you get almost the same result, it is not exactly the same. So in short, the code in the tutorial is a tiny bit more accurate than yours, although in most examples the difference is irrelevant.
Actually it is not quite the same due to resolution issues. I
What I wanted to say by “speed” was actually “how far it moves”. Without xOrigin = x it will continue to rotate until you release the button or somehow change the direction by other means (If I recall correctly).
I extended the code so that you can look up-down in addition to left-right. It is far from perfect, but may be able to help others who want to try something similar. The camera still moves if you hold down the right mouse button, but only slighty (I swear it didn’t happen last time I tried! :S)
Here: http://folk.ntnu.no/mortevas/fractal/GLUT/main.cpp
Hi,
If you remove the line “angle += deltaAngle” you could see a jump next time you press the mouse. Notice that in the function mouseMove only deltaAngle is being updated, not the angle itself.
As for the camera rotation I have not been able to reproduce your situation, but adding “deltaAngle = 0” should be a good safeguard against those situations.
In my code (the one linked in the comment above) there is no noticable difference if I remove the line “angle += deltaAngle” or not. On the other hand. If I keep the three lines below “// update camera’s direction” in the function mouseMove, it jumps each time I press the right button, so I’ve commented them out. I may have changed the code too much for it to act like in the example, I guess.
oh… sry that was from the code with the keyboard… ich copied the mouse code into that one…
gotta leave my appreciation here as well: thx for supplying a tutorial for glut/opengl that would have taken me weeks to learn otherwise!
Hi,
why do u update the lx and lz vars, 2 times ?
once in the mouseMove func and once in the computeDir func
seems unnecessary
What computeDir function are you referring to?
Wow, the first actually understandable tutorial on the internet to starting OpenGL with GLUT ( I haven’t done pure OGL yet, I figured starting managed and then moving to the native is easier.).
Thank you.
BTW, the interface now looks like the FPS games’ interface, with constant forward movement and mouse direction changing.
You rock!