OpenGL/GLFW - scroll wheel not responding - c++

I am following along with this tutorial series, but also trying to customise my solution as I go along (essentially I am trying to render a 3D point cloud -ie. a whole bunch of XYZ points).
I have been able to get the camera working and a 3D environment going. I am happy to work on the rest of that by myself, but the problem I am having is that the scroll wheel is not responding. I am hoping this is blindingly obvious to someone. It seems that the only user callback the program is getting is that of the mouse position - 100% of the time - and that's preventing the scroll_callback function form being heard. Can someone explain why my scroll wheel callback is not being received. Code below.
Let me know if any further info is required.
I am using Visual Studio 2017 Community.
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <Shader.h>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 800;
// camera
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
bool firstMouse = true;
float yaw = -90.0f; // yaw is initialized to -90.0 degrees since a yaw of 0.0 results in a direction vector pointing to the right so we initially rotate a bit to the left.
float pitch = 0.0f;
float lastX = 800.0f / 2.0;
float lastY = 600.0 / 2.0;
float fov = 45.0f;
// timing
float deltaTime = 0.0f; // time between current frame and last frame
float lastFrame = 0.0f;
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
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); // uncomment this statement to fix compilation on OS X
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
// tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// configure global opengl state
// -----------------------------
glEnable(GL_DEPTH_TEST);
Shader ourShader("VertexShader.vs", "FragShader.fs");
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
struct Point
{
float x;
float y;
float z;
};
Point points[500];
for (int i = 0; i < 500; i++)
{
points[i].x = (float)((rand() % SCR_WIDTH) + 1);
points[i].y = (float)((rand() % SCR_WIDTH) + 1);
points[i].z = (float)((rand() % SCR_WIDTH) + 1);
// X Coords to Normalised Device coordinates
if (points[i].x > 400)
{
points[i].x = points[i].x * 0.00125f;
}
else if (points[i].x < 400)
{
points[i].x = points[i].x * -0.00125f;
}
else if (points[i].x == 400)
{
points[i].x = 0.0f;
}
// Y Coords to Normalised Device coordinates
if (points[i].y > 400)
{
points[i].y = points[i].y * 0.00125f;
}
else if (points[i].y < 400)
{
points[i].y = points[i].y * -0.00125f;
}
else if (points[i].y == 400)
{
points[i].y = 0.0f;
}
// Z Coords to Normalised Device coordinates
if (points[i].z > 400)
{
points[i].z = points[i].z * 0.00125f;
}
else if (points[i].z < 400)
{
points[i].z = points[i].z * -0.00125f;
}
else if (points[i].z == 400)
{
points[i].z = 0.0f;
}
//cout << points[i].x << ", " << points[i].y << ", " << points[i].z << endl;
}
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray(0);
// uncomment this call to draw in wireframe polygons.
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window);
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// activate shader
ourShader.use();
// create transformations
glm::mat4 projection;
projection = glm::perspective(glm::radians(95.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
ourShader.setMat4("projection", projection); // note: currently we set the projection matrix each frame, but since the projection matrix rarely changes it's often best practice to set it outside the main loop only once.
// camera/view transformation
glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
ourShader.setMat4("view", view);
glm::mat4 model;
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
ourShader.setMat4("model", model);
// draw our points array
//glUseProgram(shaderProgram);
glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
glPointSize(3.0f);
glDrawArrays(GL_POINTS, 0, 500);
// glBindVertexArray(0); // no need to unbind it every time
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
float cameraSpeed = 2.5 * deltaTime;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
cameraPos += cameraSpeed * cameraFront;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
cameraPos -= cameraSpeed * cameraFront;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos;
lastY = ypos;
float sensitivity = 0.1f; // change this value to your liking
xoffset *= sensitivity;
yoffset *= sensitivity;
yaw += xoffset;
pitch += yoffset;
// make sure that when pitch is out of bounds, screen doesn't get flipped
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
glm::vec3 front;
front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
front.y = sin(glm::radians(pitch));
front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
cameraFront = glm::normalize(front);
}
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
if (fov >= 1.0f && fov <= 45.0f)
fov -= yoffset;
if (fov <= 1.0f)
fov = 1.0f;
if (fov >= 45.0f)
fov = 45.0f;
}

You're going to facepalm a little:
projection = glm::perspective(glm::radians(95.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
should be:
projection = glm::perspective(glm::radians(fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
I ran your code in a debugger and the scroll callback function is running every time but the fov value was never being used. You can use the same technique if you ever want to check if a function is being called by adding a break point anywhere in the function.

Related

GLSL compiler can't find cameraPosition definition?

I am trying to build a code that uses OpenGL and shaders that adds texture to a square pyramid. After I added the functions to add the texture, ran the code but instead of rendering, I get a console window giving me the following error:
INFO: OpenGL Version: 4.4.0 NVIDIA 512.15
ERROR::SHADER::VERTEX::COMPILATION_FAILED
0(2) : error C1503: undefined variable "cameraPosition"
0(2) : error C1503: undefined variable "cameraPosition"
0(2) : error C1503: undefined variable "cameraPosition"
0(2) : error C1035: assignment of incompatible types
I have tried copying and pasting the cameraPosition variable from the bottom of my code to one of my main functions that has the gl_Position variable. But that did not solve the problem. Do I need to change the vec3 to vec4 somewhere or do I need to copy and paste the cameraPostion variable and definition somewhere else? Here is my code:
#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>
#include <SOIL2.h> // SOIL2 library
using namespace std; // Standard namespace
/*Shader program Macro*/
#ifndef GLSL
#define GLSL(Version, Source) "#version " #Version " core \n" #Source
#endif
// Input Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
// Declare View Matrix
glm::mat4 viewMatrix;
// Initialize FOV
GLfloat fov = 45.f;
// Define Camera Attributes
glm::vec3 cameraPosition = glm::vec3(0.f, 0.f, 3.f);
glm::vec3 target = glm::vec3(0.f, 0.f, 0.f);
glm::vec3 cameraDirection = glm::normalize(cameraPosition - target);
glm::vec3 worldUp = glm::vec3(0.f, 1.f, 0.f);
glm::vec3 cameraRight = glm::normalize(glm::cross(worldUp, cameraDirection));
glm::vec3 cameraUp = glm::normalize(glm::cross(cameraDirection, cameraRight));
glm::vec3 cameraFront = glm::normalize(glm::vec3(0.f, 0.f, -1.f));
// Declare target prototype
glm::vec3 getTarget();
// Camera transformation prototype
void TransformCamera();
// Boolean for keys and mouse buttons
bool keys[1024], mouseButtons[3];
// Boolean to check camera transformations
bool isPanning = false, isOrbiting = false;
// Radius, Pitch, and Yaw
GLfloat radius = 3.f, rawYaw = 0.f, rawPitch = 0.f, degYaw, degPitch;
GLfloat deltaTime = 0.f, lastFrame = 0.f;
GLfloat lastX = 400, lastY = 300, xChange, yChange;
bool firstMouseMove = true; // Detect inititial mouse movement
void initCamera();
// Unnamed namespace
namespace
{
const char* const WINDOW_TITLE = "Basic Camera Movement"; // Macro for window title
// Variables for window width and height
int WINDOW_WIDTH = 800;
int WINDOW_HEIGHT = 600;
// Stores the GL data relative to a given mesh
struct GLMesh
{
GLuint vao; // Handle for the vertex array object
GLuint vbos[2]; // Handles for the vertex buffer objects
GLuint nIndices; // Number of indices of the mesh
};
// 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 vec3 color; // Color data from Vertex Attrib Pointer 1
layout(location = 2) in vec2 texture; // Texture data from Vertex Attrib Pointer 2
out vec3 vertexColor; // variable to transfer color data to the fragment shader
out vec3 vertexTexture;
//Global variables for the transform matrices
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform sampler2D myTexture; // Sampler
void main()
{
gl_Position = projection * view * model * vec4(cameraPosition.x, cameraPosition.y, cameraPosition.z, 1.0f); // transforms vertices to clip coordinates
vertexColor = color; // references incoming color data
vertexTexture = texture;
}
);
/* Fragment Shader Source Code*/
const GLchar* fragmentShaderSource = GLSL(440,
in vec3 vertexColor; // Variable to hold incoming color data from vertex shader
out vec3 fragmentColor;
out vec3 fragmentTexture;
void main()
{
fragmentColor = texture(myTexture, textTexture);
fragmentTexture = vec2(vertexTexture);
}
);
int main(int argc, char* argv[])
{
if (!UInitialize(argc, argv, &gWindow))
return EXIT_FAILURE;
// Create the mesh
UCreateMesh(gMesh); // Calls the function to create the Vertex Buffer Object
// Create the shader program
if (!UCreateShaderProgram(vertexShaderSource, fragmentShaderSource, gProgramId))
return EXIT_FAILURE;
// Sets the background color of the window to black (it will be implicitely used by glClear)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Set input call back functions
glfwSetKeyCallback(gWindow, key_callback);
glfwSetCursorPosCallback(gWindow, cursor_position_callback);
glfwSetMouseButtonCallback(gWindow, mouse_button_callback);
glfwSetScrollCallback(gWindow, scroll_callback);
// render loop
// -----------
while (!glfwWindowShouldClose(gWindow))
{
// Set delta time
GLfloat currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
// Resize window and graphics simultaneously
glfwGetFramebufferSize(gWindow, &WINDOW_WIDTH, &WINDOW_HEIGHT);
// input
// -----
UProcessInput(gWindow);
// Render this frame
URender();
glfwPollEvents();
// Poll camera transformations
TransformCamera();
}
// Release mesh data
UDestroyMesh(gMesh);
// Release shader program
UDestroyShaderProgram(gProgramId);
exit(EXIT_SUCCESS); // Terminates the program successfully
}
// Initialize GLFW, GLEW, and create a window
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
// ----------------
// Note: if using GLEW version 1.13 or earlier
glewExperimental = GL_TRUE;
GLenum GlewInitResult = glewInit();
if (GLEW_OK != GlewInitResult)
{
std::cerr << glewGetErrorString(GlewInitResult) << std::endl;
return false;
}
// Displays GPU OpenGL version
cout << "INFO: OpenGL Version: " << glGetString(GL_VERSION) << endl;
return true;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
void UProcessInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
float cameraSpeed = 2.5 * deltaTime;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
cameraPosition += cameraSpeed * cameraFront;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
cameraPosition -= cameraSpeed * cameraFront;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
cameraPosition -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
cameraPosition += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
cameraPosition -= cameraSpeed * cameraUp;
if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
cameraPosition += cameraSpeed * cameraUp;
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
void UResizeWindow(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
// Functioned called to render a frame
void URender()
{
// Enable z-depth
glEnable(GL_DEPTH_TEST);
// Wireframe mode
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// Clear the frame and z buffers
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(1.0f, 1.0f, 1.0f));
// 2. Rotates shape by 15 degrees in the x axis
glm::mat4 rotation = glm::rotate(45.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: move the camera back (z axis)
glm::mat4 view = glm::lookAt(cameraPosition, getTarget(), worldUp);
// Creates a perspective projection
glm::mat4 projection = glm::perspective(fov, (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, 0.1f, 100.0f);
// Set the shader to be used
glUseProgram(gProgramId);
// Retrieves and passes transform matrices to the Shader program
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));
GLuint crateTexture = {1};
glBindTexture(GL_TEXTURE_2D, crateTexture);
// Activate the VBOs contained within the mesh's VAO
glBindVertexArray(gMesh.vao);
// Draws the triangles
glDrawElements(GL_TRIANGLES, gMesh.nIndices, GL_UNSIGNED_SHORT, NULL); // Draws the triangle
// Deactivate the Vertex Array Object
glBindVertexArray(0);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
glfwSwapBuffers(gWindow); // Flips the the back buffer with the front buffer every frame.
}
// Implements the UCreateMesh function
void UCreateMesh(GLMesh& mesh)
{
// Position and Color data
GLfloat verts[] = {
0.0f, 1.0f, 0.0f, // Top Center Vertex 0
1.0f, 0.0f, 0.0f, 1.0f, // Red
0.5f, 1.0f, // UV
-1.0f, -1.0f, 1.0f, // Bottom Left Vertex 1
0.0f, 1.0f, 0.0f, 1.0f, // Green
0.0f, 0.0f, // UV
1.0f, -1.0f, 1.0f, // Bottom Right Vertex 2
0.0f, 0.0f, 1.0f, 1.0f, // Blue
1.0f, 0.0f, // UV
1.0f, -1.0f, -1.0f, // Bottom Back Right Vertex 3
1.0f, 0.0f, 1.0f, 1.0f, // Magenta
0.0f, 0.0f, // UV
-1.0f, -1.0f, -1.0f, // Bottom Back Left Vertex 4
1.0f, 1.0f, 0.0f, 1.0f, // Yellow
1.0f, 0.0f // UV
};
// Index data to share position data
GLushort indices[] = {
// Sides
0, 1, 2, // Triangle 1
0 ,2, 3, // Triangle 2
0, 3, 1, // Triangle 3
0, 3, 4, // Triangle 4
// Base
1, 2, 3, // Triangle 5
1, 4, 3 // Triangle 6
};
const GLuint floatsPerVertex = 3;
const GLuint floatsPerColor = 4;
const GLuint floatsPerTexture = 2;
glGenVertexArrays(1, &mesh.vao); // we can also generate multiple VAOs or buffers at the same time
glBindVertexArray(mesh.vao);
// Create 2 buffers: first one for the vertex data; second one for the indices
glGenBuffers(2, mesh.vbos);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos[0]); // Activates the buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU
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);
// Strides between vertex coordinates is 6 (x, y, z, r, g, b, a). A tightly packed stride is 0.
GLint stride = sizeof(float) * (floatsPerVertex + floatsPerColor);// The number of floats before each
// Create 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);
glVertexAttribPointer(2, floatsPerTexture, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerTexture));
glEnableVertexAttribArray(2);
// Load textures
int crateTexWidth, crateTexHeight, gridTexWidth, gridTexHeight;
unsigned char* crateImage = SOIL_load_image("crate.png", &crateTexWidth, &crateTexHeight, 0, SOIL_LOAD_RGB);
unsigned char* gridImage = SOIL_load_image("crate.png", &gridTexWidth, &gridTexHeight, 0, SOIL_LOAD_RGB);
// Generate Textures
GLuint crateTexture = {1};
glGenTextures(1, &crateTexture);
glBindTexture(GL_TEXTURE_2D, crateTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, crateTexWidth, crateTexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, crateImage);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(crateImage);
glBindTexture(GL_TEXTURE_2D, 0);
// Generate Textures
GLuint gridTexture;
glGenTextures(1, &gridTexture);
glBindTexture(GL_TEXTURE_2D, gridTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, gridTexWidth, gridTexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, gridImage);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(gridImage);
glBindTexture(GL_TEXTURE_2D, 0);
}
void UDestroyMesh(GLMesh& mesh)
{
glDeleteVertexArrays(1, &mesh.vao);
glDeleteBuffers(2, mesh.vbos);
}
// Implements the UCreateShaders function
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint& programId)
{
// Compilation and linkage error reporting
int success = 0;
char infoLog[512];
// Create a Shader program object.
programId = glCreateProgram();
// Create the vertex and fragment shader objects
GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
// Retrive the shader source
glShaderSource(vertexShaderId, 1, &vtxShaderSource, NULL);
glShaderSource(fragmentShaderId, 1, &fragShaderSource, NULL);
// Compile the vertex shader, and print compilation errors (if any)
glCompileShader(vertexShaderId); // compile the vertex shader
// check for shader compile errors
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); // compile the fragment shader
// check for shader compile errors
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;
}
// Attached compiled shaders to the shader program
glAttachShader(programId, vertexShaderId);
glAttachShader(programId, fragmentShaderId);
glLinkProgram(programId); // links the shader program
// check for linking errors
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); // Uses the shader program
return true;
}
void UDestroyShaderProgram(GLuint programId)
{
glDeleteProgram(programId);
}
// Define Input Callback functions
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
// Display ASCII Keycode
//cout << "ASCII: " << key << endl;
if (action == GLFW_PRESS)
keys[key] = true;
else if (action == GLFW_RELEASE)
keys[key] = false;
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
/*
// Display scroll offset
if (yoffset > 0)
cout << "Scroll Up: ";
if (yoffset < 0)
cout << "Scroll Down: ";
cout << yoffset << endl;
*/
// Clamp FOV
if (fov >= 1.f && fov <= 45.f)
fov -= yoffset * 0.01f;
//Default FOV
if (fov < 1.f)
fov = 1.f;
if (fov > 45.f)
fov = 45.f;
}
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) {
// Display mouse x and y coordinates
// cout << "Mouse X: " << xpos << endl;
// cout << "Mouse Y: " << ypos << endl;
if (firstMouseMove) {
lastX = xpos;
lastY = ypos;
firstMouseMove = false;
}
// Calculate cursor offset
xChange = xpos - lastX;
yChange = lastY - ypos;
lastX = xpos;
lastY = ypos;
// Pan camera
if (isPanning) {
if (cameraPosition.z < 0.f)
cameraFront.z = 1.f;
else
cameraFront.z = -1.f;
GLfloat cameraSpeed = xChange * deltaTime;
cameraPosition += cameraSpeed * cameraRight;
cameraSpeed = yChange * deltaTime;
cameraPosition += cameraSpeed * cameraUp;
}
// Orbit camera
if (isOrbiting) {
rawYaw += xChange;
rawPitch += yChange;
// Convert Yaw and Pitch to degrees
degYaw = glm::radians(rawYaw);
// degPitch = glm::radians(rawPitch)
degPitch = glm::clamp(glm::radians(rawPitch), -glm::pi<float>() / 2.f + .1f, glm::pi<float>() / 2.f - .1f);
// Azimuth Altitude formula
cameraPosition.x = target.x + radius * cosf(degPitch) * sin(degYaw);
cameraPosition.y = target.y + radius * sinf(degPitch);
cameraPosition.z = target.z + radius * cosf(degPitch) * cosf(degYaw);
}
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
/*
// Detect mouse button clicks
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
cout << "LMB clicked!" << endl;
if (button == GLFW_MOUSE_BUTTON_MIDDLE && action == GLFW_PRESS)
cout << "MMB clicked!" << endl;
if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
cout << "RMB clicked!" << endl;
*/
if (action == GLFW_PRESS)
mouseButtons[button] = true;
else if (action == GLFW_RELEASE)
mouseButtons[button] = false;
}
// Define getTarget function
glm::vec3 getTarget() {
if (isPanning)
target = cameraPosition + cameraFront;
return target;
}
// Define TransformCamera function
void TransformCamera() {
// Pan camera
if (keys[GLFW_KEY_LEFT_ALT] && mouseButtons[GLFW_MOUSE_BUTTON_MIDDLE])
isPanning = true;
else
isPanning = false;
// Orbit camera
if ((mouseButtons[GLFW_MOUSE_BUTTON_LEFT]))
isOrbiting = true;
else
isOrbiting = false;
// Reset camera
if (keys[GLFW_KEY_F])
initCamera();
}
void initCamera() {
cameraPosition = glm::vec3(0.f, 0.f, 3.f);
target = glm::vec3(0.f, 0.f, 0.f);
cameraDirection = glm::normalize(cameraPosition - target);
worldUp = glm::vec3(0.f, 1.f, 0.f);
cameraRight = glm::normalize(glm::cross(worldUp, cameraDirection));
cameraUp = glm::normalize(glm::cross(cameraDirection, cameraRight));
cameraFront = glm::normalize(glm::vec3(0.f, 0.f, -1.f));
}
You never actually bother to declare/define a cameraPosition (presumably) uniform in your vertex shader or set its value via an appropriate glUniform*() call.
...not that you'd really want to since then every vertex would end up being set to the same position and you'd end up with a dot somewhere (maybe) on screen.
Rather,
gl_Position = projection * view * model * vec4(cameraPosition.x, cameraPosition.y, cameraPosition.z, 1.0f);
should probably be:
gl_Position = projection * view * model * vec4(position, 1.0);
...so all your fancy geometry in verts actually has some chance of being sensibly displayed.

Circle vs Square Collision Detection AND NEED TO RESPONSE in C++ | OpenGL. My problem just this "I need to keep the circle outside the square"

I am working on a 2D Circle vs Square Collision Detection. I did the test of collision detection between circle and square, It's ok, there is no problem with collision detection, just I need to keep the circle outside of the square when circle touch to the square. I want that the circle does not enter into the square, and the circle must stay outside of the square! How can I do that? How can I keep circle outside of the square?
Picture01 My problem just this "I just need to keep the circle outside of the square when they are touching each other" I made this collision detection test looking at this site => http://jeffreythompson.org/collision-detection/circle-rect.php, but in this tutorial there is not a response of the collision detetcion
Please explain to me writing as a code
Code:
#include "shader.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include<vector>
#include<cmath>
#include <math.h>
using namespace std;
GLfloat blueSquareWidth = 0.3f, blueSquareHeight = 0.2f;
std::vector<glm::vec3> vertices;
float x, y, z, r = 0.1f;
int num_segments = 48;
void DrawCircle()
{
for (int i = 0; i < num_segments; i++)
{
float theta = 2.0f * 3.1415926f * float(i) / float(num_segments);
//get the current angle
x = r * cosf(theta);
y = r * sinf(theta);
z = 0.0f;
vertices.push_back(glm::vec3(x, y, z));
}
}
GLfloat blueSquareVertices[] =
{
0.0f, blueSquareHeight, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
blueSquareWidth, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
blueSquareWidth, blueSquareHeight, 0.0f,
0.0f, 0.0f, 1.0f
};
GLuint blueSqaureIndices[] =
{
0, 1, 2,
0, 2, 3
};
GLfloat rotationTime = 0.0f;
GLuint vbo[2], vao[2], ibo[2];
glm::vec3 blueSquarePosition(0.3f, 0.0f, 0.0f);
glm::vec3 spherePosition(0.660001f, 0.28f, 0.0f);
void inputKeys(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_TRUE)
{
glfwSetWindowShouldClose(window, true);
}
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_TRUE)
{
blueSquarePosition.y += 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_TRUE)
{
blueSquarePosition.y -= 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_A) == GLFW_TRUE)
{
blueSquarePosition.x -= 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_TRUE)
{
blueSquarePosition.x += 0.001f;
}
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_TRUE)
{
spherePosition.y += 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_TRUE)
{
spherePosition.y -= 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_TRUE)
{
spherePosition.x -= 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_TRUE)
{
spherePosition.x += 0.001f;
}
}
bool circleRect(GLFWwindow* window)
{
// temporary variables to set edges for testing
float testX = spherePosition.x;
float testY = spherePosition.y;
// which edge is closest?
if (spherePosition.x < blueSquarePosition.x)
{
testX = blueSquarePosition.x; // test left edge
}
else if (spherePosition.x > blueSquarePosition.x + blueSquareWidth)
{
testX = blueSquarePosition.x + blueSquareWidth; // right edge
}
if (spherePosition.y < blueSquarePosition.y)
{
testY = blueSquarePosition.y; // top edge
}
else if (spherePosition.y > blueSquarePosition.y + blueSquareHeight)
{
testY = blueSquarePosition.y + blueSquareHeight; // bottom edge
}
// get distance from closest edges
float distX = spherePosition.x - testX;
float distY = spherePosition.y - testY;
float distance = sqrt((distX * distX) + (distY * distY));
// if the distance is less than the radius, collision!
if (distance<= r)
{
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS)
{
// WHAT I NEED TO DO HERE
}
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS)
{
// WHAT I NEED TO DO HERE
}
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS)
{
// WHAT I NEED TO DO HERE
}
if (glfwGetKey(window, GLFW_KEY_BOTTOM) == GLFW_PRESS)
{
// WHAT I NEED TO DO HERE
}
return 1;
}
return 0;
}
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(800, 800, "Game Engine", NULL,
NULL);
if (!window)
{
cout << "Failed to create a window" << endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
cout << "Failed to initialize GLAD" << endl;
return -1;
}
DrawCircle();
glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(blueSquareVertices), blueSquareVertices, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao[0]);
glBindVertexArray(vao[0]);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3));
glGenBuffers(1, &ibo[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(blueSqaureIndices), blueSqaureIndices, GL_STATIC_DRAW);
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vertices.size(), &vertices[0], GL_STATIC_DRAW);
glGenVertexArrays(1, &vao[1]);
glBindVertexArray(vao[1]);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
Shader shader("vs2.glsl", "fs2.glsl");
shader.useShader();
while (!glfwWindowShouldClose(window))
{
inputKeys(window);
circleRect(window);
glClearColor(0.6f, 0.8f, 0.8f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glm::mat4 blueSquareTransform(1.0f);
blueSquareTransform = glm::translate(blueSquareTransform,
glm::vec3(blueSquarePosition));
GLuint blueSquareTransformUniform =
glGetUniformLocation(shader.shader, "transform");
glUniformMatrix4fv(blueSquareTransformUniform, 1, GL_FALSE,
glm::value_ptr(blueSquareTransform));
glBindVertexArray(vao[0]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glm::mat4 redSquareTransform(1.0f);
redSquareTransform = glm::translate(redSquareTransform,
glm::vec3(spherePosition));
GLuint redSquareTransformUniform = glGetUniformLocation(shader.shader,
"transform");
glUniformMatrix4fv(redSquareTransformUniform, 1, GL_FALSE,
glm::value_ptr(redSquareTransform));
glBindVertexArray(vao[1]);
glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size());
glfwSwapBuffers(window);
glfwPollEvents();
}
}
In order to perform collision detection and preventing penetration, you need
previous position
current position
The first issue is that at the "WHAT I NEED TO DO HERE" line, you already seem to miss the previous position. Once you have both, you need to do:
If current position collides, binary-search along the line from current to previous position where the switch occurs.
You need to be able to linear interpolate the position where 0 is previous and 1 is current.
Then, if you want to do nice, as opposed to just OK, you then compute a collision, update the direction and repeat for the remaining length.

OpenGL 3.3 C++ drawing a line for orbit path for a solar system

I'm currently working on an assignment on creating a solar system using openGL. I've managed to create the planets, orbit of planet around the sun, and rotation of each planet axis.
i'm stuck on how do i dynamically draw a line for the orbit path for the planets. so that even if the orbit path changes the line would change.(those thin lines that shows the orbit path in most solar system images)
Hope to get a direction to work towards to instead of the answer.
Thanks ahead for the replies (if any)
P.S : Using GLFW not GLUT library. Below is what i have so far
static void init(GLFWwindow* window)
{
glEnable(GL_DEPTH_TEST);
// Create the shader object
g_shaderProgramID = loadShaders("ModelSpaceVS.vert", "ColorFS.frag");
// Getting Locations of shader's variables
GLuint positionIndex = glGetAttribLocation(g_shaderProgramID, "aPosition");
GLuint colorIndex = glGetAttribLocation(g_shaderProgramID, "aColor");
g_modelMatrixIndex = glGetUniformLocation(g_shaderProgramID, "uModelMatrix");
// Creating camera object
// Set camera's view matrix
g_camera.setViewMatrix(vec3(0.0f, 15.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f), vec3(0, 1, 0));
// Window Aspect Ratio
int width, height;
glfwGetFramebufferSize(window, &width, &height);
float aspectRatio = static_cast<float>(width) / height;
// Set camera's projection matrix
g_camera.setProjectionMatrix(perspective(45.0f, aspectRatio, 0.1f, 100.0f));
// Initialise the model matrix to identity matrix
// Set to 1.0f so that during the transformation process where
// the matrix is multiplied, it would be 1*<value> = <value>
// The transformation && scale && rotate are placed in the update_scene Function
// as the update scene needs to update the orbitting value as well
g_modelMatrix[0] = mat4(1.0f);
g_modelMatrix[1] = mat4(1.0f);
g_modelMatrix[2] = mat4(1.0f);
g_modelMatrix[3] = mat4(1.0f);
g_modelMatrix[4] = mat4(1.0f);
// Generate identifier for VBO and copy data to GPU
glGenBuffers(4, g_VBO);
// Binding the vertices for the planet (Only 1 vertices for sun + 4 planets)
// Transformation is not done here
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(planetOrigin), planetOrigin, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_VBO[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_indices), g_indices, GL_STATIC_DRAW);
// Line Vertex
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]); // Binding the VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(linePos), linePos, GL_STATIC_DRAW); // Copy data to buffer
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[3]); // Binding the VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(lineColor), lineColor, GL_STATIC_DRAW); // Copy data to buffer
// generate identifiers for VAOs
glGenVertexArrays(2, g_VAO);
// create VAO and specify VBO data
glBindVertexArray(g_VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_VBO[1]);
// interleaved attributes
glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertices), reinterpret_cast<void*>(offsetof(Vertices, position)));
glVertexAttribPointer(colorIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertices), reinterpret_cast<void*>(offsetof(Vertices, color)));
glEnableVertexAttribArray(positionIndex); // enable vertex attributes
glEnableVertexAttribArray(colorIndex);
// Binding the VBO to a VAO
// Lines
glBindVertexArray(g_VAO[1]); // Create the VAO object
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[3]);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
}
// Keyboard Input Actions
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
// Exit the program on ESC
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
{
// Closes the window and end the program
glfwSetWindowShouldClose(window, GL_TRUE);
return;
}
else if (key == GLFW_KEY_P && action == GLFW_PRESS)
{
// Animating the planets Orbit around the sun
// and also their own individual rotation about their own axis
if (animate == false)
animate = true;
else if (animate == true)
animate = false;
}
else if (key == GLFW_KEY_R && action == GLFW_PRESS)
{
// Randomize the Size / Orbit Speed Around the Sun / Rotation Speed about their own axis
// of all the planet and the sun
//
//
// Rand + 100 to prevent the orbit or rotationSpeed from being 0
// Or being too low that it seems to stop
//
// Randomizing the orbitSpeed of planet
// Capping the orbit Speed at 300, minimum 100
orbitSpeed = (rand() % 200) + 100;
// Randomizing the rotationSpeed of planet + sun
// upon its own axis
// Capping the rotation Speed at 300, minimum 100
rotationSpeed = (rand() % 200) + 100;
// Randomizing the planet/sun size
// Values of the rand() is to ensure the planet will never be bigger than the sun
// rand() % 3 / 10 + 0.7 = min : 0.7, Max : 1.0
// rand() % 5 / 10 + 0.2 = min : 0.2, Max : 0.7
sunSize = (rand() % 2) + 3.0;
planetSize1 = (rand() % 2) + 0.9;
planetSize2 = (rand() % 2) + 0.9;
planetSize3 = (rand() % 2) + 0.9;
planetSize4 = (rand() % 2) + 0.9;
}
else if (key == GLFW_KEY_1 && action == GLFW_PRESS)
{
// Set the camera view to a far-away top down view of the
// solar system
// Looks like a RTS camera style
// Set camera's view matrix
g_camera.setViewMatrix(vec3(0.0f, 10.0f, 20.0f), vec3(0.0f, 0.0f, 0.0f), vec3(0, 1, 0));
}
else if (key == GLFW_KEY_2 && action == GLFW_PRESS)
{
// Set the camera view to a top down view
// directly looking at it from above
// Set camera's view matrix
g_camera.setViewMatrix(vec3(0.0f, 20.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f), vec3(0, 1.0, 0));
}
}
static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
{
// variables to store mouse cursor coordinates
static double previous_xpos = xpos;
static double previous_ypos = ypos;
double delta_x = xpos - previous_xpos;
double delta_y = ypos - previous_ypos;
// pass mouse movement to camera class
g_camera.updateYaw(delta_x);
g_camera.updatePitch(delta_y);
// update previous mouse coordinates
previous_xpos = xpos;
previous_ypos = ypos;
}
// Frame Buffer Action
static void framebuffer_Size_callback(GLFWwindow* window, int width, int height)
{
string title = "Assignment 1 - " + to_string(width) + " x " + to_string(height);
glfwSetWindowTitle(window, title.c_str());
}
// error callback function
static void error_callback(int error, const char* description)
{
// output error description
cerr << "Error Occurred: " << description << endl;
}
// Update Scene Function
// Updates the "planet" solitary rotation about its own axis
// Updates the "planet" orbit around a point around the "sun"
static void update_scene(GLFWwindow* window, double frameTime)
{
static float rotateAngleY = 0.0f;
static float rotateAngleY1 = 0.0f;
static float rotateAngleY2 = 0.0f;
static float rotateAngleY3 = 0.0f;
static float sunRotateAngleY = 0.0f;
static float orbitAngle1 = 0.0f;
static float orbitAngle2 = 0.0f;
static float orbitAngle3 = 0.0f;
static float orbitAngle4 = 0.0f;
if (animate == true)
{
rotateAngleY += 1.5 * rotationSpeed * frameTime;
rotateAngleY1 += 1.0 * rotationSpeed * frameTime;
rotateAngleY2 -= 2.0 * rotationSpeed * frameTime;
rotateAngleY3 -= 2.5 * rotationSpeed * frameTime;
sunRotateAngleY += 0.1 * rotationSpeed * frameTime;
orbitAngle1 += 0.6 * orbitSpeed * frameTime;
orbitAngle2 += 0.5 * orbitSpeed * frameTime;
orbitAngle3 += 0.2 * orbitSpeed * frameTime;
orbitAngle4 += 0.1 * orbitSpeed * frameTime;
}
// Updating the Scene the rotate the individual planets
// Each of the planet needs their initial translate/scale value
// if the transform/scale here is vec(0.0,0.0,0.0) || vec3(1.0,1.0,1.0)
// They will be rendered on the origin, which is where the sun is
// at the same size
//
// rotate(radians(orbitAngle1), vec3(0.0f, 1.0f, 0.0f)) - Controls Orbit Rotation of Planet
// rotate(radians(rotateAngleY), vec3(1.0f, 1.0f, 0.0f)) - Controls Orbit About Own Axis
// rotate(radians(-60.0f), vec3(0.0f, 0.0f, 1.0f)) - Controls the rotation of a planet on display(without movement)
g_modelMatrix[0] = translate(vec3(0.0f, 0.0, 0.0f)) * rotate(radians(sunRotateAngleY), vec3(0.0, 1.0, 0.0f))
* scale(vec3(1.0f, 1.0f, 1.0f) * sunSize);
g_modelMatrix[1] = rotate(radians(orbitAngle1), vec3(0.0f, 1.0f, 0.0f)) * translate(vec3(2.0f, 0.0f, 0.0f) + (sunSize/10)) * rotate(radians(rotateAngleY), vec3(0.0f, 1.0f, 0.0f))
* rotate(radians(-60.0f), vec3(0.0f, 0.0f, 1.0f)) * scale(vec3(1.0f, 1.0f, 1.0f) * planetSize1);
g_modelMatrix[2] = rotate(radians(orbitAngle2), vec3(0.0f, 1.0f, 0.0f)) * translate(vec3(4.0f, 0.0f, 0.0f) + (sunSize/10)) * rotate(radians(rotateAngleY1), vec3(0.0f, 1.0f, 0.0f))
* rotate(radians(-45.0f), vec3(0.0f, 0.0f, 1.0f)) * scale(vec3(1.0f, 1.0f, 1.0f)* planetSize2);
g_modelMatrix[3] = rotate(radians(orbitAngle3), vec3(0.0f, 1.0f, 0.0f)) * translate(vec3(6.0f, 0.0f, 0.0f) + (sunSize/10)) * rotate(radians(rotateAngleY2), vec3(0.0f, 1.0f, 0.0f))
* rotate(radians(45.0f), vec3(0.0f, 0.0f, 1.0f)) * scale(vec3(1.0f, 1.0f, 1.0f) * planetSize3);
g_modelMatrix[4] = rotate(radians(orbitAngle4), vec3(0.0f, 1.0f, 0.0f)) * translate(vec3(8.0f, 0.0f, 0.0f) + (sunSize/10)) * rotate(radians(rotateAngleY), vec3(0.0f, 1.0f, 0.0f))
* rotate(radians(60.0f), vec3(0.0f, 0.0f, 1.0f)) * scale(vec3(1.0f, 1.0f, 1.0f) * planetSize4);
}
// Render Scene Function
static void render_scene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear colour buffer && clear depth buffer
glUseProgram(g_shaderProgramID);
// Make VAO active
glBindVertexArray(g_VAO[0]);
// Sun Object
// compute multiplication of model, view and projection matrices
mat4 MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[0];
glUniformMatrix4fv(g_modelMatrixIndex, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
// Planet 1
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[1];
glUniformMatrix4fv(g_modelMatrixIndex, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
// Planet 2
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[2];
glUniformMatrix4fv(g_modelMatrixIndex, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
// Planet 3
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[3];
glUniformMatrix4fv(g_modelMatrixIndex, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
// Planet 4
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[4];
glUniformMatrix4fv(g_modelMatrixIndex, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
glFlush(); // Flushing the pipelines
}
// ------------------------------------------------------------------------------------
// Main Function
int main(void)
{
srand(time(NULL));
GLFWwindow* window = NULL; // Creating of window variable
glfwSetErrorCallback(error_callback);
// Initialise glfw
// if false = failed initialization
if (!glfwInit())
{
cout << "glfw Initialisation failed" << endl;
exit(EXIT_FAILURE);
}
// Declaring the version of OpenGL
// Version 3.3 in this case
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Creating the window object
window = glfwCreateWindow(1080, 720, "Assignment 2 - 1080 x 720", NULL, NULL);
// Check if the Creating of window Object succeeded
if (window == NULL)
{
cout << "Creation of window failed" << endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
// Making Context Current
glfwMakeContextCurrent(window);
// Determine Swap Buffer Interval
glfwSwapInterval(1);
// Set a background color for window
// Black - Solar System in space
glClearColor(0.0, 0.0, 0.0, 1.0);
// Initialise GLEW
if (glewInit() != GLEW_OK)
{
cout << "Initialisation of GLEW failed" << endl;
exit(EXIT_FAILURE);
}
// Keyboard/Mouse Input/Callbacks
glfwSetFramebufferSizeCallback(window, framebuffer_Size_callback);
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, cursor_position_callback);
// Init function
init(window);
// Frame Variables
double lastUpdateTime = glfwGetTime(); // last update time
double elapsedTime = lastUpdateTime; // time elapsed since last update
double frameTime = 0.0f; // frame time
int frameCount = 0; // number of frames since last update
// Rendering Loop
while (!glfwWindowShouldClose(window))
{
g_camera.update(window);
update_scene(window, frameTime);
render_scene();
// Swap Buffer
glfwSwapBuffers(window);
// Poll Events
glfwPollEvents();
frameCount++;
elapsedTime = glfwGetTime() - lastUpdateTime; // current time - last update time
if (elapsedTime >= 1.0f) // if time since last update >= to 1 second
{
frameTime = 1.0f / frameCount; // calculate frame time
string str = "FPS = " + to_string(frameCount) + "; FT = " + to_string(frameTime);
glfwSetWindowTitle(window, str.c_str()); // update window title
frameCount = 0; // reset frame count
lastUpdateTime += elapsedTime; // update last update time
}
}
// Cleaning Up Shader Program
glDeleteProgram(g_shaderProgramID);
// Cleaning Up Vertexes
glDeleteBuffers(14, g_VBO);
glDeleteVertexArrays(2, g_VAO);
// Destroying the window before terminating the program
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}

OpenGL/GLFW/GLM - keyboard input unresponsive

I have been following along with this tutorial series, whilst customising the code for my own goals (to render a 3D point cloud). I am able to render and move the point cloud around based on the mouse_input callback and can scroll in/out using the scroll callback. From what I've read/understood, the camera should be able to orbit around the point cloud (model) via the keyboard input. I am using W,S,A,D as forward, back, left, right inputs. I've tried lowercase and uppercase input (dont know if that makes a difference). I cant seem to get a response from the model.
I have gone over the code a few times and really can't see where I am going wrong.
Code below.
I am using Visual Studio 2017 Community.
Source.cpp
#include <glad/glad.h>
#include <C:\\Users\\jhansen\\Desktop\\OpenGL\\glad\\KHR\\khrplatform.h>
#include <C:\\Users\\jhansen\\Desktop\\OpenGL\\glad\\glad.c>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <Shader.h>
#include <Camera.h>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 800;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;
// timing
float deltaTime = 0.0f; // time between current frame and last frame
float lastFrame = 0.0f;
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
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); // uncomment this statement to fix compilation on OS X
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
// tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// configure global opengl state
// -----------------------------
glEnable(GL_DEPTH_TEST);
Shader ourShader("VertexShader.vs",
"FragShader.fs");
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
struct Point
{
float x;
float y;
float z;
};
Point points[32000];
// Generate 32000 points
for (int i = 0; i < 32000; i++)
{
points[i].x = (float)((rand() % SCR_WIDTH) + 1);
points[i].y = (float)((rand() % SCR_WIDTH) + 1);
points[i].z = (float)((rand() % SCR_WIDTH) + 1);
// X Coords to Normalised Device coordinates
if (points[i].x > 400)
{
points[i].x = points[i].x * 0.00125f;
}
else if (points[i].x < 400)
{
points[i].x = points[i].x * -0.00125f;
}
else if (points[i].x == 400)
{
points[i].x = 0.0f;
}
// Y Coords to Normalised Device coordinates
if (points[i].y > 400)
{
points[i].y = points[i].y * 0.00125f;
}
else if (points[i].y < 400)
{
points[i].y = points[i].y * -0.00125f;
}
else if (points[i].y == 400)
{
points[i].y = 0.0f;
}
// Z Coords to Normalised Device coordinates
if (points[i].z > 400)
{
points[i].z = points[i].z * 0.00125f;
}
else if (points[i].z < 400)
{
points[i].z = points[i].z * -0.00125f;
}
else if (points[i].z == 400)
{
points[i].z = 0.0f;
}
//cout << points[i].x << ", " << points[i].y << ", " << points[i].z << endl;
}
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray(0);
// uncomment this call to draw in wireframe polygons.
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window);
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// activate shader
ourShader.use();
// pass projection matrix to shader (note that in this case it could change every frame)
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
ourShader.setMat4("projection", projection);
// camera/view transformation
glm::mat4 view = camera.GetViewMatrix();
ourShader.setMat4("view", view);
glm::mat4 model;
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.3f, 0.5f));
ourShader.setMat4("model", model);
// draw our points array
//glUseProgram(shaderProgram);
glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
glPointSize(3.0f);
glDrawArrays(GL_POINTS, 0, 32000);
// glBindVertexArray(0); // no need to unbind it every time
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset);
}
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
camera.ProcessMouseScroll(yoffset);
}
Camera.h
#ifndef CAMERA_H
#define CAMERA_H
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <vector>
// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
enum Camera_Movement {
FORWARD,
BACKWARD,
LEFT,
RIGHT
};
// Default camera values
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVTY = 0.1f;
const float ZOOM = 45.0f;
// An abstract camera class that processes input and calculates the corresponding Eular Angles, Vectors and Matrices for use in OpenGL
class Camera
{
public:
// Camera Attributes
glm::vec3 Position;
glm::vec3 Front;
glm::vec3 Up;
glm::vec3 Right;
glm::vec3 WorldUp;
// Eular Angles
float Yaw;
float Pitch;
// Camera options
float MovementSpeed;
float MouseSensitivity;
float Zoom;
// Constructor with vectors
Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM)
{
Position = position;
WorldUp = up;
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
// Constructor with scalar values
Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM)
{
Position = glm::vec3(posX, posY, posZ);
WorldUp = glm::vec3(upX, upY, upZ);
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
// Returns the view matrix calculated using Eular Angles and the LookAt Matrix
glm::mat4 GetViewMatrix()
{
return glm::lookAt(Position, Position + Front, Up);
}
// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void ProcessKeyboard(Camera_Movement direction, float deltaTime)
{
float velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Front * velocity;
if (direction == BACKWARD)
Position -= Front * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
}
// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true)
{
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;
Yaw += xoffset;
Pitch += yoffset;
// Make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
// Update Front, Right and Up Vectors using the updated Eular angles
updateCameraVectors();
}
// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
void ProcessMouseScroll(float yoffset)
{
if (Zoom >= 1.0f && Zoom <= 45.0f)
Zoom -= yoffset;
if (Zoom <= 1.0f)
Zoom = 1.0f;
if (Zoom >= 45.0f)
Zoom = 45.0f;
}
private:
// Calculates the front vector from the Camera's (updated) Eular Angles
void updateCameraVectors()
{
// Calculate the new Front vector
glm::vec3 front;
front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
front.y = sin(glm::radians(Pitch));
front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Front = glm::normalize(front);
// Also re-calculate the Right and Up vector
Right = glm::normalize(glm::cross(Front, WorldUp)); // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
Up = glm::normalize(glm::cross(Right, Front));
}
};
#endif
This might help you as a good reference for this is out of my Player::move() method where different movements are enumerated types.
// -----------------------------------------------------------------------
// move()
// Move The Player In A Desired Direction
void Player::move( Action action, float fDeltaTime ) {
Vector3 v3LookDirection;
v3LookDirection = m_v3LookCenter - m_v3Position;
switch ( action ) {
case MOVING_FORWARD: {
// Prevent Vertical Motion
v3LookDirection.m_fY = 0.0f;
m_v3Position += v3LookDirection * fDeltaTime * m_fLinearSpeed;
m_v3LookCenter += v3LookDirection * fDeltaTime * m_fLinearSpeed;
break;
}
case MOVING_BACK: {
// Prevent Vertical Motion
v3LookDirection.m_fY = 0.0f;
m_v3Position -= v3LookDirection * fDeltaTime * m_fLinearSpeed;
m_v3LookCenter -= v3LookDirection * fDeltaTime * m_fLinearSpeed;
break;
}
case MOVING_LEFT: {
// Get "Side" Direction & Prevent Vertical Motion
v3LookDirection.m_fY = v3LookDirection.m_fX;
v3LookDirection.m_fX = -v3LookDirection.m_fZ;
v3LookDirection.m_fZ = v3LookDirection.m_fY;
v3LookDirection.m_fY = 0.0f;
m_v3Position -= v3LookDirection * fDeltaTime * m_fLinearSpeed;
m_v3LookCenter -= v3LookDirection * fDeltaTime * m_fLinearSpeed;
break;
}
case MOVING_RIGHT: {
// Get "Side" Direction & Prevent Vertical Motion
v3LookDirection.m_fY = v3LookDirection.m_fX;
v3LookDirection.m_fX = -v3LookDirection.m_fZ;
v3LookDirection.m_fZ = v3LookDirection.m_fY;
v3LookDirection.m_fY = 0.0f;
m_v3Position += v3LookDirection * fDeltaTime * m_fLinearSpeed;
m_v3LookCenter += v3LookDirection * fDeltaTime * m_fLinearSpeed;
break;
}
case LOOKING_LEFT: {
/*float fSin = -sin( fDeltaTime * m_fAngularSpeed );
float fCos = cos( fDeltaTime * m_fAngularSpeed );
m_v3LookCenter.m_fX = m_v3Position.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
m_v3LookCenter.m_fZ = m_v3Position.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
break;*/
// Third Person
float fSin = sin( fDeltaTime * m_fAngularSpeed );
float fCos = -cos( fDeltaTime * m_fAngularSpeed );
m_v3Position.m_fX = m_v3LookCenter.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
m_v3Position.m_fZ = m_v3LookCenter.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
break;
}
case LOOKING_RIGHT: {
/*float fSin = sin( fDeltaTime * m_fAngularSpeed );
float fCos = cos( fDeltaTime * m_fAngularSpeed );
m_v3LookCenter.m_fX = m_v3Position.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
m_v3LookCenter.m_fZ = m_v3Position.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
break;*/
// Third Person
float fSin = -sin( fDeltaTime * _fAngularSpeed );
float fCos = -cos( fDeltaTime * _fAngularSpeed );
m_v3Position.m_fX = m_v3LookCenter.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
m_v3Position.m_fZ = m_v3LookCenter.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
break;
}
case LOOKING_UP: {
m_v3LookCenter.m_fY -= fDeltaTime * m_fAngularSpeed * m_MouseLookState;
// Check Maximum Values
if ( m_v3LookCenter.m_fY > (m_v3Position.m_fY + m_fMaxUp ) ) {
m_v3LookCenter.m_fY = m_v3Position.m_fY + m_fMaxUp;
} else if ( m_v3LookCenter.m_fY < (m_v3Position.m_fY - m_fMaxDown) ) {
m_v3LookCenter.m_fY = m_v3Position.m_fY - _fMaxDown;
}
break;
}
}
} // move
This is coming from an old project when I was learning OpenGL 1.0 (Legacy). Everything was done manually without existing libraries; even had to write a few vector libraries. This player class is independent from the Camera class but gets it's position and look direction vectors from it. These are tightly integrated into an GameOGL class that creates a window, message proc, message handler and sets up all of OpenGL stuff as well as a very large Scene class object. The math used here works as this belongs to a 3D Game Engine in which a Third Person View dungeon type game is made. Just make sure you are using the appropriate rotation matrices and trig methods for doing rotations based on the handedness of your 3D graph system.
Also the rotational motion that you are trying to achieve might be different. This causes the player - camera to turn left and right as if you are looking into the distance. The type of rotation you might want would be almost considered the inverse of that where your looking direction & distance remains fixed to the model but your camera is rotating through the world at a specific rotational velocity.

Changing the view to object in OpenGL

I'm trying to play around with OpenGL and this is my very first code. How can I change to different view to 2 object drawn on the screen?
Is there anyway to do this manually, in stead of using function gluPerspective()?
I tried glRotatef(60, 0.0, 0.0, 5.0) but there is nothing happen. Cos I want to see other faces of the Pyramid and also different view of the rotating sphere.
Also I want to set different colours to different objects that I draw on the screen, how can I do that?
The code to set colour for each object, which is glColor3f, I put it in between glPushMatrix() and glPopMatrix(), also I always include the line glLoadIdentity() before starting draw objects on screen. As far as I know, this line will reset the settings of the previous objects and allows me to set new properties for new object.
Then why when I press button D, the sphere is blue when it supposes to be in white?
Here is my full code:
#include <windows.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <math.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define X .525731112119133606
#define Z .850650808352039932
#define Y 0.0
#define PI 3.1415926535898
#define CIRCLE_STEP 5000
using namespace std;
// Open an OpenGL window
GLFWwindow* window;
int keyboard = 0, itr;
bool big_Sphere = true, sphereWithNormalV = false, animation = false;
GLdouble angle = 0;
/****Step 1: define vertices in (x, y, z) form****/
// Coordinates to draw a Icosahedron
GLfloat icoVertices[12][3] = {
{-X, Y, Z}, {X, Y, Z}, {-X, Y, -Z}, {X, Y, -Z},
{Y, Z, X}, {Y, Z, -X}, {Y, -Z, X}, {Y, -Z, -X},
{Z, X, Y}, {-Z, X, Y}, {Z, -X, Y}, {-Z, -X, Y}
};
// Coordinates to draw a Pyramid
GLfloat pyVertices[4][3] = {
{0.0f, 1.0f, 0.0f},
{1.0f, 0.0f, 0.0f},
{-1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, -1.0f}
};
static GLuint icoIndices[20][3] = {
{0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
{8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
{7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
{6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };
static GLuint pyIndices[4][3] = {
{0,1,2}, {0,1,3}, {0,2,3}, {1,2,3}
};
/************************/
void normalize3f(float v[3]) {
GLfloat d = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
if (d == 0.0) {
fprintf(stderr, "zero length vector");
return;
}
v[0] /= d; v[1] /= d; v[2] /= d;
}
void sphereNormalV(GLfloat p1[3], GLfloat p2[3], GLfloat p3[3])
{
glBegin(GL_LINES);
glVertex3f(p1[0] *1.5,p1[1] *1.5, p1[2] *1.5);
glVertex3fv(p1);
glEnd();
glBegin(GL_LINES);
glVertex3f(p2[0] *1.1,p2[1] *1.1, p2[2] *1.1);
glVertex3fv(p2);
glEnd();
glBegin(GL_LINES);
glVertex3f(p3[0] *1.1,p3[1] *1.1, p3[2] *1.1);
glVertex3fv(p3);
glEnd();
}
void drawtriangle(float *v1, float *v2, float *v3)
{
glBegin(GL_LINE_LOOP);
//glNormal3fv(v1);
glVertex3fv(v1);
//glNormal3fv(v2);
glVertex3fv(v2);
//glNormal3fv(v3);
glVertex3fv(v3);
glEnd();
}
void subdivide(GLfloat *v1, GLfloat *v2, GLfloat *v3, long depth)
{
GLfloat v12[3], v23[3], v31[3];
GLint i;
if (depth == 0){
drawtriangle(v1, v2, v3);
if (sphereWithNormalV == true){
sphereNormalV(v1, v2, v3);
}
return;
}
for (i = 0; i < 3; i++) {
v12[i] = v1[i]+v2[i];
v23[i] = v2[i]+v3[i];
v31[i] = v3[i]+v1[i];
}
normalize3f(v12);
normalize3f(v23);
normalize3f(v31);
subdivide(v1, v12, v31, depth-1);
subdivide(v2, v23, v12, depth-1);
subdivide(v3, v31, v23, depth-1);
subdivide(v12, v23, v31, depth-1);
}
void drawSphere(GLfloat x, GLfloat y, GLfloat z){
glLoadIdentity();
glPushMatrix();
if (big_Sphere == true){
glScaled(0.4, 0.55, 0.4);
}else{
glScaled(0.13, 0.18, 0.13);
}
if (animation){
glTranslatef(x, y, z);
}
glBegin(GL_LINE_LOOP);
for (int i = 0; i < 20; i++) {
subdivide(&icoVertices[icoIndices[i][0]][0], &icoVertices[icoIndices[i][1]][0], &icoVertices[icoIndices[i][2]][0], 3);
}
glEnd();
glPopMatrix();
}
void drawPyramid(){//(GLfloat x, GLfloat y, GLfloat z){
glLoadIdentity();
glPushMatrix();
glScaled(0.13, 0.18, 0.13);
glBegin(GL_LINE_LOOP);
for (int i = 0; i < 4; i++){
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3fv(pyVertices[pyIndices[i][0]]);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3fv(pyVertices[pyIndices[i][1]]);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3fv(pyVertices[pyIndices[i][2]]);
}
glEnd();
glPopMatrix();
}
int getKeyPressed(){
if (glfwGetKey(window, GLFW_KEY_A)){
keyboard = GLFW_KEY_A;
}
if (glfwGetKey(window, GLFW_KEY_B)){
keyboard = GLFW_KEY_B;
}
if (glfwGetKey(window, GLFW_KEY_C)){
keyboard = GLFW_KEY_A;
}
if (glfwGetKey(window, GLFW_KEY_D)){
keyboard = GLFW_KEY_D;
}
if (glfwGetKey(window, GLFW_KEY_E)){
keyboard = GLFW_KEY_E;
}
return keyboard;
}
void controlSphere(bool _big_Sphere, bool _sphereNormalV, bool _animation){
big_Sphere = _big_Sphere;
sphereWithNormalV = _sphereNormalV;
animation = _animation;
}
void gluPerspective(double fovy,double aspect, double zNear, double zFar)
{
// Start in projection mode.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double xmin, xmax, ymin, ymax;
ymax = zNear * tan(fovy * PI / 360.0);
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
}
int main( void ) {
if (!glfwInit()){
fprintf(stderr, "Failed to initialize GLFW.\n");
return -1;
}
// Create a windowed mode window and its OpenGL context
window = glfwCreateWindow(1100, 800, "Hello World", NULL, NULL);
if (window == NULL) {
fprintf(stderr, "glfw failed to create window.\n");
//glfwTerminate();
return -1;
}
// Make the window's context current
glfwMakeContextCurrent(window);
glewInit();
if (glewInit() != GLEW_OK){
fprintf(stderr, "Failed to initialize GLEW: %s.\n", glewGetErrorString(glewInit()));
return -1;
}
// 4x anti aliasing
glfwWindowHint(GLFW_SAMPLES, 4);
/**Step 3: Main loop for OpenGL draw the shape**
/* Main loop */
int i = 0;
GLfloat pos_X, pos_Y;
glRotatef(60, 0.0f, 0.3f, 0.4f);
do{
//glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT);
switch(getKeyPressed()){
case 65:
controlSphere(true, false, false);
drawSphere(0, 0, 0);
break;
case 66:
controlSphere(true, true, false);
drawSphere(0, 0, 0);
break;
case 67:
// drawPyramid();
break;
case 68:
// drawing a Sphere moving in a circular path
controlSphere(false, false, true);
angle = 2*PI*i/CIRCLE_STEP;
pos_X = cos(angle) * 4.5;
pos_Y = sin(angle) * 4.5;
drawSphere(pos_X, pos_Y, 0);
i += 1;
angle += 1;
if (angle >= 360){
angle = 0;
}
// drawing a Pyramid rotate around its y axis
drawPyramid();
break;
default:
controlSphere(true, false, false);
drawSphere(0, 0, 0);
break;
}
Sleep(1);
// Swap front and back rendering buffers
glfwSwapBuffers(window);
//Poll for and process events
glfwPollEvents();
} // check if the ESC key was pressed or the window was closed
while(glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && glfwWindowShouldClose(window) == 0);
/***********************************************/
// Close window and terminate GLFW
glfwDestroyWindow(window);
glfwTerminate();
// Exit program
exit( EXIT_SUCCESS );
}
Is there anyway to do this manually, in stead of using function gluPerspective()?
I don't really understand this question. But if you want to set multiples objects (that have the same parameters) with different transformations, scale, rotation and/or translation, you need to push this to the stack and then draw the desired object. A good starting point can be found here: http://www.songho.ca/opengl/gl_transform.html
Also I want to set different colours to different objects that I draw on the screen, how can I do that?
Your sphere is blue because the last call for glColor3f() was in drawPyramid().
You can change the color of your ball by just calling glColor3f (1.0f, 1.0f, 1.0f); in the beginning of its draw function:
void drawSphere (GLfloat x, GLfloat y, GLfloat z)
{
glColor3f (1.0f, 1.0f, 1.0f);
...
}
A really great site to learn OpenGL from the old pipeline (what you just implemented) to the new (GLSL) is http://www.lighthouse3d.com/tutorials/.
You are looking for Multiple viewports which allows the to split the screen. In your case two different viewports two different cameras(one for each) will be enough.
Check this post.