我正在尝试创建一个粒子系统。我正在使用转换反馈,此时我只是想让它发挥作用。问题是绘制循环的每次迭代都会渲染多个点。尽管我的粒子缓冲区只有一个点的空间,但似乎点数还在不断增加。循环不是绘制一个然后移动的点,而是为每次迭代添加一个点。下面是程序的代码,然后是我的顶点着色器的代码。目前我没有使用任何几何着色器。
#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);
}
如果有任何不清楚的地方,请告诉我,并提前致谢。