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);
}
I have this class:
class Model3D
{
public:
void AddVert( Vec3D vert ) { vertices.push_back( vert ); }
void AddTri( Vec3D *v_0, Vec3D *v_1, Vec3D *v_2 );
void Draw( HDC hdc );
std::vector<Vec3D> vertices;
std::vector<Triangle3D> polys;
};
Also relevant, the Triangle3D type is defined as follows: (it is small because it's not finished)
class Triangle3D
{
public:
Vec3D *verts[3];
};
Also, Here is AddTri()
void Model3D::AddTri( Vec3D *v_0, Vec3D *v_1, Vec3D *v_2 )
{
Triangle3D triangle;
triangle.verts[0] = v_0;
triangle.verts[1] = v_1;
triangle.verts[2] = v_2;
polys.push_back( triangle );
}
Vertices members are given initial values. Looking at these members in debug through the pointers in Triangle3D shows these values correctly
Finally, I attempt to alter the members of vertices here:
std::vector<Vec3D>::iterator j;
for (j = vertices.begin(); j != vertices.end(); ++j)
{
j->x = ( j->x ) / ( j->z );
j->y = ( j->y ) / ( j->z );
}
After this loop completes, using the debugger, if I inspect the vertices vector, the members are modified as hoped. Yet, when I inspect the pointers to these members in the Triangle3D class, they are unchanged. Why is this?
EDIT here is a snippet of vertices and triangles being added (defines a cube):
Model3D Cube( Vec3D center, int size )
{
Vec3D vert;
Model3D model;
vert.z = .5;
vert.x = center.x - (float)( 0.5f * size );
vert.y = center.y + (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x + (float)( 0.5f * size );
vert.y = center.y + (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x + (float)( 0.5f * size );
vert.y = center.y - (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x - (float)( 0.5f * size );
vert.y = center.y - (float)( 0.5f * size );
model.AddVert( vert );
vert.z = 1;
//center.x += 120;
//center.y += 120;
vert.x = center.x - (float)( 0.5f * size );
vert.y = center.y + (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x + (float)( 0.5f * size );
vert.y = center.y + (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x + (float)( 0.5f * size );
vert.y = center.y - (float)( 0.5f * size );
model.AddVert( vert );
vert.x = center.x - (float)( 0.5f * size );
vert.y = center.y - (float)( 0.5f * size );
model.AddVert( vert );
//front
model.AddTri( &model.vertices[0], &model.vertices[1], &model.vertices[2] );
model.AddTri( &model.vertices[2], &model.vertices[3], &model.vertices[0] );
//top
model.AddTri( &model.vertices[4], &model.vertices[5], &model.vertices[1] );
model.AddTri( &model.vertices[1], &model.vertices[0], &model.vertices[4] );
//bottom
model.AddTri( &model.vertices[3], &model.vertices[2], &model.vertices[6] );
model.AddTri( &model.vertices[6], &model.vertices[7], &model.vertices[3] );
//left
model.AddTri( &model.vertices[4], &model.vertices[0], &model.vertices[3] );
model.AddTri( &model.vertices[3], &model.vertices[7], &model.vertices[4] );
//right
model.AddTri( &model.vertices[1], &model.vertices[5], &model.vertices[6] );
model.AddTri( &model.vertices[6], &model.vertices[2], &model.vertices[1] );
//back
model.AddTri( &model.vertices[5], &model.vertices[4], &model.vertices[7] );
model.AddTri( &model.vertices[7], &model.vertices[6], &model.vertices[5] );
return model;
}
And here is the Draw method:
void Model3D::Draw( HDC hdc )
{
std::vector<Triangle3D>::iterator i;
std::vector<Vec3D>::iterator j;
for (j = vertices.begin(); j != vertices.end(); ++j)
{
j->x = ( j->x ) / ( j->z );
j->y = ( j->y ) / ( j->z );
}
for (i = polys.begin(); i != polys.end(); ++i)
{
DrawLine( hdc, *i->verts[0], *i->verts[1], WHITE );
DrawLine( hdc, *i->verts[1], *i->verts[2], WHITE );
DrawLine( hdc, *i->verts[2], *i->verts[0], WHITE );
}
}
I'm trying billboarding, however the billboard doesn't show when i use 'newWorld' i've tested to see if it was the way i was drawing the billboard, but it isn't, as when i changed to it's own local world, it appeared on screen.
// Calculate the rotation that needs to be applied to the billboard model to face the current camera position using the arc tangent function.
XMFLOAT3 CarPos = XMFLOAT3(Billboards->GetPosition().x, Billboards->GetPosition().y, Billboards->GetPosition().z);
XMFLOAT3 CamPos = XMFLOAT3(fCam->GetEye().x, fCam->GetEye().y, fCam->GetEye().z);
float angle;
float BBrotation;
XMMATRIX newWorld = XMLoadFloat4x4(&Billboards->GetWorld());
angle = atan2(CarPos.x - CamPos.x, CarPos.z - CamPos.z) * (180 / XM_PI);
BBrotation = angle * 0.0174532925f;
XMMatrixRotationY(BBrotation);
XMMatrixTranslation(CarPos.x, CarPos.y, CarPos.z);
XMMATRIX bbRotMatix = XMMatrixRotationY(BBrotation);
XMMATRIX bbCarPos = XMMatrixTranslation(CarPos.x, CarPos.y, CarPos.z);
newWorld = bbCarPos + bbRotMatix;
XMMATRIX bilworld = XMLoadFloat4x4(&Billboards->GetWorld());
cb.World = XMMatrixTranspose(newWorld);
_pImmediateContext->UpdateSubresource(_pConstantBuffer, 0, nullptr, &cb, 0, 0);
Billboards->Draw(_pd3dDevice, _pImmediateContext, _pTreeRV, _pSpecRV);
Billboards->SetTranslation(30.0f, 0.0f, 0.0f);
Billboards->SetRotation(-90.0f, 0.0f, 0.0);
The SimpleMath DirectXMath wrapper from the Directx Tool Kit has right-handed billboard functions you might find useful as reference.
inline Matrix Matrix::CreateBillboard( const Vector3& object, const Vector3& cameraPosition, const Vector3& cameraUp, const Vector3* cameraForward )
{
using namespace DirectX;
XMVECTOR O = XMLoadFloat3( &object );
XMVECTOR C = XMLoadFloat3( &cameraPosition );
XMVECTOR Z = XMVectorSubtract( O, C );
XMVECTOR N = XMVector3LengthSq( Z );
if ( XMVector3Less( N, g_XMEpsilon ) )
{
if ( cameraForward )
{
XMVECTOR F = XMLoadFloat3( cameraForward );
Z = XMVectorNegate( F );
}
else
Z = g_XMNegIdentityR2;
}
else
{
Z = XMVector3Normalize( Z );
}
XMVECTOR up = XMLoadFloat3( &cameraUp );
XMVECTOR X = XMVector3Cross( up, Z );
X = XMVector3Normalize( X );
XMVECTOR Y = XMVector3Cross( Z, X );
XMMATRIX M;
M.r[0] = X;
M.r[1] = Y;
M.r[2] = Z;
M.r[3] = XMVectorSetW( O, 1.f );
Matrix R;
XMStoreFloat4x4( &R, M );
return R;
}
inline Matrix Matrix::CreateConstrainedBillboard( const Vector3& object, const Vector3& cameraPosition, const Vector3& rotateAxis,
const Vector3* cameraForward, const Vector3* objectForward )
{
using namespace DirectX;
static const XMVECTORF32 s_minAngle = { 0.99825467075f, 0.99825467075f, 0.99825467075f, 0.99825467075f }; // 1.0 - XMConvertToRadians( 0.1f );
XMVECTOR O = XMLoadFloat3( &object );
XMVECTOR C = XMLoadFloat3( &cameraPosition );
XMVECTOR faceDir = XMVectorSubtract( O, C );
XMVECTOR N = XMVector3LengthSq( faceDir );
if (XMVector3Less(N, g_XMEpsilon))
{
if (cameraForward)
{
XMVECTOR F = XMLoadFloat3( cameraForward );
faceDir = XMVectorNegate( F );
}
else
faceDir = g_XMNegIdentityR2;
}
else
{
faceDir = XMVector3Normalize( faceDir );
}
XMVECTOR Y = XMLoadFloat3( &rotateAxis );
XMVECTOR X, Z;
XMVECTOR dot = XMVectorAbs( XMVector3Dot( Y, faceDir ) );
if ( XMVector3Greater( dot, s_minAngle ) )
{
if ( objectForward )
{
Z = XMLoadFloat3( objectForward );
dot = XMVectorAbs( XMVector3Dot( Y, Z ) );
if ( XMVector3Greater( dot, s_minAngle ) )
{
dot = XMVectorAbs( XMVector3Dot( Y, g_XMNegIdentityR2 ) );
Z = ( XMVector3Greater( dot, s_minAngle ) ) ? g_XMIdentityR0 : g_XMNegIdentityR2;
}
}
else
{
dot = XMVectorAbs( XMVector3Dot( Y, g_XMNegIdentityR2 ) );
Z = ( XMVector3Greater( dot, s_minAngle ) ) ? g_XMIdentityR0 : g_XMNegIdentityR2;
}
X = XMVector3Cross( Y, Z );
X = XMVector3Normalize( X );
Z = XMVector3Cross( X, Y );
Z = XMVector3Normalize( Z );
}
else
{
X = XMVector3Cross( Y, faceDir );
X = XMVector3Normalize( X );
Z = XMVector3Cross( X, Y );
Z = XMVector3Normalize( Z );
}
XMMATRIX M;
M.r[0] = X;
M.r[1] = Y;
M.r[2] = Z;
M.r[3] = XMVectorSetW( O, 1.f );
Matrix R;
XMStoreFloat4x4( &R, M );
return R;
}