My ultimate goal is to render 1 million spheres of different sizes and colors at 60 fps. I want to be able to move the camera around the screen as well.
I have modified the code on this page of the tutorial I am studying to try to instance many spheres. However, I find that at as little as 64 spheres my fps falls below 60, and at 900 spheres my fps is a measly 4. My understanding of instancing is naive, but I believe that I should be getting more frames-per-second than this. 60 fps should be attainable with only 64 spheres. I believe that I am, in some way, causing the CPU and GPU to communicate more often than they should have to. So my question is: How do I instance so many objects (ideally millions) without causing the fps to fall low (ideally 60 fps)?
I am calculating fps by calculating (10 / time_elapsed) every 10 frames, where time_elapsed is the time that has elapsed since the last fps call. I am printing this out using printf on line 118 of my code.
I have been learning OpenGL through this tutorial and so I use 32-bit GLEW and 32-bit GLFW in Visual Studio 2013. I have 8 GB of RAM on a 64-bit operating system (Windows 7) with a 2.30 GHz CPU.
I have tried coding my own example based on the tutorial above. Source code:
(set line #2 to be the number of spheres to be instanced. Make sure line#2 has a whole-number square root. Set line 4 to be the detail of the sphere, the lowest it can go is 0. Higher number = more detailed.)
// Make sure NUM_INS is a square number
#define NUM_INS 1
// Detail up to 4 is probably good enough
#define SPHERE_DETAIL 4
#include <vector>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
// GL includes
#include "Shader.h"
// GLM Mathemtics
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
// Properties
GLuint screenWidth = 800, screenHeight = 600;
// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
std::vector<GLfloat> create_sphere(int recursion);
// The MAIN function, from here we start our application and run the Game loop
int main()
{
// Init GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed
glfwMakeContextCurrent(window);
// Set the required callback functions
glfwSetKeyCallback(window, key_callback);
// Initialize GLEW to setup the OpenGL Function pointers
glewExperimental = GL_TRUE;
glewInit();
// Define the viewport dimensions
glViewport(0, 0, screenWidth, screenHeight);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Comment to remove wireframe mode
// Setup OpenGL options
glEnable(GL_DEPTH_TEST);
// Setup and compile our shader(s)
Shader shader("core.vs", "core.frag");
// Generate a list of 100 quad locations/translation-vectors
std::vector<glm::vec2> translations(NUM_INS);
//glm::vec2 translations[NUM_INS];
int index = 0;
GLfloat offset = 1.0f / (float)sqrt(NUM_INS);
for (GLint y = -(float)sqrt(NUM_INS); y < (float)sqrt(NUM_INS); y += 2)
{
for (GLint x = -(float)sqrt(NUM_INS); x < (float)sqrt(NUM_INS); x += 2)
{
glm::vec2 translation;
translation.x = (GLfloat)x / (float)sqrt(NUM_INS) + offset;
translation.y = (GLfloat)y / (float)sqrt(NUM_INS) + offset;
translations[index++] = translation;
}
}
// Store instance data in an array buffer
GLuint instanceVBO;
glGenBuffers(1, &instanceVBO);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * NUM_INS, &translations[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// create 12 vertices of a icosahedron
std::vector<GLfloat> vv = create_sphere(SPHERE_DETAIL);
GLuint quadVAO, quadVBO;
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, vv.size() * sizeof(GLfloat), &vv[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat)));
// Also set instance data
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribDivisor(2, 1); // Tell OpenGL this is an instanced vertex attribute.
glBindVertexArray(0);
// For printing frames-per-second
float counter = 0;
double get_time = 0;
double new_time;
// Game loop
while (!glfwWindowShouldClose(window))
{
// Print fps by printing (number_of_frames / time_elapsed)
counter += 1;
if (counter > 10) {
counter -= 10;
new_time = glfwGetTime();
printf("fps: %.2f ", (10/(new_time - get_time)));
get_time = new_time;
}
// Check and call events
glfwPollEvents();
// Clear buffers
//glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw 100 instanced quads
shader.Use();
glm::mat4 model;
model = glm::rotate(model, 0.0f, glm::vec3(1.0f, 0.0f, 0.0f));
// Camera/View transformation
glm::mat4 view;
GLfloat radius = 10.0f;
GLfloat camX = sin(glfwGetTime()) * radius;
GLfloat camZ = cos(glfwGetTime()) * radius;
view = glm::lookAt(glm::vec3(camX, 0.0f, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
// Projection
glm::mat4 projection;
projection = glm::perspective(45.0f, (GLfloat)screenWidth / (GLfloat)screenHeight, 0.1f, 100.0f);
// Get the uniform locations
GLint modelLoc = glGetUniformLocation(shader.Program, "model");
GLint viewLoc = glGetUniformLocation(shader.Program, "view");
GLint projLoc = glGetUniformLocation(shader.Program, "projection");
// Pass the matrices to the shader
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));
glBindVertexArray(quadVAO);
glDrawArraysInstanced(GL_TRIANGLES, 0, vv.size() / 3, NUM_INS); // 100 triangles of 6 vertices each
glBindVertexArray(0);
// Swap the buffers
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
std::vector<GLfloat> add_color(std::vector<GLfloat> sphere) {
// Add color
std::vector<GLfloat> colored_sphere;
for (GLint i = 0; i < sphere.size(); i+=9) {
colored_sphere.push_back(sphere[i]);
colored_sphere.push_back(sphere[i+1]);
colored_sphere.push_back(sphere[i+2]);
colored_sphere.push_back(0.0f);
colored_sphere.push_back(0.0f);
colored_sphere.push_back(0.0f);
colored_sphere.push_back(sphere[i+3]);
colored_sphere.push_back(sphere[i+4]);
colored_sphere.push_back(sphere[i+5]);
colored_sphere.push_back(0.0f);
colored_sphere.push_back(0.0f);
colored_sphere.push_back(0.0f);
colored_sphere.push_back(sphere[i+6]);
colored_sphere.push_back(sphere[i+7]);
colored_sphere.push_back(sphere[i+8]);
colored_sphere.push_back(0.0f);
colored_sphere.push_back(0.0f);
colored_sphere.push_back(0.0f);
}
return colored_sphere;
}
std::vector<GLfloat> tesselate(std::vector<GLfloat> shape, int recursion) {
if (recursion > 0) {
std::vector<GLfloat> new_sphere = {};
for (GLint i = 0; i < shape.size(); i += 9) {
// 1.902113 approximately
GLfloat radius = sqrt(1.0f + pow((1.0f + sqrt(5.0f)) / 2.0f, 2));
// Every 9 points is a triangle. Take 1 triangle and turn it into 4 triangles.
GLfloat p_one[] = {shape[i], shape[i + 1], shape[i + 2]};
GLfloat p_two[] = {shape[i + 3], shape[i + 4], shape[i + 5]};
GLfloat p_thr[] = {shape[i + 6], shape[i + 7], shape[i + 8]};
GLfloat p_one_two[] = { (p_one[0] + p_two[0]) / 2.0f, (p_one[1] + p_two[1]) / 2.0f, (p_one[2] + p_two[2]) / 2.0f };
GLfloat p_one_thr[] = { (p_one[0] + p_thr[0]) / 2.0f, (p_one[1] + p_thr[1]) / 2.0f, (p_one[2] + p_thr[2]) / 2.0f };
GLfloat p_two_thr[] = { (p_two[0] + p_thr[0]) / 2.0f, (p_two[1] + p_thr[1]) / 2.0f, (p_two[2] + p_thr[2]) / 2.0f };
GLfloat r_one_two = sqrt((p_one_two[0]*p_one_two[0]) + (p_one_two[1]*p_one_two[1]) + (p_one_two[2]*p_one_two[2]));
GLfloat r_one_thr = sqrt((p_one_thr[0]*p_one_thr[0]) + (p_one_thr[1]*p_one_thr[1]) + (p_one_thr[2]*p_one_thr[2]));
GLfloat r_two_thr = sqrt((p_two_thr[0]*p_two_thr[0]) + (p_two_thr[1]*p_two_thr[1]) + (p_two_thr[2]*p_two_thr[2]));
GLfloat t_one_two[] = { radius * p_one_two[0] / r_one_two, radius * p_one_two[1] / r_one_two, radius * p_one_two[2] / r_one_two };
GLfloat t_one_thr[] = { radius * p_one_thr[0] / r_one_thr, radius * p_one_thr[1] / r_one_thr, radius * p_one_thr[2] / r_one_thr };
GLfloat t_two_thr[] = { radius * p_two_thr[0] / r_two_thr, radius * p_two_thr[1] / r_two_thr, radius * p_two_thr[2] / r_two_thr };
// Triangle 1:
new_sphere.push_back(p_one[0]);
new_sphere.push_back(p_one[1]);
new_sphere.push_back(p_one[2]);
new_sphere.push_back(t_one_two[0]);
new_sphere.push_back(t_one_two[1]);
new_sphere.push_back(t_one_two[2]);
new_sphere.push_back(t_one_thr[0]);
new_sphere.push_back(t_one_thr[1]);
new_sphere.push_back(t_one_thr[2]);
// Triangle 2:
new_sphere.push_back(p_two[0]);
new_sphere.push_back(p_two[1]);
new_sphere.push_back(p_two[2]);
new_sphere.push_back(t_one_two[0]);
new_sphere.push_back(t_one_two[1]);
new_sphere.push_back(t_one_two[2]);
new_sphere.push_back(t_two_thr[0]);
new_sphere.push_back(t_two_thr[1]);
new_sphere.push_back(t_two_thr[2]);
// Triangle 3:
new_sphere.push_back(p_thr[0]);
new_sphere.push_back(p_thr[1]);
new_sphere.push_back(p_thr[2]);
new_sphere.push_back(t_one_thr[0]);
new_sphere.push_back(t_one_thr[1]);
new_sphere.push_back(t_one_thr[2]);
new_sphere.push_back(t_two_thr[0]);
new_sphere.push_back(t_two_thr[1]);
new_sphere.push_back(t_two_thr[2]);
// Center Triangle:
new_sphere.push_back(t_one_two[0]);
new_sphere.push_back(t_one_two[1]);
new_sphere.push_back(t_one_two[2]);
new_sphere.push_back(t_one_thr[0]);
new_sphere.push_back(t_one_thr[1]);
new_sphere.push_back(t_one_thr[2]);
new_sphere.push_back(t_two_thr[0]);
new_sphere.push_back(t_two_thr[1]);
new_sphere.push_back(t_two_thr[2]);
}
return tesselate(new_sphere, recursion - 1);
}
printf("number of vertices to be rendered: %d || ", shape.size());
return shape;
}
std::vector<GLfloat> create_sphere(int recursion) {
// Define the starting icosahedron
GLfloat t_ = (1.0f + sqrt(5.0f)) / 2.0f;
std::vector<GLfloat> icosahedron = {
-1.0f, t_, 0.0f, -t_, 0.0f, 1.0f, 0.0f, 1.0f, t_,
-1.0f, t_, 0.0f, 0.0f, 1.0f, t_, 1.0f, t_, 0.0f,
-1.0f, t_, 0.0f, 1.0f, t_, 0.0f, 0.0f, 1.0f, -t_,
-1.0f, t_, 0.0f, 0.0f, 1.0f, -t_, -t_, 0.0f, -1.0f,
-1.0f, t_, 0.0f, -t_, 0.0f, -1.0f, -t_, 0.0f, 1.0f,
1.0f, t_, 0.0f, 0.0f, 1.0f, t_, t_, 0.0f, 1.0f,
0.0f, 1.0f, t_, -t_, 0.0f, 1.0f, 0.0f, -1.0f, t_,
-t_, 0.0f, 1.0f, -t_, 0.0f, -1.0f, -1.0f, -t_, 0.0f,
-t_, 0.0f, -1.0f, 0.0f, 1.0f, -t_, 0.0f, -1.0f, -t_,
0.0f, 1.0f, -t_, 1.0f, t_, 0.0f, t_, 0.0f, -1.0f,
1.0f, -t_, 0.0f, t_, 0.0f, 1.0f, 0.0f, -1.0f, t_,
1.0f, -t_, 0.0f, 0.0f, -1.0f, t_,-1.0f, -t_, 0.0f,
1.0f, -t_, 0.0f,-1.0f, -t_, 0.0f, 0.0f, -1.0f, -t_,
1.0f, -t_, 0.0f, 0.0f, -1.0f, -t_, t_, 0.0f, -1.0f,
1.0f, -t_, 0.0f, t_, 0.0f, -1.0f, t_, 0.0f, 1.0f,
0.0f, -1.0f, t_, t_, 0.0f, 1.0f, 0.0f, 1.0f, t_,
-1.0f, -t_, 0.0f, 0.0f, -1.0f, t_,-t_, 0.0f, 1.0f,
0.0f, -1.0f, -t_,-1.0f, -t_, 0.0f,-t_, 0.0f, -1.0f,
t_, 0.0f, -1.0f, 0.0f, -1.0f, -t_, 0.0f, 1.0f, -t_,
t_, 0.0f, 1.0f, t_, 0.0f, -1.0f, 1.0f, t_, 0.0f,
};
// Tesselate the icososphere the number of times recursion
std::vector<GLfloat> colorless_sphere = tesselate(icosahedron, recursion);
// Add color and return
return add_color(colorless_sphere);
}
Vertex Shader: (named core.vs)
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 offset;
out vec3 fColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(position.x + offset.x, position.y + offset.y, position.z, 1.0f);
fColor = color;
}
Fragment Shader: (named core.frag)
#version 330 core
in vec3 fColor;
out vec4 color;
void main()
{
color = vec4(fColor, 1.0f);
}
Shader class: (named Shader.h)
#ifndef SHADER_H
#define SHADER_H
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <GL/glew.h>
class Shader
{
public:
GLuint Program;
// Constructor generates the shader on the fly
Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
{
// 1. Retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensures ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::badbit);
try
{
// Open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// Read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// Convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const GLchar* vShaderCode = vertexCode.c_str();
const GLchar * fShaderCode = fragmentCode.c_str();
// 2. Compile shaders
GLuint vertex, fragment;
GLint success;
GLchar infoLog[512];
// Vertex Shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
// Print compile errors if any
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
// Print compile errors if any
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Shader Program
this->Program = glCreateProgram();
glAttachShader(this->Program, vertex);
glAttachShader(this->Program, fragment);
glLinkProgram(this->Program);
// Print linking errors if any
glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// Delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
}
// Uses the current shader
void Use()
{
glUseProgram(this->Program);
}
};
#endif
My ultimate goal is to render 1 million spheres of different sizes and colors at 60 fps.
This is an unreasonable expectation.
Let's say that each sphere consists of 50 triangles. Kinda small for a good sphere shape, but lets assume they're that small.
1 million spheres at 50 tris per sphere is 50 million triangles per frame. At 60 FPS, that's 3 billion triangles per second.
No commercially available GPU is good enough to do that. And that's just a 50 triangle sphere; your 4x tessellated icosahedron will be over 5,000 triangles.
Now yes, drawing 60 such spheres is only ~300,000 triangles per frame. But even that at 60 FPS is ~18 million triangles per second. Hardware does exist that can handle that many triangles, but it's very clearly a lot. And you're definitely not going to get 1 million of them.
This is not a matter of GPU/CPU communication or overhead. You're simply throwing more work at your GPU than it could handle. You might be able to improve a couple of things here and there, but nothing that's going to get you even one tenth of what you want.
At least, not with this overall approach.
For your particular case of wanting to draw millions of spheres, I would use raytraced impostors rather than actual geometry of spheres. That is, you draw quads, who's positions are generated by the vertex (or geometry) shader. You generate a quad per sphere, such that the quad circumscribes the sphere. Then the fragment shader does a simple ray-sphere intersection test to see if the fragment in question (from the direction of the camera view) hits the sphere or not. If the ray doesn't hit the sphere, you discard the fragment.
You would also need to modify gl_FragDepth to give the impostor the proper depth value, so that intersecting spheres can work.
Related
I cannot figure out why the camera will not move when i move the mouse.
Here is my entire 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>
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 = "Tutorial 4.3"; // Macro for window title
// Variables for window width and height
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
// Stores the GL data relative to a given mesh
struct GLMesh
{
GLuint vao; // Handle for the vertex array object
GLuint vbo; // Handle for the vertex buffer object
GLuint nVertices; // Number of indices of the mesh
};
// Main GLFW window
GLFWwindow* gWindow = nullptr;
// Triangle mesh data
GLMesh gMesh;
// Shader program
GLuint gProgramId;
// camera
//Camera gCamera(glm::vec3(0.0f, 0.0f, 0.0f));
glm::vec3 gCameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 gCameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 gCameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
float gLastX = WINDOW_WIDTH / 2.0f;
float gLastY = WINDOW_HEIGHT / 2.0f;
bool gFirstMouse = true;
// timing
float gDeltaTime = 0.0f; // time between current frame and last frame
float gLastFrame = 0.0f;
// Default camera values
float Yaw = -90.0f;
float Pitch = 0.0f;
float cameraSpeed = 2.5f;
// camera options
float MovementSpeed;
float MouseSensitivity;
float Zoom;
}
/* 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 UMousePositionCallback(GLFWwindow* window, double xpos, double ypos);
void UMouseScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
void UMouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
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; // variable to transfer color data to the fragment shader
//Global 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); // transforms vertices to clip coordinates
vertexColor = color; // references incoming color data
}
);
/* Fragment Shader Source Code*/
const GLchar* fragmentShaderSource = GLSL(440,
in vec4 vertexColor; // Variable to hold incoming color data from vertex shader
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); // 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);
// render loop
// -----------
while (!glfwWindowShouldClose(gWindow))
{
// per-frame timing
// --------------------
float currentFrame = glfwGetTime();
gDeltaTime = currentFrame - gLastFrame;
gLastFrame = currentFrame;
// input
// -----
UProcessInput(gWindow);
// Render this frame
URender();
glfwPollEvents();
}
// 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);
glfwSetCursorPosCallback(*window, UMousePositionCallback);
glfwSetScrollCallback(*window, UMouseScrollCallback);
glfwSetMouseButtonCallback(*window, UMouseButtonCallback);
// tell GLFW to capture our mouse
glfwSetInputMode(*window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// 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 cameraOffset = cameraSpeed * gDeltaTime;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
gCameraPos += cameraOffset * gCameraFront;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
gCameraPos -= cameraOffset * gCameraFront;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
gCameraPos -= glm::normalize(glm::cross(gCameraFront, gCameraUp)) * cameraOffset;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
gCameraPos += glm::normalize(glm::cross(gCameraFront, gCameraUp)) * cameraOffset;
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
gCameraPos += cameraOffset * gCameraUp;
if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
gCameraPos -= cameraOffset * gCameraUp;
}
// 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);
}
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void UMousePositionCallback(GLFWwindow* window, double xpos, double ypos)
{
if (gFirstMouse)
{
gLastX = xpos;
gLastY = ypos;
gFirstMouse = false;
}
float xoffset = xpos - gLastX;
float yoffset = gLastY - ypos; // reversed since y-coordinates go from bottom to top
gLastX = xpos;
gLastY = ypos;
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;
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;
// update Front, Right and Up Vectors using the updated Euler angles
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));
gCameraFront = glm::normalize(front);
}
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void UMouseScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
cameraSpeed += yoffset;
cameraSpeed = std::fmaxf(cameraSpeed, 1);
cameraSpeed = std::fminf(cameraSpeed, 100);
}
// glfw: handle mouse button events
// --------------------------------
void UMouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
switch (button)
{
case GLFW_MOUSE_BUTTON_LEFT:
{
if (action == GLFW_PRESS)
cout << "Left mouse button pressed" << endl;
else
cout << "Left mouse button released" << endl;
}
break;
case GLFW_MOUSE_BUTTON_MIDDLE:
{
if (action == GLFW_PRESS)
cout << "Middle mouse button pressed" << endl;
else
cout << "Middle mouse button released" << endl;
}
break;
case GLFW_MOUSE_BUTTON_RIGHT:
{
if (action == GLFW_PRESS)
cout << "Right mouse button pressed" << endl;
else
cout << "Right mouse button released" << endl;
}
break;
default:
cout << "Unhandled mouse button event" << endl;
break;
}
}
// Function called to render a frame
void URender()
{
// Enable z-depth
glEnable(GL_DEPTH_TEST);
// 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(2.0f, 2.0f, 2.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;
// camera/view transformation
glm::mat4 view = glm::lookAt(gCameraPos, gCameraPos + gCameraFront, gCameraUp);
// Creates a perspective projection
glm::mat4 projection = glm::perspective(45.0f, (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));
// Activate the VBOs contained within the mesh's VAO
glBindVertexArray(gMesh.vao);
// Draws the triangles
glDrawArrays(GL_TRIANGLES, 0, gMesh.nVertices);
// 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)
{
// Vertex data
GLfloat verts[] = {
// Vertex Positions // Colors (r,g,b,a)
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top Vertex
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, // Front Bottom Right Vertex
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, // Front Bottom Left Vertex
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top Vertex
0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // Back Bottom Right Vertex
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 1.0f, // Back Bottom Left Vertex
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top Vertex
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 1.0f, // Back Bottom Left Vertex
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, // Front Bottom Left Vertex
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top Vertex
0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // Back Bottom Right Vertex
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, // Front Bottom Right Vertex
0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // Back Bottom Right Vertex
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, // Front Bottom Right Vertex
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, // Front Bottom Left Vertex
0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // Back Bottom Right Vertex
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 1.0f, // Back Bottom Left Vertex
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f // Front Bottom Left Vertex
};
const GLuint floatsPerVertex = 3;
const GLuint floatsPerColor = 4;
mesh.nVertices = sizeof(verts) / (sizeof(verts[0]) * (floatsPerVertex + floatsPerColor));
glGenVertexArrays(1, &mesh.vao); // we can also generate multiple VAOs or buffers at the same time
glBindVertexArray(mesh.vao);
// Create VBO
glGenBuffers(1, &mesh.vbo);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo); // Activates the buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU
// Strides between vertex coordinates
GLint stride = sizeof(float) * (floatsPerVertex + floatsPerColor);
// 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);
}
void UDestroyMesh(GLMesh& mesh)
{
glDeleteVertexArrays(1, &mesh.vao);
glDeleteBuffers(1, &mesh.vbo);
}
// 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);
}
It was silly, took me a while to find it.
float MouseSensitivity; was declared but no default value was given. Therefore when i moved the mouse, it had no output since there was no value.
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);
}
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:
Writing a LookAt function
https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/lookat-function
https://learnopengl.com/Getting-started/Camera
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.
I have this OpenGL code the draws a cube and pyramid. However, this program rotates the pyramid and cube together. I am tasked with only making the cube itself move not both objects at the same time. I know for this to happen I have to implement shaders for both. I'm not sure how to go about implementing both of the shaders at once. Any tips?
/*
This program demonstrates simple lighting.
A pyramid is lighted by a point light and can be rotated by mouse.
Ying Zhu
Georgia State University
October 2016
*/
// GLEW header
#include <GL/glew.h> // This must appear before freeglut.h
// Freeglut header
#include <GL/freeglut.h>
// GLM header files
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
// #include <glm/gtx/transform2.hpp>
#include <glm/gtc/matrix_access.hpp>
// #include <glm/gtx/projection.hpp>
#include <glm/gtc/matrix_inverse.hpp>
#include <glm/gtc/type_ptr.hpp>
// C++ header files
#include <iostream>
using namespace std;
using namespace glm;
#define BUFFER_OFFSET(offset) ((GLvoid *) offset)
// VBO buffer IDs
GLuint vertexArrayBufferID = 0;
GLuint normalArrayBufferID = 0;
GLuint cubePosition = 0;
GLuint cubeElements = 0;
GLuint program; // shader program ID
// Shader variable IDs
GLint vPos; // vertex attribute: position
GLint normalID; // vertex attribute: normal
GLint mvpMatrixID; // uniform variable: model, view, projection matrix
GLint modelMatrixID; // uniform variable: model, view matrix
GLint normalMatrixID; // uniform variable: normal matrix for transforming normals
GLint lightSourcePositionID; // uniform variable: for lighting calculation
GLint diffuseLightProductID; // uniform variable: for lighting calculation
GLint ambientID;
GLint attenuationAID;
GLint attenuationBID;
GLint attenuationCID;
// Transformation matrices
mat4 projMatrix;
mat4 mvpMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat3 normalMatrix; // Normal matrix for transforming normals
// Light parameters
vec4 lightSourcePosition = vec4(0.0f, 4.0f, 0.0f, 1.0f);
vec4 diffuseMaterial = vec4(0.5f, 0.5f, 0.0f, 1.0f);
vec4 diffuseLightIntensity = vec4(1.0f, 1.0f, 1.0f, 1.0f);
vec4 ambient = vec4(0.2f, 0.2f, 0.2f, 1.0f);
float attenuationA = 1.0f;
float attenuationB = 0.2f;
float attenuationC = 0.0f;
vec4 diffuseLightProduct;
// Camera parameters
vec3 eyePosition = vec3(0.0f, 0.0f, 4.0f);
vec3 lookAtCenter = vec3(0.0f, 0.0f, 0.0f);
vec3 upVector = vec3(0.0f, 1.0f, 0.0f);
float fieldOfView = 30.0f;
float nearPlane = 0.1f;
float farPlane = 1000.0f;
// Mouse controlled rotation angles
float rotateX = 0;
float rotateY = 0;
struct VertexData {
GLfloat vertex[3];
VertexData(GLfloat x, GLfloat y, GLfloat z) {
vertex[0] = x; vertex[1] = y; vertex[2] = z;
}
};
//---------------------------------------------------------------
// Initialize vertex arrays and VBOs
void prepareVBOs() {
// Define a 3D pyramid.
GLfloat vertices[][4] = {
{1.0f, -1.0f, 1.0f, 1.0f}, // face 1
{-1.0f, -1.0f, -1.0f, 1.0f},
{1.0f, -1.0f, -1.0f, 1.0f},
{ 1.0f, -1.0f, -1.0f, 1.0f }, // face 2
{0.0f, 1.0f, 0.0f, 1.0f},
{ 1.0f, -1.0f, 1.0f, 1.0f },
{ 1.0f, -1.0f, 1.0f, 1.0f }, // face 3
{ 0.0f, 1.0f, 0.0f, 1.0f },
{-1.0f, -1.0f, 1.0f, 1.0f},
{ -1.0f, -1.0f, 1.0f, 1.0f }, // face 4
{ 0.0f, 1.0f, 0.0f, 1.0f },
{ -1.0f, -1.0f, -1.0f, 1.0f },
{ 0.0f, 1.0f, 0.0f, 1.0f }, // face 5
{ 1.0f, -1.0f, -1.0f, 1.0f },
{ -1.0f, -1.0f, -1.0f, 1.0f },
{ 1.0f, -1.0f, 1.0f, 1.0f }, // face 6
{ -1.0f, -1.0f, 1.0f, 1.0f },
{ -1.0f, -1.0f, -1.0f, 1.0f }
};
GLfloat normals[][4] = {
{0.0f, -1.0f, 0.0f, 1.0f}, // normal 1
{0.0f, -1.0f, 0.0f, 1.0f },
{0.0f, -1.0f, 0.0f, 1.0f },
{0.8944f, 0.4472f, 0.0f, 1.0f}, // normal 2
{ 0.8944f, 0.4472f, 0.0f, 1.0f },
{ 0.8944f, 0.4472f, 0.0f, 1.0f },
{-0.0f, 0.4472f, 0.8944f, 1.0f}, // normal 3
{ -0.0f, 0.4472f, 0.8944f, 1.0f },
{ -0.0f, 0.4472f, 0.8944f, 1.0f },
{-0.8944f, 0.4472f, 0.0f, 1.0f}, // normal 4
{ -0.8944f, 0.4472f, 0.0f, 1.0f },
{ -0.8944f, 0.4472f, 0.0f, 1.0f },
{0.0f, 0.4472f, -0.8944f, 1.0f}, // normal 5
{ 0.0f, 0.4472f, -0.8944f, 1.0f },
{ 0.0f, 0.4472f, -0.8944f, 1.0f },
{ 0.0f, -1.0f, 0.0f, 1.0f }, // normal 6
{ 0.0f, -1.0f, 0.0f, 1.0f },
{ 0.0f, -1.0f, 0.0f, 1.0f }
};
// Cube positioins
VertexData vertexData[] = {
VertexData(0.0, 0.0, 0.0), /* Index 0 */
VertexData(0.0, 0.0, 1.0), /* Index 1 */
VertexData(0.0, 1.0, 0.0), /* Index 2 */
VertexData(0.0, 1.0, 1.0), /* Index 3 */
VertexData(1.0, 0.0, 0.0), /* Index 4 */
VertexData(1.0, 0.0, 1.0), /* Index 5 */
VertexData(1.0, 1.0, 0.0), /* Index 6 */
VertexData(1.0, 1.0, 1.0), /* Index 7 */
};
// Cube elements
GLubyte indices[] = {
4, 5, 7, // +X face
4, 7, 6,
0, 2, 3, // ‐X face
0, 3, 1,
2, 6, 7, // +Y face
2, 7, 3,
0, 1, 5, // ‐Y face
0, 5, 4,
0, 4, 6, // +Z face
0, 6, 2,
1, 3, 7, // ‐Z face
1, 7, 5
};
// Get an unused buffer object name. Required after OpenGL 3.1.
glGenBuffers(1, &vertexArrayBufferID);
// If it's the first time the buffer object name is used, create that buffer.
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBufferID);
// Allocate memory for the active buffer object.
// 1. Allocate memory on the graphics card for the amount specified by the 2nd parameter.
// 2. Copy the data referenced by the third parameter (a pointer) from the main memory to the
// memory on the graphics card.
// 3. If you want to dynamically load the data, then set the third parameter to be NULL.
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &normalArrayBufferID);
glBindBuffer(GL_ARRAY_BUFFER, normalArrayBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(normals), normals, GL_STATIC_DRAW);
glGenBuffers(1, &cubePosition);
glBindBuffer(GL_ARRAY_BUFFER, cubePosition);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData),
vertexData, GL_STATIC_DRAW);
glGenBuffers(1, &cubeElements);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cubeElements);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices),
indices, GL_STATIC_DRAW);
}
//---------------------------------------------------------------
// Print out the output of the shader compiler
void printLog(GLuint obj)
{
int infologLength = 0;
char infoLog[1024];
if (glIsShader(obj)) {
glGetShaderInfoLog(obj, 1024, &infologLength, infoLog);
}
else {
glGetProgramInfoLog(obj, 1024, &infologLength, infoLog);
}
if (infologLength > 0) {
cout << infoLog;
}
}
//-------------------------------------------------------------------
void prepareShaders() {
// Vertex shader source code
// A point light source is implemented.
// For simplicity, only the ambient and diffuse components are implemented.
// The lighting is calculated in world space, not in camera space.
const char* vSource = {
"#version 330\n"
"in vec4 vPos;"
"in vec4 normal;"
"uniform mat4x4 mvpMatrix;"
"uniform mat4x4 modelMatrix;"
"uniform mat3x3 normalMatrix;"
"uniform vec4 lightSourcePosition;"
"uniform vec4 diffuseLightProduct;"
"uniform vec4 ambient;"
"uniform float attenuationA;"
"uniform float attenuationB;"
"uniform float attenuationC;"
"out vec4 color;"
"void main() {"
" gl_Position = mvpMatrix * vPos;"
// Transform the vertex position to the world space.
" vec4 transformedVertex = modelMatrix * vPos;"
// Transform the normal vector to the world space.
" vec3 transformedNormal = normalize(normalMatrix * normal.xyz);"
// Light direction
" vec3 lightVector = normalize(transformedVertex.xyz - lightSourcePosition.xyz);"
// Distance between the light source and vertex
" float dist = distance(lightSourcePosition.xyz, transformedVertex.xyz);"
// Attenuation factor
" float attenuation = 1.0f / (attenuationA + (attenuationB * dist) + (attenuationC * dist * dist));"
// Calculate the diffuse component of the lighting equation.
" vec4 diffuse = attenuation * (max(dot(transformedNormal, lightVector), 0.0) * diffuseLightProduct);"
// Combine the ambient component and diffuse component.
" color = ambient + diffuse;"
"}"
};
// Fragment shader source code
const char* fSource = {
"#version 330\n"
"in vec4 color;"
"out vec4 fragColor;"
"void main() {"
" fragColor = color;"
"}"
};
// Declare shader IDs
GLuint vShader, fShader;
// Create empty shader objects
vShader = glCreateShader(GL_VERTEX_SHADER);
fShader = glCreateShader(GL_FRAGMENT_SHADER);
// Attach shader source code the shader objects
glShaderSource(vShader, 1, &vSource, NULL);
glShaderSource(fShader, 1, &fSource, NULL);
// Compile shader objects
glCompileShader(vShader);
printLog(vShader);
glCompileShader(fShader);
printLog(fShader);
// Create an empty shader program object
program = glCreateProgram();
// Attach vertex and fragment shaders to the shader program
glAttachShader(program, vShader);
glAttachShader(program, fShader);
// Link the shader program
glLinkProgram(program);
printLog(program);
}
//---------------------------------------------------------------
// Retrieve the IDs of the shader variables. Later we will
// use these IDs to pass data to the shaders.
void getShaderVariableLocations(GLuint shaderProgram) {
// Retrieve the ID of a vertex attribute, i.e. position
vPos = glGetAttribLocation(shaderProgram, "vPos");
normalID = glGetAttribLocation(shaderProgram, "normal");
mvpMatrixID = glGetUniformLocation(shaderProgram, "mvpMatrix");
modelMatrixID = glGetUniformLocation(shaderProgram, "modelMatrix");
normalMatrixID = glGetUniformLocation(shaderProgram, "normalMatrix");
lightSourcePositionID = glGetUniformLocation(shaderProgram, "lightSourcePosition");
diffuseLightProductID = glGetUniformLocation(shaderProgram, "diffuseLightProduct");
ambientID = glGetUniformLocation(shaderProgram, "ambient");
attenuationAID = glGetUniformLocation(shaderProgram, "attenuationA");
attenuationBID = glGetUniformLocation(shaderProgram, "attenuationB");
attenuationCID = glGetUniformLocation(shaderProgram, "attenuationC");
}
//---------------------------------------------------------------
void setShaderVariables() {
// value_ptr is a glm function
glUniformMatrix4fv(mvpMatrixID, 1, GL_FALSE, value_ptr(mvpMatrix));
glUniformMatrix4fv(modelMatrixID, 1, GL_FALSE, value_ptr(modelMatrix));
glUniformMatrix3fv(normalMatrixID, 1, GL_FALSE, value_ptr(normalMatrix));
glUniform4fv(lightSourcePositionID, 1, value_ptr(lightSourcePosition));
glUniform4fv(diffuseLightProductID, 1, value_ptr(diffuseLightProduct));
glUniform4fv(ambientID, 1, value_ptr(ambient));
glUniform1f(attenuationAID, attenuationA);
glUniform1f(attenuationBID, attenuationB);
glUniform1f(attenuationCID, attenuationC);
}
//---------------------------------------------------------------
// Set lighting related parameters
void setLightingParam() {
diffuseLightProduct = diffuseMaterial * diffuseLightIntensity;
}
//---------------------------------------------------------------
// Build the model matrix. This matrix will transform the 3D object to the proper place.
mat4 buildModelMatrix() {
mat4 rotationXMatrix = rotate(mat4(1.0f), radians(rotateX), vec3(1.0f, 0.0f, 0.0f));
mat4 rotationYMatrix = rotate(mat4(1.0f), radians(rotateY), vec3(0.0f, 1.0f, 0.0f));
mat4 matrix = rotationYMatrix * rotationXMatrix;
return matrix;
}
//---------------------------------------------------------------
void buildMatrices() {
modelMatrix = buildModelMatrix();
mvpMatrix = projMatrix * viewMatrix * modelMatrix;
normalMatrix = column(normalMatrix, 0, vec3(modelMatrix[0][0], modelMatrix[0][1], modelMatrix[0][2]));
normalMatrix = column(normalMatrix, 1, vec3(modelMatrix[1][0], modelMatrix[1][1], modelMatrix[1][2]));
normalMatrix = column(normalMatrix, 2, vec3(modelMatrix[2][0], modelMatrix[2][1], modelMatrix[2][2]));
// Use glm::inverseTranspose() to create a normal matrix, which is used to transform normal vectors.
normalMatrix = inverseTranspose(normalMatrix);
}
//---------------------------------------------------------------
// Handles the display event
void display()
{
// Clear the window with the background color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
buildMatrices();
setShaderVariables();
// Activate the shader program
glUseProgram(program);
// If the buffer object already exists, make that buffer the current active one.
// If the buffer object name is 0, disable buffer objects.
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBufferID);
// Associate the vertex array in the buffer object with the vertex attribute: "position"
glVertexAttribPointer(vPos, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
// Enable the vertex attribute: "position"
glEnableVertexAttribArray(vPos);
glBindBuffer(GL_ARRAY_BUFFER, normalArrayBufferID);
glVertexAttribPointer(normalID, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(normalID);
// Start the shader program. Draw the object. The third parameter is the number of triangles.
glDrawArrays(GL_TRIANGLES, 0, 18);
glBindBuffer(GL_ARRAY_BUFFER, cubePosition);
glVertexAttribPointer(vPos, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(vPos);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cubeElements);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
// Refresh the window
glutSwapBuffers();
}
//---------------------------------------------------------------
// Handles the reshape event
void reshape(int width, int height)
{
// Specify the width and height of the picture within the window
glViewport(0, 0, width, height);
projMatrix = perspective(fieldOfView, (float)width / (float)height, nearPlane, farPlane);
viewMatrix = lookAt(eyePosition, lookAtCenter, upVector);
}
//---------------------------------------------------------------
// Read mouse motion data and convert them to rotation angles.
void passiveMotion(int x, int y) {
rotateY = (float)x * -0.8f;
rotateX = (float)y * -0.8f;
// Generate a dislay event to force refreshing the window.
glutPostRedisplay();
}
//-----------------------------------------------------------------
void init() {
prepareVBOs();
prepareShaders();
getShaderVariableLocations(program);
setLightingParam();
// Specify the background color
glClearColor(1, 1, 1, 1);
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
//---------------------------------------------------------------
void main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Lighting Demo");
glutReshapeWindow(800, 800);
glewInit();
init();
// Register the display callback function
glutDisplayFunc(display);
// Register the reshape callback function
glutReshapeFunc(reshape);
// Register the passive mouse motion call back function
// This function is called when the mouse moves within the window
// while no mouse buttons are pressed.
glutPassiveMotionFunc(passiveMotion);
// Start the event loop
glutMainLoop();
}
Well, the most obvious culprit here would be setting a single ModelMatrix for both - I can't see any logic in your code to set them independently for each object you're rendering.
Since each object has a different rotation (and presumably, unless you're planning to draw one on top of the other, a different translation), you would want to be generating / loading a different model matrix for each draw call.
You dont need to use different shaders, you just need to use different model matricies. Say you have two objects in you scene something like this:
while (!myWindow(shouldClose))
{
myShader.use();
glBindVertexArray(myVao1);
glDrawArrays(GL_TRIANGLES, 0, x); // Draw pyramid
glBindVertaxArray(myVao2);
glDrawArrays(GL_TRIANGLES, 0, x); // Draw cube
}
Say you want only the second model to rotate on the y axis, you could do something like this:
float rotationDegree = 0;
while (!myWindow(shouldClose))
{
myShader.use();
myShader.setMat4(glm::mat4(1.0f)) // Make sure to set it to normal matrix for the pyrmamid
glBindVertexArray(myVao1);
glDrawArrays(GL_TRIANGLES, 0, x); // Draw pyramid
glBindVertaxArray(myVao2);
glm::mat4 model = glm::mat4(1.0f);
glm::rotate(model, glm::radians(rotationDegree), glm::vec3(0.0f, 1.0f, 0.0f));
rotateionDegree += 0.01;
myShader.setMat4("model", model); // Set you model matrix in your shader.
glDrawArrays(GL_TRIANGLES, 0, x); // Draw cube
}
I am writing a mini OpenGL program with instancing in it. But when I ran the code, only one instance was shown. I thought that it should be easy, but I failed. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <GL/glut.h>
#include <vector>
#include <fstream>
#include <string>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <vector>
#define WIDTH 1280
#define HEIGHT 720
static const std::string vertexShader =
"#version 330 core\n"
"in vec3 position;\n"
"in vec3 color;\n"
"in ivec3 Glob_pos;\n"
"uniform mat4 MVP;\n"
"out vec3 ToFragColor;\n"
"void main(){\n"
" gl_Position = MVP * vec4(vec3(Glob_pos) + position,1.0);\n"
" ToFragColor = color;\n"
"}\n";
static const std::string fragmentShader =
"#version 330 core\n"
"in vec3 ToFragColor;\n"
"uniform vec3 Cam;\n"
"out vec3 out_color;\n"
"void main(){\n"
" out_color = ToFragColor;\n"
"}\n";
static const GLfloat CUBE_VERT[12*3*2*3] = {
-1.0f,-1.0f,-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f,-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f,
-1.0f,-1.0f,-1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, 1.0f,-1.0f, 0.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
-1.0f,-1.0f,-1.0f, 0.0f, 0.0f, 0.0f,
1.0f,-1.0f,-1.0f, 1.0f, 0.0f, 0.0f,
1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f,
1.0f,-1.0f,-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f,-1.0f,-1.0f, 0.0f, 0.0f, 1.0f,
-1.0f,-1.0f,-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
-1.0f,-1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-1.0f,-1.0f,-1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-1.0f,-1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
1.0f,-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f,-1.0f,-1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f,-1.0f, 0.0f, 1.0f, 1.0f,
1.0f,-1.0f,-1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
//TOP
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f,
1.0f, 1.0f,-1.0f, 1.0f, 0.0f, -1.0f,
-1.0f, 1.0f,-1.0f, 0.0f, 0.0f, -1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f,
-1.0f, 1.0f,-1.0f, 0.0f, 0.0f, -1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f
};
GLuint LoadShaders();
void setup(GLuint programID);
void render(GLuint programID);
void computeMatricesFromInputs(GLFWwindow* window);
GLuint vao, vbo, ib;
GLuint MatrixID;
GLuint CamID;
//For model view matrix calculation
glm::vec3 CamLoc = glm::vec3(0,0,-5);
glm::mat4 Projection = glm::perspective(glm::radians(45.0f), (float) WIDTH / (float)HEIGHT, 1.0f, 1000.0f);
glm::mat4 View = glm::lookAt(
CamLoc,
glm::vec3(0,0,0),
glm::vec3(0,1,0)
);
glm::mat4 Model = glm::mat4(1.0f);
glm::mat4 mvp = Projection * View * Model;
glm::vec3 direction;
float horizontalAngle = 3.14f;
float verticalAngle = 0.0f;
float initialFoV = 45.0f;
float speed = 3.0f;
float mouseSpeed = 0.005f;
float mtimeScale = 0.1f;
float ktimeScale = 1.0f;
float FoV = initialFoV; //- 5 * glfwGetMouseWheel();
double lastPos[] = { 0,0 };
const glm::vec3 null = glm::vec3(0,0,0);
//For model view matrix calculation -- end
std::vector<int> instanceObj;
int main(int argc, char **argv){
glutInit(&argc, argv);
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window;
window = glfwCreateWindow(WIDTH, HEIGHT, "DearDaniel's OpenGL", NULL, NULL);
glfwMakeContextCurrent(window);
glewExperimental = true;
glewInit();
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
GLuint programID = LoadShaders();
MatrixID = glGetUniformLocation(programID, "MVP");
CamID = glGetUniformLocation(programID, "Cam");
glEnable (GL_DEPTH_TEST); glDepthFunc (GL_LESS);
glEnable(GL_CULL_FACE); glCullFace(GL_BACK);
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
setup(programID);
do{
glUseProgram(programID);
computeMatricesFromInputs(window);
render(programID);
glfwSwapBuffers(window);
glfwPollEvents();
} while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && glfwWindowShouldClose(window) == 0 );
glDeleteProgram(programID);
return 0;
}
GLuint LoadShaders(){
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
char const * VertexSourcePointer = vertexShader.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
char const * FragmentSourcePointer = fragmentShader.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
glDetachShader(ProgramID, VertexShaderID);
glDetachShader(ProgramID, FragmentShaderID);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}
void setup(GLuint programID) {
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 12*3*2*3*sizeof(int), CUBE_VERT, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*) 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glGenBuffers(1, &ib);
glBindBuffer(GL_ARRAY_BUFFER, ib);
glVertexAttribPointer(2, 3, GL_INT, GL_FALSE, 3 * sizeof( int), (void*) 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glVertexAttribDivisor(2, 1);
glBindVertexArray(0);
}
void render(GLuint programID) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, ib);
instanceObj.clear();
for (int i = 0; i < 32; i+=2)
for (int j = 0; j < 32; j +=2)
for (int k = 0; k < 32; k +=2) {
instanceObj.push_back(i);
instanceObj.push_back(j);
instanceObj.push_back(k);
}
glBufferData(GL_ARRAY_BUFFER, sizeof(int)*instanceObj.size(), &instanceObj[0], GL_STATIC_DRAW);
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &mvp[0][0]);
glUniform3f(CamID, CamLoc.x, CamLoc.y, CamLoc.z);
glDrawArraysInstanced(GL_TRIANGLES, 0, 36, 16*16*16);
glBindVertexArray(0);
}
void computeMatricesFromInputs(GLFWwindow* window){
static double lastTime = glfwGetTime();
double currentTime = glfwGetTime();
float deltaTime = float(currentTime - lastTime);
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
float hori = horizontalAngle + mouseSpeed * float( xpos - lastPos[0] ) * mtimeScale;
float vert = verticalAngle + mouseSpeed * float( ypos - lastPos[1] ) * mtimeScale;
horizontalAngle = hori;
if (vert > -3.14f/2.0f && vert < 3.14f/2.0f) verticalAngle = vert;
lastPos[0] = xpos;
lastPos[1] = ypos;
direction = glm::vec3 (
cos(verticalAngle) * sin(horizontalAngle),
sin(verticalAngle),
cos(verticalAngle) * cos(horizontalAngle)
);
glm::vec3 right = glm::vec3(
sin(horizontalAngle - 3.14f/2.0f),
0,
cos(horizontalAngle - 3.14f/2.0f)
);
glm::vec3 up = glm::cross( right, direction );
if (glfwGetKey( window, GLFW_KEY_UP ) == GLFW_PRESS) CamLoc += direction * deltaTime * speed * ktimeScale;
if (glfwGetKey( window, GLFW_KEY_DOWN ) == GLFW_PRESS) CamLoc -= direction * deltaTime * speed * ktimeScale;
if (glfwGetKey( window, GLFW_KEY_RIGHT ) == GLFW_PRESS) CamLoc += right * deltaTime * speed * ktimeScale;
if (glfwGetKey( window, GLFW_KEY_LEFT ) == GLFW_PRESS) CamLoc -= right * deltaTime * speed * ktimeScale;
Projection = glm::perspective(glm::radians(FoV), 4.0f / 3.0f, 0.1f, 100.0f);
View = glm::lookAt(
CamLoc, // Camera is here
CamLoc+direction, // and looks here : at the same position, plus "direction"
up // Head is up (set to 0,-1,0 to look upside-down)
);
lastTime = currentTime;
mvp = Projection * View;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
printf("%f ", mvp[i][j]);
}
printf("\n");
}
}
I used the following command to compile my code:
g++ miniGL.cpp -Wall -std=c++11 -L/usr/local/lib -pthread -lGLEW -lGLU -lGL -lglut -lglfw3 -ldl -lrt -lXrandr -lXxf86vm -lXi -lXinerama -lX11 -lXcursor -lglfw -o ogl
I was meant to render 16*16*16 cubes onto the screen, but only one has shown. I spent more than ten hours for debugging. Now I gave up and shamelessly seeking for help.
You have to use glVertexAttribIPointer, when defining the array of generic vertex attribute data, for the vertex attrbute in ivec3 Glob_pos;.
glVertexAttribPointer is for floating point attributes only (integral data will be converted to floating point).
See the Khronos group reference page for glVertexAttribPointer:
For glVertexAttribPointer, if normalized is set to GL_TRUE, it indicates that values stored in an integer format are to be mapped to the range [-1,1] (for signed values) or [0,1] (for unsigned values) when they are accessed and converted to floating point. Otherwise, values will be converted to floats directly without normalization.
For glVertexAttribIPointer, only the integer types GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT are accepted. Values are always left as integer values.
Note, probably Glob_pos is never set and has always the same, but undefined value.
Since you don't use glGetAttribLocation to get the attribute indices for the vertex attributes (position, color, Glob_pos), you should use Layout Qualifiers:
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in ivec3 Glob_pos;
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I am supposed to draw 6 different 2D shapes (dot, line, triangle, square, star, circle) and assign them each a different color. I managed to draw all of them and color them, except for my circle. The color i gave (g_colors_circle) the circle however is drawn from the center of the circle but does not reach the edges. Here is the current output:
Can someone tell me how to fix it?
Here is my code:
SimpleTriangle.cpp:
#include <cstdio> // for C++ i/o
#include <iostream>
using namespace std; // to avoid having to use std::
#define GLEW_STATIC // include GLEW as a static library
#include <GLEW/glew.h> // include GLEW
#include <GLFW/glfw3.h> // include GLFW (which includes the OpenGL header)
#include <glm/glm.hpp> // include GLM (ideally should only use the GLM headers that are actually used)
using namespace glm; // to avoid having to use glm::
#include "shader.h"
/*-------------------- Circle Code --------------------*/
//Constants for Circle
#define PI 3.14159265
#define MAX_SLICES 32
#define MIN_SLICES 8
#define MAX_VERTICES (MAX_SLICES+2)*3 // a triangle fan should have a minimum of 3 vertices
#define CIRCLE_RADIUS 0.5
GLuint g_VBO_circle[2]; // identifiers
GLuint g_VAO_circle = 0;
//Vertices for the circle
GLfloat g_vertices_circle[MAX_VERTICES] = {
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
};
GLfloat g_colors_circle[] = {
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f
};
GLuint g_slices = MIN_SLICES; // number of circle slices
//raz: i think this generates the vertice values for array of the circle
void generate_circle()
{
float angle = PI * 2 / static_cast<float>(g_slices); // used to generate x and y coordinates
float scale_factor = static_cast<float>(768) / 1024; // scale to make it a circle instead of an elipse
int index = 0; // vertex index
g_vertices_circle[3] = CIRCLE_RADIUS * scale_factor; // set x coordinate of vertex 1
// generate vertex coordinates for triangle fan
for (int i = 2; i < g_slices + 2; i++)
{
// multiply by 3 because a vertex has x, y, z coordinates
index = i * 3;
g_vertices_circle[index] = CIRCLE_RADIUS * cos(angle) * scale_factor;
g_vertices_circle[index + 1] = CIRCLE_RADIUS * sin(angle);
g_vertices_circle[index + 2] = 0.0f;
// update to next angle
angle += PI * 2 / static_cast<float>(g_slices);
}
}
static void init_circle()
{
// generate vertices of triangle fan
generate_circle();
// create VBO (vertice positions) and buffer the data
glGenBuffers(2, g_VBO_circle);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_vertices_circle, GL_DYNAMIC_DRAW);
// create VBO (vertice color) and buffer the data
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_colors_circle, GL_STATIC_DRAW);
// create VAO and specify VBO data
glGenVertexArrays(1, &g_VAO_circle);
glBindVertexArray(g_VAO_circle);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[1]);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glEnableVertexAttribArray(0); // enable vertex attributes
glEnableVertexAttribArray(1);
}
/*---------------------------------------------------------*/
// global variables
GLuint g_VBO[2]; // vertex buffer object identifier
GLuint g_VAO = 0; // vertex array object identifier
GLuint g_shaderProgramID = 0; // shader program identifier
static void init()
{
glClearColor(0.0, 0.0, 0.0, 1.0); // set clear background colour
// create and compile our GLSL program from the shader files
g_shaderProgramID = loadShaders("SimpleVS.vert", "SimpleFS.frag");
// enable point size
glEnable(GL_PROGRAM_POINT_SIZE);
// set line width
glLineWidth(5.0);
GLfloat verticesPosition[] = {
//Dot
-0.7f, 0.7f, 0.0f,
//Line
-0.5f, 0.7f, 0.0f,
-0.2f, 0.7f, 0.0f,
//Triangle
0.2f, 0.75f, 0.0f,
0.0f, 0.4f, 0.0f,
0.4f, 0.4f, 0.0f,
//Star
0.0f, 0.2f, 0.0f,
0.1f, 0.1f, 0.0f,
0.2f, 0.05f, 0.0f,
0.1f, 0.0f, 0.0f,
0.2f, -0.1f, 0.0f,
0.0f, 0.0f, 0.0f,
-0.2f, -0.1f, 0.0f,
-0.1f, 0.0f, 0.0f,
-0.2f, 0.05f, 0.0f,
-0.1f, 0.1f, 0.0f,
//Rectangle
-0.8f, 0.4f, 0.0f,
-0.8f, 0.0f, 0.0f,
-0.3f, 0.4f, 0.0f,
-0.3f, 0.0f, 0.0f
};
GLfloat verticesColor[] = {
//Dot
1.0f, 1.0f, 1.0f,
//Line
0.5f, 0.0f, 0.0f,
0.5f, 0.0f, 0.0f,
//Triangle
0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f,
//Star
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
//Rectangle
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
// create VBO and buffer the data
glGenBuffers(2, g_VBO);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]); // bind the VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(verticesPosition), verticesPosition, GL_STATIC_DRAW); // copy data to buffer
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]); // bind the VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(verticesColor), verticesColor, GL_STATIC_DRAW); // copy data to buffer
// create VAO and specify VBO data
glGenVertexArrays(1, &g_VAO);
glBindVertexArray(g_VAO);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]); // bind the VBO
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]); // bind the VBO
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glEnableVertexAttribArray(0); // enable vertex attributes
glEnableVertexAttribArray(1);
}
// function used to render the scene
static void render_scene()
{
glClear(GL_COLOR_BUFFER_BIT); // clear colour buffer
glUseProgram(g_shaderProgramID); // use the shaders associated with the shader program
glBindVertexArray(g_VAO); // make VAO active
glDrawArrays(GL_POINTS, 0, 1); //Draw dot
glDrawArrays(GL_LINES, 1, 2); //Draw line
glDrawArrays(GL_TRIANGLES, 3, 3); //Draw triangle
glDrawArrays(GL_LINE_LOOP, 6, 10); //Draw star
glDrawArrays(GL_TRIANGLE_STRIP, 16, 4); //Draw rectangle
glFlush(); // flush the pipeline
//To draw circle
glBindVertexArray(g_VAO_circle); // make VAO for circle active
glDrawArrays(GL_TRIANGLE_FAN, 0, g_slices + 2); // display the vertices based on the primitive type
glFlush(); // flush the pipeline
}
// key press or release callback function
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
// quit if the ESCAPE key was press
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
{
// set flag to close the window
glfwSetWindowShouldClose(window, GL_TRUE);
return;
}
else if (key == GLFW_KEY_W && action == GLFW_PRESS)
{
// renderer using wireframe
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
return;
}
else if (key == GLFW_KEY_S && action == GLFW_PRESS)
{
// renderer using wireframe
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
return;
}
else if (key == GLFW_KEY_UP && action == GLFW_PRESS)
{
if (g_slices < MAX_SLICES)
{
g_slices++; // increment number of slices
// generate vertices of triangle fan
generate_circle();
// bind and copy data to GPU
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_vertices_circle, GL_DYNAMIC_DRAW);
}
return;
}
else if (key == GLFW_KEY_DOWN && action == GLFW_PRESS)
{
if (g_slices > MIN_SLICES)
{
g_slices--; // decrement number of slices
// generate vertices of triangle fan
generate_circle();
// bind and copy data to GPU
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_vertices_circle, GL_DYNAMIC_DRAW);
return;
}
}
}
// error callback function
static void error_callback(int error, const char* description)
{
cerr << description << endl; // output error description
}
int main(void)
{
GLFWwindow* window = NULL; // pointer to a GLFW window handle
glfwSetErrorCallback(error_callback); // set error callback function
// initialise GLFW
if(!glfwInit())
{
// if failed to initialise GLFW
exit(EXIT_FAILURE);
}
// minimum OpenGL version 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// create a window and its OpenGL context
window = glfwCreateWindow(1024, 768, "Assignment 1", NULL, NULL);
// if failed to create window
if(window == NULL)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window); // set window context as the current context
glfwSwapInterval(1); // swap buffer interval
// initialise GLEW
if(glewInit() != GLEW_OK)
{
// if failed to initialise GLEW
cerr << "GLEW initialisation failed" << endl;
exit(EXIT_FAILURE);
}
// set key callback function
glfwSetKeyCallback(window, key_callback);
// initialise rendering states
init();
init_circle();
// the rendering loop
while(!glfwWindowShouldClose(window))
{
render_scene(); // render the scene
glfwSwapBuffers(window); // swap buffers
glfwPollEvents(); // poll for events
}
// clean up
glDeleteProgram(g_shaderProgramID);
glDeleteBuffers(1, g_VBO);
glDeleteVertexArrays(1, &g_VAO);
glDeleteBuffers(1, g_VBO_circle);
glDeleteVertexArrays(1, &g_VAO_circle);
// close the window and terminate GLFW
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
SimpleVS.vert:
#version 330 core
// input data (different for all executions of this shader)
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec3 aColor;
// output data (will be interpolated for each fragment)
out vec3 vColor; //raz: this output is passed as input to the fragment shader
void main()
{
// set point size
gl_PointSize = 10.0;
// set vertex position
gl_Position = vec4(aPosition, 1.0);
// the color of each vertex will be interpolated
// to produce the color of each fragment
vColor = aColor;
}
SimpleFS.frag:
#version 330 core
// interpolated values from the vertex shaders
in vec3 vColor;
// output data
out vec3 fColor;
void main()
{
// set output color
fColor = vColor;
}
For each vertex in your circle geometry, you must set a color attribute. The 2 array buffers g_vertices_circle and g_colors_circle, which you are using for your attribute buffers, must have the same number of elements.
If the circle has to be unicolor, you must always use the same color for each element in the color attribute buffer.
In between the primitives the attributes are interpolate according to its barycentric coordinates. You did set the color for the center of the circle and the first outer point, but not the colors for the other outer points and left them undefined (probably black), this causes the effect you can see in your example.
Create a buffer for the color attributes in the same length as your vertex buffer and fill it up when you generate your vertices.
Your revised code should look something like this:
GLfloat g_colors_circle[MAX_VERTICES] = {
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f
};
for (int i = 2; i < g_slices + 2; i++)
{
// multiply by 3 because a vertex has x, y, z coordinates
index = i * 3;
g_vertices_circle[index] = CIRCLE_RADIUS * cos(angle) * scale_factor;
g_vertices_circle[index + 1] = CIRCLE_RADIUS * sin(angle);
g_vertices_circle[index + 2] = 0.0f;
g_colors_circle[index] = 1.0f;
g_colors_circle[index + 1] = 1.0f;
g_colors_circle[index + 2] = 0.0f;
// update to next angle
angle += PI * 2 / static_cast<float>(g_slices);
}
Note, if you only want to have single-color geometry, you can omit the color attributes and set the color through a single uniform variable.