2017-03-02 23 views
1

私はOpenGLでインスタンス化テストするためのいくつかのコードを書いた:nVidiaでglVertexAttribDivisorが正しく動作しませんか?

#include "exception" 
#include "fstream" 
#include "GL/glew.h" 
#include "glm/fwd.hpp" 
#include "glm/glm.hpp" 
#include "iostream" 
#include "SDL2/SDL.h" 
#include "sstream" 
#include "stdexcept" 
#include "unordered_map" 

int      g_xRes = 1024, g_yRes = 768; 
SDL_Window *   g_window = nullptr; 
SDL_GLContext   g_context = 0; 

void init(int * argc, char ** argv); 
void cleanup(); 
void mainLoop(); 
GLuint loadShader(const char * filepath, GLenum type); 
GLuint makeProgram(GLuint vs, GLuint gs, GLuint fs, 
        const std::unordered_map<std::string, GLuint> & fragDataLocations); 

// This is done in order to prevent missing reference error on Windows 
#ifdef main 
# undef main 
#endif 

int main(int argc, char ** argv) 
{ 
    try 
    { 
     init(&argc, argv); 
     mainLoop(); 
    } 
    catch(std::exception & ex) 
    { 
     std::cerr << argv[0] << ": " << ex.what() << std::endl; 
     return EXIT_FAILURE; 
    } 
    return EXIT_SUCCESS; 
} 

void mainLoop() 
{ 
    glm::vec3 vertices[] = { 
     glm::vec3(0, 0, 0), 
     glm::vec3(0, 0.25, 0), 
     glm::vec3(0.25, 0, 0), 
     glm::vec3(0.25, 0.25, 0), 
     glm::vec3(0.50, 0, 0), 
     glm::vec3(0.50, 0.25, 0), 
     glm::vec3(0.75, 0, 0), 
     glm::vec3(0.75, 0.25, 0), 
    }; 

    GLushort elements[] = { 
     0, 1, 2, 3, 2, 1, 4, 5, 6, 7, 6, 5 
    }; 

    glm::vec3 colors[] = { 
     glm::vec3(1, 0, 0), 
     glm::vec3(0, 1, 0) 
    }; 

    GLuint vao, vboPos, vboCol, ebo; 

    glGenVertexArrays(1, &vao); 
    glBindVertexArray(vao); 

    glGenBuffers(1, &vboCol); 
    glGenBuffers(1, &vboPos); 
    glGenBuffers(1, &ebo); 
    glBindBuffer(GL_ARRAY_BUFFER, vboPos); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 
    glBindBuffer(GL_ARRAY_BUFFER, vboCol); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW); 

    GLuint vs = loadShader("vs.glsl", GL_VERTEX_SHADER), 
      fs = loadShader("fs.glsl", GL_FRAGMENT_SHADER); 

    GLuint program = makeProgram(vs, 0, fs, { { "outColor", 0 } }); 
    glUseProgram(program); 

    glBindBuffer(GL_ARRAY_BUFFER, vboPos); 
    GLuint posAttr = glGetAttribLocation(program, "pos"); 
    glEnableVertexAttribArray(posAttr); 
    glVertexAttribPointer(posAttr, 3, GL_FLOAT, GL_FALSE, 0, 0); 

    glBindBuffer(GL_ARRAY_BUFFER, vboCol); 
    GLuint colAttr = glGetAttribLocation(program, "col"); 
    glEnableVertexAttribArray(colAttr); 
    glVertexAttribPointer(colAttr, 3, GL_FLOAT, GL_FALSE, 0, 0); 
    glVertexAttribDivisor(colAttr, 1); 

    glEnable(GL_DEPTH_TEST); 

    SDL_Event e; 
    while(true) 
    { 
     while(SDL_PollEvent(&e) != 0) 
     { 
      if(e.type == SDL_QUIT) 
       return; 
     } 

     glClearColor(0, 0, 0, 1); 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
     glDrawElementsInstanced(GL_TRIANGLES, sizeof(elements)/sizeof(elements[0]), GL_UNSIGNED_SHORT, 
      nullptr, sizeof(colors)/sizeof(colors[0])); 

     assert(glGetError() == GL_NO_ERROR); 

     SDL_GL_SwapWindow(g_window); 
    } 
} 

void init(int * argc, char ** argv) 
{ 
    std::ostringstream errMsgSStream; 

    // Initialize SDL 
    if(SDL_Init(SDL_INIT_EVERYTHING) < 0) 
    { 
     errMsgSStream << "" << SDL_GetError(); 
     throw std::runtime_error(errMsgSStream.str()); 
    } 

    // Manage OpenGL attributes 
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); 
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true); 
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); 
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); 
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); 
    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); 

    // Create window 
    g_window = SDL_CreateWindow("Example", SDL_WINDOWPOS_CENTERED, 
     SDL_WINDOWPOS_CENTERED, g_xRes, g_yRes, SDL_WINDOW_OPENGL); 
    if(!g_window) 
    { 
     errMsgSStream << "" << SDL_GetError(); 
     throw std::runtime_error(errMsgSStream.str()); 
    } 

    // Create a new device context 
    g_context = SDL_GL_CreateContext(g_window); 
    if(!g_context) 
    { 
     errMsgSStream << "" << SDL_GetError(); 
     throw std::runtime_error(errMsgSStream.str()); 
    } 

    // Initialize GLEW 
    glewExperimental = GL_TRUE; 
    if(glewInit() != GLEW_OK) 
    { 
     errMsgSStream << "failed to initialize GLEW"; 
     throw std::runtime_error(errMsgSStream.str()); 
    } 

    // Apparently GLEW can make glGetError return GL_INVALID_ENUM even if initialized correctly 
    while(glGetError() != GL_NO_ERROR); 

    if(atexit(cleanup)) 
    { 
     errMsgSStream << "failed to register cleanup function"; 
     throw std::runtime_error(errMsgSStream.str()); 
    } 

    return; 
} 

void cleanup() 
{ 
    SDL_GL_DeleteContext(g_context); 
    SDL_DestroyWindow(g_window); 
    SDL_Quit(); 
} 

GLuint loadShader(const char * filepath, GLenum type) 
{ 
    std::ifstream shaderFile; 

    shaderFile.exceptions(std::ios_base::failbit); 
    try { 
     shaderFile.open(filepath); 
    } catch(std::exception & ex) { 
     std::ostringstream ss; 
     ss << "failed to open file '" << filepath << "': " << ex.what(); 
     throw std::runtime_error(ss.str()); 
    } 
    shaderFile.exceptions(std::ios_base::goodbit); 

    GLuint res = glCreateShader(type); 

    // Get the length of the file 
    shaderFile.seekg(0, shaderFile.end); 
    size_t fileSize = shaderFile.tellg(); 
    shaderFile.seekg(0, shaderFile.beg); 

    // Allocate space for, and read the header source 
    char * shaderSrc = new char[fileSize + 1]; 
    shaderFile.read(shaderSrc, fileSize); 
    shaderSrc[fileSize] = '\0'; 

    // Try to compile shader 
    GLint status; 
    glShaderSource(res, 1, &shaderSrc, nullptr); 
    glCompileShader(res); 
    glGetShaderiv(res, GL_COMPILE_STATUS, &status); 
    if(status != GL_TRUE) 
    { 
     char buf[0x10000]; 
     std::ostringstream ss; 
     glGetShaderInfoLog(res, 0x10000, nullptr, buf); 
     ss << "failed to compile file '" << filepath << "':" << std::endl << buf; 
     glDeleteShader(res); 
     throw std::runtime_error(ss.str()); 
    } 

    return res; 
} 

GLuint makeProgram(GLuint vs, GLuint gs, GLuint fs, 
        const std::unordered_map<std::string, GLuint> & fragDataLocations) 
{ 
    GLuint res = glCreateProgram(); 

    // Attach shaders 
    if(vs) glAttachShader(res, vs); 
    if(gs) glAttachShader(res, gs); 
    if(fs) glAttachShader(res, fs); 

    // Bind data locations 
    for(const auto & ent : fragDataLocations) 
     glBindFragDataLocation(res, ent.second, ent.first.c_str()); 

    // Link program 
    GLint status; 
    glLinkProgram(res); 
    glGetProgramiv(res, GL_LINK_STATUS, &status); 
    if(vs) glDetachShader(res, vs); 
    if(gs) glDetachShader(res, gs); 
    if(fs) glDetachShader(res, fs); 
    if(status != GL_TRUE) 
    { 
     char buf[0x10000]; 
     std::ostringstream ss; 
     glGetProgramInfoLog(res, 0x10000, nullptr, buf); 
     ss << "failed to link program: " << std::endl << buf; 
     glDeleteProgram(res); 
     throw std::runtime_error(ss.str()); 
    } 

    return res; 
} 

VS:

#version 330 

in vec3 pos; 
in vec3 col; 

out vec3 fCol; 

void main() 
{ 
    gl_Position = vec4(pos, 1); 
    fCol = col; 
} 

PS:

#version 330 

in vec3 fCol; 

out vec4 outColor; 

void main() 
{ 
    outColor = vec4(fCol, 1); 
} 

私は期待していた出力は次のようになります。

enter image description here

しかし、私が得たことはこれです:

enter image description here

は私のコードに何か問題があるのか​​、私のドライバーは、(私はUbuntu Linuxの16.04で独自のNVIDIAドライバv340.102を使用し、適切にこの機能を実装していません。 )?

+1

なぜGL3.2コンテキストで '#version 330'シェーダを使用しようとしていますか? GL 3.3では '#version 330'をサポートする必要があり、[3.2は' #version 150'しか実行しません](https://en.wikipedia.org/wiki/OpenGL_Shading_Language#Versions)。 – genpfault

+0

@genpfaultええ、私はその部分を見落としましたが、3.3のコンテキストを作成しても問題は解決しません。 –

+2

期待する出力が期待される理由がわかりません。あなたは4つのクワッド、2つの赤いもの、2つの緑のものを描きます.2つの緑のものは深さテストに失敗します。あなたが得る出力は絶対に正しいです。 (これは基本的に@keltarが実際にあなたに言ったことです) – derhass

答えて

1

まず第1に、あなたのglVertexAttribPointerには、3があるときに1つのコンポーネントしかないと言われています。そして、2つのインスタンスが同じ位置にある2つのクワッドでレンダリングされます。

たとえば、次のように2番目のインスタンスの位置をシフトできます。 gl_Position = vec4(pos+gl_InstanceID*0.25, 1);少なくとも両方のインスタンスを参照してください。

+0

2つのインスタンスは別々の位置を持っています。要素バッファオブジェクトを使ってレンダリングされる頂点を選択することがわかります。最初のクワッドの最後の2つの頂点が2番目のクワッドの2つの最初の頂点であったということだけでした。それ以上の混乱を避けるために、私はそれらを完全に別々にしました。さらに、glVertexAttribPointerの属性を1から3に変更しましたが、問題は引き続き発生します。 –

+0

すべてのインスタンスにはインスタンスIDとインスタンス固有の属性があり、それ以外はすべて共有されます。私はあなたが最初のインスタンスに行くために要素の配列バッファの一部を設定することはできませんし、次の部分は、彼らは両方が同じ要素を取得します。 – keltar

関連する問題