ISSUE: When launched, GLWindow displays only a white screen and the cursor displays a loading circle, signifying that something is still being loaded. The window displays "Not Responding" shortly after that.
I have tried downgrading to openGL 3.3 and have used glad to help with that, but the problem persists.
Hello all,
I've been working to create a sphere with alternating colors using a vertex shader.
The code that I've shared below was slightly altered from code that was used to shade a quad, which worked fine. I expect that there will be issues with similar logic being used to shade a circle, or to build a sphere and shade that. I am NOT at that point yet however. Something is keeping my GL Window from displaying properly and I am hoping that someone can help me with my GLFW and glew logic to share why the window is failing to load.
NOTE:I've edited this code to include comments for every step, which makes it seem much longer than it is. I would appreciate any help or insight.
PRIMARY CLASS
#include <iostream>
#include <sstream>
#define GLEW_STATIC
//always GLEW before GLFW
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"
#include "ShaderProgram.h"
#ifndef M_PI
# define M_PI 3.141592653
#endif
/////gLOBAL
GLFWwindow* w = NULL;
const int wWidth = 800;
const int wHeight = 600;
void key_callback(GLFWwindow *w, int key, int scancode, int action, int mode);
//update colors based on average framerate
void averageFPS(GLFWwindow* window);
//screen resizing
void glfw_onFramebufferSize(GLFWwindow* window, int width, int height);
bool initOpenGL();
static void error(int error, const char *desc)
{
fputs(desc, stderr);
}
//setting up values for keys
int main() {
if (!initOpenGL()) ///5IMPR
{
// An error occured
std::cerr << "GLFW not initialized" << std::endl;
return -1;
}
glfwSetErrorCallback(error);
GLfloat vertices[] = {
-0.5f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 1.0f, 0.0f
};
GLuint indices[] = {
0, 1, 2,
0, 2, 3
};
// 2. Set up buffers on the GPU
GLuint vbo, ibo, vao;
glGenBuffers(1, &vbo); // Generate an empty vertex buffer on the GPU
glBindBuffer(GL_ARRAY_BUFFER, vbo); // "bind" or set as the current buffer we are working with
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // copy the data from CPU to GPU
glGenVertexArrays(1, &vao); // Tell OpenGL to create new Vertex Array Object
glBindVertexArray(vao); // Make it the current one
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); // Define a layout for the first vertex buffer "0"
glEnableVertexAttribArray(0); // Enable the first attribute or attribute "0"
// Set up index buffer
glGenBuffers(1, &ibo); // Create buffer space on the GPU for the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glBindVertexArray(0); // unbind to make sure other code doesn't change it
ShaderProgram shaderProgram;
shaderProgram.assignShaders("shaders/ColorShader.vert", "shaders/ColorShader.frag");
////////SETUP RENDERING
while (!glfwWindowShouldClose(w))
{
averageFPS(w);
//process events
glfwPollEvents();
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT);
shaderProgram.use();
GLfloat time = (GLfloat)glfwGetTime();
GLfloat blueSetting = (sin(time) / 2) + 0.5f;
glm::vec2 pos;
pos.x = sin(time) / 2;
pos.y = cos(time) / 2;
shaderProgram.setUniform("vertColor", glm::vec4(0.0f, 0.0f, blueSetting, 1.0f));
shaderProgram.setUniform("posOffset", pos);
/////COLOR OF CIRCLE OUTLINE
//glColor4f(0.0, 0.0, 1.0, 1.0); //RGBA
//PRIMARY BODY
// Draw our line
glBegin(GL_LINE_LOOP);
//glColor3f(0,0,1);
static double iteration = 0;
// The x, y offset onto the screen -- this should later be centered
static const int offset = 150;
static const float radius = 50;
// Calculate our x, y cooredinates
double x1 = offset + radius + 100 * cos(1);
double y1 = offset + radius + 100 * sin(1);
static double wobble = 0.0;
// A = (π * r²)
double a = M_PI * (100 * 2); //area
// C = (2 * π * r)
double c = 2 * M_PI * 100; //circumference
static double b = 128;
for (double i = 0; i < 2 * M_PI; i = i + ((2 * M_PI) / b))
{
double x = x1 + radius * cos(i);
double y = y1 + radius * sin(i);
glVertex2f(x, y);
glVertex2f(x, y);
}
iteration += 0.01;
////PRIMARY BODY End
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//glDrawElements(GL_LINE_LOOP, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
// Swap buffers and look for events
glfwSwapBuffers(w);
}
//clean up
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ibo);
//glfwDestroyWindow(w);
glfwTerminate();
return 0;
}
///////START Initializing glfw glew etc
bool initOpenGL(){
//this method will exit on these conditions
GLuint error = glfwInit();
if (!error)
return false;
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);
w = glfwCreateWindow(wWidth, wHeight, "Exercise", NULL, NULL);
//Filling Window
if (w== NULL)
{
std::cerr << "glfw window not created" << std::endl;
glfwTerminate();
return false;
}
//update context
glfwMakeContextCurrent(w);
// Initialize GLEWunifor
glewExperimental = GL_TRUE;
GLuint err = glewInit();
if (err != GLEW_OK)
{
std::cerr << "initialize GLEW Failed" << std::endl;
return false;
}
//setup key callbacks
glfwSetKeyCallback(w, key_callback);
glfwSetFramebufferSizeCallback(w, glfw_onFramebufferSize);
while (!glfwWindowShouldClose(w))
{
//int width, height;
// glfwGetFramebufferSize(w, &width, &height); //move out of while??
// glViewport(0, 0, width, height); //remove??
}
glClearColor(0.23f, 0.38f, 0.47f, 1.0f); ///5ADD
// Define the viewport dimensions
glViewport(0, 0, wWidth, wHeight); //necessary?
return true;
}
void key_callback(GLFWwindow *w, int key, int scancode, int action, int mode)
{
// See http://www.glfw.org/docs/latest/group__keys.html
if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
glfwSetWindowShouldClose(w, GL_TRUE);
if (key == GLFW_KEY_W && action == GLFW_PRESS)
{
bool showWires = false;
if (showWires)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
//whever window resizes, do this
void glfw_onFramebufferSize(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void averageFPS(GLFWwindow* window) ///5ADDdown
{
static double previousSeconds = 0.0;
static int frameCount = 0;
double passedSeconds;
double currentSeconds = glfwGetTime(); //seconds since GLFW started
passedSeconds = currentSeconds - previousSeconds;
// Limit time updates to 4 times per second
if (passedSeconds > 0.25)
{
previousSeconds = currentSeconds;
double fps = (double)frameCount / passedSeconds;
// double frameInMilSecs = 1000.0 / fps;
frameCount = 0;}
frameCount++;
}
SHADER MANAGER/HANDLER CLASS
#include "ShaderProgram.h"
#include <fstream>
#include <iostream>
#include <sstream>
ShaderProgram::ShaderProgram()
: mProgram(0){
}
ShaderProgram::~ShaderProgram()
{
glDeleteProgram(mProgram);
}
bool ShaderProgram::assignShaders(const char* vertFileName, const char* fragFileName)
{
//Shaders output objects called programs that define their relationship and lead to .exe functionality
//assigning pointer to the shader
string vsString = readFile(vertFileName);
string fsString = readFile(fragFileName);
const GLchar* fsSourcePtr = fsString.c_str();
const GLchar* vsSourcePtr = vsString.c_str();
//creating vertex shader(vs) shader object
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
//assigning shader source using address. Replaces the source code in a shader object //#arg (shader, count Strings, pointer to const File ,size)
glShaderSource(vs, 1, &vsSourcePtr, NULL);
glShaderSource(fs, 1, &fsSourcePtr, NULL);
glCompileShader(vs);
glCompileShader(fs);
testProgramCompile();
testShaderCompile(vs);
testShaderCompile(fs);
//createProgram returns GLUint which is basically an unsigned int... we will use This Handler to create a program object
mProgram = glCreateProgram();
if (mProgram == 0)
{
std::cerr << "Shader cannot be created" << std::endl;
return false;
}
//assign the program object(mProgram) to the Shader
glAttachShader(mProgram, vs);
glAttachShader(mProgram, fs);
//this method accepts a GLuint "program" . If its an object of type GL_VERTEX_SHADER,
//itll create a .exe that runs on the programmable vertex processor. same goes for geometric and fragment shaders if they were included
//it will also bind all user defined uniform variables and attributes to the program
//The program can then be made part of a defined state by calling useProgram
glLinkProgram(mProgram);
testProgramCompile();
testShaderCompile(vs);
testShaderCompile(vs);
//cleaning up the elements we already used
glDeleteShader(vs);
glDeleteShader(fs);
//clear the identifier lookup map(in this case, there's only one)
mUniformIdentifiers.clear();
return true;
}//end main
//Read the shaderFile. strngstream for reading multiple lines
string ShaderProgram:: readFile(const string& filename) {
std::stringstream strgstream;
std::ifstream file;
try
{
file.open(filename, std::ios::in);
if (!file.fail())
{
strgstream << file.rdbuf();
}
file.close();
}
catch (std::exception e)
{
std::cerr << "Error: File or File Name Issues" << std::endl;
}
return strgstream.str();
}
//use the Program Object we created in this current state(color)
void ShaderProgram::use()
{
if (mProgram != 0)
glUseProgram(mProgram);
}
void ShaderProgram::testProgramCompile() {
int status = 0;
GLuint program = mProgram;
// ///CHECKING GL_LINK_STATUS to see if Program Link was successul. Link Status will return GL_TRUE if it was
glGetProgramiv( mProgram, GL_LINK_STATUS, &status); //requesting the status
if (status == GL_FALSE)
{
std::cerr << "Linking Error with Program " << std::endl;
}
}
void ShaderProgram :: testShaderCompile(GLuint shader) {
int status = 0;
// ///CHECKING GL_LINK_STATUS to see if Program Link was successul. Link Status will return GL_TRUE if it was
glGetProgramiv(shader, GL_LINK_STATUS, &status); //requesting the status
if (status == GL_FALSE)
{
std::cerr << "Linking Error with Shader " << std::endl;
}
}
////GETTERS AND SETTERS
GLuint ShaderProgram::getProgram() const
{
return mProgram;
}
void ShaderProgram::setUniform(const GLchar* name, const glm::vec2& v)
{
GLint address = getUniformIdentifier(name);
glUniform2f(address, v.x, v.y);
}
void ShaderProgram::setUniform(const GLchar* name, const glm::vec3& v)
{
GLint address = getUniformIdentifier(name);
glUniform3f(address, v.x, v.y, v.z);
}
void ShaderProgram:: setUniform(const GLchar* name, const glm::vec4& v) {
GLint address = getUniformIdentifier(name);
glUniform4f(address, v.x, v.y, v.z, v.w);
}
//Maybe need to switch places with setUniform
GLint ShaderProgram :: getUniformIdentifier(const GLchar* name) {
std::map<std::string, GLint>::iterator it;
it = mUniformIdentifiers.find(name);
//std::map<std::string, GLint>
// Only need to query the shader program IF it doesn't already exist.
if (it == mUniformIdentifiers.end())
{
// Find it and add it to the map
mUniformIdentifiers[name] = glGetUniformLocation(mProgram, name);
}
// Return it
return mUniformIdentifiers[name];
}
You have this in your init function.
while (!glfwWindowShouldClose(w))
{
//int width, height;
// glfwGetFramebufferSize(w, &width, &height); //move out of while??
// glViewport(0, 0, width, height); //remove??
}
Your code is presumably hanging here.
Related
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 10 months ago.
Improve this question
I have a compute-heavy OpenGL vertex shader which I'm trying to profile the performance of.
Following the conventional wisdom
¹ ² ³, I'm computing the frames per second in my glfw app by waiting over 1 second and dividing the number of frames by the time elapsed. My FPS counter claims ≈30 FPS but it's clearly more like 1 FPS. Notice the grass blowing in the breeze behind the screen.
My minimal example below and in this gist, animates a densely tessellated grid and performs dummy computation in the vertex shader until the issue appears.
Is there a way to measure FPS or the performance of this shader in a way that it accurately reflects its real behavior?
// Controls how much (dummy) computation happens in the vertex shader.
const int m = 20000;
#define GL_SILENCE_DEPRECATION
#include <OpenGL/gl3.h>
#define __gl_h_
#include <Eigen/Core>
#include <Eigen/Geometry>
#define GLFW_INCLUDE_GLU
#include <GLFW/glfw3.h>
#include <chrono>
#include <string>
#include <chrono>
#include <thread>
#include <iostream>
std::string vertex_shader = R"(
#version 330 core
uniform mat4 proj;
uniform mat4 model;
uniform float t;
uniform int m;
in vec3 position;
out vec4 position_eye;
void main()
{
vec4 deformed =
vec4(
position.x,
position.y,
sin(t*3.14159)*
cos(position.x*3.14159)*
cos(position.y*3.14159)
,
1.);
for(int j = 0;j<m;j++)
{
deformed.z = deformed.z + 0.000001*float(j)/float(m);
}
position_eye = proj * model * deformed;
gl_Position = position_eye;
}
)";
std::string fragment_shader = R"(
#version 330 core
in vec4 position_eye;
out vec3 color;
void main()
{
vec3 xTangent = dFdx(position_eye.xyz);
vec3 yTangent = dFdy(position_eye.xyz);
color = normalize( cross( yTangent, xTangent ) )*0.5 + 0.5;
}
)";
// width, height, shader id, vertex array object
int w=800,h=600;
double highdpi=1;
GLuint prog_id=0;
GLuint VAO;
// Mesh data: RowMajor is important to directly use in OpenGL
Eigen::Matrix< float,Eigen::Dynamic,3,Eigen::RowMajor> V;
Eigen::Matrix<GLuint,Eigen::Dynamic,3,Eigen::RowMajor> F;
int main(int argc, char * argv[])
{
using namespace std;
const auto get_seconds = []()
{
return
std::chrono::duration<double>(
std::chrono::system_clock::now().time_since_epoch()).count();
};
if(!glfwInit())
{
cerr<<"Could not initialize glfw"<<endl;
return EXIT_FAILURE;
}
const auto & error = [] (int error, const char* description)
{
cerr<<description<<endl;
};
glfwSetErrorCallback(error);
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* window = glfwCreateWindow(w, h, "WebGL", NULL, NULL);
if(!window)
{
glfwTerminate();
cerr<<"Could not create glfw window"<<endl;
return EXIT_FAILURE;
}
glfwMakeContextCurrent(window);
int major, minor, rev;
major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);
printf("OpenGL version recieved: %d.%d.%d\n", major, minor, rev);
printf("Supported OpenGL is %s\n", (const char*)glGetString(GL_VERSION));
printf("Supported GLSL is %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
glfwSetInputMode(window,GLFW_CURSOR,GLFW_CURSOR_NORMAL);
const auto & reshape = [] (GLFWwindow* window, int w, int h)
{
::w=w,::h=h;
};
glfwSetWindowSizeCallback(window,reshape);
{
int width, height;
glfwGetFramebufferSize(window, &width, &height);
int width_window, height_window;
glfwGetWindowSize(window, &width_window, &height_window);
highdpi = width/width_window;
reshape(window,width_window,height_window);
}
// Compile each shader
const auto & compile_shader = [](const GLint type,const char * str) -> GLuint
{
GLuint id = glCreateShader(type);
glShaderSource(id,1,&str,NULL);
glCompileShader(id);
return id;
};
GLuint vid = compile_shader(GL_VERTEX_SHADER,vertex_shader.c_str());
GLuint fid = compile_shader(GL_FRAGMENT_SHADER,fragment_shader.c_str());
// attach shaders and link
prog_id = glCreateProgram();
glAttachShader(prog_id,vid);
glAttachShader(prog_id,fid);
glLinkProgram(prog_id);
GLint status;
glGetProgramiv(prog_id, GL_LINK_STATUS, &status);
glDeleteShader(vid);
glDeleteShader(fid);
// construct a regular grid mesh
const int nx = 300;
const int ny = 305;
V.resize(nx*ny,3);
for(int i = 0;i<nx;i++)
{
for(int j = 0;j<ny;j++)
{
const float x = float(i)/(nx-1);
const float y = float(j)/(ny-1);
V.row(j*nx+i) << x,y, 0;
}
}
F.resize((nx-1)*(ny-1)*2,3);
for(int y = 0;y<ny-1;y++)
{
for(int x = 0;x<nx-1;x++)
{
// index of southwest corner
const int sw = (x +nx*(y+0));
const int se = (x+1+nx*(y+0));
const int ne = (x+1+nx*(y+1));
const int nw = (x +nx*(y+1));
// Index of first triangle in this square
const int gf = 2*(x+(nx-1)*y);
F(gf+0,0) = sw;
F(gf+0,1) = se;
F(gf+0,2) = nw;
F(gf+1,0) = se;
F(gf+1,1) = ne;
F(gf+1,2) = nw;
}
}
V.rowwise() -= V.colwise().mean();
V /= (V.colwise().maxCoeff()-V.colwise().minCoeff()).maxCoeff();
V /= 1.2;
// Generate and attach buffers to vertex array
glGenVertexArrays(1, &VAO);
GLuint VBO, EBO;
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*V.size(), V.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*F.size(), F.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
double t0 = get_seconds();
const auto draw = [&]()
{
double tic = get_seconds();
// clear screen and set viewport
glClearColor(0.1,0.1,0.1,0.);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0,0,w*highdpi,h*highdpi);
// Projection and modelview matrices
Eigen::Matrix4f proj;
float near = 0.01;
float far = 100;
float top = tan(35./360.*M_PI)*near;
float right = top * (double)::w/(double)::h;
float left = -right;
float bottom = -top;
proj.setConstant(4,4,0.);
proj(0,0) = (2.0 * near) / (right - left);
proj(1,1) = (2.0 * near) / (top - bottom);
proj(0,2) = (right + left) / (right - left);
proj(1,2) = (top + bottom) / (top - bottom);
proj(2,2) = -(far + near) / (far - near);
proj(3,2) = -1.0;
proj(2,3) = -(2.0 * far * near) / (far - near);
Eigen::Affine3f model = Eigen::Affine3f::Identity();
model.translate(Eigen::Vector3f(0,0,-1.5));
// select program and attach uniforms
glUseProgram(prog_id);
GLint proj_loc = glGetUniformLocation(prog_id,"proj");
glUniformMatrix4fv(proj_loc,1,GL_FALSE,proj.data());
GLint model_loc = glGetUniformLocation(prog_id,"model");
glUniformMatrix4fv(model_loc,1,GL_FALSE,model.matrix().data());
GLint t_loc = glGetUniformLocation(prog_id,"t");
glUniform1f(t_loc,tic-t0);
GLint m_loc = glGetUniformLocation(prog_id,"m");
glUniform1i(m_loc,m);
// Draw mesh as wireframe
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, F.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
};
// Main display routine
while (!glfwWindowShouldClose(window))
{
double tic = get_seconds();
static size_t count = 0;
static double t_prev = get_seconds();
if(tic-t_prev > 1)
{
const double fps = double(count)/(tic-t_prev);
std::stringstream ss;
ss << fps <<" FPS";
glfwSetWindowTitle(window, ss.str().c_str());
count = 0;
t_prev = tic;
}
count++;
draw();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return EXIT_SUCCESS;
}
GPU execution is highly parallelised and asynchronous, so timing it in the way you would CPU code is not going to work. Your GPU vendor will have profiling tools you can download which can provide a better insight than this kind of simple time measuring.
Either I am stupid or incredibly inexperienced ( probably both ) but I got somehow stuck on drawing a simple colored rectangle using opengl. It shouldnt be a problem since I just finished a simple opengl model loader ( however it was my first project so i only did everything once with reference ). Anyways nothing is showing up except the blue background.
Ive tried to make simple classes for basic shapes. Here is the rectangle class:
class AVRect{
private:
AVcolor Color;
GLuint VBO, VAO, EBO;
GLuint indices[6] = { // Note that we start from 0!
0, 1, 3, // First Triangle
1, 2, 3 // Second Triangle
};
public:
GLfloat geometry[12];
AVRect(int Drawmode, GLfloat x, GLfloat y, GLfloat x2, GLfloat y2,GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4,GLfloat r,GLfloat b,GLfloat g,GLfloat a);
void Draw(Shader shader);
};
Dont worry about color. Ive only set it in the source but its not used anywhere else atm. I am going to implement it as soon as ive got the rectangle working with a fixed color.
Source of the rect class:
#include "stdafx.h"
#include "Shapes.h"
AVRect::AVRect(int Drawmode,GLfloat x, GLfloat y, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4, GLfloat r, GLfloat b, GLfloat g, GLfloat a) {
geometry[0] = x;
geometry[1] = y;
geometry[2] = 0.0f;
geometry[3] = x2;
geometry[4] = y2;
geometry[5] = 0.0f;
geometry[6] = x3;
geometry[7] = y3;
geometry[8] = 0.0f;
geometry[9] = x4;
geometry[10] = y4;
geometry[11] = 0.0f;
Color.r = r;
Color.b = b;
Color.g = g;
Color.a = a;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(geometry), geometry, Drawmode);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, Drawmode);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void AVRect::Draw(Shader shader) {
glUseProgram(shader.Program);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
The main is pretty self explanatory:
// Bullethell.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <GL/glew.h>
#include <SDL.h>
#include <SDL_opengl.h>
#include <GLTextures.h>
#include <Shaders.h>
#include <ctime>
#include "Shapes.h"
#define HEIGHT 600
#define WIDTH 600
int main(int argc, char* args[])
{
SDL_Window *window;
SDL_Renderer *renderer;
window = SDL_CreateWindow("BulletHell", 100, 100, HEIGHT, WIDTH, SDL_WINDOW_OPENGL);
SDL_GLContext glcontext = SDL_GL_CreateContext(window);
glewExperimental = GL_TRUE;
if (GLEW_OK != glewInit())
{
// GLEW failed!
printf("GLEW INIT FAILED!");
}
Shader basic("./shaders/colorTest/colorTest.vs", "./shaders/colorTest/colorTest.frag");
AVRect test(GL_STATIC_DRAW,0.5f,0.5f,0.5f,-0.5f,-0.5f,-0.5f,0.5f,-0.5f,0.5f,0.9f,0.2f,0.5f);
int error = 0;
while (SDL_PollEvent(NULL))
{
clock_t start = clock();
glClearColor(0.2, 0.2, 0.5, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
test.Draw(basic);
SDL_GL_SwapWindow(window);
error = glGetError();
if (error != GL_NO_ERROR)
printf("GL ERROR:%d ", error);
while (((clock() - start) * 1000 / CLOCKS_PER_SEC) <16)
;
float MS = (float)((clock() - start) * 1000 / CLOCKS_PER_SEC);
// Frames per seconds
float FPS = 1000.0f / MS;
//printf("%f \n",FPS);
// printf( "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
}
return 1;
}
The Shader class is tested and is working. The shader is simple and should also work ( only passes on values and assigns a fixed color ).
I am probably just blind because i cant see the error. Please help me on this one.
Here is the Shader source for completeness sake:
#include "stdafx.h"
#include "Shaders.h"
Shader::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 Shader::Use()
{
glUseProgram(this->Program);
}
You're drawing degenerate triangles, so no pixels will be rendered. If you look at the coordinates of your "rectangle", spaced for easier readability:
0.5f, 0.5f,
0.5f, -0.5f,
-0.5f, -0.5f,
0.5f, -0.5f
you can see that the 2nd and 4th vertex have the same coordinates. The arrangement of your vertices looks like this:
0
2 1/3
Compare that with your indices:
0, 1, 3, // First Triangle
1, 2, 3 // Second Triangle
and you will see that both triangles are degenerate, because two of their vertices are the same.
The coordinates you probably meant to use are:
0.5f, 0.5f,
0.5f, -0.5f,
-0.5f, -0.5f,
-0.5f, 0.5f
I would actually recommend to use counter-clockwise orientation for your geometry, since this is the default winding order in OpenGL. Even though it does not really matter unless you plan to enable culling.
So I am getting a strange error when compiling an OpenGL 4.3 program and was hoping someone could help. I have been working on one of the recipes in the OpenGL Development Cookbook for a RippleDeformer. I am running into a compile error and am not sure how to fix it.
It seems like there is a variable in the main.cpp program named time and also one of the OpenGL libraries also involves the time.h header, so that causes a problem with the declaration. I tried to change the name of the variable in the program and it compiles, but it gives me a different error when I run the executable.
I tried to compile using the following commands:
g++ -o mycc main.cpp GLSLShader.cpp -lglut -lGLEW -lGL -lm -lglm
So let me give you the message and then the actual main.cpp and shader program:
Error Message
^
main.cpp: At global scope:
main.cpp:62:7: error: ‘float time’ redeclared as different kind of symbol
float time = 0;
^
In file included from /usr/include/pthread.h:24:0,
from /usr/include/x86_64-linux-gnu/c++/4.8/bits/gthr-default.h:35,
from /usr/include/x86_64-linux-gnu/c++/4.8/bits/gthr.h:148,
from /usr/include/c++/4.8/ext/atomicity.h:35,
from /usr/include/c++/4.8/bits/ios_base.h:39,
from /usr/include/c++/4.8/ios:42,
from /usr/include/c++/4.8/ostream:38,
from /usr/include/c++/4.8/iostream:39,
from main.cpp:3:
/usr/include/time.h:192:15: error: previous declaration of ‘time_t time(time_t*)’
extern time_t time (time_t *__timer) __THROW;
^
main.cpp: In function ‘void OnRender()’:
main.cpp:198:7: error: assignment of function ‘time_t time(time_t*)’
time = glutGet(GLUT_ELAPSED_TIME)/1000.0f * SPEED;
^
main.cpp:198:7: error: cannot convert ‘float’ to ‘time_t(time_t*)throw () {aka long int(long int*)throw
()}’ in assignment
main.cpp:213:35: error: cannot convert ‘time_t (*)(time_t*)throw () {aka long int (*)(long int*)throw ()}’ to ‘GLfloat {aka float}’ in argument passing
glUniform1f(shader("time"), time);
^
main.cpp
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "GLSLShader.h"
#define GL_CHECK_ERRORS assert(glGetError()== GL_NO_ERROR);
#ifdef _DEBUG
#pragma comment(lib, "glew_static_x86_d.lib")
#pragma comment(lib, "freeglut_static_x86_d.lib")
#pragma comment(lib, "SOIL_static_x86_d.lib")
#else
#pragma comment(lib, "glew_static_x86.lib")
#pragma comment(lib, "freeglut_static_x86.lib")
#pragma comment(lib, "SOIL_static_x86.lib")
#endif
using namespace std;
//screen size
const int WIDTH = 1280;
const int HEIGHT = 960;
//shader reference
GLSLShader shader;
//vertex array and vertex buffer object IDs
GLuint vaoID;
GLuint vboVerticesID;
GLuint vboIndicesID;
const int NUM_X = 40; //total quads on X axis
const int NUM_Z = 40; //total quads on Z axis
const float SIZE_X = 4; //size of plane in world space
const float SIZE_Z = 4;
const float HALF_SIZE_X = SIZE_X/2.0f;
const float HALF_SIZE_Z = SIZE_Z/2.0f;
//ripple displacement speed
const float SPEED = 2;
//ripple mesh vertices and indices
glm::vec3 vertices[(NUM_X+1)*(NUM_Z+1)];
const int TOTAL_INDICES = NUM_X*NUM_Z*2*3;
GLushort indices[TOTAL_INDICES];
//projection and modelview matrices
glm::mat4 P = glm::mat4(1);
glm::mat4 MV = glm::mat4(1);
//camera transformation variables
int state = 0, oldX=0, oldY=0;
float rX=25, rY=-40, dist = -7;
//current time
float time = 0;
//mouse click handler
void OnMouseDown(int button, int s, int x, int y)
{
if (s == GLUT_DOWN)
{
oldX = x;
oldY = y;
}
if(button == GLUT_MIDDLE_BUTTON)
state = 0;
else
state = 1;
}
//mosue move handler
void OnMouseMove(int x, int y)
{
if (state == 0)
dist *= (1 + (y - oldY)/60.0f);
else
{
rY += (x - oldX)/5.0f;
rX += (y - oldY)/5.0f;
}
oldX = x;
oldY = y;
glutPostRedisplay();
}
//OpenGL initialization
void OnInit() {
//set the polygon mode to render lines
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
GL_CHECK_ERRORS
//load shader
shader.LoadFromFile(GL_VERTEX_SHADER, "shaders/shader.vert");
shader.LoadFromFile(GL_FRAGMENT_SHADER, "shaders/shader.frag");
//compile and link shader
shader.CreateAndLinkProgram();
shader.Use();
//add shader attribute and uniforms
shader.AddAttribute("vVertex");
shader.AddUniform("MVP");
shader.AddUniform("time");
shader.UnUse();
GL_CHECK_ERRORS
//setup plane geometry
//setup plane vertices
int count = 0;
int i=0, j=0;
for( j=0;j<=NUM_Z;j++) {
for( i=0;i<=NUM_X;i++) {
vertices[count++] = glm::vec3( ((float(i)/(NUM_X-1)) *2-1)* HALF_SIZE_X, 0, ((float(j)/(NUM_Z-1))*2-1)*HALF_SIZE_Z);
}
}
//fill plane indices array
GLushort* id=&indices[0];
for (i = 0; i < NUM_Z; i++) {
for (j = 0; j < NUM_X; j++) {
int i0 = i * (NUM_X+1) + j;
int i1 = i0 + 1;
int i2 = i0 + (NUM_X+1);
int i3 = i2 + 1;
if ((j+i)%2) {
*id++ = i0; *id++ = i2; *id++ = i1;
*id++ = i1; *id++ = i2; *id++ = i3;
} else {
*id++ = i0; *id++ = i2; *id++ = i3;
*id++ = i0; *id++ = i3; *id++ = i1;
}
}
}
GL_CHECK_ERRORS
//setup plane vao and vbo stuff
glGenVertexArrays(1, &vaoID);
glGenBuffers(1, &vboVerticesID);
glGenBuffers(1, &vboIndicesID);
glBindVertexArray(vaoID);
glBindBuffer (GL_ARRAY_BUFFER, vboVerticesID);
//pass plane vertices to array buffer object
glBufferData (GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_STATIC_DRAW);
GL_CHECK_ERRORS
//enable vertex attrib array for position
glEnableVertexAttribArray(shader["vVertex"]);
glVertexAttribPointer(shader["vVertex"], 3, GL_FLOAT, GL_FALSE,0,0);
GL_CHECK_ERRORS
//pass the plane indices to element array buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices[0], GL_STATIC_DRAW);
GL_CHECK_ERRORS
cout<<"Initialization successfull"<<endl;
}
//release all allocated resources
void OnShutdown() {
//Destroy shader
shader.DeleteShaderProgram();
//Destroy vao and vbo
glDeleteBuffers(1, &vboVerticesID);
glDeleteBuffers(1, &vboIndicesID);
glDeleteVertexArrays(1, &vaoID);
cout<<"Shutdown successfull"<<endl;
}
//resize event handler
void OnResize(int w, int h) {
//set the viewport size
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
//setup the projection matrix
P = glm::perspective(45.0f, (GLfloat)w/h, 1.f, 1000.f);
}
//idle event callback
void OnIdle() {
glutPostRedisplay();
}
//display callback
void OnRender() {
//get the elapse time
time = glutGet(GLUT_ELAPSED_TIME)/1000.0f * SPEED;
//clear the colour and depth buffers
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//set teh camera viewing transformation
glm::mat4 T = glm::translate(glm::mat4(1.0f),glm::vec3(0.0f, 0.0f, dist));
glm::mat4 Rx = glm::rotate(T, rX, glm::vec3(1.0f, 0.0f, 0.0f));
glm::mat4 MV = glm::rotate(Rx, rY, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 MVP = P*MV;
//bind the shader
shader.Use();
//set the shader uniforms
glUniformMatrix4fv(shader("MVP"), 1, GL_FALSE, glm::value_ptr(MVP));
glUniform1f(shader("time"), time);
//draw the mesh triangles
glDrawElements(GL_TRIANGLES, TOTAL_INDICES, GL_UNSIGNED_SHORT, 0);
//unbind the shader
shader.UnUse();
//swap front and back buffers to show the rendered result
glutSwapBuffers();
}
int main(int argc, char** argv) {
//freeglut initialization calls
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitContextVersion (3, 3);
glutInitContextFlags (GLUT_CORE_PROFILE | GLUT_DEBUG);
glutInitWindowSize(WIDTH, HEIGHT);
glutCreateWindow("Ripple deformer - OpenGL 3.3");
//glew initialization
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err) {
cerr<<"Error: "<<glewGetErrorString(err)<<endl;
} else {
if (GLEW_VERSION_3_3)
{
cout<<"Driver supports OpenGL 3.3\nDetails:"<<endl;
}
}
err = glGetError(); //this is to ignore INVALID ENUM error 1282
GL_CHECK_ERRORS
//print information on screen
cout<<"\tUsing GLEW "<<glewGetString(GLEW_VERSION)<<endl;
cout<<"\tVendor: "<<glGetString (GL_VENDOR)<<endl;
cout<<"\tRenderer: "<<glGetString (GL_RENDERER)<<endl;
cout<<"\tVersion: "<<glGetString (GL_VERSION)<<endl;
cout<<"\tGLSL: "<<glGetString (GL_SHADING_LANGUAGE_VERSION)<<endl;
GL_CHECK_ERRORS
//opengl initialization
OnInit();
//callback hooks
glutCloseFunc(OnShutdown);
glutDisplayFunc(OnRender);
glutReshapeFunc(OnResize);
glutMouseFunc(OnMouseDown);
glutMotionFunc(OnMouseMove);
glutIdleFunc(OnIdle);
//main loop call
glutMainLoop();
return 0;
}
And finally the shader code:
GLSLShader.cpp
#include "GLSLShader.h"
#include <iostream>
GLSLShader::GLSLShader(void)
{
_totalShaders=0;
_shaders[VERTEX_SHADER]=0;
_shaders[FRAGMENT_SHADER]=0;
_shaders[GEOMETRY_SHADER]=0;
_attributeList.clear();
_uniformLocationList.clear();
}
GLSLShader::~GLSLShader(void)
{
_attributeList.clear();
_uniformLocationList.clear();
}
void GLSLShader::DeleteShaderProgram() {
glDeleteProgram(_program);
}
void GLSLShader::LoadFromString(GLenum type, const string& source) {
GLuint shader = glCreateShader (type);
const char * ptmp = source.c_str();
glShaderSource (shader, 1, &ptmp, NULL);
//check whether the shader loads fine
GLint status;
glCompileShader (shader);
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *infoLog= new GLchar[infoLogLength];
glGetShaderInfoLog (shader, infoLogLength, NULL, infoLog);
cerr<<"Compile log: "<<infoLog<<endl;
delete [] infoLog;
}
_shaders[_totalShaders++]=shader;
}
void GLSLShader::CreateAndLinkProgram() {
_program = glCreateProgram ();
if (_shaders[VERTEX_SHADER] != 0) {
glAttachShader (_program, _shaders[VERTEX_SHADER]);
}
if (_shaders[FRAGMENT_SHADER] != 0) {
glAttachShader (_program, _shaders[FRAGMENT_SHADER]);
}
if (_shaders[GEOMETRY_SHADER] != 0) {
glAttachShader (_program, _shaders[GEOMETRY_SHADER]);
}
//link and check whether the program links fine
GLint status;
glLinkProgram (_program);
glGetProgramiv (_program, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetProgramiv (_program, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *infoLog= new GLchar[infoLogLength];
glGetProgramInfoLog (_program, infoLogLength, NULL, infoLog);
cerr<<"Link log: "<<infoLog<<endl;
delete [] infoLog;
}
glDeleteShader(_shaders[VERTEX_SHADER]);
glDeleteShader(_shaders[FRAGMENT_SHADER]);
glDeleteShader(_shaders[GEOMETRY_SHADER]);
}
void GLSLShader::Use() {
glUseProgram(_program);
}
void GLSLShader::UnUse() {
glUseProgram(0);
}
void GLSLShader::AddAttribute(const string& attribute) {
_attributeList[attribute]= glGetAttribLocation(_program, attribute.c_str());
}
//An indexer that returns the location of the attribute
GLuint GLSLShader::operator [](const string& attribute) {
return _attributeList[attribute];
}
void GLSLShader::AddUniform(const string& uniform) {
_uniformLocationList[uniform] = glGetUniformLocation(_program, uniform.c_str());
}
GLuint GLSLShader::operator()(const string& uniform){
return _uniformLocationList[uniform];
}
#include <fstream>
void GLSLShader::LoadFromFile(GLenum whichShader, const string& filename){
ifstream fp;
fp.open(filename.c_str(), ios_base::in);
if(fp) {
string line, buffer;
while(getline(fp, line)) {
buffer.append(line);
buffer.append("\r\n");
}
//copy to source
LoadFromString(whichShader, buffer);
} else {
cerr<<"Error loading shader: "<<filename<<endl;
}
}
Debug 1 [RESOLVED]
Ahh, so I did what #KimKulling suggested and made the variable into elapsedTime instead of just time. So the file does compile to an executable mycc, but when I run it I get the following error:
Inconsistency detected by ld.so: dl-version.c: 224: _dl_check_map_versions: Assertion `needed != ((void *)0)' failed!
The line that it points to: 224 is just the first line of the main function int main() . . ..
I worked on it some more and discovered this issue has to do with an existing bug associated with dynamic library inconsistencies with OpenGL/C++. There is an existing bug filed on this issue.
https://bugs.launchpad.net/ubuntu/+source/nvidia-graphics-drivers-319/+bug/1248642
The good news is that someone found a workaround.
error running a compiled C++ file (uses OpenGL). Error: “Inconsistency detected by ld.so: dl-version.c: 224”
All I had to do was use different compile settings. It was really not intuitive.
I had to add a directory link to the video driver. Here is what worked:
g++ -L/usr/lib/nvidia-340/ main.cpp GLSLShader.cpp -lglut -lGLEW -lGL
The compiler seems to be right. There is already a symbol named time, so you have to change the name for something like
float elapsedTime = 0.0f;
When other errors occurres afterwards you have to fix them as well of course. But I thing the reason for them are a little bit different, so try to investigate the reasons and fix them step by step.
Maybe posting the next error could be a beginning :-).
I found a lot cases to create multiple objects by one single vertices array. And then through transform to get different ones, such as Draw 2 cubes in OpenGL using GLM and Cant draw multiple objects in opengl.
But what I want is to create complete diff objects by complete diff vertices arrays. A typical case is http://www.spacesimulator.net/wiki/index.php?title=Tutorials:Matrices_%28OpenGL3.3%29. How to implement it by GLM? I tried to find some example codes.
Next code are a complete example to draw 2 cubes using OpenGL and Linux Debian 9. Also, has a class to see pressed buton and positions if click the mouse. All sources and Makefile are included.
To compile: copy all files with correct name in same directory and
type make
To execute: type ./start
All needed libraries are installed with next commands:
apt-get install libglew-dev
apt-get install freeglut3-dev
apt-get install libglm-dev
The example are created from multiple examples from Internet and changed to Object Oriented code to clarify.
I hope it's useful.
File: cube.hpp
#ifndef CUBE_H
#define CUBE_H
#include <stdio.h>
#include <stdlib.h>
#include <glm/gtc/type_ptr.hpp>
#include <GL/glew.h>
#include <GL/glut.h>
class Cube{
private:
GLuint vboCubeVertex, vboCubeColors, vboCubeFaces;
GLint attribute_coord3d, attribute_v_color;
public:
int init_resources(GLuint shaderProgram);
void draw(GLint uniform_mvp, glm::mat4 mvp);
void disable();
void deleteBuffers();
};
#endif
File: cube.cpp
#include "cube.hpp"
int Cube::init_resources(GLuint shaderProgram)
{
fprintf(stderr, "init_resources\n");
//**********************************************************
// VERTEX **************************************************
//**********************************************************
// Each vertex has the format x,y,z
GLfloat arrCubeVertex[] = {
// front
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// back
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
-1.0, 1.0, -1.0,
};
//**********************************************************
// COLORS OF EACH VERTEX ***********************************
//**********************************************************
GLfloat arrCubeColors[] = {
// front colors
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
1.0, 1.0, 1.0,
// back colors
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
1.0, 1.0, 1.0,
};
// Faces are squares, each square are maked wit two triangles.
// See document OpenGL_Charly.pdf.
GLushort arrCubeFaces[] = {
// front
0, 1, 2,
2, 3, 0,
// right
1, 5, 6,
6, 2, 1,
// back
7, 6, 5,
5, 4, 7,
// left
4, 0, 3,
3, 7, 4,
// bottom
4, 5, 1,
1, 0, 4,
// up
3, 2, 6,
6, 7, 3,
};
glGenBuffers(1, &vboCubeVertex);
glBindBuffer(GL_ARRAY_BUFFER, vboCubeVertex);
glBufferData(GL_ARRAY_BUFFER, sizeof(arrCubeVertex), arrCubeVertex, GL_STATIC_DRAW);
// Las mismas operaciones que hicimos con los vertices, las hacemos ahora con los colores.
glGenBuffers(1, &vboCubeColors);
glBindBuffer(GL_ARRAY_BUFFER, vboCubeColors);
glBufferData(GL_ARRAY_BUFFER, sizeof(arrCubeColors), arrCubeColors, GL_STATIC_DRAW);
// Ahora lo mismo pero con las caras.
glGenBuffers(1, &vboCubeFaces);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboCubeFaces);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(arrCubeFaces), arrCubeFaces, GL_STATIC_DRAW);
//**********************************************************
attribute_coord3d = glGetAttribLocation(shaderProgram, "coord3d");
if (attribute_coord3d == -1)
{
fprintf(stderr, "Could not bind attribute %s\n", "coord3d");
return 0;
}
attribute_v_color = glGetAttribLocation(shaderProgram, "v_color");
if (attribute_v_color == -1)
{
fprintf(stderr, "Could not bind attribute %s\n", "v_color");
return 0;
}
return 1;
}
void Cube::draw(GLint uniform_mvp, glm::mat4 mvp){
glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
// Cube vertices
glEnableVertexAttribArray(attribute_coord3d);
glBindBuffer(GL_ARRAY_BUFFER, vboCubeVertex);
// Attribute, elements per vertex (x,y,z), the type of each element, take our values as-is, no extra data between each position, offset of first element
glVertexAttribPointer(attribute_coord3d, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Cube colors
glEnableVertexAttribArray(attribute_v_color);
glBindBuffer(GL_ARRAY_BUFFER, vboCubeColors);
// Attribute, elements per vertex (R,G,B), the type of each element, take our values as-is, no extra data between each position, offset of first element
glVertexAttribPointer(attribute_v_color, 3, GL_FLOAT, GL_FALSE, 0, 0);
/* Push each element in buffer_vertices to the vertex shader */
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboCubeFaces);
int size;
glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
glDrawElements(GL_TRIANGLES, size/sizeof(GLushort), GL_UNSIGNED_SHORT, 0);
}
void Cube::disable(){
glDisableVertexAttribArray(attribute_coord3d);
glDisableVertexAttribArray(attribute_v_color);
}
void Cube::deleteBuffers(){
glDeleteBuffers(1, &vboCubeVertex);
glDeleteBuffers(1, &vboCubeColors);
glDeleteBuffers(1, &vboCubeFaces);
}
File: mouse.hpp
#ifndef MOUSE_H
#define MOUSE_H
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
struct Point {
GLint x;
GLint y;
};
class Mouse{
private:
Point p1, p2;
public:
int show(int button, int state, int x, int y);
};
#endif
File: mouse.cpp
#include "mouse.hpp"
int Mouse::show(int button, int state, int x, int y)
{
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
printf("%s\n", "LEFT DOWN");
}
else if(button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
printf("%s\n", "LEFT UP");
}
printf("mouse X: %d, Y: %d\n", x, y);
}
File: shader_utils.hpp
#ifndef _CREATE_SHADER_H
#define _CREATE_SHADER_H
#include <GL/glew.h>
char* file_read(const char* filename);
void print_log(GLuint object);
GLuint create_shader(const char* filename, GLenum type);
GLuint create_program(const char* vertexfile, const char *fragmentfile);
GLuint create_gs_program(const char* vertexfile, const char *geometryfile, const char *fragmentfile, GLint input, GLint output, GLint vertices);
GLint get_attrib(GLuint program, const char *name);
GLint get_uniform(GLuint program, const char *name);
#endif
File: shader_utils.cpp
#include <stdio.h>
#include <stdlib.h>
#include "shader_utils.hpp"
char* file_read(const char* filename)
{
FILE* in = fopen(filename, "rb");
if (in == NULL) return NULL;
int res_size = BUFSIZ;
char* res = (char*)malloc(res_size);
int nb_read_total = 0;
while (!feof(in) && !ferror(in)) {
if (nb_read_total + BUFSIZ > res_size) {
if (res_size > 10*1024*1024) break;
res_size = res_size * 2;
res = (char*)realloc(res, res_size);
}
char* p_res = res + nb_read_total;
nb_read_total += fread(p_res, 1, BUFSIZ, in);
}
fclose(in);
res = (char*)realloc(res, nb_read_total + 1);
res[nb_read_total] = '\0';
return res;
}
void print_log(GLuint object)
{
GLint log_length = 0;
if (glIsShader(object))
glGetShaderiv(object, GL_INFO_LOG_LENGTH, &log_length);
else if (glIsProgram(object))
glGetProgramiv(object, GL_INFO_LOG_LENGTH, &log_length);
else {
fprintf(stderr, "printlog: Not a shader or a program\n");
return;
}
char* log = (char*)malloc(log_length);
if (glIsShader(object))
glGetShaderInfoLog(object, log_length, NULL, log);
else if (glIsProgram(object))
glGetProgramInfoLog(object, log_length, NULL, log);
fprintf(stderr, "%s", log);
free(log);
}
GLuint create_shader(const char* filename, GLenum type)
{
const GLchar* source = file_read(filename);
if (source == NULL) {
fprintf(stderr, "Error opening %s: ", filename); perror("");
return 0;
}
GLuint res = glCreateShader(type);
const GLchar* sources[] = {
// Define GLSL version
#ifdef GL_ES_VERSION_2_0
"#version 100\n"
#else
"#version 120\n"
#endif
,
// GLES2 precision specifiers
#ifdef GL_ES_VERSION_2_0
// Define default float precision for fragment shaders:
(type == GL_FRAGMENT_SHADER) ?
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
"precision highp float; \n"
"#else \n"
"precision mediump float; \n"
"#endif \n"
: ""
// Note: OpenGL ES automatically defines this:
// #define GL_ES
#else
// Ignore GLES 2 precision specifiers:
"#define lowp \n"
"#define mediump\n"
"#define highp \n"
#endif
,
source };
glShaderSource(res, 3, sources, NULL);
free((void*)source);
glCompileShader(res);
GLint compile_ok = GL_FALSE;
glGetShaderiv(res, GL_COMPILE_STATUS, &compile_ok);
if (compile_ok == GL_FALSE) {
fprintf(stderr, "%s:", filename);
print_log(res);
glDeleteShader(res);
return 0;
}
return res;
}
GLuint create_program(const char *vertexfile, const char *fragmentfile) {
GLuint program = glCreateProgram();
GLuint shader;
if(vertexfile) {
shader = create_shader(vertexfile, GL_VERTEX_SHADER);
if(!shader)
return 0;
glAttachShader(program, shader);
}
if(fragmentfile) {
shader = create_shader(fragmentfile, GL_FRAGMENT_SHADER);
if(!shader)
return 0;
glAttachShader(program, shader);
}
glLinkProgram(program);
GLint link_ok = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
if (!link_ok) {
fprintf(stderr, "glLinkProgram:");
print_log(program);
glDeleteProgram(program);
return 0;
}
return program;
}
#ifdef GL_GEOMETRY_SHADER
GLuint create_gs_program(const char *vertexfile, const char *geometryfile, const char *fragmentfile, GLint input, GLint output, GLint vertices) {
GLuint program = glCreateProgram();
GLuint shader;
if(vertexfile) {
shader = create_shader(vertexfile, GL_VERTEX_SHADER);
if(!shader)
return 0;
glAttachShader(program, shader);
}
if(geometryfile) {
shader = create_shader(geometryfile, GL_GEOMETRY_SHADER);
if(!shader)
return 0;
glAttachShader(program, shader);
glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, input);
glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output);
glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, vertices);
}
if(fragmentfile) {
shader = create_shader(fragmentfile, GL_FRAGMENT_SHADER);
if(!shader)
return 0;
glAttachShader(program, shader);
}
glLinkProgram(program);
GLint link_ok = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
if (!link_ok) {
fprintf(stderr, "glLinkProgram:");
print_log(program);
glDeleteProgram(program);
return 0;
}
return program;
}
#else
GLuint create_gs_program(const char *vertexfile, const char *geometryfile, const char *fragmentfile, GLint input, GLint output, GLint vertices) {
fprintf(stderr, "Missing support for geometry shaders.\n");
return 0;
}
#endif
GLint get_attrib(GLuint program, const char *name) {
GLint attribute = glGetAttribLocation(program, name);
if(attribute == -1)
fprintf(stderr, "Could not bind attribute %s\n", name);
return attribute;
}
GLint get_uniform(GLuint program, const char *name) {
GLint uniform = glGetUniformLocation(program, name);
if(uniform == -1)
fprintf(stderr, "Could not bind uniform %s\n", name);
return uniform;
}
File: start.cpp
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "shader_utils.hpp"
#include "mouse.hpp"
#include "cube.hpp"
int scrWidth = 600;
int scrHeight = 600;
GLuint shaderProgram;
GLint uniform_mvp;
Cube cube1;
Cube cube2;
glm::mat4 mvpCube1;
glm::mat4 mvpCube2;
Mouse theMouse;
void onIdle()
{
glm::vec3 rotationCube1(0, 1, 0); // Rotate cube 1 over Y axis
float angleCube1 = glutGet(GLUT_ELAPSED_TIME) / 1000.0 * 5; // 5° per second
glm::vec3 translationCube1 (0.0, 0.0, -2.0); // Translate cube 1 over Z axis
glm::vec3 rotationCube2(1, 0, 0); // Rotate cube 2 over X axis
float angleCube2 = glutGet(GLUT_ELAPSED_TIME) / 1000.0 * 3; // 3° per second
glm::vec3 translationCube2 (1.0, 0.0, 0.0); // Translate cube 2 over X axis
// Frustum parameters
float angleVision = 45.0f; // Also called Fovy
float aspect = 1.0f * scrWidth / scrHeight;
float zNear = 0.1f;
float zFar = 10.f;
// Camera parameters
glm::vec3 cameraEye(0.0, 2.0, -10.0);
glm::vec3 cameraCenter(0.0, 0.0, -5.0);
glm::vec3 cameraUp(0.0, 1.0, 0.0);
// Method lookAt has 3 parameters: eye, center, up
glm::mat4 view = glm::lookAt(cameraEye, cameraCenter, cameraUp);
// Create the projection matrix
glm::mat4 projection = glm::perspective(angleVision, aspect, zNear, zFar);
glm::mat4 modelCube1 = glm::mat4(); // Carga model con la identity matrix
modelCube1 = glm::translate(modelCube1, translationCube1); // El modelo queda trasladado.
modelCube1 = glm::rotate(modelCube1, angleCube1, rotationCube1); // El modelo ahora queda trasladado y rotado.
mvpCube1 = projection * view * modelCube1;
glm::mat4 modelCube2 = glm::mat4(); // Carga model con la identity matrix
modelCube2 = glm::translate(modelCube2, translationCube2); // El modelo queda trasladado.
modelCube2 = glm::rotate(modelCube2, angleCube2, rotationCube2); // El modelo ahora queda trasladado y rotado.
mvpCube2 = projection * view * modelCube2;
glUseProgram(shaderProgram);
glutPostRedisplay();
}
void onDisplay()
{
glClearColor(0.0, 0.0, 0.0, 1.0); // Set color (0, 0, 0 = Black)
// R,G,B,A
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram); // Program with loaded shaders
cube1.draw(uniform_mvp, mvpCube1);
cube1.disable();
cube2.draw(uniform_mvp, mvpCube2);
cube2.disable();
glutSwapBuffers();
}
void onReshape(int width, int height)
{
fprintf(stderr, "onReshape\n");
scrWidth = width;
scrHeight = height;
glViewport(0, 0, scrWidth, scrHeight);
}
void free_resources()
{
fprintf(stderr, "free_resources\n");
glDeleteProgram(shaderProgram);
cube1.deleteBuffers();
cube2.deleteBuffers();
}
void myMouseFunc(int button, int state, int x, int y)
{
theMouse.show(button, state, x, y);
}
int init(){
uniform_mvp = glGetUniformLocation(shaderProgram, "mvp");
if (uniform_mvp == -1)
{
fprintf(stderr, "Could not bind uniform %s\n", "mvp");
return 0;
}
return 1;
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA|GLUT_ALPHA|GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(scrWidth, scrHeight);
glutCreateWindow("Two Cubes");
GLenum glew_status = glewInit();
if (glew_status != GLEW_OK)
{
fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status));
return 1;
}
if (!GLEW_VERSION_2_0)
{
fprintf(stderr, "Error: your graphic card does not support OpenGL 2.0\n");
return 1;
}
GLint link_ok = GL_FALSE;
GLuint vs, fs;
if ((vs = create_shader("cube_vertex.glsl", GL_VERTEX_SHADER)) == 0) return 0;
if ((fs = create_shader("cube_fragment.glsl", GL_FRAGMENT_SHADER)) == 0) return 0;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vs);
glAttachShader(shaderProgram, fs);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &link_ok);
if (!link_ok)
{
fprintf(stderr, "glLinkProgram:");
print_log(shaderProgram);
return 0;
}
cube1 = Cube();
cube2 = Cube();
if (init() && cube1.init_resources(shaderProgram) && cube2.init_resources(shaderProgram))
{
glutMouseFunc(myMouseFunc);
glutDisplayFunc(onDisplay); // Set the display function for the current window.
glutReshapeFunc(onReshape); // Set the reshape function for the current window.
glutIdleFunc(onIdle); // Set the global idle callback (perform background proccessing)
// Enable server side capabilities
glEnable(GL_BLEND); // GL_BLEND: If enabled, blend the computed fragment color values with the
// values in the color buffers. See glBlendFunc.
glEnable(GL_DEPTH_TEST); // GL_DEPTH_TEST: If enabled, do depth comparisons and update the depth buffer.
// Note that even if the depth buffer exists and the depth mask is non-zero,
// the depth buffer is not updated if the depth test is disabled. See glDepthFunc
// and glDepthRange.
//glDepthFunc(GL_LESS);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutMainLoop();
}
free_resources();
return 0;
}
File: cube_fragment.glsl
varying vec3 f_color;
void main(void) {
gl_FragColor = vec4(f_color.x, f_color.y, f_color.z, 1.0);
}
File: cube_vertex.glsl
attribute vec3 v_color;
uniform mat4 mvp;
varying vec3 f_color;
void main(void)
{
gl_Position = mvp * vec4(coord3d, 1.0);
f_color = v_color;
}
File: Makefile
LDLIBS=-lglut -lGLEW -lGL -lm
all: start
clean:
rm -f *.o start
start: mouse.o shader_utils.o cube.o
.PHONY: all clean
The result are two rotating cubes:
Firstly, GLM is a maths library that provides vectors, matrices etc that behave and look like (as much as possible) vectors and matrices used in GLSL - that is, shader code. GLM is useful when writing applications that use OpenGL, but it actually isn't necessary, and it's got nothing to do with rendering objects.
If you want to draw different objects using different vertex arrays, read a tutorial such as the one mentioned or check out http://www.arcsynthesis.org/gltut/. See how it loads data into a vertex array and renders it, then do this twice for your different arrays. Bear in mind that switching vertex arrays is slow - you might want to load multiple objects into one vertex buffer and then use a render command with index offsets (e.g. glMultiDrawElementsBaseVertex).
I am trying to implement soft particles in my projects.
Everything is fine , I implement the texture also. But when the mouse is moved to a certain angle,
the particles get distorted. The particle is generated in view space.
So, I would like to know how could I implement the billboard in my project so that every particles seem uniform.Here is my code:
bool CETSmokeRenderer::InitBuffers()
{
size_t vertexSize = 3 * 4 * m_NumVertex * sizeof(float);
size_t colorSize = 4 * 4 * m_NumVertex * sizeof(float);
size_t texCoordSize = 2 * 4 * m_NumVertex * sizeof(float);
if(!vertexBuffer)
{
glDeleteBuffersARB(1, &vertexBuffer);
glDeleteBuffersARB(1, &colorBuffer);
glDeleteBuffersARB(1, &texCoordBuffer);
}
glGenBuffersARB(1, &vertexBuffer);
glGenBuffersARB(1, &colorBuffer);
glGenBuffersARB(1, &texCoordBuffer);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffer);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexSize, NULL, GL_STREAM_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, colorBuffer);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, colorSize, NULL, GL_STREAM_DRAW_ARB);
// Creates the static texture data
size_t len = 2 * 4 * m_NumVertex;
if(0 > m_NumVertex)
{
return false;
}
else if(0 == m_NumVertex)
{
return true;
}
float *texCoords = new float[len];
{
size_t i = 0;
while(i < len)
{
// u v
texCoords[i++] = 0.0f; texCoords[i++] = 0.0f;
texCoords[i++] = 1.0f; texCoords[i++] = 0.0f;
texCoords[i++] = 1.0f; texCoords[i++] = 1.0f;
texCoords[i++] = 0.0f; texCoords[i++] = 1.0f;
}
}
glBindBufferARB(GL_ARRAY_BUFFER_ARB, texCoordBuffer);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, texCoordSize, (void*)texCoords, GL_STATIC_DRAW_ARB);
delete texCoords;
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
return 0;
}
void CETSmokeRenderer::Draw(Camera &cam, bool useTex)
{
if(useTex)
glBindTexture(GL_TEXTURE_2D, texID);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
mBaseView->SetupViewingTransform();
size_t len = particleStore.size();
std::vector<SimpleSmokeParticle> toDraw;
for(size_t i = 0; i < len; i++)
{
SimpleSmokeParticle sp;
sp.transP = particleStore[i].p;
sp.index = i;
toDraw.push_back(sp);
}
//std::sort(toDraw.begin(), toDraw.end(), ParticleCmp);
#ifdef USE_VBO
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffer);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, 3 * 4 * m_NumVertex * sizeof(float), NULL, GL_STREAM_DRAW_ARB);
float *vertexPtr = (float*)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
assert(vertexPtr);
for(size_t i = 0, count = 0; count < len; count++)
{
SmokeParticle &prt = particleStore[ toDraw[count].index ];
Point3f &p = toDraw[count].transP;
float w = prt.w / 0.5f;
float h = prt.h / 1.0f;
vertexPtr[i++] = p.x - w; vertexPtr[i++] = p.y - h; vertexPtr[i++] = p.z;
vertexPtr[i++] = p.x + w; vertexPtr[i++] = p.y - h; vertexPtr[i++] = p.z;
vertexPtr[i++] = p.x + w; vertexPtr[i++] = p.y + h; vertexPtr[i++] = p.z;
vertexPtr[i++] = p.x - w; vertexPtr[i++] = p.y + h; vertexPtr[i++] = p.z;
}
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, colorBuffer);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, 4 * 4 * m_NumVertex * sizeof(float), NULL, GL_STREAM_DRAW_ARB);
float *colorPtr = (float*)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
assert(colorBuffer);
for(size_t i = 0, count = 0; count < len; count++)
{
SmokeParticle &prt = particleStore[ toDraw[count].index ];
// r g b a
colorPtr[i++] = prt.r; colorPtr[i++] = prt.g; colorPtr[i++] = prt.b; colorPtr[i++] = prt.alpha;
colorPtr[i++] = prt.r; colorPtr[i++] = prt.g; colorPtr[i++] = prt.b; colorPtr[i++] = prt.alpha;
colorPtr[i++] = prt.r; colorPtr[i++] = prt.g; colorPtr[i++] = prt.b; colorPtr[i++] = prt.alpha;
colorPtr[i++] = prt.r; colorPtr[i++] = prt.g; colorPtr[i++] = prt.b; colorPtr[i++] = prt.alpha;
}
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
// Draws buffered data
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffer);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, colorBuffer);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, texCoordBuffer);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glDrawArrays(GL_QUADS, 0, (GLsizei)len *4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
#else
{..}
glPopMatrix();
}
void CETSmokeRenderer::Render()
{
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Renders depth information
if(useSoftParticles)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE);
glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE);
glClampColorARB(GL_CLAMP_READ_COLOR_ARB, GL_FALSE);
glClearColor(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX);
glClear(GL_COLOR_BUFFER_BIT);;
glUseProgramObjectARB(0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, GL_TRUE);
glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_TRUE);
glClampColorARB(GL_CLAMP_READ_COLOR_ARB, GL_TRUE);
glBindTexture(GL_TEXTURE_2D, 0);
// renders the soft particles
glUseProgramObjectARB(particleShader);
// Sets texture data
GLint texloc = glGetUniformLocationARB(particleShader, "tex");
GLint depthTexloc = glGetUniformLocationARB(particleShader, "depthInfo");
GLint powerloc = glGetUniformLocationARB(particleShader, "power");
glUniform1fARB(powerloc, (float)softParticlePower);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, TextureID());
glUniform1iARB(texloc, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depthTex);
glUniform1iARB(depthTexloc, 1);
Draw(m_pCamera, false);
// Unbinds shader and textures
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgramObjectARB(0);
}
else
{
glUseProgramObjectARB(particleShader);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, TextureID());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depthTex);
Draw(m_pCamera, true);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgramObjectARB(0);
}
}
One way of achieving what you are looking for is to utilise point sprites, I have attached some code below that illustrates this in a simple way, hope this helps:
main.cpp
/*
Simple point-sprite particle demo - renders particles using spheres
Requirements:
GLM maths library
Freeglut
*/
#include <gl/glew.h>
#include <gl/freeglut.h>
#include <iostream>
#include "GLSLShader.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_projection.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <cassert>
#define GL_CHECK_ERRORS assert(glGetError()== GL_NO_ERROR)
using namespace std;
class Screen
{
public:
int width, height;
string title;
unsigned int displayFlags, contextFlags;
Screen(string ititle, int iwidth = 1024, int iheight = 768){
Screen(ititle, (GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA), (GLUT_CORE_PROFILE | GLUT_DEBUG), iwidth, iheight)
}
Screen(string ititle, unsigned int disFlags, unsigned int contFlags, int iwidth = 1024, int iheight = 768){
title = ititle; width = iwidth; height = iheight;
displayFlags = disFlags;
contextFlags = contFlags;
}
};
const int TOTAL= 9;
GLfloat positions[3*TOTAL]={-1,0,-1, 0,0,-1, 1,0,-1,-1,0, 0, 0,0, 0, 1,0, 0,-1,0, 1, 0,0, 1, 1,0,1};
GLuint vboID, vaoID;
GLsizei stride = sizeof(GLfloat)*3;
GLSLShader shader;
int filling=1;
// Absolute rotation values (0-359 degrees) and rotiation increments for each frame
float rotation_x=0, rotation_x_increment=0.1f;
float rotation_y=0, rotation_y_increment=0.05f;
float rotation_z=0, rotation_z_increment=0.03f;
glm::mat4 P; //projection matrix;
bool bRotate=true;
void InitShaders(void)
{
shader.LoadFromFile(GL_VERTEX_SHADER, "shader.vert");
shader.LoadFromFile(GL_FRAGMENT_SHADER, "shader.frag");
shader.CreateAndLinkProgram();
shader.Use();
shader.AddAttribute("vVertex");
shader.AddUniform("Color");
shader.AddUniform("lightDir");
shader.AddUniform("MVP");
glUniform3f(shader("lightDir"), 0,0,1);
glUniform3f(shader("Color"),1,0,0);
shader.UnUse();
GL_CHECK_ERRORS;
}
void InitVAO() {
GL_CHECK_ERRORS;
//Create vao and vbo stuff
glGenVertexArrays(1, &vaoID);
glGenBuffers (1, &vboID);
GL_CHECK_ERRORS;
glBindVertexArray(vaoID);
glBindBuffer (GL_ARRAY_BUFFER, vboID);
glBufferData (GL_ARRAY_BUFFER, sizeof(positions), &positions[0], GL_STATIC_DRAW);
GL_CHECK_ERRORS;
glEnableVertexAttribArray(shader["vVertex"]);
glVertexAttribPointer (shader["vVertex"], 3, GL_FLOAT, GL_FALSE,stride,0);
glBindVertexArray(0);
GL_CHECK_ERRORS;
}
void SetupGLBase() {
glGetError();
GL_CHECK_ERRORS;
glClearColor(0.0f,0.0f,0.2f,0.0f);
GL_CHECK_ERRORS;
InitShaders();
InitVAO();
glEnable(GL_DEPTH_TEST); // We enable the depth test (also called z buffer)
GL_CHECK_ERRORS;
glPointSize(50);
}
void OnRender() {
GL_CHECK_ERRORS;
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
//setup matrices
glm::mat4 T = glm::translate(glm::mat4(1.0f),glm::vec3(0.0f, 0.0f, -5));
glm::mat4 Rx = glm::rotate(T, rotation_x, glm::vec3(1.0f, 0.0f, 0.0f));
glm::mat4 Ry = glm::rotate(Rx, rotation_y, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 MV = glm::rotate(Ry, rotation_z, glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 MVP = P*MV;
//draw the points
shader.Use();
glUniformMatrix4fv(shader("MVP"), 1, GL_FALSE, glm::value_ptr(MVP));
glBindVertexArray(vaoID);
glDrawArrays(GL_POINTS, 0, TOTAL);
glBindVertexArray(0);
shader.UnUse();
glutSwapBuffers();
}
void OnResize(int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
//setup the projection matrix
P = glm::perspective(45.0f, (GLfloat)w/h, 1.f, 1000.f);
}
void OnShutdown() {
glDeleteBuffers(1, &vboID);
glDeleteVertexArrays(1, &vaoID);
}
void OnKey(unsigned char key, int x, int y)
{
switch (key)
{
case ' ': bRotate=!bRotate; break;
case 'r': case 'R':
if (filling==0)
{
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); // Filled Polygon Mode
filling=1;
}
else
{
glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); // Outline Polygon Mode
filling=0;
}
break;
}
}
void OnSpecialKey(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_UP: rotation_x_increment = rotation_x_increment +0.005f; break;
case GLUT_KEY_DOWN: rotation_x_increment = rotation_x_increment -0.005f; break;
case GLUT_KEY_LEFT: rotation_y_increment = rotation_y_increment +0.005f; break;
case GLUT_KEY_RIGHT: rotation_y_increment = rotation_y_increment -0.005f; break;
}
}
void OnIdle() {
if(bRotate) {
rotation_x = rotation_x + rotation_x_increment;
rotation_y = rotation_y + rotation_y_increment;
rotation_z = rotation_z + rotation_z_increment;
}
if (rotation_x > 359) rotation_x = 0;
if (rotation_y > 359) rotation_y = 0;
if (rotation_z > 359) rotation_z = 0;
glutPostRedisplay();
}
void glTestAndInfo(GLEnum glewInitResponse)
{
if (GLEW_OK != glewInitResponse) {
cerr<<"Error: "<<glewGetErrorString(glewInitResponse)<<endl;
} else {
if (GLEW_VERSION_3_3)
{
cout<<"Driver supports OpenGL 3.3 or greater.\nDetails:"<<endl;
}
}
cout<<"Using GLEW "<<glewGetString(GLEW_VERSION)<<endl;
cout<<"Vendor: "<<glGetString (GL_VENDOR)<<endl;
cout<<"Renderer: "<<glGetString (GL_RENDERER)<<endl;
cout<<"Version: "<<glGetString (GL_VERSION)<<endl;
cout<<"GLSL: "<<glGetString (GL_SHADING_LANGUAGE_VERSION)<<endl;
}
void main(int argc, char** argv) {
Screen *screen = news Screen("Point sprites as spheres in OpenGL 3.3");
atexit(OnShutdown);
glutInit(&argc, argv);
glutInitDisplayMode(screen->displayFlags);
glutInitContextVersion (3, 3);
glutInitContextFlags (screen->contextFlags);
glutInitWindowSize(screen->width, screen->height);
glutCreateWindow(screen->title);
glewExperimental = GL_TRUE;
glTestAndInfo(glewInit());
SetupGLBase();
glutDisplayFunc(OnRender);
glutReshapeFunc(OnResize);
glutKeyboardFunc(OnKey);
glutSpecialFunc(OnSpecialKey);
glutIdleFunc(OnIdle);
glutMainLoop();
}
GLSLShader.h
#pragma once
#ifndef GLSL_SHADER_H
#define GLSL_SHADER_H
#include <GL/glew.h>
#include <map>
#include <string>
using namespace std;
class GLSLShader
{
public:
GLSLShader(void);
~GLSLShader(void);
void LoadFromString(GLenum whichShader, const string source);
void LoadFromFile(GLenum whichShader, const string filename);
void CreateAndLinkProgram();
void Use();
void UnUse();
void AddAttribute(const string attribute);
void AddUniform(const string uniform);
GLuint operator[](const string attribute);// indexer: returns the location of the named attribute
GLuint operator()(const string uniform);
private:
enum ShaderType {VERTEX_SHADER, FRAGMENT_SHADER, GEOMETRY_SHADER};
GLuint _program;
int _totalShaders;
GLuint _shaders[3];//0 vertexshader, 1 fragmentshader, 2 geometryshader
map<string,GLuint> _attributeList;
map<string,GLuint> _uniformLocationList;
};
#endif
GLSLShader.cpp
/*
Really basic glsl shader class
*/
#include "GLSLShader.h"
#include <iostream>
#include <fstream>
// constructor
GLSLShader::GLSLShader(void)
{
_totalShaders=0;
_shaders[VERTEX_SHADER]=0;
_shaders[FRAGMENT_SHADER]=0;
_shaders[GEOMETRY_SHADER]=0;
_attributeList.clear();
_uniformLocationList.clear();
}
// destructor
GLSLShader::~GLSLShader(void)
{
_attributeList.clear();
_uniformLocationList.clear();
glDeleteProgram(_program);
}
// loader functions
void GLSLShader::LoadFromString(GLenum type, const string source) {
GLuint shader = glCreateShader (type);
const char * ptmp = source.c_str();
glShaderSource (shader, 1, &ptmp, NULL);
//check whether the shader loads fine
GLint status;
glCompileShader (shader);
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *infoLog= new GLchar[infoLogLength];
glGetShaderInfoLog (shader, infoLogLength, NULL, infoLog);
cerr<<"Compile log: "<<infoLog<<endl;
delete [] infoLog;
}
_shaders[_totalShaders++]=shader;
}
void GLSLShader::LoadFromFile(GLenum whichShader, const string filename){
ifstream fp;
fp.open(filename.c_str(), ios_base::in);
if(fp) {
string line, buffer;
while(getline(fp, line)) {
buffer.append(line);
buffer.append("\r\n");
}
//copy to source
LoadFromString(whichShader, buffer);
} else {
cerr<<"Error loading shader: "<<filename<<endl;
}
}
// utilitarian functions
void GLSLShader::CreateAndLinkProgram() {
_program = glCreateProgram ();
if (_shaders[VERTEX_SHADER] != 0) {
glAttachShader (_program, _shaders[VERTEX_SHADER]);
}
if (_shaders[FRAGMENT_SHADER] != 0) {
glAttachShader (_program, _shaders[FRAGMENT_SHADER]);
}
if (_shaders[GEOMETRY_SHADER] != 0) {
glAttachShader (_program, _shaders[GEOMETRY_SHADER]);
}
//link and check whether the program links fine
GLint status;
glLinkProgram (_program);
glGetProgramiv (_program, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetProgramiv (_program, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *infoLog= new GLchar[infoLogLength];
glGetProgramInfoLog (_program, infoLogLength, NULL, infoLog);
cerr<<"Link log: "<<infoLog<<endl;
delete [] infoLog;
}
glDeleteShader(_shaders[VERTEX_SHADER]);
glDeleteShader(_shaders[FRAGMENT_SHADER]);
glDeleteShader(_shaders[GEOMETRY_SHADER]);
}
void GLSLShader::Use() {
glUseProgram(_program);
}
void GLSLShader::UnUse() {
glUseProgram(0);
}
void GLSLShader::AddAttribute(const string attribute) {
_attributeList[attribute]= glGetAttribLocation(_program, attribute.c_str());
}
// indexer: returns the location of the named attribute
GLuint GLSLShader::operator [](const string attribute) {
return _attributeList[attribute];
}
void GLSLShader::AddUniform(const string uniform) {
_uniformLocationList[uniform] = glGetUniformLocation(_program, uniform.c_str());
}
GLuint GLSLShader::operator()(const string uniform){
return _uniformLocationList[uniform];
}
This code is pretty old and I have no way to test rendering here (no distinct GFX card) so if there are any issues let me know and I can fix it once at my GFX dev machine.
Addendum:
Shaders may help too (dont know how I forgot them, old age maybe catching up on me!) so here they are:
Vertex shader (shader.vert)
#version 330 // set this to whatever minimum version you want to support
in vec3 vVertex;
uniform mat4 MVP;
void main()
{
gl_Position = MVP*vec4(vVertex,1);
}
Fragment shader (shader.frag)
#version 330
out vec4 vFragColour;
uniform vec3 Colour;
uniform vec3 lightDirection;
void main(void)
{
// calculate normal from texture coordinates
vec3 N;
N.xy = gl_PointCoord* 2.0 - vec2(1.0);
float mag = dot(N.xy, N.xy);
if (mag > 1.0) discard; // kill pixels outside the circle we want
N.z = sqrt(1.0-mag); // this might be expensive depending on your hardware
float diffuse = max(0.0, dot(lightDirection, N)); // calculate lighting
vFragColour = vec4(Colour,1) * diffuse;
}
Addendum 2:
To add the freeglut libraries to your build and resolve LNK 1104 errors simply go to *Project >> Properties >> VC++ Directories* and add the directories where your freeglut includes, source libraries and dlls are stored, for example for lib files go to
Add the folders as follows:
DLL Directories: add to Executable Directories
.h file Directories(include folder): add to Include Directories
.cpp file Directories: add to Source Directories
.lib file Directories: add to Library Directories
Hope this helps:)