[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