Can't rotate object around its own center on mouse click OpenGL - c++

I succesfully managed to rotate my object but I need to right click on the object to stop its rotation. I don't know how to make the object to rotate just around its center and then stop, I'll attach the code to see exactly what's happening with this shape. The problem, I think, is with the spinDisplay() function... the thing is that I need to rotate around its center on left mouse click and on the right mouse click I should change the color of the object....
#include <stdlib.h>
#include <math.h>
#include "dependente\freeglut\freeglut.h"
#include "dependente\glfw\glfw3.h"
#include <stdio.h> //incluziuni librarii
float ORG[3] = { 0,0,0 };
static GLfloat spin = 0.0;
GLfloat viewangle = 0, tippangle = 0, traj[120][3]; //variabila pentru unghi camera
GLfloat d[3] = { 0.1, 0.1, 0.1 }; //vector directie
GLfloat xAngle = 0.0, yAngle = 0.0, zAngle = 0.0;
bool draw_triangle = false; //variabila desenat figuri
bool draw_square = false;
bool draw_decagon = false;
void Triangle(void) //draw the triangle shape
{
glBegin(GL_TRIANGLE_FAN);//triangles have a common vertex, which is the central vertex
glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(0.0f, 1.0f, 0.0f); //V0(red)
glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); //V1(green)
glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(1.0f, -1.0f, 1.0f); //V2(blue)
glEnd();
}
void Square(void) {
glBegin(GL_QUADS);
glVertex2f(-1.0f, 1.0f); // top left
glVertex2f(1.0f, 1.0f); // top right
glVertex2f(1.0f, -1.0f); // bottom right
glVertex2f(-1.0f, -1.0f); // bottom left
glEnd();
}
void Decagon(void) //draw the decagon shape
{
glBegin(GL_POLYGON);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.72f,0.8f, 0.0f); //a1
glVertex3f(0.52f, 0.8f,0.0f); //z
glVertex3f(0.35f, 0.64f, 0.0f); //b1
glVertex3f(0.3f, 0.48f, 0.0f); //d1
glVertex3f(0.35f, 0.3f, 0.0f); //e1
glVertex3f(0.52f, 0.16f, 0.0f); //l1
glVertex3f(0.72f, 0.16f, 0.0f); //m1
glVertex3f(0.9f, 0.3f, 0.0f); //o1
glVertex3f(0.95f, 0.48f, 0.0f); //p1
glVertex3f(0.9f, 0.64f, 0.0f); //c1
glScalef(10, 10, 10);
glTranslatef(1, 2, 3);
glEnd();
}
void Keyboard(unsigned char key, int x, int y) //press a key to perform actions
{
switch (key) {
case 'd': d[0] += 0.1; break; //camera right
case 'a': d[0] -= 0.1; break; //camera left
case 'w': d[1] += 0.1; break; //camera up
case 's': d[1] -= 0.1; break; //camera down
case 'm': d[2] += 0.1; break; //magnify
case 'n': d[2] -= 0.1; break; //minify
case 't': draw_triangle = true; draw_decagon = false; break; //draw pyramid when key is pressed
case 'q': draw_square = true; draw_decagon = false; draw_triangle = false; break; //draw cube when key is pressed
case 'l': draw_decagon = true; draw_triangle = false; draw_square = false; break; //draw prism when key is pressed
case 'x': xAngle += 5; break; //modify x axis angle
case 'y': yAngle += 5; break; //modify y axis angle
case 'z': zAngle += 5; break; //modify z axis angle
default: printf(" Keyboard %c == %d", key, key); //see what key it's pressed
}
glutPostRedisplay();
}
void spinDisplay() //here it's the problematic function
{
spin = spin + 0.1;
if (spin > 360.0)
{
spin = 0.0;
}
glutPostRedisplay();
}
void mouse(int buton, int state, int x, int y)
{
switch (buton) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
glutIdleFunc(spinDisplay);
break;
case GLUT_RIGHT_BUTTON: //here I don't know how to change the color of the shape
glutIdleFunc(NULL);
default:glutIdleFunc(NULL);
break;
}
}
void redraw(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glLoadIdentity();
glTranslatef(0, 0, -3);
glRotatef(tippangle, 1, 0, 0); // Up and down arrow keys 'tip' view.
glRotatef(viewangle, 0, 1, 0); // Right/left arrow keys 'turn' view.
glDisable(GL_LIGHTING);
glPushMatrix();
glTranslatef(d[0], d[1], d[2]); // Move box down X axis.
glScalef(0.7f, 0.7f, 0.7f); //increase the object size
glRotatef(zAngle, 0, 0, 1);
glRotatef(yAngle, 0, 1, 0);
glRotatef(xAngle, 1, 0, 0);
glRotatef(spin, 0.0, 0.0, 1.0);
if (draw_triangle)
Triangle();
if (draw_decagon)
Decagon();
if (draw_square)
Square();
glPopMatrix();
glutSwapBuffers();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitWindowSize(900, 600);
glutInitWindowPosition(300, 300);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE);
glutCreateWindow("Figure Rotation");
glutDisplayFunc(redraw);
glutKeyboardFunc(Keyboard);
glutMouseFunc(mouse);
glClearColor(0.1, 0.0, 0.1, 1.0);
glMatrixMode(GL_PROJECTION);//specify which matrix is the current matrix, matrix that represents your camera's lens (aperture, far-field, near-field, etc).
gluPerspective(60, 1.5, 1, 10); //set up a perspective projection matrix
glMatrixMode(GL_MODELVIEW); //specify which matrix is the current matrix,matrix that represents your camera (position, pointing, and up vector).
glutMainLoop();
return 1;
}

Solely based on your code, the main problem is at Decagon() for its shape vertices definition.
As such vertices are defined not at the center of the shape itself but defined towards the top right, thus it won't rotate around itself but seem to orbit around the center although your sequence of matrix multiplications are working ok.
For simplicity, I would visualize centering it at 0,0 along xy plane, then define right half of its shape then mirror it back to the left one. You can take advantage of - minus sign. Implicitly take advantage of defining shape in NDC (Normalizd Device Coordinate) space.
Note: not exactly the same ratio as per your original definition, but to get you an idea. You can try swapping the following into yours, then it should rotate around itself.
glBegin(GL_POLYGON);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.25f, 0.5f, 0.0f);
glVertex3f(0.45f, 0.30f, 0.0f);
glVertex3f(0.55f, 0.0f, 0.0f);
glVertex3f(0.45f, -0.30f, 0.0f);
glVertex3f(0.25f, -0.5f, 0.0f);
glVertex3f(-0.25f, -0.5f, 0.0f);
glVertex3f(-0.45f, -0.30f, 0.0f);
glVertex3f(-0.55f, 0.0f, 0.0f);
glVertex3f(-0.45f, 0.30f, 0.0f);
glVertex3f(-0.25f, 0.5f, 0.0f);
//glScalef(10, 10, 10); // this won't have any effect on result
//glTranslatef(1, 2, -3);// the same
glEnd();
You have 2 options here
Completely change the vertices definition (only with Decagon to be similar to above relative to the origin). Other shapes are already good, it's defined relative to the origin.
Carefully determine the origin of the shape regardless of how your defined shape's vertices. Use such position to translate back the shape as part of matrix operation firstly before all other operations (please read on to know why).
Concept of rotation around itself
The concept of rotation around itself is that we need to do the following operations in order
Scale (in this case we don't have)
Rotation
Translation
Scaling although we don't have in this case, should be last otherwise it might affect other two operations.
If we translate first to the arbitrary position, then the rotation will happen around such point. In fact, rotation works relatively to the origin 0,0, thus we just need to do by any means to place the object back to origin first before we proceed, then we can rotate, translate to desire position it should be, and scale.
Let's see your matrix multiplication order
glScalef(0.7f, 0.7f, 0.7f); //increase the object size
glTranslatef(d[0], d[1], d[2]); // Move box down X axis.
glRotatef(zAngle, 0, 0, 1);
glRotatef(yAngle, 0, 1, 0);
glRotatef(xAngle, 1, 0, 0);
glRotatef(spin, 0.0, 0.0, 1.0);
This means we do the following in order
rotate around z-axis with spin angle
rotate around x-axis with xAngle angle
rotate around y-axis with yAngle angle
rotate around z-axis with zAngle angle
Although we could possibly combine the first and last together, but anyway it's ok.
Also you might want to further look at Euler Angles when we rotate around 3 cardinal axes like this, it can lead to Gimbal lock problem but it can be solved by limiting angles user can rotate around a certain axis.
The order is right. This is translated into mathematics terms as S * T * Rz * Ry * Rx * Rspin in which you can see it's inverse of the order in code. Rspin happen first, then Rx then so on.
Now what happen if Decagon shape is defined not relative to the origin, but defined to in the way that it translated to the right.
Take my vertices definition, but + 0.55f for all x position, we will have
glBegin(GL_POLYGON);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.80f, 0.5f, 0.0f);
glVertex3f(1.0f, 0.30f, 0.0f);
glVertex3f(1.10f, 0.0f, 0.0f);
glVertex3f(1.0f, -0.30f, 0.0f);
glVertex3f(0.80f, -0.5f, 0.0f);
glVertex3f(0.30f, -0.5f, 0.0f);
glVertex3f(0.10f, -0.30f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.1f, 0.30f, 0.0f);
glVertex3f(0.30f, 0.5f, 0.0f);
glEnd();
If you swap above code to your vertices definition, then it won't rotate around itself anymore. But we know that it takes -0.55f in x-axis to bring this shape back to origin, thus if we add glTranslatef(-0.55f, 0.0f, 0.0f) to be the first operation to execute then it will work the same.
We'd have
glScalef(0.7f, 0.7f, 0.7f);
glTranslatef(d[0], d[1], d[2]);
glRotatef(zAngle, 0, 0, 1);
glRotatef(yAngle, 0, 1, 0);
glRotatef(xAngle, 1, 0, 0);
glRotatef(spin, 0.0, 0.0, 1.0);
glTranslatef(-0.55f, 0.0f, 0.0f); // <------ add this
In short, translate target object to be at origin first before rotating (around itself), then proceed proper sequence as before.
If you desire to have such object to be located at the location you've defined the shape's vertices i.e. it's to the right +0.55f along x-axis and still rotate around itself. Then you use glTranslatef(d[0] + 0.55f, d[1], d[2]) instead.
Further Notes
The last two gl operations glScalef() and glTranslatef() won't have any effect as you already drew the shape. These two operations get discarded every frame when you call glLoadIdentity().
Just note that source code is still based on fixed-function pipeline of OpenGL. You might want to also take a look at modern programmable pipeline. This will allows you more flexibility in controlling virtual camera thus matrix operations are more clear cut and separated to the object itself whenever we need to move around. So this will make matrix operations easier to grasp, and to understand.
Edit
For additional control and satisfy application requirement as follows
Left click to rotate indefinitely, then left click again to stop
Right click to cycle through the color for rendered shape
We have to have control flags, and information for us to change at any frame time as follows.
bool isSpinning = false;
#define NUM_COLOR 4
int sCurrColor = 0;
GLfloat sColor[NUM_COLOR][3] = {
{1.0f, 1.0f, 1.0f},
{1.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 1.0f}
};
So for colors, we have white, red, blue, and green. Total in 4 colors, each color has 3 component values for RGB. We start with white color as seen in sCurrColor for our index.
Now your mouse() function would looks like this
void mouse(int buton, int state, int x, int y)
{
switch (buton) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN && !isSpinning)
isSpinning = true;
else if (state == GLUT_DOWN && isSpinning)
isSpinning = false;
break;
case GLUT_RIGHT_BUTTON: //here I don't know how to change the color of the shape
if (state == GLUT_DOWN)
sCurrColor = (sCurrColor + 1) % NUM_COLOR;
break;
default:glutIdleFunc(NULL);
break;
}
}
We optimized moving glutIdleFunc(spinDisplay); to be called inside main() function just before glutMainLoop(). As your requirements, we don't have to change it every frame.
Thus, spinDisplay() is now changed to be
void spinDisplay() //here it's the problematic function
{
if (isSpinning)
{
spin = spin + 3.0;
if (spin > 360.0)
{
spin = 0.0;
}
}
glutPostRedisplay();
}
Probably better to change the name of function to something like display() as it's more generic to not confuse that we have to spin everytime. Anyway, I didn't change this for the sake of brevity and consistency of your code.
Now the last part is to plug in sColor to be used by all those shapes in rendering. For example for Decagon you can do this
glColor3f(sColor[sCurrColor][0], sColor[sCurrColor][1], sColor[sCurrColor][2]);
This will be the same for other shapes if you like to have the same effect by right clicking to cycle through the color.

Related

GLUT just draw a Ship for Asteroid game but cant move and rotate ship correctly

Ship Asteroid primitive:
just draw a Ship for Asteroid game but cant move and rotate ship correctly
Problem: Cant find how use the Angle variable to rotate ship by center correctly;
Problem: Cant find how use angle with position to got correct direction to move ship
Look my code and if possible help me:
typedef struct {float x; float y; float z; float angle;} point2D;
class player //player class is ship
{
protected:
public:
point2D position, angle;
player()
{
position.x = 0.0;
position.y = 0.0;
angle.z = 0.0;
}
void set_position(float x, float y) //Set position of player
{
position.x=x;
position.y=y;
}
void draw_ship()
{
glPushMatrix();
glTranslatef(position.x,position.y,0);
glRotatef(angle.z, 0.,0.,0.1);
glScalef(0.10,0.075,0.10);
glBegin(GL_LINE_LOOP);
glColor3ub(redc, greenc, bluec);
glVertex2f( 1.0f, 2.0f);
glVertex2f( 1.4f, 0.4f);
glVertex2f( 1.2f, 0.6f);
glVertex2f( 0.8f, 0.6f);
glVertex2f( 0.6f, 0.4f);
glEnd();
glPopMatrix();
}
};
player ship;
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
glClear(GL_COLOR_BUFFER_BIT);// Clear the color buffer (background
glEnable( GL_TEXTURE_2D );
background();
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glDisable( GL_TEXTURE_2D );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
ship.draw_ship();
glutSwapBuffers(); // Double buffered - swap the front and back buffers
}
* Callback handler for special-key event */
void specialKeys(int key, int x, int y) {
switch (key) {
case GLUT_KEY_RIGHT:
ship.angle.z -= 10.0f;
break;
case GLUT_KEY_LEFT:
ship.angle.z += 10.0f;
break;
case GLUT_KEY_UP:
ship.position.x = ship.position.x + sin(ship.angle.z) * 0.02;
ship.position.y = ship.position.y + cos(ship.angle.z) * 0.02;
printf("posx is: %f", ship.position.x);
printf("posy is: %f", ship.position.y);
break;
}
}
You problem is that glRotate is always rotating around (0,0,0) ... so to make your transform right first rotate identity and then translate. But there is a slight problem because glTranslate will use local coordinates and you need global ... luckily you can set the matrix origin directly. As the comments where not enough for you here how it would look like:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); // unit matrix
glRotatef(angle.z,0.0,0.0,1.0); // rotate around (0,0,0) and z axis
double m[16];
glGetDoublev(GL_MODELVIEW_MATRIX,m);// get actual matrix into CPU side memory/code
m[12]=position.x; // change the global position
m[13]=position.y;
m[14]=0.0;
glLoadMatrix(m); // update GL matrix with the changed one
glScalef(0.10,0.075,0.10); // scale ship
In case your position is in already scaled coordiantes then the scale will go directly after the rotate.
Beware I wrote this directly in answer editor so there might be minor syntax errors ...
btw you can use the m also for movement in ship direction m[0,1,2] is x axis direction and m[4,5,6] is y axis. not sure in which your ship model points. You just add this forward vector multiplied by speed/deltatime to your position in some timer.
For more info about matrices see: Understanding 4x4 homogenous transform matrices

Looking along z axis gluLookAt works when theta=360 but not when theta=0

I was playing around with rendering a triangle in OpenGL and I came across an interesting problem. Obviously, when you look along the 'Up' direction, which in my case means that Eye_z=Up_z (and since I was working in spherical coordinates, this means that theta=0), the object is not displayed (refer to the top answer to OpenGL is not displaying anything when looking along the y axis for a mathematical explanation).
However, when I make the angle 360 degrees instead of 0, the object gets displayed without any problem. Does anyone know why? I've attached snippets of my code along with a screenshot here:
triangle.cpp
void Triangle::render(Camera C){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glLoadIdentity();
float th = C.Getth();
float ph = C.Getph();
float Eye_x = r*sin(th*DEGtoRAD)*cos(ph*DEGtoRAD);
float Eye_y = r*sin(th*DEGtoRAD)*sin(ph*DEGtoRAD);
float Eye_z = r*cos(th*DEGtoRAD);
float Up_z = (th>=180.0f && th<360.0f)?-1.0f:1.0f;
gluLookAt(Eye_x,Eye_y,Eye_z,0.0,0.0,0.0,0.0,0.0,Up_z);
glRotatef(m_rotationAngle, 0.0f, 0.0f, 1.0f);
// Draw Triangle
glBegin(GL_TRIANGLES);
glColor3f(1.0f,0.0f,0.0f);
glVertex3f(-0.5f,-0.5f,0.0f);
glColor3f(1.0f,1.0f,0.0f);
glVertex3f(0.5f,-0.5f,0.0f);
glColor3f(0.0f,0.0f,1.0f);
glVertex3f(0.0f,0.5f,0.0f);
glEnd();
// Draw Axes
glBegin(GL_LINES);
glColor3f(1.0f,0.0f,0.0f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(1.0f,0.0f,0.0f);
glColor3f(0.0f,1.0f,0.0f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(0.0f,1.0f,0.0f);
glColor3f(0.0f,0.0f,1.0f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(0.0f,0.0f,1.0f);
glEnd();
}
camera.cpp:
void Camera::Move(int dir){
switch(dir){
case 1: // +th
th += move_amt;
if(th>360.0f){
th-=360.0f;
}
break;
case -1: // -th
th -= move_amt;
if(th<=0.0f){
th+=360.0f;
}
break;
case 2: // ph
ph += move_amt;
if(ph>=360.0f){
ph-=360.0f;
}
break;
case -2: // -ph
ph -= move_amt;
if(ph<=0.0f){
ph+=360.0f;
}
break;
default:
break;
}
}
This is what I get when Theta=0
This is what I get when Theta=360

How to select a specific viewport to transform, while keeping the previous transformations in OpenGL

So this is for an assignment that I'm supposed to do, where the guidelines that I'm currently focusing on are :
 The user can select the “active” viewport by clicking on it (you should change the color of the
border when a viewport is selected). Any transformation (rotation, translation, etc…) should be
performed on the active viewport only.
 User should be able to navigate the scene in the selected viewport using WASD keys and/or arrow
keys (for ortho projections). Mouse control (like in an FPS game) and WASD keys and/or arrows
for the perspective projection. Navigation should be allowed only in the active viewport. The
other viewports should remain static.
I already have code that can transform the perspective view in fps fashion, and hardcoded some camera transformations for the front view, but I can't seem to figure out how to make a function or something that can differentiate between the viewports, cause if I could I would be able to just insert the code for transforming into that. I'm currently using a mouseclickcallbackfunction to detect where the mouse is, but the main problem being it runs after my displaycallbackfunction, which is where viewports are created and run, thus meaning i have to find a way to make it so i can transform from the display funciton instead of the mouse one detecting it.
some of my code is this:
void DisplayCallbackFunction(void)
{
/* clear the screen */
glViewport(0, 0, windowWidth, windowHeight);
glClearColor(0.2f, 0.2f, 0.2f, 0.8f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//create viewport
setViewport(1);
//Perspective
//glFrustum(-1.0f,1.0f, -1.0f, 1.0f, 1.0f, 100);
gluPerspective(45.0f,1.0f, 0.1f, 100.0f);
//Orthographic
//glOrtho(-1.0f, 1.0f, -1.0, 1.0, 1.0f, 100.0f);
//gluOrtho2D(1.0f, 1.0f, 1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/*
if (x < windowWidth / 2 && y < windowHeight / 2) {
viewport = 3;
std::cout << "Viewport =" << viewport << std::endl;
}
if (x > windowWidth / 2 && y < windowHeight / 2) {
viewport = 4;
std::cout << "Viewport =" << viewport << std::endl;
}
if (x > windowWidth / 2 && y > windowHeight / 2) {
viewport = 2;
std::cout << "Viewport =" << viewport << std::endl;
}
if (x < windowWidth / 2 && y > windowHeight / 2) {
viewport = 1;
std::cout << "Viewport =" << viewport << std::endl;
}
break;*/
gluLookAt(
cameraPosition.x, cameraPosition.y, cameraPosition.z,// camera position
cameraPosition.x + forwardVector.x,
cameraPosition.y + forwardVector.y,
cameraPosition.z + forwardVector.z,// what the camera is looking at
0.0f, 1.0f, 0.0f);//what the camera thinks is up
/* This is where we draw things */
//glColor3f(0.5f, 0.8f, 0.1f); //RGB or 4f-> RGBA
//drawObjects();
//cube code is here
//second viewport
setViewport(2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
rz, rz2, 6.0f,// camera position
rz, rz2, 0.0f,// what the camera is looking at
0.0f, 1.0f, 0.0f);//what the camera thinks is up
//other cube
//third viewport
setViewport(3);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
-6.0f, 0.0f, 0.0f,// camera position
0.0f, 0.0f, 0.0f,// what the camera is looking at
0.0f, 1.0f, 0.0f);//what the camera thinks is up
//3rd cube
//fourth viewport
setViewport(4);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
0.0f, 6.0f, 0.0f,// camera position
0.0f, 0.0f, 0.0f,// what the camera is looking at
0.0f, 0.0f, 1.0f);//what the camera thinks is up
//fourth cube
//HUD or Overlay viewport
glViewport(0, 0, windowWidth, windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_QUADS);
glVertex3f(-0.02, -1.0, 0.0);// bottom left
glVertex3f(0.02, -1.0, 0.0); //bottom right
glVertex3f(0.02, 1.0, 0.0); // top right
glVertex3f(-0.02, 1.0, 0.0); // top left
glBegin(GL_QUADS);
glVertex3f(-1.0, -0.02, 0.0);// bottom left
glVertex3f(1.0, -0.02, 0.0); //bottom right
glVertex3f(1.0, 0.02, 0.0); // top right
glVertex3f(-1.0, 0.02, 0.0); // top left
glBegin(GL_QUADS);
glVertex3f(0.0, 0.0, 0.0);// bottom left
glVertex3f(0.02, 0.0, 0.0); //bottom right
glVertex3f(0.02, 1.0, 0.0); // top right
glVertex3f(0.0, 1.0, 0.0); // top left
glEnd();
/* Swap Buffers to Make it show up on screen */
glutSwapBuffers();
}
void KeyboardCallbackFunction(unsigned char key, int x, int y)
{
std::cout << "Key Down:" << (int)key << std::endl;
switch (key)
{
case 32: // the space bar
break;
case 27: // the escape key
//case 'q': // the 'q' key
exit(0);
break;
case 'W':
case 'w':
cameraPosition += (forwardVector * movementScalar);
break;
case 'S':
case 's':
cameraPosition -= (forwardVector * movementScalar);
break;
case 'A':
case 'a':
rightVector = glm::cross(forwardVector, glm::vec3(0.0f, 1.0f, 0.0f));
rightVector = glm::normalize(rightVector);
cameraPosition -= (rightVector * movementScalar);
break;
case 'D':
case 'd':
rightVector = glm::cross(forwardVector, glm::vec3(0.0f, 1.0f, 0.0f));
rightVector = glm::normalize(rightVector);
cameraPosition += (rightVector * movementScalar);
break;
}
}
void SpecialInput(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_LEFT:
rz += 1.0;
break;
case GLUT_KEY_RIGHT:
rz -= 1.0f;
break;
case GLUT_KEY_UP:
rz2 -= 1.0f;
break;
case GLUT_KEY_DOWN:
rz2 += 1.0f;
break;
}
glutPostRedisplay();
}
void MouseClickCallbackFunction(int button, int state, int x, int y)
{
// Handle mouse clicks
switch (button) {
if (state == GLUT_DOWN) {
case GLUT_RIGHT_BUTTON:
std::cout << "Mouse X: " << x << "Mouse Y: " << y << std::endl;
break;
case GLUT_LEFT_BUTTON:
std::cout << "Mouse X: " << x << "Mouse Y: " << y << std::endl;
if (x < windowWidth / 2 && y < windowHeight / 2) {
viewport = 3;
std::cout << "Viewport =" << viewport<<std::endl;
}
if (x > windowWidth / 2 && y < windowHeight / 2) {
viewport = 4;
std::cout << "Viewport ="<< viewport << std::endl;
}
if (x > windowWidth / 2 && y > windowHeight / 2) {
viewport = 2;
std::cout << "Viewport ="<< viewport << std::endl;
}
if (x < windowWidth / 2 && y > windowHeight / 2) {
viewport = 1;
std::cout << "Viewport ="<< viewport << std::endl;
}
break;
}
}
}
So I'm probably screwed since this is supposed to be due midnight, and the teacher didn't tell us enough information to complete this properly. I would appreciate help if someone could tell me how to select a specific viewport to transform with left click, that would then transform the camera by the arrow keys.
Actually you know everything you need to do that. OpenGL won't save the state for you. Instead you are responsible for remembering the state and transferring it to OpenGL for each viewport you render. So define:
struct ViewportState {
int vp[2], vs[2]; // position annd size of the viewport on screen
vec3 pos; // camera position in the world
vec3 rot; // euler angles of camera rotation
};
ViewportState viewports[number_of_viewports];
int active_viewport = 0;
Write a function to calculate the view matrix of a viewport:
mat4 ViewMatrix(const ViewportState &vp)
{
// build a view matrix m based on vp.pos and vp.rot
return m;
}
Now use these during rendering:
void DisplayViewport(int i)
{
const ViewportState &vp = viewports[i];
glViewport(vp.vp[0], vp.vp[1], vp.vs[0], vp.vs[1]);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if(i == active_vieport)
{
// draw a highlighted border around viewport
}
// load ViewMatrix(vp)
// draw the actual 3d content of the viewport
}
void DisplayCallbackFunction(void)
{
// ...
for(int i = 0; i < nviewports; ++i)
DisplayViewport(i);
//...
}
The keyboard and the mouse will modify the active viewport:
void KeyboardCallbackFunction(unsigned char key, int x, int y)
{
// ...
case 'w':
viewports[active_viewport].pos -= (ViewMatrix(viewports[active_viewport]) * vec4(0,0,movementScalar,1)).xyz;
break;
case 'a':
viewports[active_viewport].pos -= (ViewMatrix(viewports[active_viewport]) * vec4(movementScalar,0,0,1)).xyz;
break;
// ...
}
To activate a different viewport:
void MouseClickCallbackFunction(int button, int state, int x, int y)
{
// iterate over viewports, find the one within x/y coordinates and set active_viewport accordingly
}
You have 2 choices.
Render your viewport scene to a frame buffer backed by a texture. Then render the texture to the screen
Transform your scene from viewport space to screen space using matrices. To prevent yourself drawing out the box use a scissor test to clip to the viewport

How to rotate a lightsource around a fixed object (OpenGL)?

I'm trying to make a light source rotate around my character model in my OpenGL project, but as I try it, all I got so far is my model rotating like crazy (or the floor).
My rendering code looks like this:
void mainRender() {
updateState();
renderScene();
glFlush();
glutPostRedisplay();
//spin = (spin + 30) % 360;
Sleep(30);
}
void renderScene() {
glClearColor(backgrundColor[0],backgrundColor[1],backgrundColor[2],backgrundColor[3]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // limpar o depth buffer
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
updateCam();
renderFloor();
modelAL.Translate(0.0f,1.0f,0.0f);
modelAL.Draw();
}
void renderFloor() {
// set things up to render the floor with the texture
glShadeModel(GL_SMOOTH);
glEnable(type);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glPushMatrix();
glTranslatef(-(float)planeSize/2.0f, 0.0f, -(float)planeSize/2.0f);
float textureScaleX = 10.0;
float textureScaleY = 10.0;
glColor4f(1.0f,1.0f,1.0f,1.0f);
int xQuads = 40;
int zQuads = 40;
for (int i = 0; i < xQuads; i++) {
for (int j = 0; j < zQuads; j++) {
glBegin(GL_QUADS);
glTexCoord2f(1.0f, 0.0f); // coords for the texture
glNormal3f(0.0f,1.0f,0.0f);
glVertex3f(i * (float)planeSize/xQuads, 0.0f, (j+1) * (float)planeSize/zQuads);
glTexCoord2f(0.0f, 0.0f); // coords for the texture
glNormal3f(0.0f,1.0f,0.0f);
glVertex3f((i+1) * (float)planeSize/xQuads, 0.0f, (j+1) * (float)planeSize/zQuads);
glTexCoord2f(0.0f, 1.0f); // coords for the texture
glNormal3f(0.0f,1.0f,0.0f);
glVertex3f((i+1) * (float)planeSize/xQuads, 0.0f, j * (float)planeSize/zQuads);
glTexCoord2f(1.0f, 1.0f); // coords for the texture
glNormal3f(0.0f,1.0f,0.0f);
glVertex3f(i * (float)planeSize/xQuads, 0.0f, j * (float)planeSize/zQuads);
glEnd();
}
}
glDisable(type);
glPopMatrix();
}
How could I make this new lightsource rotate around my "modelAL" object?
For the fixed pipeline, light source position assigned with glLight() are transformed with the model-view matrix, just as normal objects are. So you can use the transformation functions to position and rotate your light source as you would normal objects.
To rotate a light source (or other object) around a point, you need to follow these steps. Let L be where the light source will be when the rotation is 0 degrees, and O be the subject - the object around which you want to rotate the light source.
Position the light source at L-O (the position of the light source relative to the subject)
Rotate it about the required axis (probably the Y axis)
Translate it by O to move it into position.
Because of the way OpenGL works, you essentially do these in backwards order. Basically it would go like this:
glPushMatrix();
glTranslatef(O.x,O.y,O.z);
glRotate(angle,0,1,0);
GLfloat lightpos[4] = {L.x-O.x,L.y-O.y,L.z-O.z,1};
glLightfv(GL_LIGHT0,GL_POSITION,lightpos);
glPopMatrix();
Note, this only applies to positioned light sources, not directional ones i.e. with w=0.

Begun learning OpenGL, need help figuring out this problem

So I have begun learning OpenGL, reading from the book "OpenGL Super Bible 5 ed.". It's explains things really well, and I have been able to create my first gl program myself! Just something simple, a rotating 3d pyramid.
Now for some reason one of the faces are not rendering. I checked the vertecies (plotted it on paper first) and it seemed to be right. Found out if I changed the shader to draw a line loop, it would render. However it would not render a triangle. Can anyone explain why?
void setupRC()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
shaderManager.InitializeStockShaders();
M3DVector3f vVerts1[] = {-0.5f,0.0f,-0.5f,0.0f,0.5f,0.0f,0.5f,0.0f,-0.5f};
M3DVector3f vVerts2[] = {-0.5f,0.0f,-0.5f,0.0f,0.5f,0.0f,-0.5f,0.0f,0.5f};
M3DVector3f vVerts3[] = {-0.5f,0.0f,0.5f,0.0f,0.5f,0.0f,0.5f,0.0f,0.5f};
M3DVector3f vVerts4[] = {0.5f,0.0f,0.5f,0.0f,0.5f,0.0f,0.5f,0.0f,-0.5f};
triangleBatch1.Begin(GL_LINE_LOOP, 3);
triangleBatch1.CopyVertexData3f(vVerts1);
triangleBatch1.End();
triangleBatch2.Begin(GL_TRIANGLES, 3);
triangleBatch2.CopyVertexData3f(vVerts2);
triangleBatch2.End();
triangleBatch3.Begin(GL_TRIANGLES, 3);
triangleBatch3.CopyVertexData3f(vVerts3);
triangleBatch3.End();
triangleBatch4.Begin(GL_TRIANGLES, 3);
triangleBatch4.CopyVertexData3f(vVerts4);
triangleBatch4.End();
glEnable(GL_CULL_FACE);
}
float rot = 1;
void renderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GLfloat vRed[] = {1.0f, 0.0f, 0.0f, 0.5f};
GLfloat vBlue[] = {0.0f, 1.0f, 0.0f, 0.5f};
GLfloat vGreen[] = {0.0f, 0.0f, 1.0f, 0.5f};
GLfloat vWhite[] = {1.0f, 1.0f, 1.0f, 0.5f};
M3DMatrix44f transformMatrix;
if (rot >= 360)
rot = 0;
else
rot = rot + 1;
m3dRotationMatrix44(transformMatrix,m3dDegToRad(rot),0.0f,1.0f,0.0f);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformMatrix, vRed);
triangleBatch1.Draw();
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformMatrix, vBlue);
triangleBatch2.Draw();
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformMatrix, vGreen);
triangleBatch3.Draw();
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformMatrix, vWhite);
triangleBatch4.Draw();
glutSwapBuffers();
glutPostRedisplay();
Sleep(10);
}
You've most likely defined the vertices in clockwise order for the triangle that isn't showing, and in counterclockwise order (normally the default) for those that are. Clockwise winding essentially creates an inward facing normal and thus OpenGL won't bother to render it when culling is enabled.
The easiest way to check this is to set glCullFace(GL_FRONT)--that should toggle it so you see the missing triangle and no longer see the other three.
The only thing I see that affects polygons here is glEnable(GL_CULL_FACE);.
You shouldn't have that, because if you plot your vertices backwards, the polygon won't render.
Remove it or actually call glDisable(GL_CULL_FACE); to be sure.
In your case, it's not likely that you want to draw a polygon that you can see from one side only.