Shader 渲染粒子

Shader 渲染粒子,shader,vertex-buffer,particle-system,transform-feedback,Shader,Vertex Buffer,Particle System,Transform Feedback,我正在尝试创建一个粒子系统。我正在使用转换反馈,现在我只是想让它在一点上起作用。问题在于,绘制循环的每次迭代都会渲染多个点。尽管我的粒子缓冲区只能容纳一个点,但点似乎一直在增加。循环不是绘制一个然后移动的点,而是为每次迭代添加一个点。下面是程序的代码,然后是顶点着色器的代码。此时我不使用任何几何体着色器 #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include

我正在尝试创建一个粒子系统。我正在使用转换反馈,现在我只是想让它在一点上起作用。问题在于,绘制循环的每次迭代都会渲染多个点。尽管我的粒子缓冲区只能容纳一个点,但点似乎一直在增加。循环不是绘制一个然后移动的点,而是为每次迭代添加一个点。下面是程序的代码,然后是顶点着色器的代码。此时我不使用任何几何体着色器

    #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);
    }
#包括“stdafx.h”
#包括
#包括
#包括“依赖项/glew/glew.h”
#包括“依赖项/glut/glut.h”
#包括
#包括
#包括
#包括“依赖项/glm/glm.hpp”
使用名称空间glm;
结构粒子{
vec3位置=vec3(0.0,0.0,0.0);
//vec3速度=vec3(0.0,0.0,0.0);
};
闪烁输入;
GLuint程序、programFrag程序、drawProgram程序//用于使用上述着色器的程序对象
GLuint m_TFB[2],m_PB[2]//两个Transfromfb和两个PBuffer
GLuint查询//跟踪对象的数量
无符号整数m_currVB;
无符号整数m_currTFB;
bool first=true;
const static int MAX_NUMBER=1;
char*readShaderFile(常量char*filename){
文件*文件;
结构统计;
file=fopen(文件名为“r”);
if(file==NULL){
fprintf(stderr,“错误:无法打开着色器文件!”);
返回0;
}
stat(文件名,&st);
int bytesinfle=标准标准尺寸;
char*buffer=(char*)malloc(bytesinfle+sizeof(char));
int bytesread=fread(缓冲区,1,bytesinfile,文件);
buffer[bytesread]=0;//用0终止字符串
fclose(文件);
返回缓冲区;
}
void loader着色器(){
//加载我们的顶点着色器
闪烁顶点着色器=glCreateShader(GLU顶点着色器);
const char*vertexAssembly=readShaderFile(“vertex_shader.vert”);
glShaderSource(vertShader,1和vertexAssembly,NULL);
glCompileShader(vertShader);
自由((空*)顶点组件);
闪闪发光;
glGetShaderiv(顶点着色器、GL\u编译状态和isCompiled);
如果(isCompiled==GL_FALSE)
{
char-str[256];
glGetShaderInfoLog(vertShader,256,NULL,str);
fprintf(stderr,“顶点着色器编译错误:%s\n”,str);
}
program=glCreateProgram();
glAttachShader(程序、顶点着色器);
const GLchar*反馈变量[1];
反馈变量[0]=“位置0”;
//反馈变量[1]=“速度0”;
glTransformFeedbackVaryings(程序,1,反馈变量,GLU交错属性);
glLinkProgram(program);
//加载顶点绘制着色器
闪烁顶点绘制=glCreateShader(GL_顶点_着色器);
const char*drawVertAssembly=readShaderFile(“draw.vert”);
glShaderSource(vertDraw,1和drawVertAssembly,NULL);
glCompileShader(vertDraw);
自由((空*)组件);
glGetShaderiv(垂直绘制、GL编译状态和isCompiled);
如果(isCompiled==GL_FALSE)
{
char-str[256];
glGetShaderInfoLog(vertDraw,256,NULL,str);
fprintf(stderr,“顶点绘制着色器编译错误:%s\n”,str);
}
否则{

std::cout我自己设法解决了它。行“glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);”是错误的,应该是“glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);”

如果这对我有帮助的话,我发现12的粒子大小不匹配(m_PB[m_currTFB])也就是4。但可能是我不明白顶点指针是怎么工作的。