BillBoarding实施

时间:2013-11-26 03:21:24

标签: c++ opengl shader

我正在尝试在我的项目中实现软粒子。 一切都很好,我也实现了纹理。但是当鼠标移动到某个角度时,  粒子变形了。粒子在视图空间中生成。 所以,我想知道如何在我的项目中实现广告牌,以便每个粒子看起来都是均匀的。这是我的代码:

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

        }

}

1 个答案:

答案 0 :(得分:0)

实现你正在寻找的东西的一种方法是利用点精灵,我在下面附上了一些代码,以简单的方式说明了这一点,希望这会有所帮助:

的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];
}

这段代码已经很老了,我无法在这里测试渲染(没有明显的GFX卡),所以如果有任何问题请告诉我,我可以在我的GFX开发机上修复一次。

附录:

着色器也可能有所帮助(不知道我是怎么忘记他们的,老年人可能会抓住我!)所以他们在这里:

顶点着色器(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);
}

片段着色器(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;
}

附录2:

要将freeglut库添加到构建并解决LNK 1104错误,只需转到*Project >> Properties >> VC++ Directories*并添加freeglut包含的目录,存储源库和dll,例如对于lib文件,请转到{{0 }}

按如下方式添加文件夹:

  • DLL目录:添加到可执行目录
  • .h文件目录(包含文件夹):添加到包含目录
  • .cpp文件目录:添加到源目录
  • .lib文件目录:添加到库目录

希望这会有所帮助:)