I made a simple OpenGL program that draws a 2D texture to the screen. When you resize the window, it doesn't adjust properly, so to fix that, I would just run the projection matrix code again:
if (windowSizeChange)
{
std::cout << "Window resized." << std::endl;
std::cout << windowWidth << " " << windowHeight << std::endl;
windowSizeChange = false;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, windowWidth, windowHeight, 0.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
However, running this code warps the image. To my understanding, to make it so I can draw 2D-like on the screen, my texture is drawn using an orthographic projection matrix which means there is a plane that is "parallel" with the window port or something like that which I draw on. When I try to re-make it to accommodate for the new window size, it doesn't adjust properly. What's going wrong with this code?
In your code you're changing the ortho matrix, but you also need to change the glViewport:
if (windowSizeChange)
{
glViewport(0, 0, windowWidth, windowHeight); // <-- Add this
std::cout << "Window resized." << std::endl;
std::cout << windowWidth << " " << windowHeight << std::endl;
windowSizeChange = false;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, windowWidth, windowHeight, 0.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
Orthographic matrices are, like you said, just a matrix that in this case is parallel to the screen. When we call glOrtho, it changes the size of the matrix we're working with, and glViewport tells openGL the size of the viewport (in this case, our window) we're working with. You'll generally want glOrtho and glViewport to be the same dimensions
When the size of the window and the framebuffer has been changed, then you have to adjust the viewport rectangle.
The viewport rectangle can be set by glViewport and specifies how the normalized device coordinates are mapped to window coordinates. It defines the area of the framebuffer, where the normalized device coordinates from (-1, -1) to (1, 1) are mapped to.
glViewport(0, 0, windowWidth, windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, windowWidth, windowHeight, 0.0, -1.0, 1.0);
Related
I am using the glc library to render font in the context of glfw window. However, I am not able to set co-ordinate to the font. It is always rendering the font at (0,0) position (i.e. at the below-left corner).
Below is the code to render sample string using GLC library,
int main(){
GLint ctx, myFont;
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
GLFWwindow* window = glfwCreateWindow(500, 500, "font rendering", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
glfwSwapInterval(1);
if ( GLEW_OK != glewInit( ) )
{
std::cout << "Failed to initialize GLEW" << std::endl;
}
ctx = glcGenContext();
glcContext(ctx);
myFont = glcGenFontID();
glcNewFontFromFamily(myFont, "Palatino");
glcFontFace(myFont, "Normal");
glcFont(myFont);
glViewport(0, 0, 500, 500);
glMatrixMode(GL_PROJECTION); // make the projection matrix the current matrix
glLoadIdentity(); // init the projection matrix by the identity matrix
glOrtho(0.0, 500.0, 500.0, 0.0, -1.0, 1.0); // top-left (0, 0); bottom-right (500, 500)
glcScale(100,100);
glcRenderString("Sample Text");
glMatrixMode(GL_MODELVIEW); // make the modelview matrix the current matrix
glLoadIdentity(); // init the modelview matrix by the identity matrix
glfwSwapBuffers(window);
while(!glfwWindowShouldClose(window)){
}
Here, glTranslatef(100,100, 0); does not work and if I use glRasterPos3f(x,y,z); then nothing will get render onto the screen.
Did I miss something here?
The projection matrix describes how the objects are projected onto the viewport. If there is no projection matrix, the objects have to be setup in normalized device space where all coordinates are int the range [-1.0, 1.0].
Since you want to draw in 2D, I recommend to setup an orthographic projection, which maps the viewspace 1:1 to window coordinates.
Use glOrtho for this and use glMatrixMode to switch between the projection matrix stack and the modelview matrix stack:
glViewport(0, 0, 500, 500);
glMatrixMode(GL_PROJECTION); // make the projection matrix the current matrix
glLoadIdentity(); // init the projection matrix by the identity matrix
glOrtho(0.0, 500.0, 500.0, 0.0, -1.0, 1.0); // top-left (0, 0); bottom-right (500, 500)
glMatrixMode(GL_MODELVIEW); // make the modelview matrix the current matrix
glLoadIdentity(); // init the modelview matrix by the identity matrix
glcScale(100,100);
.....
glcRenderString renders a string by using glBitmap respectively glDrawPixels. Becaus of that the positon has to be set by glRasterPos.
If you want to render the string in red, then you have to skip the red an green color component. This can be done by glPixelTransfer.
e.g.
glPixelTransferf(GL_RED_SCALE, 1.0f);
glPixelTransferf(GL_GREE_SCALE, 0.0f);
glPixelTransferf(GL_BLUE_SCALE, 0.0f);
I want to draw a model of a chair that I exported from 3ds max as a txt file. I read the file and display it in OpenGL (using Visual Studio -> C++). My problem is that I have to multiplicate the chair many times (10). I did try to multiplicate it twice but it does not work. The program crashes with these "Program is not responding" Windows errors. I have a main class that calls all of the nessessery methods from CDrawModel like that:
CDrawModel mModel;
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB);
glutInitWindowSize( 1000, 600 );
glutInitWindowPosition(100, 100);
glutCreateWindow("Georgi Koemdzhiev - 1306794");
glutKeyboardFunc(KeyResponse);
glutDisplayFunc(DrawGLScene);
glutReshapeFunc(ReSizeGLScene);
mModel.initGL();
glutMainLoop();
}
void DrawGLScene(void) {
mModel.myDrawGLScene();
}
GLvoid ReSizeGLScene(GLsizei fwidth, GLsizei fheight) {
mModel.MyReSizeGLScene(fwidth, fheight);
}
CDrawModal initialises an object of type CPolygonMesh which handles the reading from the file and drawing on the screen functionality. I know my code works since I am getting my modal drawn on the screen:
this is my CDrawModal class:
oid CDrawModel::initGL(void) {
glClearColor(1.0, 1.0, 1.0, 1.0);
near = 1.0;
far = 1000.0;
height = 1.5;
glCullFace(GL_BACK); // don’t draw back facing faces
glEnable(GL_CULL_FACE); // enable face culling
glPolygonMode(GL_FRONT, GL_LINE); // select front polygons and draw edges only
}
void CDrawModel::MyReSizeGLScene(int fwidth, int fheight) // Resize And Initialize The GL Window{
// Store window size so it can be accessed in myDrawGLScene()
wWidth = fwidth;
wHeight = fheight;
// Set fovy so that the viewing frustum has the specified height at the
// near clipping plane
fovy = (360 / PI) * atan(height / (2.0 * near));
// Calculate the aspect ratio of the VIEWPORT
// so that we can set the camera’s aspect ratio to the same value
aspect_ratio = (double)fwidth / (double)fheight;
glMatrixMode(GL_PROJECTION); // Select The Projection Stack
glLoadIdentity();
/* void glOrtho( GLdouble left,
GLdouble right,
GLdouble bottom,
GLdouble top,
GLdouble nearVal,
GLdouble farVal);*/
gluPerspective(90, aspect_ratio, near, far); // perspective view
//glOrtho(-130.0,130.0,-130.0,130.0,near,far);
glViewport(0, 0, wWidth, wHeight); // Viewport fills the window
// Print values of parameters
cout << fixed; // Use fixed-point notation
cout.precision(3); // Number of digits after the decimal point
cout << "fovy = " << fovy << endl;
cout << "aspect_ratio = " << aspect_ratio << endl;
cout << "near = " << near << endl;
cout << "far = " << far << endl;
}
void CDrawModel::myDrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the drawing area
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -200);
mesh.draw_model();
glutSwapBuffers(); // Needed if we're running an animation
glFlush();
}
What I need to do in order to draw it twice.This is my drawModal method in CPolugonMesh:
void CPolygonMesh::draw_model(void){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 0.0, 0.0); // draw red things
glBegin(GL_TRIANGLES);
for (int i = 0; i < Mesh_NumFaces; i++) {
// Look up the coordinates of each vertex
// in vertex_list[]
glVertex3fv(vertex_list[ face_list[i][0] ]);
glVertex3fv(vertex_list[ face_list[i][1] ]);
glVertex3fv(vertex_list[ face_list[i][2] ]);
//cout << "Drawing face: " << i << endl;
}
glEnd();
}
Your CPolygonMesh::draw_model(void) method actually clears the screen each time you draw a model, so only the last call will leave anything on the screen.
The line
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
is totally wrong there. You already do clear the screen at the beginning of your frame.
I need to draw a cube and project it with the default projection matrix. Also, I want to draw a hud controlling the orientation of the sphere. The hud is projected with another projection matrix.
render()
{
DrawGUI(); // project GUI with another projection matrix
glPushMatrix();
glutSolidCube(); // project the cube with the default projection matrix
glPopMatrix();
glutSwapBuffers();
}
reshape()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(...);
...
}
DrawGUI()
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(...); // project the GUI with this matrix
glMatrixMode(GL_MODELVEIW);
glPushMatrix();
glLoadIdentity();
glBegin();
//... drawing GUI
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
#define BUFFER_LENGTH 64
void processSelection(int xPos, int yPos)
{
static GLuint selectBuff[BUFFER_LENGTH];
GLint hits, viewport[4];
glSelectBuffer(BUFFER_LENGTH, selectBuff);
glGetIntegerv(GL_VIEWPORT, viewport);
// Switch to projection and save the matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glRenderMode(GL_SELECT);
glLoadIdentity();
gluPickMatrix(xPos, viewport[3] - yPos, 2,2, viewport);
glOrtho (-100, 100, -100, 100, -100, 100); // this line of code is the most
glMatrixMode(GL_MODELVIEW);
render();
hits = glRenderMode(GL_RENDER);
//...process hits
// Restore the projection matrix
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
The render part works well. Both the GUI and the cube are drawn without problem. However, the selection does not work as intended.
My question is: Since I project 3D models with different projection matrix, how should I deal with selection? I try to implement the typical selection buffer approach, but every time I click in the window, the selection buffer always contains the GUI even if I do not click on the GUI. Also, if I click on the cube, the selection buffer ends up with both the cube and the GUI.
If you use the selection buffer approach, you render with mixed projections as you do when doing the usual render. The only difference, is, that you apply that pick matrix as well. Also don't try to be too clever with the matrix pushing / poping. It rarely makes sense to use that in the projection matrix stack (hence it requires to have only 2 push levels, instead of the 32 for the modelview). Also don't use the reshape function to define the projection matrix.
DrawCube()
{
glMatrixMode(GL_MODELVEIW);
glLoadIdentity();
glutSolidCube();
}
DrawGUI()
{
glMatrixMode(GL_MODELVEIW);
glLoadIdentity();
glBegin();
//... drawing GUI
glEnd();
}
void render()
{
// base the projection on whats already in the projection
// matrix stack. For normal render this is identity, for
// selection it is a pick matrix.
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluOrtho2D(...); // project the GUI with this matrix
DrawGUI();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluPerspective(...);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
}
void display()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
render();
glutSwapBuffers();
}
#define BUFFER_LENGTH 64
void select(int xPos, int yPos)
{
static GLuint selectBuff[BUFFER_LENGTH];
GLint hits, viewport[4];
glSelectBuffer(BUFFER_LENGTH, selectBuff);
glGetIntegerv(GL_VIEWPORT, viewport);
// Switch to projection and augment it with a picking matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPickMatrix(xPos, viewport[3] - yPos, 2,2, viewport);
glRenderMode(GL_SELECT);
render();
hits = glRenderMode(GL_RENDER);
//...process hits
}
Note that OpenGL selection mode is usually not GPU accelerated and hence very slow. Also it's been deprecated and removed from modern OpenGL versions. It's highly recommended to use either index buffer selection (i.e. render each object with a dedicated index "color") or perform manual ray-intersection picking into the scene data.
I am making a game in OpenGL using GLUT on UNIX. It is a 3D game where the player can move side to side (x-axis) jump (y-axis) and is constantly moving forward and has to avoid oncoming obstacles (for my implementation the player actual stands still while the world constantly moves at the player).
I am having trouble when trying to draw a HUD with bitmap text on it. I have tried creating an orthogonal view and then drawing the text but it always ends up at a random spot on the x-axis and constantly moves towards the player with the world on the z-axis. Once it gets past the player it disappears (which is what happens to all the world objects to cut processing). I want the text in one place and to stay there.
gameSpeed = Accumulator*6;
DrawRobot(); //player
ModelTrans.loadIdentity(); //ModelTrans has helper functions to manipulate
ModelTrans.pushMatrix(); //the current matrix stack
ModelTrans.translate(vec3(0, 0, -gameSpeed)); //move the whole world
...Then I do a bunch of drawing of the game objects...
And here I attempt to do some bitmap fonts. Disabling the depth test helps put the text in front of all the other objects but the other code to create the orthogonal view actually could be commented out and I would still have the same problem.
ModelTrans.popMatrix();
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
ModelTrans.pushMatrix();
glLoadIdentity();
gluOrtho2D(0, WindowWidth, 0, WindowHeight);
glScalef(1, -1, 1);
glTranslatef(0, -WindowHeight, 0);
glMatrixMode(GL_MODELVIEW);
std::string str = "sup";
renderBitmapString(0.5 + xText, 5.0, GLUT_BITMAP_HELVETICA_18, str);
//xText adjusts for the moving left and right of the player
glMatrixMode(GL_PROJECTION);
ModelTrans.popMatrix();
glMatrixMode(GL_MODELVIEW);
glUseProgram(0);
glutSwapBuffers();
glutPostRedisplay();
printOpenGLError();
Here is some other code that may be of use:
void renderBitmapString(float x, float y, void *font, std::string s)
{
glRasterPos2f(x, y);
for (string::iterator i = s.begin(); i != s.end(); ++i)
{
char c = *i;
glutBitmapCharacter(font, c);
}
}
void Timer(int param)
{
Accumulator += StepSize * 0.001f;
glutTimerFunc(StepSize, Timer, 1);
}
void Reshape(int width, int height)
{
WindowWidth = width;
WindowHeight = height;
glViewport(0, 0, width, height);
}
I am making a game in OpenGL using GLUT on UNIX
First of all, you're not doing it on Unix, but most likely using X11. Also I'm pretty sure your OS is a variant of Linux, which is not Unix (a …BSD would be a true Unix).
Anyway, in this code snippet you're adjusting the projection, but not the modelview matrix
glMatrixMode(GL_PROJECTION);
ModelTrans.pushMatrix();
glLoadIdentity();
gluOrtho2D(0, WindowWidth, 0, WindowHeight);
glScalef(1, -1, 1);
glTranslatef(0, -WindowHeight, 0);
glMatrixMode(GL_MODELVIEW);
std::string str = "sup";
renderBitmapString(0.5 + xText, 5.0, GLUT_BITMAP_HELVETICA_18, str);
//xText adjusts for the moving left and right of the player
glMatrixMode(GL_PROJECTION);
ModelTrans.popMatrix();
glMatrixMode(GL_MODELVIEW);
I'm not entirely sure what ModelTrans is, but it has pushMatrix and popMatrix and if I assume, that those are just glPushMatrix and glPopMatrix then your code mises a
glPushMatrix();
glLoadIdentity()
…
glPopMatrix();
block acting on the Modelview matrix. Modelview and Projection matrices have their own stacks in OpenGL and must be pushed/poped individually.
Been integrating this camera tutorial http://www.swiftless.com/tutorials/opengl/camera2.html and having a bit of trouble centering the camera in the skybox.
Using this code below makes my camera inside the box:
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-1.0, 1.0, -1.0*(GLfloat)h/(GLfloat)w,
1.0*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
else
glOrtho(-1.0*(GLfloat)w/(GLfloat)h,
1.0*(GLfloat)w/(GLfloat)h, -1.0, 1.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
}
To draw the skybox, I followed this tutorial: http://sidvind.com/wiki/Skybox_tutorial
I've been trying to translate objects closer to the camera, but didn't work as I expected. Now I'm not sure what I need to do.
Appreciate any help.
First: Don'y apply the projection in the reshape handler. Otherwise simple things appear impossible (like doing a skybox). Second: For a skybox to work you must use the very same projection like for the rendering of the rest of the scene. What you should change is the translation of the modelview to 0, yet keeping the camera orientation.
You can do this by setting the last column of the modelview matrix to (0,0,0,1).
So this makes your rendering code like this:
void render_skybox()
{
push_modelview();
set_modelview_column(3, 0, 0, 1);
draw_skybox();
pop_modelview();
}
void render()
{
set_viewport();
set_projection();
apply_camera_transform();
render_skybox();
render_scene();
}