【问题标题】:OSX + offscreen rendering + CoreGL + framebuffers + shaders = headache?OSX + 屏幕外渲染 + CoreGL + 帧缓冲区 + 着色器 = 头痛?
【发布时间】:2016-05-06 17:08:52
【问题描述】:

上下文与这个非常相似:Apple OSX OpenGL offline rendering with CoreGL

我编写了一个非常小的 C++/OpenGL 程序(我们实际上无法想象更简单),它应该在着色器的帮助下在屏幕外绘制一个白色三角形......但它没有。我基本上使用了几个帧缓冲区/渲染缓冲区,这些帧缓冲区/渲染缓冲区链接到 CoreGL 上下文中分配的缓冲区,灵感来自这里:http://renderingpipeline.com/2012/05/windowless-opengl-on-macos-x/。然后,将缓冲区的内容写入位图图片。

结果很奇怪。我使用glClearColor 命令在图片上设置了正确的背景颜色。这让我觉得 CoreGL 上下文已成功初始化......但不幸的是我什么也没得到(没有三角形)。

没有着色器编译/链接问题。我的帧缓冲区 / VBO / VAO / 顶点属性绑定没有问题……但就像我的着色器在 CoreGL 上下文中不存在一样。

这是定义和编译我的着色器的函数:

int loadShader()
{
  const GLchar* vertexSource = 
    "#version 150\n"
    "in vec3 position;"
    "void main(void)"
    "{ gl_Position = vec4(position, 1.); }";

  const GLchar* fragmentSource =
    "#version 150\n"
    "out vec4 fragColor;"
    "void main(void)"
    "{ fragColor = vec4(1.); }";

  vertexID = glCreateShader(GL_VERTEX_SHADER);
  fragmentID = glCreateShader(GL_FRAGMENT_SHADER);

  glShaderSource(vertexID, 1, &vertexSource, NULL);
  glShaderSource(fragmentID, 1, &fragmentSource, NULL);

  glCompileShader(vertexID);
  glCompileShader(fragmentID);

  if (!checkShaderCompilation(vertexID) || !checkShaderCompilation(fragmentID))
    throw std::runtime_error("bad shader compilation");

  programID = glCreateProgram();
  if (programID == 0)
    throw std::runtime_error("unable to create shader program");

  glAttachShader(programID, vertexID);
  glAttachShader(programID, fragmentID);
  glLinkProgram(programID);

  GLint programState = 0;
  glGetProgramiv(programID, GL_LINK_STATUS, &programState);
  if (programState != GL_TRUE)
    throw std::runtime_error("bad shader link");

  glUseProgram(programID);

  return 0;
}

这里,渲染函数:

GLfloat triangleVertices[] =
  {
      0.0f , 0.5f, 0.0f,    
      0.5f, -0.5f, 0.0f,
     -0.5f, -0.5f, 0.0f
  };

void displayTriangle()
{
  glClearColor(0.3, 0.1, 0.1, 1.);
  glPointSize(40.f);

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  loadShader();

  GLint fragmentGPUProcessing, vertexGPUProcessing;
  CGLGetParameter(CGLGetCurrentContext(), kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
  CGLGetParameter(CGLGetCurrentContext(), kCGLCPGPUVertexProcessing, &vertexGPUProcessing);

  if (!fragmentGPUProcessing || !vertexGPUProcessing)
    throw std::runtime_error("vertex and fragment shaders seem not correctly bound!");

  GLuint vaoID, vboID;
  glGenVertexArrays(1, &vaoID);
  glBindVertexArray(vaoID);

  glGenBuffers(1, &vboID);
  glBindBuffer(GL_ARRAY_BUFFER, vboID);
  glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices, GL_STATIC_DRAW);

  positionID = glGetAttribLocation(programID, "position");
  if (positionID < 0)
    throw std::runtime_error("unable to find 'position' name in vertex shader!");

  glVertexAttribPointer(positionID, 3, GL_FLOAT, GL_TRUE, 0, NULL);
  glEnableVertexAttribArray(positionID);

  glDrawArrays(GL_TRIANGLES, 0, 3);

  glFinish();
}

和 main(),定义 CoreGL 上下文和帧缓冲区对象: (注意 OpenGL 3.2 核心配置文件 已设置)

int main(int argc, char** argv)
{
  CGLContextObj context;

  CGLPixelFormatAttribute attributes[4] = { kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core,
                        kCGLPFAAccelerated,  // no software rendering
                        (CGLPixelFormatAttribute)0
  };

  CGLPixelFormatObj pix;
  GLint num;
  CGLError errorCode = CGLChoosePixelFormat(attributes, &pix, &num);
  if (errorCode != kCGLNoError)
    throw std::runtime_error("CGLChoosePixelFormat failure");

  errorCode = CGLCreateContext(pix, NULL, &context);
  if (errorCode != kCGLNoError)
    throw std::runtime_error("CGLCreateContext failure");

  CGLDestroyPixelFormat(pix);

  errorCode = CGLSetCurrentContext(context);
  if (errorCode != kCGLNoError)
    throw std::runtime_error("CGLSetCurrentContext failure");

  GLuint framebufferID, renderbufferID;
  glGenFramebuffers(1, &framebufferID);
  glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);

  glGenRenderbuffers(1, &renderbufferID);
  glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, WIDTH, HEIGHT);

  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbufferID);

  if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    throw std::runtime_error("framebuffer is not complete!");

  displayTriangle();

  GLubyte* buffer = new GLubyte[WIDTH * HEIGHT * 3 * sizeof(GLubyte)];
  glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, buffer);

  writeBitmap("path/to/the/bitmap/file", buffer, WIDTH, HEIGHT);

  glDeleteRenderbuffers(1, &renderbufferID);
  glDeleteFramebuffers(1, &framebufferID);

  CGLSetCurrentContext(NULL);
  CGLDestroyContext(context);

  delete[] buffer;

  return 0;
}

怎么了?

【问题讨论】:

  • 不相关,但是......您应该继续在着色器中的所有 GLSL 行中添加换行符,而不仅仅是预处理器版本指令。如果您现在要获取编译器日志,它将无法为您提供行号,您必须猜测哪一行有问题。
  • 对于初学者,您可以调用 glGetError 看看会发生什么。
  • GL_RGB8 不是渲染缓冲区支持的格式。试试GL_RGBA8
  • 安东:谢谢。通常我为我的着色器创建文件。但是,在这个非常简单的例子中,我这样做是为了避免使主题过于复杂。我不认为这里的问题来自着色器本身。
  • 安德烈亚斯:是的。实际上,我在每一行之后都已经这样做了,但不幸的是,OpenGL 方面没有发现任何错误。好像一切都很顺利。

标签: c++ macos opengl shader framebuffer


【解决方案1】:

我终于设法解决了这个问题。我实际上忘了用这个命令设置视口:

glViewport(0, 0, WIDTH, HEIGHT);

现在,一切看起来都很好,并且我的着色器使用正确。

这里简化为最基本形式的代码示例实际上是跨平台离屏渲染项目的一部分。问题是,在 OSMesa 库的帮助下,我已经在 Linux 上运行了它。这意味着 OSMesa 不需要视口初始化来执行与 CoreGL 相反的正确渲染。很高兴知道!

【讨论】:

    猜你喜欢
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-26
    • 1970-01-01
    • 2019-10-23
    • 2011-05-21
    • 1970-01-01
    • 2014-07-28
    相关资源
    最近更新 更多