[osg-users] Direct OpenGL Callback RTT Not Rendering Correctly

Kevin Pitstick kevin.pitstick at gmail.com
Mon Feb 22 13:55:33 PST 2016


Hi all,

I am running into issues using direct OpenGL calls inside a camera's pre-draw (or post-draw) callback while having the camera render into a framebuffer object. The texture is bound to a geode which is displayed in the default framebuffer on screen. The OpenGL calls should render an animated scene, but the texture is only updated once at the start. When using a post-draw callback, the texture is not updated at all.

For simplicity's sake, I'll describe and post the code of a simple example that demonstrates my issue. Here's the setup:
- A CompositeViewer with two Views sharing the same context.
- One View's camera is set up to render into a framebuffer object and is attached to a color texture and a packed depth-stencil texture. Its render order is set to NESTED-1. It has a pre-draw callback on it that performs OpenGL calls, but it does not do any rendering itself (no scene data, clear mask set to 0).
- The other View's camera renders to a single screen (default framebuffer). Its scene data is a square geode that is attached to the texture as its scene data. Its render order is set to NESTED-2 to occur after the render-to-texture.
- The OpenGL callback is pretty simple. It pushes the OpenGL state, sets up the viewport/scissor, clears the buffer, sets the frustum, draws a rotated square, and pops the OpenGL state. The rotation changes with each call with the intent of drawing a rotating square to the screen.

This direct OpenGL pre-draw callback works great if it is attached to a camera that is rendering to the default framebuffer (no render-to-texture). With render-to-texture, the square is shown in its initial rotation state but does not spin. If I use a post-draw callback instead, nothing is drawn at all.

A few more notes:
- I am using OpenSceneGraph 3.4.0 and have seen this behavior on both on a Macbook Pro (OS X 10.11) as well as on an Nvidia TX1 running Ubuntu 14.04.
- I have verified that the callback is being executed every frame.
- I have tried setting dirty on the Image as well as dirtyBound on the texture geode's geometry with no success.
- When using a pre-draw callback, calling dirtyAttachmentMap on the RTT camera has the desired effect; however, it appears to reconstruct the FBO which I do not want to do every frame. Also, using this method does not fix the behavior of the post-draw callback.

My guess is that I'm missing a flag or a setting that will cause the scene graph to update appropriately.

Here is the full code for my example:


Code:
#include <osgViewer/Viewer>
#include <osgViewer/CompositeViewer>

#include <osg/Texture2D>

#include <osg/Geode>
#include <osg/PolygonMode>
#include <osg/Matrixd>

void pushState() {
  glPushAttrib(GL_ALL_ATTRIB_BITS); 
  glMatrixMode(GL_MODELVIEW); 
  glPushMatrix(); 
  glMatrixMode(GL_PROJECTION); 
  glPushMatrix(); 
  glMatrixMode(GL_TEXTURE); 
  glPushMatrix(); 
}

void popState() 
{ 
  glMatrixMode(GL_TEXTURE); 
  glPopMatrix(); 
  glMatrixMode(GL_PROJECTION); 
  glPopMatrix(); 
  glMatrixMode(GL_MODELVIEW); 
  glPopMatrix(); 
  glPopAttrib(); 
} 

class OpenGlCallback : public osg::Camera::DrawCallback {
public:
  OpenGlCallback(int width, int height) :
    width(width), height(height) {}
  
  virtual void operator()(osg::RenderInfo& renderInfo) const override {
    static double xRotate = 0.0;
    static double yRotate = 0.0;
    static double zRotate = 0.0;
    pushState();

    glEnable(GL_SCISSOR_TEST);
    glViewport(0, 0, width, height);
    glScissor(0, 0, width, height);

    glClearColor(0.3, 0.3, 0.3, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);

    GLfloat zNear = 0.5f;
    GLfloat zFar = 20.0f;
    GLfloat fov = 40.0;
    GLfloat aspect = float(width)/float(height);
    GLfloat fH = tan(float(fov/360.0f * osg::PI)) * zNear;
    GLfloat fW = fH * aspect;
    glFrustum(-fW, fW, -fH, fH, zNear, zFar);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glTranslatef(0.0, 0.0, -4.5);
    glColor3f(0.7, 0.1, 0.1);
    glRotatef(xRotate, 1.0, 0.0, 0.0);
    glRotatef(yRotate, 0.0, 1.0, 0.0);
    glRotatef(zRotate, 0.0, 0.0, 1.0);

    glScalef(1.0, 1.0, 1.0);
    glBegin(GL_POLYGON);
      glVertex3f(-0.5, -0.5, -0.5);
      glVertex3f(-0.5, 0.5, -0.5);
      glVertex3f(0.5, 0.5, -0.5);
      glVertex3f(0.5, -0.5, -0.5);
    glEnd();

    popState();

    renderInfo.getCurrentCamera()->dirtyAttachmentMap();

    xRotate += 1.0;
    yRotate += 1.0;
    zRotate += 1.0;
  }
private:
  int width;
  int height;
};

osg::ref_ptr<osg::Texture2D> createColorTexture(int width, int height);
osg::ref_ptr<osg::Texture2D> createDepthStencilTexture(int width, int height);
osg::ref_ptr<osg::Geode> createTextureGeode(int x, int y, int width, int height);

int main(int argc, char** argv) {
  osg::ref_ptr<osgViewer::CompositeViewer> viewer = new osgViewer::CompositeViewer();
  viewer->setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);

  osg::ref_ptr<osgViewer::View> drawView = new osgViewer::View();
  osg::ref_ptr<osgViewer::View> oglView = new osgViewer::View();
  drawView->setUpViewOnSingleScreen(0);
  viewer->addView(drawView);
  viewer->addView(oglView);

  osgViewer::CompositeViewer::Windows windows;
  viewer->getWindows(windows);

  int width = windows[0]->getTraits()->width;
  int height = windows[0]->getTraits()->height;

  int textureX = 100;
  int textureY = 100;
  int textureWidth = width-200;
  int textureHeight = height-200;

  osg::ref_ptr<osg::Camera> oglCamera = oglView->getCamera();
  oglCamera->setGraphicsContext(windows[0]);
  oglCamera->setPreDrawCallback(new OpenGlCallback(textureWidth, textureHeight));
  oglCamera->setClearMask(0);
  oglCamera->setClearColor(osg::Vec4(1.0, 0.3, 0.3, 1.0));
  oglCamera->setViewport(0, 0, textureWidth, textureHeight);
  oglCamera->setRenderOrder(osg::Camera::RenderOrder::NESTED_RENDER, 1);
  oglCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);

  drawView->getCamera()->setProjectionMatrixAsOrtho2D(0, width, 0, height);
  drawView->getCamera()->setRenderOrder(osg::Camera::NESTED_RENDER, 2);

  osg::ref_ptr<osg::Texture2D> colorTexture = createColorTexture(textureWidth, textureHeight);
  osg::ref_ptr<osg::Texture2D> depthStencilTexture = createDepthStencilTexture(textureWidth, textureHeight);
  oglCamera->attach(osg::Camera::COLOR_BUFFER, colorTexture.get());
  oglCamera->attach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, depthStencilTexture.get());

  osg::ref_ptr<osg::Geode> textureGeode = createTextureGeode(textureX, textureY, textureWidth, textureHeight);
  textureGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, colorTexture, osg::StateAttribute::ON);
  drawView->setSceneData(textureGeode);

  viewer->realize();
  while(!viewer->done()) {
    viewer->frame();
  }
}

osg::ref_ptr<osg::Texture2D> createColorTexture(int width, int height) {
  osg::ref_ptr<osg::Image> image = new osg::Image();
  image->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
  image->setInternalTextureFormat(GL_RGBA);

  osg::ref_ptr<osg::Texture2D> colorTexture = new osg::Texture2D();
  colorTexture->setImage(image);
  colorTexture->setResizeNonPowerOfTwoHint(false);

  return colorTexture;
}

osg::ref_ptr<osg::Texture2D> createDepthStencilTexture(int width, int height) {
  osg::ref_ptr<osg::Texture2D> depthStencilTexture = new osg::Texture2D();
  depthStencilTexture->setTextureSize(width, height);
  depthStencilTexture->setInternalFormat(GL_DEPTH24_STENCIL8_EXT);
  depthStencilTexture->setSourceFormat(GL_DEPTH_STENCIL_EXT);
  depthStencilTexture->setSourceType(GL_UNSIGNED_INT_24_8_EXT);
  depthStencilTexture->setResizeNonPowerOfTwoHint(false);
  return depthStencilTexture;
}

osg::ref_ptr<osg::Geode> createTextureGeode(int x, int y, int width, int height) {
  osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();

  osg::ref_ptr<osg::Vec3Array> vertexArray = new osg::Vec3Array();
  vertexArray->push_back(osg::Vec3(x, y, 0));
  vertexArray->push_back(osg::Vec3(x+width, y, 0));
  vertexArray->push_back(osg::Vec3(x+width, y+height, 0));
  vertexArray->push_back(osg::Vec3(x, y+height, 0));
  geometry->setVertexArray(vertexArray);

  osg::ref_ptr<osg::Vec4Array> colorArray = new osg::Vec4Array();
  colorArray->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
  geometry->setColorArray(colorArray);
  geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

  osg::ref_ptr<osg::Vec2Array> texCoordArray = new osg::Vec2Array();
  texCoordArray->push_back(osg::Vec2(0.0f, 0.0f));
  texCoordArray->push_back(osg::Vec2(1.0f, 0.0f));
  texCoordArray->push_back(osg::Vec2(1.0f, 1.0f));
  texCoordArray->push_back(osg::Vec2(0.0f, 1.0f));
  geometry->setTexCoordArray(0, texCoordArray);

  geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_FAN, 0, 4));

  osg::ref_ptr<osg::Geode> textureGeode = new osg::Geode();
  textureGeode->addDrawable(geometry);

  return textureGeode;
}



I appreciate any help or suggestions on this.

Thank you,
Kevin[/quote]

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=66389#66389








More information about the osg-users mailing list