2017-05-13 5 views
0

익숙하지 않은 모든 사람들에게 OpenGL 인스턴스 드로잉은 하나의 셰이더 호출로 많은 객체가 그려지는 곳이기 때문에 모든 객체에 대해 한 번이 아니라 천 개의 객체에 대해 glDrawArrays가 한 번만 호출됩니다.움직이는 객체로 OpenGL 인스턴스 드로잉 사용하기

이제 문제는 : 끊임없이 변화하는 정점을 가진 객체에 대해 OpenGL 3에서 인스턴스 렌더링을 어떻게 구현합니까? 배열을 생성하거나 정점 쉐이더에서 오브젝트가 작동하지 않는 위치에만 지정하는 위치를 지정하면 모든 프레임마다 다른 속도로 좌표가 이동하는 오브젝트의 벡터가 계속 변경됩니다.

내가 사용하고있는 객체 클래스의 헤더와 내가 가지고있는 버텍스 쉐이더는 참조 용으로 아래에 설명되어 있습니다.

//CLASS 
class Laser { 

public: 

    GLfloat x, y, xVelocity, yVelocity; 
    GLuint texture; 
    GLfloat angle; 
    GLfloat velocity; 
    GLfloat width, height; 
    GLfloat drawWidth = 16; 
    GLfloat drawHeight = 16; 
    GLfloat damage; 
    GLint actsToDissapear = -1; 
    GLint actsExisting = 0; 
    GLboolean expired = false; 
    GLboolean isRotated = false; 
    GLboolean variableColor = false; 
    glm::vec3 color; 
    std::string type = "Laser"; 

    Laser(GLfloat damage, GLfloat width, GLfloat height, GLuint texture, GLfloat x, GLfloat y, GLfloat xVelocity, GLfloat yVelocity, GLfloat drawWidth, GLfloat drawHeight, GLfloat actsToDissapear, GLboolean isRotated, GLfloat angle, GLboolean variableColor, glm::vec3 color); 
    virtual void draw(SpriteRenderer* s); 
    virtual void move(Rachel* player); 
}; 

//VERTEX SHADER 
#version 330 core 
layout (location = 0) in vec4 vertex; 

uniform mat4 model; 
uniform mat4 projection; 
out vec2 TexCoords; 

void main() { 
    TexCoords = vec2(vertex.z, vertex.w); 
    gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0); 
} 
+2

"* 나는 계속이 개체에 대한 OpenGL은 3 인스턴스화 된 렌더링을 구현하려면 어떻게 변화하는 정점? * "나는 당신이 그것을 의미한다는 것을 정말로 모른다. 그리고 헤더 파일을 보여주는 것은 정확히 밝히지 않습니다. –

+0

인스턴스 렌더링을 설명하기 위해 편집되었습니다. 헤더 파일에 관해서, 나는 다양한 프레임 데이터와 함께 매 프레임마다 수백 배의 그림을 그려야한다는 것을 보여주고 싶었습니다. 위치는 매 프레임마다 변하고 속도는 각 물체마다 다를 수 있습니다. –

+2

인스턴스 렌더링이 무엇인지 알고 있습니다. 제가 이해하지 못하는 것은 "끊임없이 변하는 정점"에 관한 부분입니다. 한 인스턴스의 정점 데이터를 변경하면 * all *에 대한 정점 데이터가 변경됩니다. 인스 턴싱은 동일한 정점 데이터를 사용하여 인스턴스별로 다른 데이터를 가진 여러 객체를 렌더링합니다 (일반적으로 인스턴스의 위치를 ​​정의하는 데 사용되지만 색상과 같은 다른 요소에도 영향을 미칠 수 있습니다). 당신이 성취하고자하는 바를 묘사 해주십시오. –

답변

0

당신이 보는 개념은 속성 제수입니다. glVertexAttribDivisor을 참조하십시오.

즉, 모델 행렬을 uniform에서 버퍼에서 읽은 인스턴스 속성으로 변경합니다. 각 프레임은 해당 버퍼를 각 인스턴스의 새 위치로 업데이트합니다. 이것을 구현할 때 고려해야 할 한 가지는 소비 된 속성의 수를 반으로 줄이기 위해 모델 행렬에 대한 (vec3 offset, quat4 orientation) 표현을 사용하는 것입니다. 또한 현재 가지고있는 정확한 문제에 따라 계산 쉐이더가있는 GPU에서 버퍼를 직접 업데이트 할 수 있습니다.

+0

감사합니다. 나는 그것을 들여다 볼 것이다. –

0

Heres 당신이 찾고 있다고 생각하는 코드 예제. 저는 파티클 시스템을 위해 인스턴스 렌더링을 사용했고, 텍스처, 색상 및 움직임을 지원합니다. 안드로이드 OpenGL 및 Windows에서 모두 작동합니다. 이 코드는 실행하는 데 약간의 작업이 필요하지만 진행하기가 쉽습니다.

#include "ParticleSystem.h" 
    #include "Engine.h" 
    #include "Transform.h" 
    #include "Shader.h" 
    #include "Texture.h" 
    #include "Mesh.h" 
    #include "ShaderHandler.h" 

    ParticleSystem::ParticleSystem() 
    { 
    } 

    ParticleSystem::~ParticleSystem() 
    { 
     shader = nullptr; 
     texture = nullptr; 
     glDeleteVertexArrays(1, &vertexArrayObject); 
    } 

    void ParticleSystem::init(Engine * engine, float size, Texture * texture, float maxVelocity, bool gravity) 
    { 
     this->maxVelocity = maxVelocity; 
     this->gravity = gravity; 

     this->size = size; 
     vertex = 
     { 
      -size, -size, 0.0f, 
      -size, size, 0.0f, 
      size, size, 0.0f, 
      size, -size, 0.0f 
     }; 

     indices = 
     { 
      1, 0, 2, 3 
     }; 

     this->shader = engine->getShaderHandler()->loadShader("res/shaders/texturedInstancedShader"); 
     this->texture = texture; 

     glGenVertexArrays(1, &this->vertexArrayObject); 
     glBindVertexArray(this->vertexArrayObject); 

     glGenBuffers(ParticleSystem::NUM_BUFFERS, this->vertexArrayBuffer); 

     glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->VERTEX_VB]); 
     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * this->vertex.size(), &this->vertex[0], GL_STATIC_DRAW); //send model to GPU 

     glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->TEXTURE_VB]); 
     glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * this->texCoords.size(), &this->texCoords[0], GL_STATIC_DRAW); 

     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->vertexArrayBuffer[this->INDEX_VB]); 
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indices.size(), &this->indices[0], GL_STATIC_DRAW); 

     glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->POSITION_VB]); 
     glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * this->positions.size(), NULL, GL_STREAM_DRAW); //NULL (empty) buffer 

     glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->COLOR_VB]); 
     glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec4) * this->colors.size(), NULL, GL_STREAM_DRAW); //NULL (empty) buffer 

     glBindVertexArray(0); 
    } 


    void ParticleSystem::createPoint(float pps, float deltaTime, glm::vec3 position, float maxLife, glm::vec4 color, glm::vec3 velocity) 
    { 
     Particle particle; 
     float amountPerSecond = pps * deltaTime; 
     for (float i = 0; i < amountPerSecond; i++) 
     { 
      particle.life = (rand() % static_cast<int>(maxLife * 100))/100.f; 
      particle.velocity = 
      { 
       ((rand() % 200/100.f) - 1.f) * velocity.x, 
       ((rand() % 200/100.f) - 1.f) * velocity.y, 
       ((rand() % 200/100.f) - 1.f) * velocity.z 
      }; 
      particles.emplace_back(particle); 
      positions.emplace_back(position); 
      colors.emplace_back(color); 
     } 
    } 

    void ParticleSystem::draw(glm::mat4 view) 
    { 
     if (particles.size() > 0) 
     { 
      Transform transform; 
      this->shader->bind(); 
      this->shader->loadTransform(transform, view); 
      this->shader->loadInt(U_TEXTURE0, 0); 
      this->texture->bind(0); 

      glBindVertexArray(vertexArrayObject); 

      glVertexAttribDivisor(0, 0); 
      glVertexAttribDivisor(1, 1); 
      glVertexAttribDivisor(2, 1); 
      glVertexAttribDivisor(3, 0); 

      glEnableVertexAttribArray(0); 
      glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->VERTEX_VB]); 
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); 

      glEnableVertexAttribArray(1); 
      glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->POSITION_VB]); 
      glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * positions.size(), &positions[0], GL_STREAM_DRAW); 
      glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); 

      glEnableVertexAttribArray(2); 
      glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->COLOR_VB]); 
      glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec4) * colors.size(), &colors[0], GL_STREAM_DRAW); 
      glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (void*)0); 

      glEnableVertexAttribArray(3); 
      glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->TEXTURE_VB]); 
      glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); 

      glDrawElementsInstanced(GL_TRIANGLE_STRIP, indices.size(), GL_UNSIGNED_INT, 0, positions.size()); 

      glDisableVertexAttribArray(0); 
      glDisableVertexAttribArray(1); 
      glDisableVertexAttribArray(2); 

      glBindVertexArray(0); 
     } 
    } 

    void ParticleSystem::update(float deltaTime) 
    { 
     for (std::size_t i = 0; i < particles.size(); i++) 
     { 
      particles[i].life -= (1.f * deltaTime); //decrease life with 1 per second 
      if (particles[i].life <= 0.f) //dead 
      { 
       particles.erase(particles.begin() + i); 
       colors.erase(colors.begin() + i); 
       positions.erase(positions.begin() + i); 
       continue; 
      } 

      if (this->gravity == true) 
      { 
       if (particles[i].velocity.y > -maxVelocity) 
       { 
        particles[i].velocity.y -= maxVelocity * deltaTime; //1 second to reach maximum velocity 
       } 
       else 
       { 
        particles[i].velocity.y = -maxVelocity; 
       } 
      } 
      positions[i] += (particles[i].velocity * deltaTime); 
     } 
    } 

을 Heres 쉐이더 :

버텍스 쉐이더 :

#version 330 core 

    layout(location = 0) in vec3 vertex; 
    layout(location = 1) in vec3 positions; 
    layout(location = 2) in vec4 colors; 
    layout(location = 3) in vec2 texCoords; 

    out vec2 texCoord; 
    out vec4 color; 

    uniform mat4 transform; 

    void main() 
    { 
     color = colors; 
     texCoord = texCoords; 
     gl_Position = transform * vec4(vertex + positions, 1.0); 
    } 

조각 쉐이더 :

#version 330 core 

    in vec4 color; 
    in vec2 texCoord; 

    out vec4 colors; 

    uniform sampler2D texture0; 

    void main() 
    { 
     vec4 texel = texture2D(texture0, texCoord); 
     if (texel.a <= 0.5) 
     { 
      discard; 
     } 
     colors = color * texel; 
    }