I'm using QGLWidget and this code to draw a text on the screen but the rendering is catastrophic if the string's length is too high :
Here's my code :
glPushMatrix();
glRotatef(90, 0, 0, 1);
QString qStr = QString("Here's a very long string which doesn't mean anything at all but had some rendering problems");
renderText(0.0, 0.0, 0.0, qStr);
glPopMatrix();
I had the exact same problem when using Helvetica. Changing the font to Arial solved it.
I did a small wrapper around it to make things easier:
void _draw_text(double x, double y, double z, QString txt)
{
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
qglColor(Qt::white);
renderText(x, y, z, txt, QFont("Arial", 12, QFont::Bold, false) );
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
}
From the documentation:
This function can only be used inside a QPainter::beginNativePainting()/QPainter::endNativePainting() block if the default OpenGL paint engine is QPaintEngine::OpenGL. To make QPaintEngine::OpenGL the default GL engine, call QGL::setPreferredPaintEngine(QPaintEngine::OpenGL) before the QApplication constructor.
Hence, have you tried to use QPainter::beginNativePainting() just before the call, and QPainter::endNativePainting() just after?
Also, note that the text is rendered in window coordinate, not taking into account at all your current OpenGL matrix state (in short, your glRotatef(90, 0, 0, 1) call has no effect). You can see in the implementation here that they save your current OpenGL state by calling qt_save_gl_state(), then create their brand new matrices with:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, width, height);
glOrtho(0, width, height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Then draw the text, and finally restore your previous OpenGL state with qt_restore_gl_state()
Related
I'm starting to work in a 2D game, but I don't know the way I'm supposed to use viewPort(). This is my Init() code:
void init(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(100, 100, 800, 600);
gluOrtho2D(0, 800, 600, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0, 0.0, 0.0, 0.0);
}
What I want to know is that, after drawing an image to the window, how can I look only at a part of it, and not the whole world?
Everything you did there belongs into the drawing code. Loading textures and shaders, setting up framebuffer objects would be initialization, but you're not doing that up there.
Also glClear must come after glClearColor.
Last but not least, the viewport does not affect clear operations (you have to use scissor testing for clear operations to be limited to a certain rectangle).
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.
I have a studying project which represents simple 3D scene. I want to draw sphere in some non-origin point. Later I'm going implement this as separate function or method.
I'm setting point of view using gluLookAt() then I'm transforming model-view matrix using glTranslatef() with little offset and drawing sphere. Unfortunately, the sphere isn't shown. Am I right with model-view matrix approaching?
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
gluLookAt(1, 0 ,1, 0, 0, 0, 0, 1, 0);
glColor3b(197, 96, 63);
glPushMatrix();
glLoadIdentity();
glTranslatef(0.1, 0, 0);
glutWireSphere(0.2, 20, 10);
glPopMatrix();
glFlush();
}
void reshape(int w, int h){
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho ((float)w/(float)h, (float)-w/(float)h, -1, 1, 0.8, 100);
glMatrixMode(GL_MODELVIEW);
}
No, you aren't.
gluLookAt(1, 0 ,1, 0, 0, 0, 0, 1, 0);
glColor3b(197, 96, 63);
glPushMatrix();
glLoadIdentity(); // why it should be there?
By zeroing the view matrix there, you are drawing your object relatively to the origin coordinates, not taking your glLookAt into account. The call to it is effectively ignored. It should be coded as:
Set up the "camera matrix"
Push the matrix on the stack
Translate to the object's position
Draw the object
Pop and go back to 2.
So if you want to set up hypothetical "camera", you have to combine positions of objects with the camera matrix itself.
Your approach doesn't look that unreasonable. The problem is here:
glPushMatrix();
glLoadIdentity();
glTranslatef(0.1, 0, 0);
The pushing (and later popping) is a good idea, but by setting the matrix to identity before the translation, you loose any transformations done before, in particular the viewing transformations established with gluLookAt. So just remove this glLoadIdentity to properly concatenate the individual transformations.
Always keep in mind that all the matrix transformation functions, like glTranslate, glOrtho, or gluLookat always modify the currently selected (with glMatrixMode) matrix and don't just replace it. This is also the reason why you do a glLoadIdentity before the calls to glOrtho and gluLookAt.
I'm trying to display a text-overlay (basically a help screen which shows my keyboard shortcuts) on top of a 3D Texture I'm rendering. The texture works great and I've got some east-to-use rotations and translations for the user.
My thought was to use
const unsigned char tmp[100] = "text to render";
glRasterPos2i(x, y);
glColor4b(255, 255, 255, 255);
glutBitmapString(GLUT_BITMAP_HELVETICA_18, tmp);
As recommended in How do I use glutBitmapString() in C++ to draw text to the screen? .
This works great except that the text now rotates with the object instead of remaining in a static location on the screen. I read some documentation and found that the glRasterPos functions are manipulated when you manipulate the model view matrix:
The object coordinates presented by glRasterPos are treated just like those of a glVertex command: They are transformed by the current modelview and projection matrices and passed to the clipping stage.
-Source
I then found via another post that you could push and pop the current matrix with glPushMatrix and glPopMatrix.
-Source
When I do this, the text disappears all together. At first I thought I might have had the coordinates wrong for the text, but I tried x=y=0 through x=y=25 in intervals of .01 and never saw the text. It's still possible I'm misunderstanding where this should be drawn, but I'm not sure what to try next.
My drawing function is calling something akin to:
glLoadIdentity();
glPushMatrix();
glTranslatef(0,0,-sdepth);
glRotatef(-stheta, 1.0, 0.0, 0.0);
glRotatef(sphi, 0.0, 0.0, 1.0);
glRotatef(rotateX,0,1,1);
glRotatef(rotateY,1,0,0);
glTranslatef(-0.5,-0.5,-0.5);
glPopMatrix();
glRasterPos2i(2, 2);
glColor4b(255, 255, 255, 255);
glutBitmapString(GLUT_BITMAP_HELVETICA_18, tmp);
Anyone have any recommendations for debug/troubleshooting steps to try to get this text to display in a single, static location on the screen?
Well, if glRasterPos is treated the same way as glVertex, then you need to set up proper projection (GL_PROJECTION) matrix (using gluOrtho2D) before calling glRasterPos.
Give this a shot:
#include <GL/glut.h>
#include <string>
using namespace std;
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3ub(255,0,0);
glPushMatrix();
glScalef(5,5,5);
glBegin(GL_QUADS);
glVertex2f(-1,-1);
glVertex2f(1,-1);
glVertex2f(1,1);
glVertex2f(-1,1);
glEnd();
glPopMatrix();
glColor3ub(0,255,0); // A
glRasterPos2i(0,0); // B
string tmp( "wha-hey!" );
for( size_t i = 0; i < tmp.size(); ++i )
{
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, tmp[i]);
}
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double aspect_ratio = (double)w / (double)h;
glOrtho(-10*aspect_ratio, 10*aspect_ratio, -10, 10, -1, 1);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(800,600);
glutCreateWindow("Text");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return EXIT_SUCCESS;
}
Oddly enough swapping lines A and B causes the glColor3ub() call to not take effect. I think that's what you were running into with the code sequence you posted.
As an aside glColor4b() takes chars which max out at 127. You should switch to glColor4ub() if you want to persist in passing in 255.
Documented here ("The sequence of glRasterPos(), glColor(), glBitmap() doesn't result in the desired bitmap color"), but no explanation given :(
EDIT: Ah ha! The current raster position contains its own color state, which is only updated during a glRasterPos() call.
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();
}