I'm pretty new to osgPPU and I'm working on a port of Jimenez's MLAA full scene antialiasing algorithm.
It's a 3-pass post processing effect and I got it working on osgPPU.
- The first step detects the edges of the RTT'd scene and makes an 'edge texture'.
- The second step uses the previous texture and a precomputed one to calculate the area which pixels belonging to an edge would cover from an ideal trapeze.
- The final step blends each pixel in its 4-neighborhood according to the weights calculated in the previous step.
I got it fully working in osgPPU, however, an important optimization can be done by using the stencil buffer. The idea behind this is:
- Initially the stencil is cleared out to 0
- The first step of the post effect (edges detection) creates a stencil mask writing 1's to the stencil wherever there's an edge pixel. The pixels not belonging to an edge are discarded in the shader, so no writting to the stencil will occur in that case.
- In the subsequent steps the stencil test discards every pixel not covered by the mask, hence only the edge pixels are processed (weights calculation and final blend).
And this is how I tried to achieve it:
- I created two osg::Stencils, one for creating the mask and other for using the mask and discarding everything else.
- I attached the stencils to their corresponding osgPPU::Unit's.
(now, I need to clear the stencil at the beginning of the postFX chain, but not between each pass)
- I'm not sure about where glClear (with the clear mask of the camera the osgPPU::Processor is using) is called, but my guess is when rendering the scene to texture, not between units so I think that setting the clearMask in the camera is pointless.
- I tried to call glClear(GL_STENCIL_BUFFER_BIT) in a notify callback set in the first unit of my chain.
This has been driving me nuts for a couple of days now. It seems that the stencil buffer is not being written, or cleared prematurely between passes. And the stencil test only seems to be done if I enable it in the last unit's stateset.
What am I missing?
I can post the code if you want!
...
Thank a lot in advance!
Cheers,
Miguel
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=39894#39894
_______________________________________________
osg-users mailing list
osg-...@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
Hi,
I'm pretty new to osgPPU and I'm working on a port of Jimenez's MLAA full scene antialiasing algorithm.
It's a 3-pass post processing effect and I got it working on osgPPU.
- The first step detects the edges of the RTT'd scene and makes an 'edge texture'.
- The second step uses the previous texture and a precomputed one to calculate the area which pixels belonging to an edge would cover from an ideal trapeze.
- The final step blends each pixel in its 4-neighborhood according to the weights calculated in the previous step.
I got it fully working in osgPPU, however, an important optimization can be done by using the stencil buffer. The idea behind this is:
- Initially the stencil is cleared out to 0
- The first step of the post effect (edges detection) creates a stencil mask writing 1's to the stencil wherever there's an edge pixel. The pixels not belonging to an edge are discarded in the shader, so no writting to the stencil will occur in that case.
- In the subsequent steps the stencil test discards every pixel not covered by the mask, hence only the edge pixels are processed (weights calculation and final blend).
And this is how I tried to achieve it:
- I created two osg::Stencils, one for creating the mask and other for using the mask and discarding everything else.
- I attached the stencils to their corresponding osgPPU::Unit's.
(now, I need to clear the stencil at the beginning of the postFX chain, but not between each pass)
- I'm not sure about where glClear (with the clear mask of the camera the osgPPU::Processor is using) is called, but my guess is when rendering the scene to texture, not between units so I think that setting the clearMask in the camera is pointless.
- I tried to call glClear(GL_STENCIL_BUFFER_BIT) in a notify callback set in the first unit of my chain.
This has been driving me nuts for a couple of days now. It seems that the stencil buffer is not being written, or cleared prematurely between passes. And the stencil test only seems to be done if I enable it in the last unit's stateset.
What am I missing?
I can post the code if you want!
> - Have you create an opengl context with a stencil buffer ?
> - Have you try to use osg:ClearNode to clear the stencil buffer ?
> - Have you check opengl call order in a debugger like gDEBugger ?
- Yes I the context that osgViewer creates when realizing has a working stencil (I tested it).
- No, I didn't know that one was allowed to put nodes such as osg::ClearNode inbetween osgPPU::Unit's
- No, but I was planning to use GLintercept as a last resort
> yes please, could be more simple to find the bug.
Sure!, here it is:
This function generates the whole pipeline and attaches its processor to an osg::Group which is returned
Code:
// This is a dirty workaround for not using an osg::ClearNode
struct CamClearMaskCallback : public osgPPU::Unit::NotifyCallback
{
osg::Camera * m_cam;
GLbitfield m_mask;
CamClearMaskCallback(osg::Camera *cam, GLbitfield mask) : osgPPU::Unit::NotifyCallback(), m_cam(cam), m_mask(mask) {}
virtual void operator()(osg::RenderInfo& ri, const osgPPU::Unit* u) const
{
m_cam->setClearMask(m_mask);
if(m_mask & GL_STENCIL_BUFFER_BIT)
{
glClear(GL_STENCIL_BUFFER_BIT);
// printf("CLEAR\n");
} else {
// printf("\n");
}
}
};
osg::Group* MLAARendering::createMLAAPipeline(osg::Camera* camera)
{
osg::Group* finalGroup = new osg::Group;
osg::ref_ptr<CamClearMaskCallback> clearStencilCallback = new CamClearMaskCallback(camera, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
osg::ref_ptr<CamClearMaskCallback> dontClearStencilCallback = new CamClearMaskCallback(camera, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
osg::ref_ptr<osgDB::ReaderWriter::Options> fragmentOptions = new osgDB::ReaderWriter::Options("fragment");
osg::ref_ptr<osgDB::ReaderWriter::Options> vertexOptions = new osgDB::ReaderWriter::Options("vertex");
// Setup the clear mask and the stencil clear value
camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
camera->setClearStencil(0);
osg::Vec2f pixelSize(1.0/camera->getGraphicsContext()->getTraits()->width,
1.0/camera->getGraphicsContext()->getTraits()->height);
// This stencil is intended to create the mask by writting a 1 to the stencil wherever a fragment is not discarded in the shader of the unit it's
// attached to. However, the stencil test has to pass always and osgPPU disables the Z test, so I don't know if this is really working as I want!
osg::Stencil * createMaskStencil = new osg::Stencil;
{
createMaskStencil->setFunctionRef(1);
createMaskStencil->setFunction(osg::Stencil::ALWAYS);
createMaskStencil->setWriteMask(1);
createMaskStencil->setOperation(osg::Stencil::REPLACE, osg::Stencil::REPLACE, osg::Stencil::REPLACE);
}
// This one is intended to discard every fragment not masked by a 1 in the stencil
osg::Stencil * useMaskStencil = new osg::Stencil;
{
useMaskStencil->setFunctionRef(1);
useMaskStencil->setFunction(osg::Stencil::EQUAL); // TODO: TEMP!!, Should be osg::Stencil::EQUAL!
useMaskStencil->setWriteMask(1);
useMaskStencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
}
// This is for testing purposes (it always passes and doesn't change the buffer)
osg::Stencil * testStencil = new osg::Stencil;
{
testStencil->setFunction(osg::Stencil::ALWAYS,1,~0u);
testStencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
}
// Create a processor for this pipeline
m_processor = new osgPPU::Processor();
m_processor->setName("Processor");
m_processor->setCamera(camera);
osgPPU::UnitCameraAttachmentBypass* bypass = new osgPPU::UnitCameraAttachmentBypass();
{
bypass->setBufferComponent(osg::Camera::COLOR_BUFFER0);
bypass->setName("MLAA.mainCamOutputTex");
// I want the stencil to be cleared here, I don't really care if it's done before or after 'drawing'
bypass->setBeginDrawCallback(clearStencilCallback.get());
}
osgPPU::UnitCameraAttachmentBypass* bypassDepth = new osgPPU::UnitCameraAttachmentBypass();
{
bypassDepth->setBufferComponent(osg::Camera::DEPTH_BUFFER);
bypassDepth->setName("MLAA.mainCamOutputDepthTex");
}
// First step: Edges detection and stencil mask creation
edgeDetection = new osgPPU::UnitInOut();
edgeDetection->setName("MLAA.edgeDetectionUnit");
{
edgeDepthShader = new osgPPU::ShaderAttribute();
edgeDepthShader->addShader(osgDB::readShaderFile("Shaders\\edge_depth_frag.frag", fragmentOptions.get()));
edgeDepthShader->addShader(osgDB::readShaderFile("Shaders\\offset_vert.vert", vertexOptions.get()));
edgeDepthShader->setName("EdgeDetectionShader");
edgeDepthShader->add("threshold", osg::Uniform::FLOAT);
edgeDepthShader->set("threshold", edgeThreshold);
edgeDepthShader->add("pixelSize", osg::Uniform::FLOAT_VEC2);
edgeDepthShader->set("pixelSize", pixelSize);
edgeDepthShader->add("bias", osg::Uniform::FLOAT);
edgeDepthShader->set("bias", edgeThreshold);
edgeDepthShader->add("scale", osg::Uniform::FLOAT);
edgeDepthShader->set("scale", 0.1f);
edgeDetection->setInputToUniform(bypass, "colorMapG", true);
edgeDetection->setInputToUniform(bypassDepth, "depthMap", true);
edgeDetection->getOrCreateStateSet()->setAttributeAndModes(edgeDepthShader);
// Attach the 'createMask' stencil and enable the GL_STENCIL_TEST
edgeDetection->getOrCreateStateSet()->setAttributeAndModes(createMaskStencil, osg::StateAttribute::ON);
edgeDetection->getOrCreateStateSet()->setMode(GL_STENCIL_TEST, osg::StateAttribute::ON);
edgeDetection->setBeginDrawCallback(dontClearStencilCallback.get());
}
// This unit just loads up a texture which is needed by the next shader
osgPPU::UnitTexture* areaTexture = new osgPPU::UnitTexture();
areaTexture->setName("MLAA.areaTextureUnit");
{
osg::Image *areaImg = osgDB::readImageFile("Textures\\AreaMap65.dds");
// An extremely dirty error checking
if(!areaImg)
{
osg::notify(osg::FATAL) << "> Can't load the area map, aborting ...\n";
exit(-1);
}
osg::Texture2D *areaTex = new osg::Texture2D;
areaTex->setResizeNonPowerOfTwoHint(false);
areaTex->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST);
areaTex->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST);
areaTex->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
areaTex->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
areaTex->setImage(areaImg);
areaTex->setNumMipmapLevels(1);
areaTexture->setTexture(areaTex);
}
// Second step: Weights calculation only in the fragments masked by the stencil (whose values are == 1)
weightsCalculation = new osgPPU::UnitInOut();
weightsCalculation->setName("MLAA.weightsCalculationUnit");
{
weightsShader = new osgPPU::ShaderAttribute();
weightsShader->addShader(osgDB::readShaderFile("Shaders\\weights_frag.frag", fragmentOptions.get()));
weightsShader->addShader(osgDB::readShaderFile("Shaders\\offset_vert.vert", vertexOptions.get()));
weightsShader->setName("WeightsCalculationShader");
weightsCalculation->setInputToUniform(areaTexture, "areaMap", true);
weightsCalculation->setInputToUniform(edgeDetection, "edgesMapL", true);
weightsShader->add("maxSearchSteps", osg::Uniform::INT);
weightsShader->set("maxSearchSteps", 12);
weightsShader->add("pixelSize", osg::Uniform::FLOAT_VEC2);
weightsShader->set("pixelSize", pixelSize);
weightsCalculation->getOrCreateStateSet()->setAttributeAndModes(weightsShader);
weightsCalculation->setInputTextureIndexForViewportReference(1); // Choose to have an output the same size as edgesMap has
// Attach the 'usueMask' stencil here
weightsCalculation->getOrCreateStateSet()->setAttributeAndModes(useMaskStencil, osg::StateAttribute::ON);
weightsCalculation->getOrCreateStateSet()->setMode(GL_STENCIL_TEST, osg::StateAttribute::ON);
// Just to make sure that the stencil is not being cleared anymore
weightsCalculation->setBeginDrawCallback(dontClearStencilCallback.get());
}
// Last step: Blend the edge pixels with their 4-neighborhood according to the blending weights
// (again, only the masked pixels have to be processed)
osgPPU::UnitInOut* pixelBlend = new osgPPU::UnitInOut();
pixelBlend->setName("MLAA.pixelblendingUnit");
{
osgPPU::ShaderAttribute* blendShader = new osgPPU::ShaderAttribute();
blendShader->addShader(osgDB::readShaderFile("Shaders\\blend_frag.frag", fragmentOptions.get()));
blendShader->addShader(osgDB::readShaderFile("Shaders\\offset_vert.vert", vertexOptions.get()));
blendShader->setName("BlendShader");
pixelBlend->setInputToUniform(weightsCalculation, "blendMap", true);
blendShader->add("pixelSize", osg::Uniform::FLOAT_VEC2);
blendShader->set("pixelSize", pixelSize);
pixelBlend->setInputToUniform(bypass, "colorMapL", true);
pixelBlend->getOrCreateStateSet()->setAttributeAndModes(blendShader);
// Attach the 'useMask' stencil
pixelBlend->getOrCreateStateSet()->setAttributeAndModes(useMaskStencil, osg::StateAttribute::ON);
pixelBlend->getOrCreateStateSet()->setMode(GL_STENCIL_TEST, osg::StateAttribute::ON);
}
// This output unit just acts as a switch for displaying the original RTT, the final processed image or the textures inbetween (edges and weights)
unitOut= new osgPPU::UnitOut();
shaderAttributeOut= new osgPPU::ShaderAttribute();
{
osg::Shader* shader= new osg::Shader(osg::Shader::FRAGMENT);
const char* shaderSource=
"uniform sampler2D finalMap;\n"
"uniform sampler2D edgesMap;\n"
"uniform sampler2D weightsMap;\n"
"uniform sampler2D colorMap;\n"
"uniform int switchFlag;\n"
"void main()\n"
"{\n"
"if(switchFlag == 0)\n"
" gl_FragColor=texture2D(edgesMap,gl_TexCoord[0].st);\n"
"else if(switchFlag == 1)\n"
" gl_FragColor=texture2D(weightsMap,gl_TexCoord[0].st);\n"
"else if(switchFlag == 2)\n"
" gl_FragColor=texture2D(finalMap,gl_TexCoord[0].st);\n"
"else if(switchFlag == 3)\n"
" gl_FragColor=texture2D(colorMap,gl_TexCoord[0].st);\n"
"}";
shader->setShaderSource(shaderSource);
shaderAttributeOut->addShader(shader);
shaderAttributeOut->setName("nomShaderAttribute");
shaderAttributeOut->add("switchFlag", osg::Uniform::INT);
shaderAttributeOut->set("switchFlag", 2);
unitOut->setInputToUniform(pixelBlend, "finalMap", true);
unitOut->setInputToUniform(edgeDetection, "edgesMap", true);
unitOut->setInputToUniform(weightsCalculation, "weightsMap", true);
unitOut->setInputToUniform(bypass, "colorMap", true);
unitOut->setInputTextureIndexForViewportReference(1); // Choose to have an output the same size as edgesMap has
unitOut->setName("MLAA.finalOutputUnit");
unitOut->setViewport(new osg::Viewport(0,0, camera->getGraphicsContext()->getTraits()->width,
camera->getGraphicsContext()->getTraits()->height));
unitOut->getOrCreateStateSet()->setAttributeAndModes(shaderAttributeOut.get());
// It looks like for some reason no stencil testing is performed at all unless I enable the GL_STENCIL_TEST in this unit
// Let's recall that the testStencil does always pass
unitOut->getOrCreateStateSet()->setAttributeAndModes(testStencil, osg::StateAttribute::ON);
unitOut->getOrCreateStateSet()->setMode(GL_STENCIL_TEST, osg::StateAttribute::ON);
}
// Link the units
bypass->addChild(edgeDetection);
bypassDepth->addChild(edgeDetection);
edgeDetection->addChild(areaTexture);
edgeDetection->addChild(weightsCalculation);
areaTexture->addChild(weightsCalculation);
weightsCalculation->addChild(pixelBlend);
pixelBlend->addChild(unitOut);
m_processor->addChild(bypass);
m_processor->addChild(bypassDepth);
finalGroup->addChild(m_processor);
m_processor->dirtyUnitSubgraph();
// Set the edges texture properties
{
osg::Texture2D *outTex = static_cast<osg::Texture2D*>(edgeDetection->getOrCreateOutputTexture());
if(outTex)
{
outTex->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
outTex->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
outTex->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
outTex->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
}
}
// Set the weights texture properties
{
osg::Texture2D *outTex = static_cast<osg::Texture2D*>(weightsCalculation->getOrCreateOutputTexture());
if(outTex)
{
outTex->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST);
outTex->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST);
outTex->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
outTex->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
}
}
isInit = true;
return finalGroup;
}
... the first shader looks like this ...
Code:
/**
* Copyright (C) 2010 Jorge Jimenez ()
* Copyright (C) 2010 Belen Masia ()
* Copyright (C) 2010 Jose I. Echevarria ()
* Copyright (C) 2010 Fernando Navarro ()
* Copyright (C) 2010 Diego Gutierrez ()
* All rights reserved.
*
* Adaptated by Miguel Angel Exposito ()
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the following statement:
*
* "Uses Jimenez's MLAA. Copyright (C) 2010 by Jorge Jimenez, Belen Masia,
* Jose I. Echevarria, Fernando Navarro and Diego Gutierrez."
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holders.
*/
#version 120
varying vec4 offset[2];
uniform sampler2D depthMap;
uniform float threshold;
void main()
{
float D = texture2D(depthMap, gl_TexCoord[0].st).r;
float Dleft = texture2D(depthMap, offset[0].xy).r;
float Dtop = texture2D(depthMap, offset[0].zw).r;
float Dright = texture2D(depthMap, offset[1].xy).r;
float Dbottom = texture2D(depthMap, offset[1].zw).r;
vec4 delta = abs(vec4(D) - vec4(Dleft, Dtop, Dright, Dbottom));
vec4 edges = step(vec4(threshold) / 10.0, delta); // Dividing by 10 give us results similar to the color-based detection.
if (dot(edges, vec4(1.0)) == 0.0)
discard;
gl_FragData[0] = edges;
}
(Note that in order to make it work without the stencil test I have to comment the discard part in the sader).
... and the main program goes like this ...
Code:
void main(int argc, char **argv)
{
printHelp(); // Output some console text
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
MLAA = new MLAARendering;
unsigned int screenWidth;
unsigned int screenHeight;
unsigned int windowWidth = 1280;
unsigned int windowHeight = 720;
// Init the stencil and disable the default MSAA
osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);
osg::DisplaySettings::instance()->setNumMultiSamples(0);
osg::ref_ptr<KeyboardEventHandler> kbHandler;
// Get the screen resolution
osg::GraphicsContext::getWindowingSystemInterface()->
getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0),screenWidth,
screenHeight);
// Setup the view in a screen centered window
viewer->setUpViewInWindow((screenWidth-windowWidth)/2,
(screenHeight-windowHeight)/2, windowWidth, windowHeight);
// Set single-threading model
viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
// Setup the viewer camera and RTT
osg::Camera* camera = viewer->getCamera();
camera->setViewport(new osg::Viewport(0,0,windowWidth, windowHeight));
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
osg::Texture* textureView = createRenderTextureWrks(windowWidth, windowHeight);
osg::Texture* textureDepth = createDepthTextureWrks(windowWidth, windowHeight);
camera->attach(osg::Camera::COLOR_BUFFER0, textureView);
camera->attach(osg::Camera::DEPTH_BUFFER, textureDepth);
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
traits->samples = 0; // No multisampling AA
traits->width = windowWidth;
traits->height = windowHeight;
traits->x = (screenWidth-windowWidth)/2;
traits->y = (screenHeight-windowHeight)/2;
traits->doubleBuffer = true;
traits->sharedContext = 0;
traits->stencil = 8;
traits->supportsResize = false;
traits->windowDecoration = true;
traits->windowName = "Jimenez's MLAA for OSG";
osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
camera->setGraphicsContext(gc);
// Load up the scene
osg::ref_ptr<osg::Node> scene;
if(argc > 1)
{
osg::notify(osg::NOTICE) << "> Loading requested model '" << argv[1] << "' ...\n";
scene = osgDB::readNodeFile(std::string(argv[1]));
} else {
osg::notify(osg::NOTICE) << "> No model specified, defaulting to 'Models\\cow.osg' ...\n";
scene = osgDB::readNodeFile("Models\\cow.osg");
}
if(!scene)
{
if(argc == 1)
osg::notify(osg::FATAL) << "> Can't load default model 'Models\\cow.osg', aborting...\n";
else
osg::notify(osg::FATAL) << "> Can't load requested model, '" << argv[1] << "' aborting...\n";
exit(-1);
}
osg::ref_ptr<osg::Group> group = new osg::Group();
group->setName("Antialiased Scene");
group = MLAA->createMLAAPipeline(camera);
group->addChild(scene);
osg::ref_ptr<osgViewer::StatsHandler> statsHandler = new osgViewer::StatsHandler();
statsHandler->setKeyEventPrintsOutStats('s'); // Map the statistics HUD to the 's' key
viewer->addEventHandler(statsHandler);
kbHandler = new KeyboardEventHandler(viewer, MLAA);
// Add the keyboard event handler
viewer->addEventHandler(kbHandler);
scene->getOrCreateStateSet()->setMode(GL_STENCIL_TEST, osg::StateAttribute::OFF);
viewer->realize();
viewer->setSceneData(group);
viewer->run();
}
...
Thank you!
Cheers,
Miguel
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=39976#39976
Sorry for bumping this but I couldn't figure out this yet :(
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=40065#40065
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=40121#40121