I am not sure why why code doesn't show a rotating cube. I am looking for the reason why. I think it has something to do with the perspective or view but I am not sure. I just need to understand why I can't get a simple cube onto the screen.
#include <iostream>
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
#include "LoadShader.hpp" // just a function in a header that returns a GLuint for a shaderProgram
#define FS1 "shader1.frag"
#define VS1 "shader1.vert"
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <assimp/cimport.h>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;
// The MAIN function, from here we start the application and run the game loop
int main()
{
// Init GLFW
glfwInit( );
// Set all the required options for GLFW
glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE );
glfwWindowHint( GLFW_RESIZABLE, GL_FALSE );
// Create a GLFWwindow object that we can use for GLFW's functions
GLFWwindow *window = glfwCreateWindow( WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr );
int screenWidth, screenHeight;
glfwGetFramebufferSize( window, &screenWidth, &screenHeight );
if ( nullptr == window )
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate( );
return EXIT_FAILURE;
}
glfwMakeContextCurrent( window );
// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
glewExperimental = GL_TRUE;
// Initialize GLEW to setup the OpenGL Function pointers
if ( GLEW_OK != glewInit( ) )
{
std::cout << "Failed to initialize GLEW" << std::endl;
return EXIT_FAILURE;
}
glEnable( GL_DEPTH_TEST ) ;
//glDepthFunc( GL_LESS ) ;
// Define the viewport dimensions
glViewport( 0, 0, screenWidth, screenHeight );
//glMatrixMode(GL_PROJECTION);
// Set up vertex data (and buffer(s)) and attribute pointers
GLfloat vertices[ ] =
{ // verticies a0 // colors a1
// front
-1.0, -1.0, 1.0, .70f , 0.32f , 0.31f ,
1.0, -1.0, 1.0, .20f , 0.4f , 0.21f ,
1.0, 1.0, 1.0, .50f , 0.32f , 0.71f ,
-1.0, 1.0, 1.0, .60f , 0.62f , 0.11f ,
// back
-1.0, -1.0, -1.0, .30f , 0.87f , 0.60f ,
1.0, -1.0, -1.0, .30f , 0.87f , 0.f ,
1.0, 1.0, -1.0, .10f , 0.f , 0.60f ,
-1.0, 1.0, -1.0, .20f , 0.87f , 0.60f ,
// side Right
1.0f , 1.0 , 1.0 , .45f , .3f , .4f ,
1.0 , -1.0 , 1.0 , .5f , .8f, .1f ,
1.0 , -1.0 , -1.0 , .3f , .6f , .0f ,
1.0 , 1.0 , -1.0 , .45f , .87f , .53f ,
// left Side
-1.0f , 1.0 , 1.0 , .45f , .23f , .54f ,
-1.0 , -1.0 , 1.0 , .51f , .84f, .81f ,
-1.0 , -1.0 , -1.0 , .6f , .4f , .78f ,
-1.0 , 1.0 , -1.0 , .45f , .87f , .53f ,
//top
-1.f , 1.f , 1.f , .35f , .87f , .54f ,
-1.f , 1.f , -1.f , .45f , .98f, .92f ,
1.f , 1.f , 1.f , .50f , 0.f , .32f ,
1.f , 1.f , -1.f , 1.f , .72f , .87f ,
// bottom
-1.f , -1.f , 1.f , .35f , .87f , .54f ,
-1.f , -1.f , -1.f , .45f , .98f, .92f ,
1.f , -1.f , 1.f , .50f , .89f , .32f ,
1.f , -1.f , -1.f , 0.f , .72f , .87f
};
GLuint indices[ ] =
{
0 , 1 , 2 , 0 , 2 , 3 ,
4 , 5 , 6 , 4 , 6 , 7 ,
8 , 9 , 10 , 8 , 10 , 11 ,
12 , 13 , 14 , 12 , 14 , 15 ,
16 , 19 , 18 , 16 , 17 , 19 ,
20 , 23 , 22 , 20 , 21 , 23
} ;
int numOfIndices = sizeof( indices ) / sizeof ( GLuint ) ;
std::cout << numOfIndices << std::endl ;
GLuint VAO , VBO , EBO ;
glGenVertexArrays( 1 , &VAO ) ;
glBindVertexArray( VAO ) ;
glGenBuffers( 1 , &VBO ) ;
glBindBuffer( GL_ARRAY_BUFFER , VBO ) ;
glBufferData( GL_ARRAY_BUFFER , sizeof( vertices ) , vertices , GL_STATIC_DRAW ) ;
glVertexAttribPointer( 0 , 3 , GL_FLOAT , GL_FALSE , 6 * sizeof(GLfloat) , ( GLvoid * ) 0 ) ;
glEnableVertexAttribArray( 0 ) ;
glVertexAttribPointer( 1 , 3 , GL_FLOAT , GL_FALSE , 6 * sizeof(GLfloat) , (GLvoid*)(3 * sizeof(GL_FLOAT)) ) ;
glEnableVertexAttribArray( 1 ) ;
glGenBuffers( 1 , &EBO ) ;
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER , EBO ) ;
glBufferData( GL_ELEMENT_ARRAY_BUFFER , sizeof( indices ) , indices , GL_STATIC_DRAW ) ;
GLuint program = LoadShaders( VS1 , FS1 ) ;
glUseProgram( program ) ;
float rotationDegrees = 1.f ;
float fov = 1.0f ;
glm::mat4 view;
view = glm::lookAt(glm::vec3( 0.0f, 1.0f, -3.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 projectionMatrix = glm::perspective( fov , ( ( float ) HEIGHT ) / WIDTH , 1.f , 10.0f ) ;
glm::mat4 modelTransform = glm::translate( glm::mat4( 1.f ) , glm::vec3( .0f , -3.0f , -3.0f ) ) ;
glm::mat4 rotation = glm::rotate( glm::mat4(1.f) , rotationDegrees , glm::vec3( 1.f , 1.f , 0.f ) ) ;
//glm::mat4 rotation = glm::rotate( rotation1 , 30.f , glm::vec3( 0.f , 2.f , 0.f ) ) ;
glm::mat4 fullTransform = projectionMatrix * modelTransform * rotation ;
GLuint transformLocation = glGetUniformLocation( program , "uModelTranslate" ) ;
GLuint projectionLocation = glGetUniformLocation( program , "uProjectionMatrix" ) ;
//modelTransform = modelTransform * rotation ;
glUniformMatrix4fv( transformLocation , 1 , GL_FALSE , &modelTransform[0][0] ) ;
glUniformMatrix4fv( projectionLocation , 1 , GL_FALSE , &fullTransform[0][0] ) ;
bool canUp , canDown , canL , canR , canW , canS ,canA , canD , canQ , canE ;
canQ = true ;
canE = true ;
canD= true ;
canA = true ;
canUp = true ;
canS = true ;
canDown = true ;
canR = true ;
canL = true ;
canW = true ;
float nearF = 0.1f ;
float zZ = -3.0 ;
float yY = 1.0f ;
float xX = 0.f ;
while ( !glfwWindowShouldClose( window ) )
{
// Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
glfwPollEvents( );
rotationDegrees += .0001f ;
if( rotationDegrees >= 360 )
{
rotationDegrees =0 ;
}
view = glm::lookAt(glm::vec3( yY , xX, zZ),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 rotation = glm::rotate( glm::mat4(1.f) , rotationDegrees , glm::vec3( 1.f , 1.f , 0.f ) ) ;
glm::mat4 projectionMatrix = glm::perspective(glm::radians(fov), (float) WIDTH / (float)HEIGHT , nearF, 10.0f);
glm::mat4 fullTransform = projectionMatrix * view * rotation ;
glUniformMatrix4fv( projectionLocation , 1 , GL_FALSE , &fullTransform[0][0] ) ;
// Render
// Clear the colorbuffer
glClearColor( 0.f, 0.f, 0.f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
if (glfwGetKey(window,GLFW_KEY_ESCAPE) == GLFW_PRESS )
{
glfwSetWindowShouldClose(window,true);
}
if (glfwGetKey(window,GLFW_KEY_UP) == GLFW_PRESS && canUp )
{
canUp = false ;
fov += 1.f ;
std::cout << fov << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_UP) != GLFW_PRESS && !canUp )
{
canUp = true ;
}
if (glfwGetKey(window,GLFW_KEY_DOWN) == GLFW_PRESS && canDown)
{
canDown = false ;
fov += -1.f ;
std::cout << fov << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_DOWN) != GLFW_PRESS && !canDown)
{
canDown = true ;
}
if (glfwGetKey(window,GLFW_KEY_ESCAPE) == GLFW_PRESS )
{
glfwSetWindowShouldClose(window,true);
}
if (glfwGetKey(window,GLFW_KEY_LEFT) == GLFW_PRESS && canL )
{
canL = false ;
nearF += 1.f ;
std::cout << nearF << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_LEFT) != GLFW_PRESS && !canL )
{
canL = true ;
}
if (glfwGetKey(window,GLFW_KEY_RIGHT) == GLFW_PRESS && canR)
{
canR = false ;
nearF += -1.f ;
std::cout << nearF << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_RIGHT) != GLFW_PRESS && !canR)
{
canR = true ;
}
if (glfwGetKey(window,GLFW_KEY_W) == GLFW_PRESS && canW)
{
canW = false ;
zZ += -1.f ;
std::cout << zZ << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_W) != GLFW_PRESS && !canW)
{
canW = true ;
}
if (glfwGetKey(window,GLFW_KEY_S) == GLFW_PRESS && canS)
{
canS = false ;
zZ += +1.f ;
std::cout << zZ << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_S) != GLFW_PRESS && !canS)
{
canS = true ;
}
if (glfwGetKey(window,GLFW_KEY_A) == GLFW_PRESS && canA)
{
canA = false ;
xX += +1.f ;
std::cout << xX << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_A) != GLFW_PRESS && !canA)
{
canA = true ;
}
if (glfwGetKey(window,GLFW_KEY_D) == GLFW_PRESS && canD)
{
canD = false ;
xX += -1.f ;
std::cout << xX << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_D) != GLFW_PRESS && !canD)
{
canD = true ;
}
if (glfwGetKey(window,GLFW_KEY_Q) == GLFW_PRESS && canQ)
{
canQ = false ;
yY += -1.f ;
std::cout << yY << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_Q) != GLFW_PRESS && !canQ)
{
canQ = true ;
}
if (glfwGetKey(window,GLFW_KEY_E) == GLFW_PRESS && canE)
{
canE = false ;
yY += 1.f ;
std::cout << yY << std::endl ;
}
if (glfwGetKey(window,GLFW_KEY_E) != GLFW_PRESS && !canE)
{
canE = true ;
}
//glUseProgram( program ) ;
glDrawElements( GL_TRIANGLES , numOfIndices , GL_UNSIGNED_INT , 0 ) ;
// Swap the screen buffers
glfwSwapBuffers( window );
}
glfwTerminate( );
return EXIT_SUCCESS;
}
The unit of the angle for glm::perspective and glm::rotate is radians. A field of view of 1° is far to small.
The translation component of the modelTransform matrix moves the object out of the viewing frustum and has to be reduced.
Furthermore I recommend to enable the Depth Test.
e.g.:
float rotationDegrees = 0.0f;
float fov = 90.0f;
float nearF = 0.1f;
float zZ = -3.0;
float yY = 1.0f;
float xX = 0.0f;
glEnable(GL_DEPTH_TEST);
while (!glfwWindowShouldClose(wnd))
{
glm::mat4 rotation = glm::rotate(glm::mat4(1.0f), glm::radians(rotationDegrees), glm::vec3(1.0f , 1.0f , 0.0f)) ;
glm::mat4 modelTransform = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.5f, 0.0f)) ;
glm::mat4 view = glm::lookAt(glm::vec3(yY , xX, zZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 modelview = view * modelTransform * rotation;
glm::mat4 projectionMatrix = glm::perspective(glm::radians(fov), (float)WIDTH / (float)HEIGHT, nearF, 10.0f);
rotationDegrees += 1.0f;
glUniformMatrix4fv(transformLocation, 1, GL_FALSE, glm::value_ptr(modelview));
glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
// [...]
}
Vertex shader:
#version 330 core
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inColor;
out vec3 vertCol;
uniform mat4 uProjectionMatrix;
uniform mat4 uModelTranslate;
void main()
{
vertCol = inColor;
gl_Position = uProjectionMatrix * uModelTranslate * vec4(inPos.xyz, 1.0);
}
In this post the rectangle moved via mouse. I want to add a triangle and move like rectangle via mouse.
The triangle function like this:
void drawTriangle(float x,float y,float size){
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_TRIANGLES );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, 1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glEnd();
glPopMatrix();
Rectangle and triangle moved together. But I want to move it different. So what is my wrong?
You'll have to maintain an array of Shape objects and test each one for mouse collisions, as well as keep track of which Shape you're dragging:
#include <GL/glut.h>
#include <vector>
using namespace std;
struct Shape
{
float mX, mY;
float mSize;
bool mIsRectangle;
bool PointInside( const float x, const float y ) const
{
return
mX - mSize <= x && x <= mX + mSize
&&
mY - mSize <= y && y <= mY + mSize;
}
};
vector< Shape > objects;
Shape* dragging = NULL;
void mouse( int button, int state, int x, int y )
{
if( GLUT_DOWN == state )
{
dragging = NULL;
for( Shape& obj : objects )
{
if( obj.PointInside( x, y ) )
{
dragging = &obj;
glutPostRedisplay();
break;
}
}
}
else
{
dragging = NULL;
}
}
void motion( int x, int y )
{
if( dragging )
{
dragging->mX = x;
dragging->mY = y;
glutPostRedisplay();
}
}
void drawRect( float x, float y, float size )
{
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_QUADS );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, -1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glVertex2f( -1, 1 );
glEnd();
glPopMatrix();
}
void drawTriangle( float x, float y, float size )
{
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_TRIANGLES );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, 1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glEnd();
glPopMatrix();
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
const double w = glutGet( GLUT_WINDOW_WIDTH );
const double h = glutGet( GLUT_WINDOW_HEIGHT );
glOrtho( 0, w, h, 0, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
for( const Shape& obj : objects )
{
if( obj.mIsRectangle )
drawRect( obj.mX, obj.mY, obj.mSize );
else
drawTriangle( obj.mX, obj.mY, obj.mSize );
}
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMouseFunc( mouse );
glutMotionFunc( motion );
Shape temp;
temp.mSize = 50;
temp.mX = temp.mY = 100;
temp.mIsRectangle = true;
objects.push_back( temp );
temp.mX = temp.mY = 200;
temp.mIsRectangle = false;
objects.push_back( temp );
glutMainLoop();
return 0;
}
I got some problem with OpenGL matrix system.
I made five instances like below. I want to get their individual working.
C_IMGMGR cImgmgr1( 200 , 170 );
C_IMGMGR cImgmgr2( 200 , 170 );
C_IMGMGR cImgmgr3( 200 , 170 );
C_IMGMGR cImgmgr4( 200 , 170 );
C_IMGMGR cImgmgr5( 200 , 170 );
this is main,
int main( int argc, char** argv )
{
int nWinSizeX = 1280;
int nWinSizeY = 768;
glutInit( &argc , argv );
mainWindow = CreateMain( nWinSizeX , nWinSizeY );
SetProjection( nWinSizeX , nWinSizeY );
SetStateSettings();
NowFrameMove();
return 1;
}
and SetProjection()
void SetProjection( int nWinSizeX , int nWinSizeY )
{
cImgmgr1.Init_Viewport( 540 , 599 , nWinSizeX , nWinSizeY );
cImgmgr2.Init_Viewport( 40 , 299 , nWinSizeX , nWinSizeY );
cImgmgr3.Init_Viewport( 540 , 299 , nWinSizeX , nWinSizeY );
cImgmgr4.Init_Viewport( 1040 , 299 , nWinSizeX , nWinSizeY );
cImgmgr5.Init_Viewport( 540 , -1 , nWinSizeX , nWinSizeY );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0.0 , 1280 , 0.0 , 768 , -10000.0 , 10000.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( (200 / 2) , (170 / 2) , 0 );
}
and SetStateSetting()
void SetStateSettings()
{
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_TEXTURE_2D );
cImgmgr1.Init_Sprite( "data\\Image\\symbol01_Pay\\" );
cImgmgr2.Init_Sprite( "data\\Image\\symbol01_Pay\\" );
cImgmgr3.Init_Sprite( "data\\Image\\symbolTemp_Pay\\" );
cImgmgr4.Init_Sprite( "data\\Image\\symbol01_Pay\\" );
cImgmgr5.Init_Sprite( "data\\Image\\symbol01_Pay\\" );
}
here is Update() for glutDisplayFunc() and glutIdleFunc(),
void Update()
{
//////////////////////////////////////////////////////////////////////////
//Process
cImgmgr1.Process( FLIP_VERTICAL );
cImgmgr2.Process( FLIP_HORIZONTAL );
cImgmgr3.Process( NORMAL );
cImgmgr4.Process( NORMAL );
cImgmgr5.Process( NORMAL );
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//Render
glClearColor( 0.0F , 0.0F , 0.0F , 0.0F );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glClearDepth( 1.0 );
cImgmgr1.Render_Sprite( cImgmgr1.Get_Frame() );
cImgmgr2.Render_Sprite( cImgmgr2.Get_Frame() );
cImgmgr3.Render_Sprite( cImgmgr3.Get_Frame() );
cImgmgr4.Render_Sprite( cImgmgr4.Get_Frame() );
cImgmgr5.Render_Sprite( cImgmgr5.Get_Frame() );
//////////////////////////////////////////////////////////////////////////
glutSwapBuffers();
}
and IMGMGR class,
void C_IMGMGR::Process( E_RENDER_MODE eMode )
{
if( m_nFrame >= m_nFileCount )
m_nFrame = 0;
switch ( eMode )
{
case NORMAL :
break;
case FLIP_VERTICAL :
m_fRotationAngle = 1.0F;
m_fRotationX = 1.0F;
break;
case FLIP_HORIZONTAL :
m_fRotationAngle = 1.0F;
m_fRotationY = 1.0F;
break;
case FAN_LEFT :
m_fRotationAngle = 1.0F;
m_fRotationZ = 1.0F;
break;
case FAN_RIGHT :
m_fRotationAngle = 1.0F;
m_fRotationZ = -1.0F;
break;
case TRANSLATE_VERTICAL :
break;
case TRANSLATE_HORIZONTAL :
break;
}
}
void C_IMGMGR::Render_Sprite( int nFrame )
{
glBindTexture( GL_TEXTURE_2D , m_pLoadedSprite[nFrame] );
glViewport( m_nViewPortX , m_nViewPortY , m_nScreenW , m_nScreenH );
glPushMatrix();
glRotatef( m_fRotationAngle , m_fRotationX , m_fRotationY , m_fRotationZ );
glTranslatef( m_fTranslateX , m_fTranslateY , m_fTranslateZ );
glScalef( m_fScaleX , m_fScaleY , m_fScaleZ );
glBegin( GL_QUADS );
glTexCoord2f( 0.0F , 1.0F); glVertex2f( -(float)m_nImgX_half , -(float)m_nImgY_half);
glTexCoord2f( 1.0F , 1.0F); glVertex2f( (float)m_nImgX_half , -(float)m_nImgY_half);
glTexCoord2f( 1.0F , 0.0F); glVertex2f( (float)m_nImgX_half , (float)m_nImgY_half);
glTexCoord2f( 0.0F , 0.0F); glVertex2f( -(float)m_nImgX_half , (float)m_nImgY_half);
glEnd();
glPopMatrix();
}
they rotating together that looks like sharing FLIP_VERTICAL and FLIP_HORIZONTAL.
so, how can I separate their matrix for individual instance working?
There are a couple of issues with the posted code:
OpenGL operates as a state machine. When you make a draw call, it uses the state set at the time of the draw call. Therefore, the transformations need to be specified before the draw call if they should be applied to a draw call.
Related, calls like glRotatef() and glTranslatef() modify the current transformation matrix. Unless you do something about it, each of these calls combines the specified transformation with the previous current transformation. If you simply make a few of these calls for each draw call, all the transformations will be combined.
To fix these two problems, you need to change the order of the calls, and use glPushMatrix() and glPopMatrix() to save/restore the previous transformation when you apply the transformations for a specific draw call. The code will then look like this:
glPushMatrix();
glRotatef( m_fRotationAngle , m_fRotationX , m_fRotationY , m_fRotationZ );
glTranslatef( m_fTranslateX , m_fTranslateY , m_fTranslateZ );
glScalef( m_fScaleX , m_fScaleY , m_fScaleZ );
glBegin( GL_QUADS );
glTexCoord2f( 0.0F , 1.0F); glVertex2f( -(float)m_nImgX_half , -(float)m_nImgY_half);
glTexCoord2f( 1.0F , 1.0F); glVertex2f( (float)m_nImgX_half , -(float)m_nImgY_half);
glTexCoord2f( 1.0F , 0.0F); glVertex2f( (float)m_nImgX_half , (float)m_nImgY_half);
glTexCoord2f( 0.0F , 0.0F); glVertex2f( -(float)m_nImgX_half , (float)m_nImgY_half);
glEnd();
glPopMatrix();
I hope you are already aware that almost all of the OpenGL calls used in this code are deprecated, and not available anymore in modern versions of OpenGL. If you want to learn current OpenGL, look for tutorials for the OpenGL Core Profile, or for OpenGL ES 2.0 or later.
Currently I am using glOrtho to zoom and pan around a 2D graph I am rendering.
I have setup up the viewport to the standard width and height. Then I set the glOrtho so that my frustrum makes screen coordinates match world coordinates.
glViewport(0, 0, window_width,window_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, window_width,window_height,0 , 100, -100);
When I do my zoom function in my mouse callback, I multiply the frustrum edges by a zoom factor....
glOrtho( 0 * zoomOut,
window_width * zoomOut,
window_height * zoomOut,
0 * zoomOut,
100, -100);
My question is.... how do I zoom using mouse position as a centre?
I have tried this... (where mouseStoreX and mouseStoreY are the position stored at the first click)
glOrtho( (0 -mouseStoreX )* zoomOut + mouseStoreX,
(window_width - mouseStoreX) * zoomOut + mouseStoreX,
(window_height - mouseStoreY) * zoomOut + mouseStoreY,
(0 - mouseStoreY) * zoomOut + mouseStoreY,
100, -100);
It seems to work but the frustrum jumps around when I do a new click. I think somewhere I'm not taking into account the zoomOut factor when doing the mouse position storing.
EDIT: here is my latest code which I am still struggling with...
void ZoomOrtho(){ //ON MOUSE CLICK.....
if (zooming == false){
keyStore.LMx = keyStore.Mx; //store mouse pos for next comparison
keyStore.LMy = keyStore.My;
//get mouse pos
mouseStoreX = keyStore.Mx;//mouse pos at this moment
mouseStoreY = keyStore.My;
//get current projection matrices
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );
//flip Y for opengl reasons
winY = (float)viewport[3] - winY;
//get world mouse coordinate
gluUnProject( mouseStoreX, mouseStoreY , 0.0, modelview, projection, viewport, &posX_,&posY_, &posZ_);
// calc difference between mouse world pos and centre of 'camera'
dx = posX_ - FS.centerX;
dy = posY_ - FS.centerY;
}
//ON DRAG......
zooming = true;
//do mouse movement detection and increment zoomOut
//#################################################
int xDiff = keyStore.Mx - keyStore.LMx; //mouse drag difference in screen space just for incrementing zoom
int yDiff = keyStore.My - keyStore.LMy; //
if (xDiff > 0 && (zoomFactor >= 0.5 ) ) {
zoomFactor -= zoomInc;
if (zoomFactor < 0.5 ) {zoomFactor = 0.5;}
}
else if (xDiff < 0 && (zoomFactor <= 2.0 )) {
zoomFactor += zoomInc;
if (zoomFactor > 2.0){zoomFactor = 2.0;}
}
//#################################################
//fill structure with clipping plane values. zooms ortho projection and keeps mouse pos anchored.
FS.left = ((FS.centerX - dx - (window_width/2.0))*zoomFactor) +dx;
FS.right = ((FS.centerX -dx + (window_width/2.0))*zoomFactor)+dx ;
FS.bottom = ((FS.centerY -dy + (window_width/2.0))*zoomFactor)+dy;
FS.top = ((FS.centerY -dy - (window_width/2.0))*zoomFactor) +dy;
// store last mouse pos for next comparison.
keyStore.LMx = keyStore.Mx;
keyStore.LMy = keyStore.My;
}
void zoomRelease(){
cout << " releasing" << std::endl;
//set zoom to false so we know we are not draggin mouse anymore.
zooming = false;
keyStore.LMx = 0;
keyStore.LMy = 0;
// recenter by taking midpoint between new left and right clipping planes so dx has a reference point
FS.centreX = (FS.right-FS.left)/2.0;
}
void DrawGui(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(FS.left, FS.right,FS.bottom, FS.top, 1, -1);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
//do drawing
}
Give this a shot:
// g++ main.cpp -o main -lglut -lGL && ./main
#include <GL/glut.h>
double centerX = 0, centerY = 0;
double width = 0, height = 0;
void mouse( int button, int state, int mx, int my )
{
// flip mouse y axis so up is +y
my = glutGet( GLUT_WINDOW_HEIGHT ) - my;
// convert mouse coords to (-1/2,-1/2)-(1/2, 1/2) box
double x = ( mx / (double)glutGet( GLUT_WINDOW_WIDTH ) ) - 0.5;
double y = ( my / (double)glutGet( GLUT_WINDOW_HEIGHT ) ) - 0.5;
if( GLUT_UP == state )
{
double preX = ( x * width );
double preY = ( y * height );
double zoomFactor = 1.5;
if( button == GLUT_LEFT_BUTTON )
{
// zoom in
width /= zoomFactor;
height /= zoomFactor;
}
if( button == GLUT_RIGHT_BUTTON )
{
// zoom out
width *= zoomFactor;
height *= zoomFactor;
}
double postX = ( x * width );
double postY = ( y * height );
// recenter
centerX += ( preX - postX );
centerY += ( preY - postY );
}
glutPostRedisplay();
}
void display()
{
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho
(
centerX - ( width / 2.0 ),
centerX + ( width / 2.0 ),
centerY - ( height / 2.0 ),
centerY + ( height / 2.0 ),
-1,
1
);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3ub( 255, 0, 0 );
glBegin( GL_TRIANGLES );
glVertex2i( 0, 0 );
glVertex2i( 150, 0 );
glVertex2i( 0, 150 );
glVertex2i( 0, 0 );
glVertex2i( -150, 0 );
glVertex2i( 0, -150 );
glEnd();
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMouseFunc( mouse );
width = glutGet( GLUT_WINDOW_WIDTH );
height = glutGet( GLUT_WINDOW_HEIGHT );
glutMainLoop();
return 0;
}
I'm assuming that when you do the second click you're storing its value into mouseStoreXY. If so, this is causing the jumping. You were drawing with an offset of the old mouseStoreXY and you suddenly offset to the new one.
The solution will be to store the projection matrix inputs persistently and then modify them incrementally on each frame.
Give this a shot:
// g++ main.cpp -o main -lglut -lGL && ./main
#include <GL/glut.h>
#include <cmath>
void getMouseCoords( int mx, int my, double& x, double& y )
{
// flip mouse y axis so up is +y
my = glutGet( GLUT_WINDOW_HEIGHT ) - my;
// convert mouse coords to (-1/2,-1/2)-(1/2, 1/2) box
x = ( mx / (double)glutGet( GLUT_WINDOW_WIDTH ) ) - 0.5;
y = ( my / (double)glutGet( GLUT_WINDOW_HEIGHT ) ) - 0.5;
}
int btn;
double baseX, baseY;
double baseWidth, baseHeight;
double centerX = 0, centerY = 0;
double width = 0, height = 0;
void mouse( int button, int state, int mx, int my )
{
baseWidth = width;
baseHeight = height;
btn = button;
getMouseCoords( mx, my, baseX, baseY );
}
void motion( int mx, int my )
{
if( btn != GLUT_LEFT_BUTTON )
{
return;
}
double x, y;
getMouseCoords( mx, my, x, y );
double preX = ( baseX * width );
double preY = ( baseY * height );
double zoomFactor = exp( baseY - y );
width = baseWidth * zoomFactor;
height = baseHeight * zoomFactor;
double postX = ( baseX * width );
double postY = ( baseY * height );
// recenter
centerX += ( preX - postX );
centerY += ( preY - postY );
glutPostRedisplay();
}
void display()
{
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho
(
centerX - ( width / 2.0 ),
centerX + ( width / 2.0 ),
centerY - ( height / 2.0 ),
centerY + ( height / 2.0 ),
-1,
1
);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3ub( 255, 0, 0 );
glBegin( GL_TRIANGLES );
glVertex2i( 0, 0 );
glVertex2i( 150, 0 );
glVertex2i( 0, 150 );
glVertex2i( 0, 0 );
glVertex2i( -150, 0 );
glVertex2i( 0, -150 );
glEnd();
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMouseFunc( mouse );
glutMotionFunc( motion );
width = glutGet( GLUT_WINDOW_WIDTH );
height = glutGet( GLUT_WINDOW_HEIGHT );
glutMainLoop();
return 0;
}
If you wanted to go a different route and simply use glTranslate and gluPerspective, you can acheive the same effect. The mouse event for the scroll wheel (using PyOpenGL) might look something like:
def MouseWheelScroll(self, event):
"""Called when the mouse's scroll wheel is scrolled up or down. This modifies the zoomFactor
which renders the graphics closer or further away on the screen. It also translates the graphics
slightly based on the position of the mouse. This creates an effect of zooming to the location
of the mouse on the screen.
"""
scrolledUp = event.GetWheelRotation() # Returns positive for up, negative for down
self.x, self.y = event.GetPosition()
viewport = glGetIntegerv(GL_VIEWPORT)
width = viewport[2]
height = viewport[3]
centerX = width / 2.0
centerY = height / 2.0
# Make sure cursor is on the screen
if ((self.x > 0 and self.x < width) and (self.y > 0 and self.y < height)):
if (scrolledUp > 0):
self.zoomFactor -= 2.0
self.translation[0] -= (self.x - centerX)
self.translation[1] += (self.y - centerY)
else:
self.zoomFactor += 2.0
self.translation[0] += (self.x - centerX)
self.translation[1] += (self.y - centerY)
if (self.zoomFactor > 150.0):
self.zoomFactor = 150.0
elif (self.zoomFactor < 0.1):
self.zoomFactor = 0.1
self.Refresh(False)
You would then just need to translate the graphics, set up your perspective, and then render the scene.
# Translate graphics
glTranslatef(0.0, 0.0, (self.translation[1]/100.0) * (math.tan(self.cameraPosition[0]/self.cameraPosition[1])))
glTranslatef(0.0, (self.translation[0]/100.0) * (math.tan(self.cameraPosition[0]/self.cameraPosition[1])), 0.0)
# Set Perspective
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(self.zoomFactor, float(width)/float(height), self.nearPlane, self.farPlane)
# Render Scene
glMatrixMode(GL_MODELVIEW)
...Draw stuff here...