I am trying to create a ring of 8 spike-plates using freeglut. Every plate should be rotated/tilted by 30 degrees relative to the center ball, and all of them are supposed to be ordered in ring-form. Here is an example:
Here is my attempt:
void Larvitar::drawTail()
{
// Create tail ball
glPushMatrix();
glColor4f(0.2, 0, 1, 1.0);
GLUquadric *tail;
tail = gluNewQuadric();
glTranslatef(0, 0.2, -3.0);
gluSphere(tail, 1, 100, 30);
glPopMatrix();
double xrotate = 30;
for (int i = 0; i < 360; i += 45)
{
double rnd = ((double)rand() / (RAND_MAX));
glPushMatrix();
glColor4f(rnd, 0, rnd, 1.0);
glRotatef(xrotate, 1, 0, 0); // kippen?
glRotatef(i, 0, 0, 1); // Kreisform
glScalef(1, 0.4, 2);
glTranslatef(0, -2, -2.1);
glutSolidCube(1);
glPopMatrix();
xrotate -= xrotate;
}
}
The problem is that the plates are in ring form but not each one is tilted by 30 degrees outwards, only the first one is. What am I doing wrong? How can I solve this in a loop without having to create every plate by hand?
Solved it myself.
void Larvitar::drawTail() {
// Create tail ball
glPushMatrix();
glColor4f(0.2, 0, 1, 1.0);
GLUquadric *tail;
tail = gluNewQuadric();
glTranslatef(0, 0.2, -3.0);
gluSphere(tail, 1, 100, 30);
glPopMatrix();
glColor4f(0.58, 0.655, 0.482, 1.0);
for (int i = 0; i < 360; i += 45) {
glPushMatrix();
glRotatef(i, 0, 0, 1);
glRotatef(30, 1, 0, 0);
glScalef(1, 0.5, 2);
glTranslatef(0, -2, -2.1);
glutSolidCube(1);
glPopMatrix();
}
}
Related
I want to do something like a 3d-shooter.
The calculations seems to be correct, but it is works every other time with a spread with 180 degree rotation on every call glutPostRedisplay(). I understood that thanks to that red line.
I do this with such IDE: Code Blocks / Qt Creator under Linux(Ubuntu x64).
main.cpp
#include "Functions.h"
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(wnd_width, wnd_height);
glutInitWindowPosition(300, 100);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);
glutCreateWindow("OpenGL my");
glutDisplayFunc(display);
glutIdleFunc(Idle);
glutSpecialFunc(KeyPressed);
GLdouble aspect = wnd_width/wnd_height;
gluPerspective(90, aspect, 0.1, 10);
glTranslatef(0, -0.3, 0);
glutMainLoop();
return 0;
}
Functions.h
#include <GL/glut.h>
#include <math.h>
#include <iostream>
int wnd_width=1300;
int wnd_height=900;
float pos_x=0, pos_z=0.1;
float angle = 0;
float speed = 0.1;
void DrawFloor(){
glVertex3d(1, 0, 2.5);
glVertex3d(1, 0, 0);
glVertex3d(-1, 0, 0);
glVertex3d(-1, 0, 2.5);
}
void DrawWall(float x, float width, float height){
glVertex3f(x, height, 0);
glVertex3f(x, height, width);
glVertex3f(x, 0, width);
glVertex3f(x, 0, 0);
}
void DrawLine(){
glVertex3f(0, 0.1, -1);
glVertex3f(0, 0.1, 1);
}
void KeyPressed(int key, int x, int y){
switch (key) {
case GLUT_KEY_UP: {
//pos_x = speed * cos(3.14*angle/180);
//pos_z = speed * sin(3.14*angle/180);
pos_z+=0.1;
break;
}
case GLUT_KEY_DOWN: {
pos_x = speed*cos(angle);
pos_z = speed*sin(angle);
break;
}
case GLUT_KEY_LEFT: {
angle += 1;
pos_x = speed * cos(3.14 * angle/180);
pos_z = speed * sin(3.14 * angle/180);
break;
}
case GLUT_KEY_RIGHT: {
angle -= 3;
pos_x = speed * cos(3.14 * angle/180);
pos_z = speed * sin(3.14 * angle/180);
break;
}
}
std::cout<<"x: "<<pos_x<<'\t';
std::cout<<"z: "<<pos_z<<'\n';
glutPostRedisplay();
}
void display(){
glClearColor(0.6, 0.8, 1, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gluLookAt(pos_x, 0, pos_z, pos_x, 0, pos_z+0.2, 0, 1, 0);
glBegin(GL_QUADS);
glColor3f(0, 0, 0.7);
DrawFloor();
glColor3f(0, 0.8, 0.1);
DrawWall(-0.5, 2, 0.7);
DrawWall(0.5, 2, 0.7);
glEnd();
glLineWidth(2);
glColor3f(0.7, 0.2, 0.2);
glBegin(GL_LINES);
DrawLine();
glEnd();
glutSwapBuffers();
}
void Idle(){
//pos_z+=0.01;
//glutPostRedisplay();
}
You're using the fixed function stack, so you'll have to learn what glMatrixMode does and how transformation matrices are managed in those old ways.
Anyway, consider this a possible implementation of glMatrixMode
void glMatrixMode(GLenum m)
{
switch(m){
case GL_MODELVIEW: ctx->M = &ctx->matrix_modelview; break;
case GL_PROJECTION: ctx->M = &ctx->matrix_projection; break;
case GL_TEXTURE: ctx->M = &ctx->matrix_texture; break;
case GL_COLOR: ctx->M = &ctx->matrix_color; break;
}
}
On other words, there's a (context) global matrix selected with glMatrixMode, that's subsequently used for all folloing matrix manipulations.
Hence, glMatrixMode is not some form of initialization, but something you use to switch (often several times) during rendering a frame! Your use of it in the main function is kind of pointless. You must use it in your drawing function.
Furthermore, every matrix manipulation multiplies on top, of what's currently in ctx->M. gluLookAt is normally used with a identity matrix. If you don't reset you identity, that gluLookAt will work relative to the look-at done previously. So what you want is this:
void display(){
glClearColor(0.6, 0.8, 1., 1.); /* <<<----* */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTIOM);
glLoadIdentity();
setup_projection_here();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(pos_x, 0, pos_z, pos_x, 0, pos_z+0.2, 0, 1, 0);
glBegin(GL_QUADS);
/* ... */
glutSwapBuffers();
}
(*) Also you normally want to clear to alpha = 1 on the main framebuffer, unless you're planning on drawing window-translucent imagery. With alpha = 0 things might look correct in the window, but if a screenshot is taken, or some screen recording or sharing is used, it may cause undesired transparence.
I draw many lines to form a grid. I want to see the grid rotated on its X-axis, but I never get the intended result. I tried glRotatef and gluLookAt which does not work the way I want. Please see the pictures below.
this is the grid
this is how I want to see it
Edit: geez, posting the code here is also hard, lol, anyway here it is.
Edit2: removed, only leave the code that has issues.
Please find the code below, no matter how I set the gluLookAt, the grid result won't be in the perspective I want.
#include <GL/glut.h>
void display() {
...
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINES);
for (int i = 0; i < 720; i += 3)
{
glColor3f(0, 1, 1);
glVertex3f(linePoints[i], linePoints[i + 1], linePoints[i + 2]);
}
glEnd();
glFlush();
}
void init() {
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 4.0 / 3.0, 1, 40);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, -2, 1.25, 0, 0, 0, 0, 1, 0);
}
Lets assume, that you have a grid in the xy plane of the world:
glColor3f(0, 1, 1);
glBegin(GL_LINES);
for (int i = 0; i <= 10; i ++)
{
// horizontal
glVertex3f(-50.0f + i*10.0f, -50.0f, 0.0f);
glVertex3f(-50.0f + i*10.0f, 50.0f, 0.0f);
// vertical
glVertex3f(-50.0f, -50.0f + i*10.0f, 0.0f);
glVertex3f( 50.0f, -50.0f + i*10.0f, 0.0f);
}
glEnd();
Ensure that the distance of to the far plane of the projection is large enough (see gluPerspective). All the geometry which is not in between the near an far plane of the Viewing frustum is clipped.
Further more ensure that the aspect ratio (4.0 / 3.0) match the ratio of the viewport rectangle (window).
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 4.0 / 3.0, 1, 200);
For the use of gluLookAt, the up vector of the view has to be perpendicular to the grid. If the grid is arranged parallel to the xy plane, then the up vector is z axis (0, 0, 1).
The target (center) is the center of the grid (0, 0, 0).
The point of view (eye position) is ought to be above and in front of the grid, for instance (0, -55, 50). Note the point of view is used for a grid with the bottom left of (-50, -50, 0) and a top right of (50, 50, 0).
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, -55.0, 50.0, 0, 0, 0, 0, 0, 1);
I've got a taks from university and have to make a small example of solar system, the objects have to rotate etc. The problem is that when I do not call GluLookAt() everything looks fine, but I would like to change the view and when I call the function, there occurs that one orbit renders completely strangely.
I do not know if problem is with wrong creation of the first orbit, or with the proper values in gluLookAt parameters. Can anyone help?
Here's how it looks without calling gluLookAt():
Here's how it looks after gluLookAt():
Here's the code:
#include "stdafx.h"
#include <GL\glut.h>
#include <math.h>
GLfloat yRotated=1;
GLfloat movement = 0;
void drawCircle(float r) { // radius
glBegin(GL_LINE_LOOP);
for (int i = 0; i <= 300; i++) {
double angle = 2 * 3.14 * i / 300;
double x = r*cos(angle);
double y = r*sin(angle);
glVertex3d(x, y, -5.5);
}
glEnd();
}
void display(void) {
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
//gluLookAt(5, 5, 5, 0, 0, -8, 0, 1, 0); // 3rd coordinate - depth
float radius1 = 6;
float radius2 = 1;
//first orbit
glColor3f(1, 1, 1);
glPushMatrix();
glTranslatef(0, 0, -5.5);
drawCircle(radius1);
glPopMatrix();
//second orbit with rotation
glPushMatrix();
glRotatef(yRotated, 0, 0, 1);
glPushMatrix();
glTranslatef(radius1 / 2, 0, 0);
drawCircle(radius2);
glPopMatrix();
glPopMatrix();
//first czajnik
glColor3f(0.8, 0.2, 0.1);
glPushMatrix();
glTranslatef(0.0, 0.0, -5.5);
// glScalef(1.0, 1.0, 1.0);
glRotatef(yRotated, 0, 0, 1);
glRotatef(90, 1, 0, 0);
glutSolidSphere(1,20,20);
//second czajnik
glPushMatrix();
glColor3f(0, 0, 1);
glTranslatef(radius1/2, 0, 0);
glRotatef(yRotated, 0, 1, 0);
glutSolidSphere(0.5, 20, 20);
//third czajnik
glPushMatrix();
glTranslatef(radius2, 0, 0);
glColor3f(1, 1, 0);
glRotatef(yRotated, 0, 1, 0);
glutSolidSphere(0.2, 20, 20);
glPopMatrix();
//second czajnik pop
glPopMatrix();
//first czajnik pop
glPopMatrix();
glFlush();
}
void idle() {
yRotated += 0.1;
Sleep(2);
display();
}
void myReshape(int w, int h) {
if (w == 0 || h == 0) return;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70.0, (GLdouble)w / (GLdouble)h, 0.5, 20.0);
glViewport(0, 0, w, h);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(900, 600);
glutCreateWindow("Solar system");
//window with a title
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glClearColor(0, 0, 0, 1.0);
glutDisplayFunc(display);
glutReshapeFunc(myReshape);
glutIdleFunc(idle);
glutMainLoop();
return 0;
}
Some of your objects are at different z values, e.g. 1st orbit at -5.5, second at 0, because you "popped" the matrix.
In general, do not do so many push\pops nested into each other, matrix stack isn't made of rubber.
There is more efficient circle drawing procedure than to calculate sine and cosine for each step, e.g. to get advantage of circle being a figure of rotation:
inline void circle(F32 r, U32 quality)
{
if (r < F_ALMOST_ZERO) return;
F32 th = M_PI /(quality-1);
F32 s = sinf(th);
F32 c = cosf(th);
F32 t;
F32 x = r;
F32 y = 0;
::glBegin (GL_LINE_LOOP);
for(U32 i = 0; i < quality; i++)
{
glVertex2f(x, y);
t = x;
x = c*x + s*y;
y = -s*t + c*y;
}
::glEnd();
}
it can be optimized further by using symmetry, but this one is the basis.
I'm really pulling my hair out with this problem. I'm trying to create a simple game where the player rolls a ball around a playing area.
I'm using WinAPI for window management and input handling.
I tried to render some simple quads too, instead of the GLU sphere, but that didn't work either.
I've separated the code across different classes. I present the relevant code below. This code is in my WinMain:
while (running) {
PeekMessage(&msg, hwnd, NULL, NULL, PM_REMOVE);
if (msg.message == WM_QUIT)
running = false;
else {
// handle key presses
// update
gameWorld->update(getDirections());
// render
gameWorld->render(deviceContext);
// I added this block of code for testing, still does not work
glColor4f(1, 1, 1, 1);
glBegin(GL_QUADS);
glVertex3f(10, 10, 0);
glVertex3f(10, -10, 0);
glVertex3f(-10, -10, 0);
glVertex3f(-10, 10, 0);
glEnd();
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Here's GameWorld.cpp:
GameWorld::GameWorld()
{
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
this->ball = new Ball(1, 10, 10);
this->camera = new Camera(ball);
}
GameWorld::~GameWorld()
{
delete this->ball;
}
void GameWorld::render(HDC deviceContext) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
this->ball->draw();
SwapBuffers(deviceContext);
}
void GameWorld::update(Directions dirs) {
glLoadIdentity();
this->ball->handleInput(dirs);
this->ball->update();
this->camera->update();
}
Here's Camera update method:
void Camera::update() {
GLdouble ballX = ball->getLocation()->getX();
GLdouble ballY = ball->getLocation()->getY();
GLdouble ballZ = ball->getLocation()->getZ();
GLdouble x = ballX + cos(90) * this->distanceFromBall;
GLdouble y = ballY + cos(90) * this->distanceFromBall;
GLdouble z = ballZ + cos(90) * this->distanceFromBall;
gluLookAt(
x, y, z,
ballX, ballY, ballZ,
0, 1, 0
);
}
Here's the Ball draw method:
void Ball::draw() {
glPushMatrix();
this->quadric = gluNewQuadric();
glTranslated(this->location->getX(), this->location->getY(), this->location->getZ());
gluQuadricDrawStyle(this->quadric, GLU_FILL);
glColor4f(1, 1, 1, 1);
gluSphere(this->quadric, this->radius, this->slices, this->stacks);
gluDeleteQuadric(this->quadric);
glPopMatrix();
}
What the #!#% is wrong with this code? I should get this thing done in a week, so I really could use some help...
I had to use the gluPerspective() function to make this work. My GameWorld constructor now looks like this:
GameWorld::GameWorld()
{
glViewport(0, 0, WIDTH, HEIGHT); // reset the viewport to new dimensions
glMatrixMode(GL_PROJECTION); // set projection matrix current matrix
glLoadIdentity(); // reset projection matrix
// calculate aspect ratio of window
gluPerspective(54.0f, (GLfloat)WIDTH / (GLfloat)HEIGHT, 1.0f, 1000.0f);
glMatrixMode(GL_MODELVIEW); // set modelview matrix
glLoadIdentity();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
this->ball = new Ball(1, 20, 20);
this->camera = new Camera(ball);
}
The code is copied from the sample code of Dave Astle's book "OpenGL Game Programming".
I need to draw a 3d letter A and axes using opengl. In order to draw letter A I draw 2d letter A with z == 50 and then draw letter A with z = 50 - offset.
Here my opengl and letter a coordinates initialization
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(WIDTH, HEIGHT);
glutCreateWindow("PROJECT");
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, WIDTH, 0, HEIGHT, -100, 100);
glMatrixMode(GL_MODELVIEW);
p1.x = 0; p1.y = 400 ; p1.z = 50;
p2.x = -300; p2.y = -500; p2.z = 50;
p3.x = -200; p3.y = -500; p3.z = 50;
p4.x = -100; p4.y = -200; p4.z = 50;
p5.x = 100; p5.y = -200; p5.z = 50;
p6.x = 200; p6.y = -500; p6.z = 50;
p7.x = 300; p7.y = -500; p7.z = 50;
p8.x = -130; p8.y = -100; p8.z = 50;
p9.x = 130; p9.y = -100; p9.z = 50;
p10.x = 0; p10.y = 100; p10.z = 50;
glutDisplayFunc(display);
glutMainLoop();
In function display I draw axes and two letters A.
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
axes();
drawLetter(0);
drawLetter(100);
glFlush();
glutSwapBuffers();
}
Here initial values for axes
float angle = 17;
float AXIS_X[3] = { 250, 0, 0 },
AXIS_Y[3] = { 0, 250, 0 },
AXIS_Z[3] = { 0, 0, 150 };
I draw axes like this
void axes() {
glPushMatrix();
glTranslatef(WIDTH/2, HEIGHT/2, 0);
glBegin(GL_LINES);
glColor3f(1, 0, 0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3fv(AXIS_X);
glEnd();
glBegin(GL_LINES);
glColor3f(0, 0, 1);
glVertex3f(0.0, 0.0, 0.0);
glVertex3fv(AXIS_Y);
glEnd();
glBegin(GL_LINES);
glColor3f(0, 1, 0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3fv(AXIS_Z);
glEnd();
glPopMatrix();
}
Here is code for the letter
void drawLetter(float offset) {
glPushMatrix();
glTranslatef(WIDTH/2, HEIGHT/2, 0);
glScalef(0.3, 0.3, 0.3);
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(p1.x, p1.y, p1.z - offset);
glVertex3f(p2.x, p2.y, p2.z - offset);
glVertex3f(p3.x, p3.y, p3.z - offset);
glVertex3f(p10.x, p10.y, p10.z - offset);
glEnd();
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(p1.x, p1.y, p1.z - offset);
glVertex3f(p10.x, p10.y, p10.z - offset);
glVertex3f(p6.x, p6.y, p6.z - offset);
glVertex3f(p7.x, p7.y, p7.z - offset);
glEnd();
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(p8.x, p8.y, p8.z - offset);
glVertex3f(p4.x, p4.y, p4.z - offset);
glVertex3f(p5.x, p5.y, p5.z - offset);
glVertex3f(p9.x, p9.y, p9.z - offset);
glEnd();
glPopMatrix();
}
By default it looks like this
but when I add glRotatef(angle, 0.0, 1.0, 0.0); before axes() it looks like this(simple green line yes)
What's the problem?
Also a question - how to create orthogonal and perspective projections on the different planes(xy, yz, xz) for my letter? I need to use glFrustrum and glOrtho?
Normally you want to do the operations in this order:
Scale
Rotate
Translate
Since OpenGL uses column-major matrices, you want:
Translate
Rotate
Scale
NOTE: Conceptually the order is the same, you just have to do matrix multiplication in a different order when you use column-major.
I would start by addressing this.
The other important thing to note is that if you rotate outside of either drawLetter (...) or axes (...) in this code, the rotation is going to accumulate over multiple frames (since you do not load an identity matrix). You should either load an identity matrix for modelview each frame, or do the rotation inside your PushMatrix / PopMatrix blocks (you need to do this for proper rotation anyway).