I'm going to show FPS on the screen with the freeglut function glutBitmapString,but it shows nothing. Here is my code. Is there anyone can figure where the problem is?
void PrintFPS()
{
frame++;
time=glutGet(GLUT_ELAPSED_TIME);
if (time - timebase > 100) {
cout << "FPS:\t"<<frame*1000.0/(time-timebase)<<endl;
char* out = new char[30];
sprintf(out,"FPS:%4.2f",frame*1000.0f/(time-timebase));
glColor3f(1.0f,1.0f,1.0f);
glRasterPos2f(20,20);
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24,(unsigned char* )out);
timebase = time;
frame = 0;
}
}
void RenderScene(void)
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 0.5f };
GLfloat vYellow[] = {1.0f,1.0f,0.0f,1.0f};
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vYellow);
//triangleBatch.Draw();
squareBatch.Draw();
PrintFPS();
glutSwapBuffers();
}
it supposed to show the FPS on the top left of the screen
The position that's provided by glRasterPos is treated just like a vertex, and transformed by the current model-view and projection matrices. In you example, you specify the text to be position at (20,20), which I'm guessing is supposed to be screen (viewport, really) coordinates.
If it's the case that you're rendering 3D geometry, particularly with a perspective projection, your text may be clipped out. However, there are (at least) two simple solutions (presented in order of code simplicity):
use one of the glWindowPos functions instead of glRasterPos. This function bypasses the model-view and projection transformations.
use glMatrixMode, glPushMatrix, and glPopMatrix to temporarily switch to window coordinates for rendering:
// Switch to window coordinates to render
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
gluOrtho2D( 0, windowWidth, 0, windowHeight );
glRasterPos2i( 20, 20 ); // or wherever in window coordinates
glutBitmapString( ... );
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
Related
Here's the vertex buffer information of the quad I'm drawing:
static const GLfloat pv_quad[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
This quad is used to draw 2D frames on the screen as part of the graphical user interface. The class I use to do this is Mage::Interface::Frame. I'll spare you the header definition and instead give you the class's implementation, as it's small. There's some test code in here, so ignore the fact the shader is part of the class. I know it shouldn't be there.
#include <Mage/Root.h>
#include <Mage/Interface/Frame.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
using Mage::Interface::Frame;
Frame::Frame()
: width(300), height(200), position(0, 0), color(1.0, 1.0, 1.0), model(1.0), rotation(0) {
prog.compileFile("Data/Shaders/FrameVertex.glsl", Mage::ShaderType::VERTEX);
prog.compileFile("Data/Shaders/FrameFragment.glsl", Mage::ShaderType::FRAGMENT);
prog.link();
this->calcTransform();
}
void Frame::setSize(int w, int h) {
this->width = w;
this->height = h;
this->calcTransform();
}
void Frame::setColor(int r, int g, int b) {
this->color = glm::vec3(float(r) / 256, float(g) / 256, float(b) / 256);
}
void Frame::setRotation(float degrees) {
this->rotation = glm::radians(degrees);
this->calcTransform();
}
void Frame::calcTransform() {
this->model = glm::mat4(1.0f); // reset model to origin.
// 1280 and 720 are the viewport's size. This is only hard coded for tests.
this->model = glm::scale(this->model, glm::vec3(float(width) / 1280, float(height) / 720, 1.0f));
this->model = glm::rotate(this->model, this->rotation, glm::vec3(0.0f, 0.0f, 1.0f));
this->model = glm::translate(this->model, glm::vec3(position.x, position.y, 0.0f));
}
void Frame::draw() {
Mage::VertexObject obj = ROOT.getRenderWindow()->getVertexBufferObject()->getObject("PrimitiveQuad");
prog.use();
prog.setUniform("mvp", this->model);
prog.setUniform("fColor", this->color);
glEnableVertexAttribArray(0);
ROOT.getRenderWindow()->getVertexBufferObject()->bind();
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)obj.begin);
glDrawArrays(GL_TRIANGLE_STRIP, 0, obj.size);
glDisableVertexAttribArray(0);
}
Here's the drawing function that's called every frame:
void RenderWindow::render() {
Mage::Interface::Frame F;
F.setSize(400, 200);
F.setRotation(0);
while (glfwWindowShouldClose(this->win) == 0) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
F.draw();
glfwSwapBuffers(this->win);
glfwPollEvents();
}
}
When I have setRotation(0), the resulting quad is indeed, 400 pixels wide and 200 pixels high, right in the centre of my screen as you would expect.
However, if I set the rotation to (90), well, this happens:
As you can see, that's not at all close to a 90 degrees turn. It should be 400px high and 200px wide.
Anyone care to explain what's going on here?
EDIT: Some playing around has shown me that the problem is with the scale, not the rotation. When I comment out the scale, the rotation appears to be correct.
The angle argument to glm::rotate() is in radians, not degrees:
m: Input matrix multiplied by this rotation matrix.
angle: Rotation angle expressed in radians.
axis: Rotation axis, recommanded [sic] to be normalized.
Use this:
void Frame::setRotation(float degrees) {
this->rotation = glm::radians( degrees );
this->calcTransform();
}
I am assuming that this game is supposed to be a 3D game with a 2D GUI, although this was not specified in the question, though not entirely necessary, as my answer will be the same.
When rendering with a 3D matrix, using a perspective view (Field of View taken into account), as opposed to using an orthographic view, the shapes will bend to their position depending on the fov.
So with that, I propose that you use a simple solution, and initialize a 2D viewing matrix (or orthographic matrix) for your 2D interface. If you are just looking for a simple way to render a 2D quad onto the screen freeGLUT(free Graphics Library Utility Toolkit) is there for you. There are plenty of docs out there to help install freeglut, so once you finish that, initialize a 2D rendering matrix, then render the quad using glVertex2i/f or glVertex3i/f, like so:
void setView2d()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, *SCREEN_WIDTH, *SCREEN_HEIGHT, 0);
glMatrixMode( GL_MODELVIEW );
glDisable(GL_DEPTH_TEST);
glLoadIdentity();
}
void setView3d()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70, (GL_FLOAT)*SCREEN_WIDTH / *SCREEN_HEIGHT, 0.1, 100);
glEnable(GL_DEPTH_TEST);
glLoadIdentity();
}
void render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_TEST);
setView2d(); //Render 2D objects
glPushMatrix();
{
//glTranslatef() and glRotatef() still work for 2D
//if using rotate, rotate on z axis, like so:
glRotatef(90, 0, 0, 1);
glBegin(GL_TRIANGLES);
{
glVertex2i(0, 0);
glVertex2i(100, 0);
glVertex2i(0, 100);
/*
glVertex2i is replacable with glVertex2f, glVertex3i, and glVertex3f
if using a glVertex3, set the z value to 0
*/
}
glEnd();
}
glPopMatrix();
setView3d(); //Render 3D objects
glPushMatrix();
{
//render 3D stuff
}
glPopMatrix();
glutSwapBuffers();
}
I should also mention that when using the gluOrtho2D, coordinates used in vertex x,y are based on pixels, instead of the 3D blocks.
Hope this helped,
-Nick
In OpenGL's fixed pipeline, by default, specifying vertex coordinates using glVertex3f is equivalent to specifying a location between -1.0 and +1.0 in screen space. Therefore, given a set of 4 perfectly adjacent screen-space vertices using GL_TRIANGLE_STRIP (or even GL_QUADS), and unless your window is already perfectly square, you will always render a rectangle instead of a perfect square...
Knowing the width, height and aspect ratio of a window, is there some way to correct this?
I have tried multiplying the vertex coordinates by the aspect ratio, which unfortunately seemed to achieve the same visual effect.
Here's the full source code I'm currently using:
#include "main.h"
#pragma comment(lib, "glut32.lib")
int g_width = 800;
int g_height = 600;
int g_aspectRatio = double(g_width) / double(g_height);
bool g_bInitialized = false;
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(0, 0);
glutInitWindowSize(g_width, g_height);
glutCreateWindow("OpenGL Test App");
glutDisplayFunc(onRender);
glutReshapeFunc(onSize);
glutIdleFunc(onRender);
glutMainLoop();
return 0;
}
void onInit()
{
glFrontFace(GL_CW);
}
void onRender()
{
if(!g_bInitialized)
onInit();
static float angle = 0.0f;
const float p = 0.5f * g_aspectRatio;
glLoadIdentity();
gluLookAt(
0.0f, 0.0f, 10.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f
);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glScalef(1, -1, 1); // Flip the Y-axis
glRotatef(angle, 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLE_STRIP);
{
glColor4f(1.0, 0.0, 0.0, 1.0); // Red
glVertex3f(-p, -p, 0.0); // Top-Left
glColor4f(0.0, 1.0, 0.0, 1.0); // Green
glVertex3f(p, -p, 0.0); // Top-Right
glColor4f(0.0, 0.0, 1.0, 1.0); // Blue
glVertex3f(-p, p, 0.0); // Bottom-Left
glColor4f(1.0, 1.0, 0.0, 1.0); // Yellow
glVertex3f(p, p, 0.0); // Bottom-Left
}
glEnd();
angle += 0.6f;
glutSwapBuffers();
}
void onSize(int w, int h)
{
g_width = max(w, 1);
g_height = max(h, 1);
g_aspectRatio = double(g_width) / double(g_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
gluPerspective(45, g_aspectRatio, 1, 1000);
glMatrixMode(GL_MODELVIEW);
}
EDIT:
This has been solved... In the above code, I had defined g_aspectRatio as an int instead of a floating-point value. Therefore, it's value was always 1...
In my (old) experience, that's just why you have an aspect ratio argument to gluPerspective().
The manual page says:
In general, the aspect ratio in gluPerspective should match
the aspect ratio of the associated viewport. For example, aspect = 2.0
means the viewer's angle of view is twice as wide in x as it is in y.
If the viewport is twice as wide as it is tall, it displays the image
without distortion.
Check your g_aspectRatio value.
by default, specifying vertex coordinates using glVertex3f is equivalent to specifying a location between -1.0 and +1.0 in screen space
Wrong. Coordinates passed to OpenGL through glVertex or a glVertexPointer vertex array are in model space. The transformation to screen space happens by transforming into view space by the modelview matrix and from view space to clip space by the projection matrix. Then clipping is applied and the perspective divide applied to reach normalized coordinate space.
Hence the value range for glVertex can be whatever you like it to be. By applying the right projection matrix you get your view space to be in [-aspect; aspect]×[-1, 1] if you like that.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-aspect, aspect, -1, 1, -1, 1);
i am Making a pool game using openGL and finding this problem vary irritating.
while i am trying to print one text on the screen and move my camera the text is also leaving its original position in the window and moving with the camera.
here is the code that i have in draw().
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen and Depth Buffer
glLoadIdentity();
// GLfloat position1[] = { 00.0, 100.0, 00.0, 1.0 };
//cam position update
gluLookAt( world.camera->cameraFrom.x,world.camera->cameraFrom.y,world.camera->cameraFrom.z, world.camera->cameraTo.x,0,world.camera->cameraTo.z, 0,1,0); // Define a viewing transformation
// Pop the current matrix stack
//**************************************************************
drawTable(world.table);
world.update();
glPushMatrix();
sprintf(str, "Player 1 Score: 1, Player 2 Score: 10");
glRasterPos2f(10, 10);
glutBitmapString(font,(unsigned char*)str);
glPopMatrix();
glutSwapBuffers();
}
glRasterPos() transforms the given position by the modelview and projection matrices. You'll have to reset those to something that positions your text correctly:
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
// set projection matrix here
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
//cam position update
gluLookAt
(
world.camera->cameraFrom.x, world.camera->cameraFrom.y, world.camera->cameraFrom.z,
world.camera->cameraTo.x, 0, world.camera->cameraTo.z,
0,1,0
);
drawTable(world.table);
world.update();
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
// set appropriate projection matrix here
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
sprintf(str, "Player 1 Score: 1, Player 2 Score: 10");
glRasterPos2f(10, 10);
glutBitmapString(font,(unsigned char*)str);
glutSwapBuffers();
}
Or use glWindowPos2f() instead, which bypasses both matrices and sets the raster position directly.
For the entire night, I've been looking around the internet, both stackoverflow and elsewhere, to find something to say how to print text on GLUT. While I've found places that say how, none have explained it well, saying which parts of the function is neccessary, which parts aren't. I've also tried to copy in some of the code with the closest to a success is something that made my entire screen white except for some blue pixels. So I've given up, and I'm hoping this will clear up confusion for me and the many people who are confused, like me.
So, I have found this code:
glColor3f(1.0f, 0.0f, 0.0f);
glRasterPos2f(1280, 720);
int len = menu.length();
for (int i = 0; i < len; i++) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}
and I have placed it in my code:
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(-_cameraAngle, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.0f, -9.0f + zoom);
glTranslatef(0.0f, -1.0f, 0.0f);
string menu = "Hello!";
glColor3f(1.0f, 0.0f, 0.0f);
glRasterPos2f(1280, 720);
int len = menu.length();
for (int i = 0; i < len; i++) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
} /*if I need to post the rest of drawScene(), which is the function delegated
as the Display Func, tell me. I don't want to because it's long
What I want to know is what am I doing wrong, and what do future readers in my position need to do in order to get good results.
You don't say what's specifically wrong, but I'm suspecting that your text is not showing up. The reason is likely that the raster position is being clipped, and this is causing your text to not be rendered.
The raster position is the "anchor point" of where a bitmap will be drawn. Usually, this is the lower-left corner of the bitmap (the glBitmap can change that with by setting the x and y parameters to something other than zero, but assume you're not doing that). The raster position is transformed by the model-view matrix, just like a vertex in a geometric primitive. And just like a vertex, if the transformed raster position lies outside of the viewport, it's clipped, and nothing is rendered. What's important to know here is that any rendering of a bitmap - regardless of its size - is predicated on the raster position being inside of the viewport.
In your example, you don't show the viewport you're using, nor the projection transformation (the matrix on the GL_PROJECTION stack), but you set the raster position to (1280, 720), which may well be outside of the viewport.
Let's say you want to render your text in the lower-left corner of your window (and for the sake of argument, let's say your window is 1280 x 1024). When it's time to render your text, drop the following into your rendering routine:
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
gluOrtho2D( 0, 1280, 0, 1024 );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glRasterPos2i( 10, 1014 ); // move in 10 pixels from the left and bottom edges
for ( int i = 0; i < len; ++i ) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}
glPopMatrix();
glMatrixMode( GL_PROJECTION );
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
Depending on which version of OpenGL you're using, you may be able to use a simpler routine glWindowPos2i() (the 2i can be replaced with other dimension-type pairs like other OpenGL functions), which bypasses transforming the raster position by the model-view and projection matrices, and works directly in window coordinates. In that case, you'd write the above code as:
glWindowPos2i( 10, 1014 ); // move in 10 pixels from the left and bottom edges
for ( int i = 0; i < len; ++i ) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}
I'm trying to draw a simple string (overlay) on the screen.
From what I've found over the internet, I'm using it this way:
void write(string text, int x, int y){
glRasterPos2i(x,y);
for(int i = 0; i < text.length(); i++){
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text.data()[i]);
}
}
But it draws the string according to the world coordinates. Say, if x and y are set to 10, they are drawn at (10,10,0) coordinates in the world. But I simple need this string at window's (10,10) coordinates in 2D.
This is part of a small project, and the draw method is given as below. I don't want to change it much as it may break something else in the project.
void disp(){
// set viewing translation and object rotations
glMatrixMode( GL_MODELVIEW );
glLoadIdentity ();
glTranslatef( INIT_VIEW_X, INIT_VIEW_Y, INIT_VIEW_Z );
glRotatef( xRot, 1.0, 0.0, 0.0 );
glRotatef( zRot, 0.0, 0.0, 1.0 );
glScalef( scaleFactor, scaleFactor, scaleFactor );
glClear(GL_COLOR_BUFFER_BIT);
draw();
glFlush();
}
I also don't exactly know what they do, and I think drawing the text to world coordinates have to do with something in this code. I've also tried Using GLUT bitmap fonts but it doesn't work either.
How can I simple draw onto the screen. OpenGL is over complicating things; I try to simply write to the window, but it takes the whole thing and translates into 3D world. I just don't want this.
From twall, yes you need to clear BOTH the modelview and projection matrices
//TEXT
glMatrixMode( GL_PROJECTION ) ;
glPushMatrix() ; // save
glLoadIdentity();// and clear
glMatrixMode( GL_MODELVIEW ) ;
glPushMatrix() ;
glLoadIdentity() ;
glDisable( GL_DEPTH_TEST ) ; // also disable the depth test so renders on top
glRasterPos2f( 0,0 ) ; // center of screen. (-1,0) is center left.
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
char buf[300];
sprintf( buf, "Oh hello" ) ;
const char * p = buf ;
do glutBitmapCharacter( GLUT_BITMAP_HELVETICA_18, *p ); while( *(++p) ) ;
glEnable( GL_DEPTH_TEST ) ; // Turn depth testing back on
glMatrixMode( GL_PROJECTION ) ;
glPopMatrix() ; // revert back to the matrix I had before.
glMatrixMode( GL_MODELVIEW ) ;
glPopMatrix() ;
From what I can gather, it seems what you're after is orthographic projection.
I'm not sure about OpenGL specifically (I'm used to higher-level graphics libraries), but here's a couple of links that could be a starting point:
Setting a orthographic projection matrix?
http://www.cprogramming.com/tutorial/opengl_projections.html
you can step back to "2D" coordinates like so:
//save your current matrix on the stack, so you don't lose it
glPushMatrix();
//load identity matrix, so you don't have any 3d transformations
glLoadIdentity ();
//now you also can transform the text
//to the position just as you like
//glTransformf( ... )
//make sure the text is draw, even though it might be outside the viewing area
glDisable( GL_DEPTH_TEST )
drawMyFunkyText();
glEnable( GL_DEPTH_TEST )
//restore the matrix as it was before,
//so you can draw all your shapes as before
glPopMatrix();