使用FBO绘制到renderbuffer

时间:2013-04-04 00:02:16

标签: c++ opengl

我的问题非常接近这个问题:FBO and Render to renderbuffer。 我目前正在尝试在渲染缓冲区中渲染一个简单的三角形,就像在tutorial中一样。我的程序是Igor Pro的一个插件,它使用OpenGL执行屏幕外渲染。

不幸的是,当我尝试读取像素值时,我只得到零。 我已经知道initBuffers函数有效,问题出在display函数中。

1)我的代码有什么问题?

2)我想在不使用立即模式的情况下渲染顶点数据列表。我之前已经用VBO完成了一个实现。我可以重用该代码吗?

我的代码如下:

/*  
RenderTriangle.cpp
*/

#include "VC10\triangulation.h"
#include "XOPStandardHeaders.h"         // Include ANSI headers, Mac headers, IgorXOP.h, XOP.h and XOPSupport.h
#include <vector>


// Prototypes
HOST_IMPORT int main(IORecHandle ioRecHandle);

// Global Variables
const int windowSize = 512;

int size,el_size;
float* waveX=NULL;
float* waveY=NULL;
float* waveZ=NULL;
GLuint framebuffer, renderbuffer;

// Custom error codes
#define OLD_IGOR 1 + FIRST_XOP_ERR
#define NON_EXISTENT_WAVE 2 + FIRST_XOP_ERR
#define REQUIRES_SP_OR_DP_WAVE 3 + FIRST_XOP_ERR

#pragma pack(2)     // All structures passed to Igor are two-byte aligned.
typedef struct WaveParams {
  waveHndl waveZ;
  waveHndl waveY;
  waveHndl waveX;   
  double result;
} WaveParams, *WaveParamsPtr;
#pragma pack()      // Restore default structure alignment

// Prototypes of the OpenGL callbacks
void initBuffers(void);
void display(void);
void readPixels(void);

void initBuffers(void){

  GLenum status;

  //Generate the fbo where we will bind a render buffer object
  glGenFramebuffers(1,&framebuffer);
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER,framebuffer);

  //Generate render buffer object
  glGenRenderbuffers(1,&renderbuffer);
  glBindRenderbuffer(GL_RENDERBUFFER,renderbuffer);

  glRenderbufferStorage(GL_RENDERBUFFER,GL_RGBA8, windowSize, windowSize);

  glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);

  status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

  if (status != GL_FRAMEBUFFER_COMPLETE)
    XOPNotice("Error Framebuffer Complete");
  else
    XOPNotice("Framebuffer Complete");
}

void display(void){//display a simple triangle

  glViewport(0,0,windowSize,windowSize);
  glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  glClearColor(1.0f, 0.0f, 0.0f,0.5f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();

  glBegin(GL_TRIANGLES);// Drawing Using Triangles
    glColor3f(1.0f, 0.0f, 0.0f);glVertex3f( 0.0f, 1.0f, 0.0f);// Top
    glColor3f(1.0f, 0.0f, 0.0f);glVertex3f(-1.0f,-1.0f, 0.0f);// Bottom Left
    glColor3f(1.0f, 0.0f, 0.0f);glVertex3f( 1.0f,-1.0f, 0.0f);// Bottom Right
  glEnd();// Finished Drawing The Triangle

  glFlush();

}

// Idle callback function for OpenGL API
void readPixels(void){

  //glBindFramebuffer(GL_FRAMEBUFFER, 0);

  float* pixels = (float*)malloc(windowSize*windowSize*sizeof(float));
  glReadBuffer(GL_COLOR_ATTACHMENT0);
  glReadPixels(0, 0, windowSize, windowSize, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);

  waveHndl waveH;
  char waveName[MAX_OBJ_NAME+1];
  DataFolderHandle dfH;
  CountInt dimensionSizes[MAX_DIMENSIONS+1];
  float* wp;
  IndexInt p;
  double offset, delta;
  int err;
  strcpy(waveName, "wave1");
  dfH = NULL; // Put wave in the current data folder
  MemClear(dimensionSizes, sizeof(dimensionSizes));

  dimensionSizes[ROWS] = windowSize; // Make 1D wave with 100 points
  dimensionSizes[COLUMNS] = windowSize;

  if (MDMakeWave(&waveH, waveName, dfH, dimensionSizes, NT_FP32, 1))
    XOPNotice("Can't create wave when reading pixel values");

  wp = (float*)WaveData(waveH); // Get a pointer to the wave data

  for(p = 0; p < windowSize*windowSize; p++)
  *wp++ = pixels[p]; // Store point number in wave



}
void deleteBuffers(){
  glDeleteFramebuffers(1,&framebuffer);
  glDeleteRenderbuffers(1,&renderbuffer);
}
// Main function for the XOP
extern "C" int
  RenderTriangle(WaveParamsPtr p)
{
  //Pointers to the input waves
  waveX=(float*)WaveData(p->waveX);
  waveY=(float*)WaveData(p->waveY);
  waveZ=(float*)WaveData(p->waveZ);

  //Creates the window
  char *myargv [1];
  int myargc=1, windowHandle;
  myargv [0]=strdup ("RenderTriangle");

  glutInit(&myargc,myargv);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_DEPTH | GLUT_RGB);
  glutInitWindowSize(windowSize,windowSize);
  windowHandle = glutCreateWindow("OpenGL");

  //Init glew library 
  glewInit(); 

  //Creates the fbo and render buffer object
  initBuffers(); 

  display();

  readPixels();

  //Deletes the fbo and render buffer object
  deleteBuffers();

  p->result = 1;

  return 0;
}

static XOPIORecResult
  RegisterFunction()
{
  int funcIndex;

  funcIndex = (int)GetXOPItem(0);           // Which function invoked ?
  switch (funcIndex) {
  case 0:                                   // y = RenderTriangle(w,x) (curve fitting function).
    return (XOPIORecResult)RenderTriangle;  // This function is called using the direct method.
    break;
  }
  return 0;
}

/*  XOPEntry()

This is the entry point from the host application to the XOP for all
messages after the INIT message.
*/
extern "C" void
  XOPEntry(void)
{   
  XOPIORecResult result = 0;

  switch (GetXOPMessage()) {
  case FUNCADDRS:
    result = RegisterFunction();    // This tells Igor the address of our function.
    break;
  }
  SetXOPResult(result);
}

/*  main(ioRecHandle)

This is the initial entry point at which the host application calls XOP.
The message sent by the host must be INIT.
main() does any necessary initialization and then sets the XOPEntry field of the
ioRecHandle to the address to be called for future messages.
*/
HOST_IMPORT int
  main(IORecHandle ioRecHandle)
{   
  XOPInit(ioRecHandle);                         // Do standard XOP initialization.
  SetXOPEntry(XOPEntry);                            // Set entry point for future calls.

  if (igorVersion < 600) {
    SetXOPResult(OLD_IGOR);
    return EXIT_FAILURE;
  }

  SetXOPResult(0);
  return EXIT_SUCCESS;
}

3 个答案:

答案 0 :(得分:1)

我建议另一个教程:http://www.songho.ca/opengl/gl_fbo.html

但关于你的代码:

直接渲染到纹理会更简单。这样就没有理由使用glReadPixels了。整个操作将更快,更容易实施。

创建空纹理并通过glFramebufferTexture2D将其添加到FBO,并在渲染后将结果添加到纹理中。

答案 1 :(得分:1)

你需要一个工作的OpenGL上下文来完成剩下的工作,你不需要创建一个!您正在使用GLUT作为框架,但GLUT仅在调用glutCreateWindow时才创建渲染上下文。在此之前,你根本没有活跃的RC,其余的将无法工作。

也许Igor本身会在某个时刻创建一个OpenGL上下文而你正在诋毁那个。

您应该使用系统级API

,而不是使用GLUT
  1. 存储当前上下文状态(如果上下文在当前线程中处于活动状态,如果是,则为上下文句柄)

  2. 如果尚未完成:为您的插件创建一个离屏渲染上下文(与FBO一起使用PBuffer或不可见的窗口)

  3. 使用您自己的上下文进行渲染

  4. 恢复保存在1中的上下文状态。

答案 2 :(得分:0)

同样,这是一个使用renderbuffers的例子。

How to render offscreen on OpenGL?

1)创建上下文 2)创建FBO(存储颜色,深度,模板)和绑定 3)画画 4)回读(根据2))

我不确定说整个操作使用纹理更快更容易实现是否正确。这完全取决于我们想做什么(glReadPixels是同步的)。