渲染粒子

时间:2015-05-28 08:29:55

标签: shader vertex-buffer particle-system transform-feedback

我正在尝试创建一个粒子系统。我正在使用转换反馈,此时此刻我只想尝试将其用于一点。问题是绘制循环的每次迭代都会渲染多个点。尽管我的粒子缓冲区只有一个单点的空间,但似乎点数仍在增加。循环不是绘制一个随后移动的点,而是为每次迭代添加一个点。下面是程序的代码,然后是我的顶点着色器的代码。此时我不使用任何几何着色器。

    #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);
    }

如果有任何不清楚的地方,请告诉我,并提前致谢。

1 个答案:

答案 0 :(得分:0)

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