2017-10-06 9 views
2

私はglReadPixelsの出力を理解するのに苦労していますが、これは理論的には単純なようですが、実際には(少なくとも私にとっては)結果が不思議です。glReadPixelsは常にglClearColorで同じ値を返します

色の値がvec4(0.2、0、0、0)の単一の三角形を描画するシンプルなフラグメントシェーダを使用し、背景色が(0.3,1.0,1.0,0)に設定されているとします。私はデフォルトのフレームバッファを使用していますことを、

#include "shader.h" // shader compile/link/use 
#include <GLFW\glfw3.h> 
#include <iostream> 

const int DISPLAY_WIDTH = 16; 
const int DISPLAY_HEIGHT = 16; 

//============= shader code ========================== 

const GLchar *vertexShaderSource = R"glsl(#version 440 
in vec2 position; 
void main() 
{ 
    gl_Position = vec4(position, 0.0, 1.0); 
})glsl"; 

const GLchar *fragmentShaderSource = R"glsl(#version 440 
out vec4 outColor; 

void main() 
{ 
    outColor = vec4(0.2,0.,0.,0.); 
})glsl"; 

//============= c++ entry point ========================== 

int main(int argc, char** argv) { 

    glfwInit(); 
    GLFWwindow* window = glfwCreateWindow(DISPLAY_WIDTH, DISPLAY_HEIGHT, "test", NULL, NULL); 
    glfwMakeContextCurrent(window); 

    GLenum res = glewInit(); 

    // triangle data (xy-position) 
    float vertices[] = { 
    0.0f, 0.5f, 
    0.5f, -0.5f, 
    -0.5f, -0.5f 
    }; 

    GLuint vbo; 
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 

    // enable vertex xy-position attribute 
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); 
    glEnableVertexAttribArray(0); 

    // compile, link and use shader program 
    Shader shader(vertexShaderSource, fragmentShaderSource); 
    shader.Use(); 

    // rendering loop 
    while (!glfwWindowShouldClose(window)) { 

     glClearColor(0.3f, 1.0f, 1.0f, 0.0f); 
     glClear(GL_COLOR_BUFFER_BIT); 

     glDrawArrays(GL_TRIANGLES, 0, 3); 
     glFlush(); 

     // read pixels from backbuffer 
     GLubyte data[DISPLAY_WIDTH * DISPLAY_HEIGHT]; 
     glReadPixels(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, GL_RED, GL_UNSIGNED_BYTE, data); 

     for (int i = 0; i < DISPLAY_WIDTH * DISPLAY_HEIGHT; i++) { 
      int a = data[i]; // implicit conversion of unsigned char to int 
      std::cout << a << std::endl; 
     } 
     std::getchar(); // wait for user input 

     glfwSwapBuffers(window); 
     glfwPollEvents(); 
    } 

    glfwTerminate(); 
    return 0; 
} 

注:以下はenter image description here

は、私は上記の画像を生成するために使用します(シェーダ建設を除く)の完全なコードは次のようになりますので、同じよう私のカラー値は正規化されたものとして扱われます私のジオメトリの色は(51、0、0、0)になるのに対し、私の背景色は(76,255,255、0)になります。 )。

ジオメトリを描画してバッファをスワップした後、イメージが取得されます。今私は色の値を読みたいと思います。 、私は赤チャンネルを抽出、Iはフレームバッファから読み出された画素値を検査するプロセスを容易にするために

GLubyte* data = new GLubyte[DISPLAY_WIDTH * DISPLAY_HEIGHT]; 
glReadPixels(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, GL_RED, GL_UNSIGNED_BYTE, data); 

:それを行うために、私はバッファをスワップ直前必要glReadPixels関連するコードを挿入します画素データを格納するために必要なデータのサイズはDISPLAY_WIDTH * DISPLAY_HEIGHTです。さらに、私がプリントアウトした値は背景色では76、ジオメトリでは51となっているはずです。

驚くべきことに、ジオメトリが無視されたように、驚いたことに、すべての単一赤チャネルピクセルデータ(すべてのDISPLAY_WIDTH * DISPLAY_HEIGHTピクセルが印刷されます)は、私が印刷すると「76」になります。描画呼び出しの後、バッファを交換する前にピクセルを読み込むことに注意してください。

ここで私が何が不足しているかを教えていただければ幸いです。私のDebianのストレッチボックスに微細

+3

オブジェクトの背景ではなく色を取得した場合、 'glReadPixels'は「クリアカラー」と「スワップバッファ」の間を読み込んでいるようです。あるいは、最初のスワップ後にデフォルトの 'back buffer'の代わりに' front buffer'から読み込んでいます。 – Ripi2

+1

あなたがしていることが正しいように見えます。背景ピクセルしか見ていないのですか?あなたの写真から、最初のジオメトリの前に多くの背景ピクセルが存在するでしょう... – Bahbar

+0

[mcve]で編集してください。 [this](https://stackoverflow.com/a/8841923/44729)を自由に使用してください。 – genpfault

答えて

1

ここでは完全な話です。 Bahbarが言ったように、ピクセルを正確に読み取っていたことに言及する価値があります。しかし、私が作成したウィンドウの大きさにディメンションが設定されている、デフォルトのフレームバッファーのサイズについて間違った前提がありました。

glfwCreateWindowのコードで指定するウィンドウのサイズは16x16です。明らかに、元の質問で添付した画像の幅が広いです。

GLFW documentationglfwSetWindowSizeを参照)以下の状態:「とこれらの制限をオーバーライドするべきではないことができないウィンドウマネージャ許可されているどのような大きさに制限を置いてもよいGLFWを。」は。私のWindows 10マシンでは120ピクセル以下の幅を設定することはできません。続いて、dataの16x16ピクセルではなく、120x16ピクセルの配列を調べると、実際に正しく記録されていることが明らかになりました。

次に、ジオメトリを描画したい場所に正確に描画するために、描画する前にgViewportを呼び出して、正規化されたデバイス座標(NDC)からの変換を指定する必要があります。ウィンドウ(または、ユーザー定義のフレームバッファオブジェクトで画面外にレンダリングしている場合は、レンダーバッファ内のピクセルまたはテクスチャ)に表示されます。以下の出力とgenpfaultによって提供わずかに修正されたコードは、(彼のコードは完全に自己完結型であり、私の例では、欠けているシェーダ構成ビットを含む)である:

GLEW version: 2.0.0 
GLFW version: 3.2.1 Win32 WGL EGL VisualC 
GL_VERSION : 4.5.0 NVIDIA 376.53 
GL_VENDOR : NVIDIA Corporation 
GL_RENDERER : GeForce GTX 970/PCIe/SSE2 

76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 51 51 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 51 51 76 76 76 76 76 76 76 
76 76 76 76 76 76 51 51 51 51 76 76 76 76 76 76 
76 76 76 76 76 76 51 51 51 51 76 76 76 76 76 76 
76 76 76 76 76 51 51 51 51 51 51 76 76 76 76 76 
76 76 76 76 76 51 51 51 51 51 51 76 76 76 76 76 
76 76 76 76 51 51 51 51 51 51 51 51 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 

コード自体が右ループをレンダリングする前にglViewportコールを(含んでいます)と実際の画像に出力を一致させるために少し変更し印刷ループ:

#include <GL/glew.h> 
#include <GLFW/glfw3.h> 
#include <iostream> 
#include <cstdarg> 

struct Program 
{ 
    static GLuint Load(const char* shader, ...) 
    { 
     GLuint prog = glCreateProgram(); 
     va_list args; 
     va_start(args, shader); 
     while (shader) 
     { 
      const GLenum type = va_arg(args, GLenum); 
      AttachShader(prog, type, shader); 
      shader = va_arg(args, const char*); 
     } 
     va_end(args); 
     glLinkProgram(prog); 
     CheckStatus(prog); 
     return prog; 
    } 

private: 
    static void CheckStatus(GLuint obj) 
    { 
     GLint status = GL_FALSE; 
     if (glIsShader(obj)) glGetShaderiv(obj, GL_COMPILE_STATUS, &status); 
     if (glIsProgram(obj)) glGetProgramiv(obj, GL_LINK_STATUS, &status); 
     if (status == GL_TRUE) return; 
     GLchar log[1 << 15] = { 0 }; 
     if (glIsShader(obj)) glGetShaderInfoLog(obj, sizeof(log), NULL, log); 
     if (glIsProgram(obj)) glGetProgramInfoLog(obj, sizeof(log), NULL, log); 
     std::cerr << log << std::endl; 
     exit(EXIT_FAILURE); 
    } 

    static void AttachShader(GLuint program, GLenum type, const char* src) 
    { 
     GLuint shader = glCreateShader(type); 
     glShaderSource(shader, 1, &src, NULL); 
     glCompileShader(shader); 
     CheckStatus(shader); 
     glAttachShader(program, shader); 
     glDeleteShader(shader); 
    } 
}; 

const GLchar *vertexShaderSource = R"glsl(#version 130 
    in vec2 position; 
    void main() 
    { 
     gl_Position = vec4(position, 0.0, 1.0); 
    })glsl"; 

const GLchar *fragmentShaderSource = R"glsl(#version 130 
    out vec4 outColor; 

    void main() 
    { 
     outColor = vec4(0.2,0.,0.,0.); 
    })glsl"; 


const int DISPLAY_WIDTH = 16; 
const int DISPLAY_HEIGHT = 16; 


int main(int argc, char** argv) 
{ 
    glfwInit(); 
    GLFWwindow* window = glfwCreateWindow(DISPLAY_WIDTH, DISPLAY_HEIGHT, "test", NULL, NULL); 
    glfwMakeContextCurrent(window); 

    GLenum res = glewInit(); 

    std::cout << "GLEW version: " << glewGetString(GLEW_VERSION) << std::endl; 
    std::cout << "GLFW version: " << glfwGetVersionString() << std::endl; 
    std::cout << "GL_VERSION : " << glGetString(GL_VERSION) << std::endl; 
    std::cout << "GL_VENDOR : " << glGetString(GL_VENDOR) << std::endl; 
    std::cout << "GL_RENDERER : " << glGetString(GL_RENDERER) << std::endl << std::endl; 

    // triangle data (xy-position) 
    float vertices[] = 
    { 
     0.0f, 0.5f, 
     0.5f, -0.5f, 
     -0.5f, -0.5f 
    }; 

    GLuint vbo; 
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 

    // enable vertex xy-position attribute 
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); 
    glEnableVertexAttribArray(0); 

    // compile, link and use shader program 
    GLuint program = Program::Load 
     (
     vertexShaderSource, GL_VERTEX_SHADER, 
     fragmentShaderSource, GL_FRAGMENT_SHADER, 
     NULL 
     ); 
    glUseProgram(program); 

    glViewport(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT); 
    // rendering loop 
    while (!glfwWindowShouldClose(window)) { 

     glClearColor(0.3f, 1.0f, 1.0f, 0.0f); 
     glClear(GL_COLOR_BUFFER_BIT); 

     glDrawArrays(GL_TRIANGLES, 0, 3); 
     glFlush(); 

     // read pixels from backbuffer 
     GLubyte data[DISPLAY_WIDTH * DISPLAY_HEIGHT]; 
     glReadPixels(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, GL_RED, GL_UNSIGNED_BYTE, data); 

     for (int y = DISPLAY_HEIGHT-1; y >= 0; y--) 
     { 
      for (int x = 0; x < DISPLAY_WIDTH; x++) 
      { 
       std::cout << (int)data[y*DISPLAY_HEIGHT + x] << " "; // implicit conversion of unsigned char to int 
      } 
      std::cout << std::endl; 
     } 
     std::getchar(); 
     std::cout << std::endl; 

     glfwSwapBuffers(window); 
     glfwPollEvents(); 
    } 

    glfwTerminate(); 
    return 0; 
} 

最後に、私はstackoverflowのの機能を使用して画像をアップロードすることができませんでしたので、ここで興味を持っている人のためにimgurへのリンクです:https://imgur.com/6bfLhfW

これが回答として受け入れることができる場合は誰でも私に知らせることができます。私は先に進み、ボタンを押すだけです。あるいは、他の人がもっと意味のある答えを与えるかもしれません。入力してくれてありがとう!

2

ワーキン:

// g++ main.cpp -lGLEW -lGL -lglfw 
#include <GL/glew.h> 
#include <GLFW/glfw3.h> 
#include <iostream> 
#include <cstdarg> 

struct Program 
{ 
    static GLuint Load(const char* shader, ...) 
    { 
     GLuint prog = glCreateProgram(); 
     va_list args; 
     va_start(args, shader); 
     while(shader) 
     { 
      const GLenum type = va_arg(args, GLenum); 
      AttachShader(prog, type, shader); 
      shader = va_arg(args, const char*); 
     } 
     va_end(args); 
     glLinkProgram(prog); 
     CheckStatus(prog); 
     return prog; 
    } 

private: 
    static void CheckStatus(GLuint obj) 
    { 
     GLint status = GL_FALSE; 
     if(glIsShader(obj)) glGetShaderiv(obj, GL_COMPILE_STATUS, &status); 
     if(glIsProgram(obj)) glGetProgramiv(obj, GL_LINK_STATUS, &status); 
     if(status == GL_TRUE) return; 
     GLchar log[ 1 << 15 ] = { 0 }; 
     if(glIsShader(obj)) glGetShaderInfoLog(obj, sizeof(log), NULL, log); 
     if(glIsProgram(obj)) glGetProgramInfoLog(obj, sizeof(log), NULL, log); 
     std::cerr << log << std::endl; 
     exit(EXIT_FAILURE); 
    } 

    static void AttachShader(GLuint program, GLenum type, const char* src) 
    { 
     GLuint shader = glCreateShader(type); 
     glShaderSource(shader, 1, &src, NULL); 
     glCompileShader(shader); 
     CheckStatus(shader); 
     glAttachShader(program, shader); 
     glDeleteShader(shader); 
    } 
}; 

const GLchar *vertexShaderSource = R"glsl(#version 130 
in vec2 position; 
void main() 
{ 
    gl_Position = vec4(position, 0.0, 1.0); 
})glsl"; 

const GLchar *fragmentShaderSource = R"glsl(#version 130 
out vec4 outColor; 

void main() 
{ 
    outColor = vec4(0.2,0.,0.,0.); 
})glsl"; 


const int DISPLAY_WIDTH = 16; 
const int DISPLAY_HEIGHT = 16; 


int main(int argc, char** argv) 
{ 
    glfwInit(); 
    GLFWwindow* window = glfwCreateWindow(DISPLAY_WIDTH, DISPLAY_HEIGHT, "test", NULL, NULL); 
    glfwMakeContextCurrent(window); 

    GLenum res = glewInit(); 

    std::cout << "GLEW version: " << glewGetString(GLEW_VERSION) << std::endl; 
    std::cout << "GLFW version: " << glfwGetVersionString() << std::endl; 
    std::cout << "GL_VERSION : " << glGetString(GL_VERSION) << std::endl; 
    std::cout << "GL_VENDOR : " << glGetString(GL_VENDOR) << std::endl; 
    std::cout << "GL_RENDERER : " << glGetString(GL_RENDERER) << std::endl; 

    // triangle data (xy-position) 
    float vertices[] = 
    { 
     0.0f, 0.5f, 
     0.5f, -0.5f, 
     -0.5f, -0.5f 
    }; 

    GLuint vbo; 
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 

    // enable vertex xy-position attribute 
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); 
    glEnableVertexAttribArray(0); 

    // compile, link and use shader program 
    GLuint program = Program::Load 
     (
     vertexShaderSource, GL_VERTEX_SHADER, 
     fragmentShaderSource, GL_FRAGMENT_SHADER, 
     NULL 
     ); 
    glUseProgram(program); 

    // rendering loop 
    while (!glfwWindowShouldClose(window)) { 

    glClearColor(0.3f, 1.0f, 1.0f, 0.0f); 
    glClear(GL_COLOR_BUFFER_BIT); 

    glDrawArrays(GL_TRIANGLES, 0, 3); 
    glFlush(); 

    // read pixels from backbuffer 
    GLubyte data[DISPLAY_WIDTH * DISPLAY_HEIGHT]; 
    glReadPixels(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, GL_RED, GL_UNSIGNED_BYTE, data); 

    int i = 0; 
    for (int y = 0; y < DISPLAY_HEIGHT; y++) 
    { 
     for (int x = 0; x < DISPLAY_WIDTH; x++) 
     { 
      int a = data[i]; // implicit conversion of unsigned char to int 
      std::cout << a << " ";; 
      i++; 
     } 
     std::cout << std::endl; 
    } 
    std::cout << std::endl; 

    glfwSwapBuffers(window); 
    glfwPollEvents(); 
    } 

    glfwTerminate(); 
    return 0; 
} 
を:すべて一緒に(メサは、非コア文脈でGL 3.0を超えて何かをサポートしていないため 130にシェーダ #versionを落とした)
GLEW version: 2.0.0 
GLFW version: 3.2.1 X11 GLX EGL clock_gettime /dev/js Xf86vm shared 
GL_VERSION : 3.0 Mesa 13.0.6 
GL_VENDOR : Intel Open Source Technology Center 
GL_RENDERER : Mesa DRI Intel(R) Kabylake GT2 

76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 51 51 51 51 51 51 51 51 76 76 76 76 
76 76 76 76 76 51 51 51 51 51 51 76 76 76 76 76 
76 76 76 76 76 51 51 51 51 51 51 76 76 76 76 76 
76 76 76 76 76 76 51 51 51 51 76 76 76 76 76 76 
76 76 76 76 76 76 51 51 51 51 76 76 76 76 76 76 
76 76 76 76 76 76 76 51 51 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 51 51 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 

+1

私は最終的に何が起こっているかを知った。 'glfwCreateWindow'で指定したウィンドウのサイズは16x16です。明らかに、私が付けた画像の幅が広い。 [GLFWドキュメント](http://www.glfw.org/docs/latest/group__window.html#ga371911f12c74c504dd8d47d832d095cb)(glfwSetWindowSize参照)には、次のように記載されています。 "ウィンドウマネージャは、どのサイズが許可されているかに制限を設ける場合があります。これらの制限を無効にするべきではありません "。さて、120ピクセル以下の幅を設定することはできません。 「データ」配列を調べると、実際に「51」の値が適切に記録されていることがわかりました。 – MutomboDikey

関連する問題