0

I am trying to implement a camera into my code to move around a pyramid. Specifically, I need: WASD keys: These keys should be used to control the forward, backward, left, and right motion. QE keys: These keys should be used to control the upward and downward movement. Mouse cursor: This should be used to change the orientation of the camera so it can look up and down or right and left. Mouse scroll: This should be used to adjust the speed of the movement, or the speed the camera travels around the scene. My code for a pyramid is below. Can someone tell me what I need to add??? I am a beginner with openGL and C++. Anything will help!!

#include <iostream>         // cout, cerr
#include <cstdlib>          // EXIT_FAILURE
#include <GL/glew.h>        // GLEW library
#include <GLFW/glfw3.h>     // GLFW library

// GLM Math Header inclusions
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>

using namespace std; // Standard namespace

/*Shader program Macro*/
#ifndef GLSL
#define GLSL(Version, Source) "#version " #Version " core \n" #Source
#endif

// Unnamed namespace
namespace
{
 const char* const WINDOW_TITLE = "Upside Down Pyramid!"; // title

 // width and height
 const int WINDOW_WIDTH = 800;
 const int WINDOW_HEIGHT = 600;

 // mesh data
 struct GLMesh
 {
     GLuint vao;         // vertex array object
     GLuint vbos[2];     // vertex buffer objects
     GLuint nIndices;    // Number of indices
 };

 // Main GLFW window
 GLFWwindow* gWindow = nullptr;
 // Triangle mesh data
 GLMesh gMesh;
 // Shader program
 GLuint gProgramId;
}

/* User-defined Function prototypes to:
* initialize the program, set the window size,
* redraw graphics on the window when resized,
* and render graphics on the screen
*/
bool UInitialize(int, char* [], GLFWwindow** window);
void UResizeWindow(GLFWwindow* window, int width, int height);
void UProcessInput(GLFWwindow* window);
void UCreateMesh(GLMesh& mesh);
void UDestroyMesh(GLMesh& mesh);
void URender();
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint& programId);
void UDestroyShaderProgram(GLuint programId);


/* Vertex Shader Source Code*/
const GLchar* vertexShaderSource = GLSL(440,
 layout(location = 0) in vec3 position; // Vertex data from Vertex Attrib Pointer 0
layout(location = 1) in vec4 color;  // Color data from Vertex Attrib Pointer 1

out vec4 vertexColor; 

// variables for the  transform matrices
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
 gl_Position = projection * view * model * vec4(position, 1.0f); //coordinates
 vertexColor = color;
}
);

const GLchar* fragmentShaderSource = GLSL(440,
 in vec4 vertexColor;

out vec4 fragmentColor;

void main()
{
 fragmentColor = vec4(vertexColor);
}
);


int main(int argc, char* argv[])
{
 if (!UInitialize(argc, argv, &gWindow))
     return EXIT_FAILURE;

 // Create the mesh
 UCreateMesh(gMesh);

 // Create the shader program
 if (!UCreateShaderProgram(vertexShaderSource, fragmentShaderSource, gProgramId))
     return EXIT_FAILURE;

 // Sets the background color
 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

 // render loop
 // -----------
 while (!glfwWindowShouldClose(gWindow))
 {
     // input
     // -----
     UProcessInput(gWindow);
     URender();

     glfwPollEvents();
 }

 // Release mesh data
 UDestroyMesh(gMesh);

 // Release shader program
 UDestroyShaderProgram(gProgramId);

 exit(EXIT_SUCCESS); //program successfull
}


// Initialize
bool UInitialize(int argc, char* argv[], GLFWwindow** window)
{
 // GLFW: initialize and configure
 // ------------------------------
 glfwInit();
 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

 // GLFW: window creation
 // ---------------------
 * window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, NULL, NULL);
 if (*window == NULL)
 {
     std::cout << "Failed to create GLFW window" << std::endl;
     glfwTerminate();
     return false;
 }
 glfwMakeContextCurrent(*window);
 glfwSetFramebufferSizeCallback(*window, UResizeWindow);

 // GLEW: initialize
 glewExperimental = GL_TRUE;
 GLenum GlewInitResult = glewInit();

 if (GLEW_OK != GlewInitResult)
 {
     std::cerr << glewGetErrorString(GlewInitResult) << std::endl;
     return false;
 }

 cout << "INFO: OpenGL Version: " << glGetString(GL_VERSION) << endl;

 return true;
}


// process all input
void UProcessInput(GLFWwindow* window)
{
 if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
     glfwSetWindowShouldClose(window, true);
}


void UResizeWindow(GLFWwindow* window, int width, int height)
{
 glViewport(0, 0, width, height);
}

void URender()
{
 // z-depth
 glEnable(GL_DEPTH_TEST);

 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 // 1. Scales the object by 2
 glm::mat4 scale = glm::scale(glm::vec3(2.0f, 2.0f, 2.0f));
 // 2. Rotates shape by 360 degrees in the x axis
 glm::mat4 rotation = glm::rotate(360.0f, glm::vec3(1.0, 1.0f, 1.0f));
 // 3. Place object at the origin
 glm::mat4 translation = glm::translate(glm::vec3(0.0f, 0.0f, 0.0f));
 // Model matrix: transformations are applied right-to-left order
 glm::mat4 model = translation * rotation * scale;

 // Transforms the camera
 glm::mat4 view = glm::translate(glm::vec3(0.0f, 0.0f, -5.0f));

 // Creates a orthographic projection
 glm::mat4 projection = glm::ortho(-5.0f, 5.0f, -5.0f, 5.0f, 0.1f, 100.0f);

 // Set the shader to be used
 glUseProgram(gProgramId);

 // Retrieves and passes transform matrices
 GLint modelLoc = glGetUniformLocation(gProgramId, "model");
 GLint viewLoc = glGetUniformLocation(gProgramId, "view");
 GLint projLoc = glGetUniformLocation(gProgramId, "projection");

 glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
 glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
 glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

 // Activate the VBOs contained within the mesh's VAO
 glBindVertexArray(gMesh.vao);

 // Draws the triangles to create pyramid
 glDrawElements(GL_TRIANGLES, gMesh.nIndices, GL_UNSIGNED_SHORT, NULL); // Draws the triangle

 glBindVertexArray(0);

 glfwSwapBuffers(gWindow);    // Flips the the back buffer with the front buffer every frame.
}


// Implements the UCreateMesh
void UCreateMesh(GLMesh& mesh)
{
 // color position
 GLfloat verts[] = {
     // Vertex Positions    // Colors
      -0.5f,  -0.5f, -0.5f,   1.0f, 0.0f, 0.0f, 1.0f, // Top
      0.5f, -0.5f, -0.5f,   0.0f, 1.0f, 0.0f, 1.0f, // Middle
     0.0f, 0.5f, 0.0f,   0.0f, 0.0f, 1.0f, 1.0f, // Bottom

     -0.5f,  -0.5f, 0.5f,   1.0f, 0.0f, 1.0f, 1.0f, // Top
      0.5f, -0.5f, 0.5f,  0.5f, 0.5f, 1.0f, 1.0f, // Middle
      0.0f,  0.5f, 0.0f,  1.0f, 1.0f, 0.5f, 1.0f, // Bottom

     -0.5f,  -0.5f, -0.5f,  0.2f, 0.2f, 0.5f, 1.0f, // Top
     -0.5f, -0.5f, 0.5f,  1.0f, 0.0f, 1.0f, 1.0f,  // Middle
      0.0f, 0.5f, 0.0f,  0.5f, 0.5f, 1.0f, 1.0f, // Bottom

      0.5f,  -0.5f, -0.5f,  1.0f, 1.0f, 0.5f, 1.0f, // Top
     0.5f,  -0.5f, 0.5f,  0.2f, 0.2f, 0.5f, 1.0f, //  Middle
     0.0f, 0.5f, 0.0f,  1.0f, 0.0f, 1.0f, 1.0f,  //  Bottom

      0.5f,  -0.5f, -0.5f,  1.0f, 1.0f, 0.5f, 1.0f, // Top
     0.5f,  -0.5f, 0.5f,  0.2f, 0.2f, 0.5f, 1.0f, //  Middle
     0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, // Bottom

     -0.5f,  -0.5f, 0.5f,  1.0f, 1.0f, 0.5f, 1.0f, // Top
     -0.5f,  -0.5f, -0.5f,  0.2f, 0.2f, 0.5f, 1.0f, //  Middle
     0.0f, 0.5f, 0.0f,  1.0f, 0.0f, 1.0f, 1.0f  //  Bottom
 };

 // Index data to share position data
 GLushort indices[] = {
     2, 1, 0,  // Triangle 1
     3, 1, 0,   // Triangle 2

   
 };

 const GLuint floatsPerVertex = 3;
 const GLuint floatsPerColor = 4;

 glGenVertexArrays(1, &mesh.vao); 
 glBindVertexArray(mesh.vao);

 // Create 2 buffers
 glGenBuffers(2, mesh.vbos);
 glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos[0]);
 glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);

 mesh.nIndices = sizeof(indices) / sizeof(indices[0]);
 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos[1]);
 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

 GLint stride = sizeof(float) * (floatsPerVertex + floatsPerColor);

 // Vertex Attribute Pointers
 glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
 glEnableVertexAttribArray(0);

 glVertexAttribPointer(1, floatsPerColor, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerVertex));
 glEnableVertexAttribArray(1);
}


void UDestroyMesh(GLMesh& mesh)
{
 glDeleteVertexArrays(1, &mesh.vao);
 glDeleteBuffers(2, mesh.vbos);
}


//Shader function
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint& programId)
{
 // error report
 int success = 0;
 char infoLog[512];

 programId = glCreateProgram();

 // Create the vertex and fragment shader objects
 GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
 GLuint fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);

 // Retrieve the shader source
 glShaderSource(vertexShaderId, 1, &vtxShaderSource, NULL);
 glShaderSource(fragmentShaderId, 1, &fragShaderSource, NULL);

 // compile and check for errors)
 glCompileShader(vertexShaderId); 
 glGetShaderiv(vertexShaderId, GL_COMPILE_STATUS, &success);
 if (!success)
 {
     glGetShaderInfoLog(vertexShaderId, 512, NULL, infoLog);
     std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;

     return false;
 }

 glCompileShader(fragmentShaderId);
 glGetShaderiv(fragmentShaderId, GL_COMPILE_STATUS, &success);
 if (!success)
 {
     glGetShaderInfoLog(fragmentShaderId, sizeof(infoLog), NULL, infoLog);
     std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;

     return false;
 }

 // Compiled shaders
 glAttachShader(programId, vertexShaderId);
 glAttachShader(programId, fragmentShaderId);

 glLinkProgram(programId); 
 glGetProgramiv(programId, GL_LINK_STATUS, &success);
 if (!success)
 {
     glGetProgramInfoLog(programId, sizeof(infoLog), NULL, infoLog);
     std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;

     return false;
 }

 glUseProgram(programId); 

 return true;
}


void UDestroyShaderProgram(GLuint programId)
{
 glDeleteProgram(programId);
}
0x5453
  • 12,753
  • 1
  • 32
  • 61

1 Answers1

0

There are multiple ways to move the camera around your scene (please note that you aren't moving around the camera but all vertices usually). One way would be to use the lookAt method. This method returns a rotation matrix, which you can use as the view matrix of your camera. This approach was discussed in great detail already in many sources:

Simply put you are defining your camera orientation with a camera position, a target of the camera (which the camera will look at), and an up vector. You can describe the orientation of the camera with these three vectors. So your view matrix would be calculated with: glm::mat4 view = glm::lookAt(position, target, up) (instead of glm::mat4 view = glm::translate(glm::vec3(0.0f, 0.0f, -5.0f))). How you generate these vectors is up to you and therefore how your camera behaves. If you want to have a look at an implementation of a camera model here is one.

Sebphil
  • 488
  • 5
  • 12