如何将抗锯齿图像渲染为纹理(然后写入PNG)? [英] How to render anti-aliased image to a texture (and then write to PNG)?

查看:130
本文介绍了如何将抗锯齿图像渲染为纹理(然后写入PNG)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用渲染纹理"范例来编写OpenGL 3D渲染的.png屏幕截图.我可以在没有的情况下进行多次采样,但是我一直在努力获取抗锯齿图像.

I'd like to use the "render to texture" paradigm to write a .png screenshot of my OpenGL 3D rendering. I have it working without multi-sampling, but I'm struggling to get an anti-aliased image.

首先,这可能吗?

第二,API调用的正确组合是什么?

Second, what is the right combination of API calls?

(第三个问题,我该如何更好地调试它?glCheckFramebufferStatus显然还不够).

(meta third question, how can I better debug this? glCheckFramebufferStatus is clearly not enough).

这就是我正在使用的东西:

Here's what I'm working with:

  // https://stackoverflow.com/questions/7402504/multisampled-render-to-texture-in-ios
  GLuint texture;
  glGenTextures(1, &texture);
  glBindTexture(GL_TEXTURE_2D, texture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

  GLuint resolved_framebuffer, resolvedColorRenderbuffer;
  glGenFramebuffers(1, &resolved_framebuffer);
  glBindFramebuffer(GL_FRAMEBUFFER, resolved_framebuffer);
  glGenRenderbuffers(1, &resolvedColorRenderbuffer);
  glBindRenderbuffer(GL_RENDERBUFFER, resolvedColorRenderbuffer);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);

  assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);

  GLuint framebuffer;
  glGenFramebuffers(1, &framebuffer);
  glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

  GLuint colorRenderbuffer, depthRenderbuffer;
  glGenRenderbuffers(1, &colorRenderbuffer);
  glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
  glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, width, height);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);

  glGenRenderbuffers(1, &depthRenderbuffer);
  glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
  glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);


  assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);

  glBindFramebuffer( GL_FRAMEBUFFER, framebuffer );
  glClearColor(background_color(0), background_color(1), background_color(2), 0.f);
  glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT);

  draw_scene();

  glBindFramebuffer( GL_READ_FRAMEBUFFER, framebuffer );
  glBindFramebuffer( GL_DRAW_FRAMEBUFFER, resolved_framebuffer );
  // https://forum.juce.com/t/ios-8-getting-the-demo-building/13570/20
  glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
  // ^--- this is throwing `GL_INVALID_OPERATION`


  GLubyte* pixels = (GLubyte*)calloc(width*height*4,sizeof(GLubyte));
  glReadPixels(0, 0,width, height,GL_RGBA, GL_UNSIGNED_BYTE, pixels);

  writePNG(pixels);

当前我得到的是空白图像,glBlitFramebuffer正在抛出GL_INVALID_OPERATION.显然,此错误可能与很多情况相对应,并且我不确定哪个在申请. glCheckFramebufferStatus,我的缓冲区看起来不错".

Currently I'm getting a blank image and glBlitFramebuffer is throwing GL_INVALID_OPERATION. Apparently this error can correspond to many things, and I'm not sure which is applying. My buffers seem "good" according to glCheckFramebufferStatus.

此问题之前曾以类似的形式被提出:

This question has been asked in similar forms before:

  • Cannot render to texture with multisampling
  • Multisampled render to texture in ios

但是,所有答案都没有一个完整的可行示例.我很想找到/创建一个 minimum 示例.

But none of the answers have lead to a complete working example. I would love to find/create a minimal example of this.

推荐答案

该教程位于 https: //learnopengl.com/Advanced-OpenGL/Anti-Aliasing 基本上满足了我的需求.可行的解决方案是:

The tutorial at https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing basically had what I needed. The working solution is:

  unsigned int framebuffer;
  glGenFramebuffers(1, &framebuffer);
  glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  // create a multisampled color attachment texture
  unsigned int textureColorBufferMultiSampled;
  glGenTextures(1, &textureColorBufferMultiSampled);
  glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled);
  glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA, width, height, GL_TRUE);
  glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0);
  // create a (also multisampled) renderbuffer object for depth and stencil attachments
  unsigned int rbo;
  glGenRenderbuffers(1, &rbo);
  glBindRenderbuffer(GL_RENDERBUFFER, rbo);
  glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
  glBindRenderbuffer(GL_RENDERBUFFER, 0);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
  assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
  glBindFramebuffer(GL_FRAMEBUFFER, 0);

  // configure second post-processing framebuffer
  unsigned int intermediateFBO;
  glGenFramebuffers(1, &intermediateFBO);
  glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
  // create a color attachment texture
  unsigned int screenTexture;
  glGenTextures(1, &screenTexture);
  glBindTexture(GL_TEXTURE_2D, screenTexture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0);    // we only need a color buffer
  assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
  glBindFramebuffer(GL_FRAMEBUFFER, 0);

  glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

  draw_scene();

  glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO);
  glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);

  glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
  GLubyte* pixels = (GLubyte*)calloc(width*height*4,sizeof(GLubyte));
  glReadPixels(0, 0,width, height,GL_RGBA, GL_UNSIGNED_BYTE, pixels);

  writePNG(pixels);

似乎原始问题中的代码中至少存在两个错误:

It seems there're at least two errors in the code in the original question:

  1. framebuffer应该附加多采样的 texture ,而不是渲染缓冲区(glFramebufferTexture2D(... GL_TEXTURE_2D_MULTISAMPLE而不是glRenderbufferStorageMultisample)
  2. 发短信后且glReadPixels之前必须呼叫glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
  1. The framebuffer should have a multisample texture attached, not a renderbuffer (glFramebufferTexture2D(... GL_TEXTURE_2D_MULTISAMPLE instead of glRenderbufferStorageMultisample)
  2. Must call glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); after blitting and before glReadPixels

这篇关于如何将抗锯齿图像渲染为纹理(然后写入PNG)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆