I am trying to create a particle system. I am using transform feedback and at this moment I am just trying to get this to work for one point. The problem is that more than one point is rendered for every iteration of the draw loop. It seems that points keeps getting added despite the fact that my particle buffer only have room for one single point. Instead of drawing one point which is then moved, the loop adds one point for every iteration. Below is the code for the program and then the code for my vertex shader. At this moment I do not use any geometry shader.
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include "Dependencies/glew/glew.h"
#include "Dependencies/glut/glut.h"
#include <time.h>
#include <iostream>
#include <sys/stat.h>
#include "Dependencies/glm/glm.hpp"
using namespace glm;
struct Particles{
vec3 Position = vec3(0.0, 0.0, 0.0);
//vec3 Velocity = vec3(0.0, 0.0, 0.0);
};
GLint inputAttrib;
GLuint program, programFrag, drawProgram; //Program object for using shaders above
GLuint m_TFB[2], m_PB[2]; //two transfromfbs and 2 pbuffers
GLuint query; //Keep track of amount of objects
unsigned int m_currVB;
unsigned int m_currTFB;
bool first = true;
const static int MAX_NUMBER = 1;
char* readShaderFile(const char *filename) {
FILE *file;
struct stat st;
file = fopen(filename, "r");
if (file == NULL){
fprintf(stderr, "ERROR: Cannot open shader file!");
return 0;
}
stat(filename, &st);
int bytesinfile = st.st_size;
char *buffer = (char*)malloc(bytesinfile + sizeof(char));
int bytesread = fread(buffer, 1, bytesinfile, file);
buffer[bytesread] = 0; // Terminate the string with 0
fclose(file);
return buffer;
}
void loadShaders(){
//load our vertex shader
GLint vertShader = glCreateShader(GL_VERTEX_SHADER);
const char *vertexAssembly = readShaderFile("vertex_shader.vert");
glShaderSource(vertShader, 1, &vertexAssembly, NULL);
glCompileShader(vertShader);
free((void *)vertexAssembly);
GLint isCompiled;
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE)
{
char str[256];
glGetShaderInfoLog(vertShader, 256, NULL, str);
fprintf(stderr, "Vertex shader compile error: %s\n", str);
}
program = glCreateProgram();
glAttachShader(program, vertShader);
const GLchar* feedbackVaryings[1];
feedbackVaryings[0] = "Position0";
//feedbackVaryings[1] = "Velocity0";
glTransformFeedbackVaryings(program, 1, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);
glLinkProgram(program);
//load our vertex draw shader
GLint vertDraw = glCreateShader(GL_VERTEX_SHADER);
const char *drawVertAssembly = readShaderFile("draw.vert");
glShaderSource(vertDraw, 1, &drawVertAssembly, NULL);
glCompileShader(vertDraw);
free((void *)drawVertAssembly);
glGetShaderiv(vertDraw, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE)
{
char str[256];
glGetShaderInfoLog(vertDraw, 256, NULL, str);
fprintf(stderr, "Vertex draw shader compile error: %s\n", str);
}
else{
std::cout << "Vert draw ok!" << std::endl;
}
drawProgram = glCreateProgram();
glAttachShader(drawProgram, vertDraw);
//load our vertex shader
GLint fragDraw = glCreateShader(GL_FRAGMENT_SHADER);
const char *drawFragAssembly = readShaderFile("draw.frag");
glShaderSource(fragDraw, 1, &drawFragAssembly, NULL);
glCompileShader(fragDraw);
free((void *)drawFragAssembly);
glGetShaderiv(fragDraw, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE)
{
char str[256];
glGetShaderInfoLog(fragDraw, 256, NULL, str);
fprintf(stderr, "Fragment draw shader compile error: %s\n", str);
}
else{
std::cout << "Frag draw ok!" << std::endl;
}
glAttachShader(drawProgram, fragDraw);
glLinkProgram(drawProgram);
}
void initSystem(){
loadShaders();
Particles data[MAX_NUMBER];
data[0].Position = vec3(0.0, 0.0, 0.0);
//data[0].Velocity = vec3(0.1, 0.0, 0.0);
glGenTransformFeedbacks(2, m_TFB);
glGenBuffers(2, m_PB);
for (int i = 0; i < 2; i++){
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_TFB[i]);
glBindBuffer(GL_ARRAY_BUFFER, m_PB[i]);
//glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(GL_FLOAT), data, GL_STREAM_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec3), &data[0], GL_DYNAMIC_DRAW);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_PB[i]);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
void updateParticles(){
glClear(GL_COLOR_BUFFER_BIT || GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
//Don't draw anything yet
glEnable(GL_RASTERIZER_DISCARD);
//Bind particle buffer to write from
glBindBuffer(GL_ARRAY_BUFFER, m_PB[m_currVB]);
//Create our attribute pointer. We only have position in the loop. The array is tightly packed maybe? We want to start drawing from the beginning?
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Particles), (GLvoid*)0);
//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GL_FLOAT), (const GLvoid*)(3 * sizeof(GL_FLOAT)));
glEnableVertexAttribArray(0);
//glEnableVertexAttribArray(1);
//Bind transform buffer to write to
//glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_TFB[m_currTFB]);
//Begin transformfeedback here we go man!!
//Use our shaders for updating
glUseProgram(program);
glBeginTransformFeedback(GL_POINTS);
glPointSize(20.0f);
if (first){
glDrawArrays(GL_POINTS, 0, 1);
first = false;
}
else{
glDrawTransformFeedback(GL_POINTS, m_TFB[m_currVB]);
}
glEndTransformFeedback();
glUseProgram(0);
//Disable dose arrays
glDisableVertexAttribArray(0);
//glDisableVertexAttribArray(1);
//Unbind our buffer to end this part of the operation
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
}
void drawParticles(){
//Now we want to actually draw some shit on the screen
glDisable(GL_RASTERIZER_DISCARD);
//Use our program for rendering
glUseProgram(drawProgram);
glClear(GL_COLOR_BUFFER_BIT || GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
//Bind particle buffer to draw points retrived from this draw call
glBindBuffer(GL_ARRAY_BUFFER, m_PB[m_currTFB]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Particles), (GLvoid*)0);
glEnableVertexAttribArray(0);
//Draw as many points as we have got in this draw call
glDrawTransformFeedback(GL_POINTS, m_TFB[m_currVB]);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
glutSwapBuffers();
}
void render(){
updateParticles();
drawParticles();
/*unsigned int tmp;
tmp = m_currTFB;
m_currTFB = m_currVB;
m_currVB = tmp;*/
m_currVB = m_currTFB;
m_currTFB = (m_currTFB + 1) & 0x1;
}
void init(){
glEnable(GL_DEPTH_TEST);
srand(time(NULL));
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutCreateWindow("ShaderTest");
glutInitWindowPosition(100, 100);
printf("%s\n", glGetString(GL_VERSION));
glewInit();
if (glewIsSupported("GL_VERSION_4_3"))
{
std::cout << " GLEW Version is 4.3\n ";
}
else
{
std::cout << "GLEW 4.3 not supported\n ";
}
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
init();
initSystem();
glutDisplayFunc(render);
glutIdleFunc(idle);
glutReshapeFunc(reshape);
glutMainLoop();
}
Below is the code for my vertex shader
#version 330
layout (location = 0) in vec3 Position;
layout (location = 0) out vec3 Position0;
void main() {
Position0 = Position + vec3(0.1,0.1,0.0);// + Velocity;
//Velocity0 = Velocity;
}
Furthermore I use a separate vertex shader and fragment shader for rendering the points.
#version 330
layout (location = 0) in vec3 Position;
out vec4 gl_Position;
void main() {
gl_Position.xyz = Position;
gl_Position.w = 1;
}
#version 330
out vec4 frag_color;
void main() {
frag_color = vec4(1,0,0,1);
}
Please let me know if anything is unclear and thanks in advance.
I managed to solve it myself. The line "glClear(GL_COLOR_BUFFER_BIT || GL_DEPTH_BUFFER_BIT);" was wrong and should be "glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);".