OpenSceneGraph — Плащ-невидимка

Я новичок в использовании OSG, и у меня возникли некоторые проблемы при попытке решить проблему.

Я создал сцену (квадрат и две сферы с фиксированным фоном) и пытаюсь закрыть одну из сфер прозрачным четырехугольником. Я имею в виду, сделать "Плащ-невидимку", чтобы я мог видеть через него фоновое изображение, но не сферу (или что-то в проективной линии), которая находится за ним.

Я полностью застрял, так как все тесты, которые я проводил, даже близко не приблизили меня к тому, что я хочу. Я был бы очень признателен, если бы вы могли помочь мне с этим, любая идея (или код!) Буду более чем приветствоваться!! знак равно

Прикрепляю код простой сцены, которую использую для тестов.

#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Depth>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/ShapeDrawable>
#include <osg/BlendFunc>
#include <osgGA/TrackBallManipulator>

int main ()
{
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
osg::ref_ptr<osg::Image> image = osgDB::readImageFile( "C:/OpenSceneGraph-3.4.0/esc.jpg" );
texture->setDataVariance(osg::Object::DYNAMIC);
texture->setResizeNonPowerOfTwoHint(false);
texture->setImage( image.get() );

// Background
osg::ref_ptr<osg::Drawable> quad = osg::createTexturedQuadGeometry(osg::Vec3(),osg::Vec3(1.0f,0.0f,0.0f),osg::Vec3(0.0f, 1.0f, 0.0f));
quad->getOrCreateStateSet()->setTextureAttributeAndModes( 0, texture.get() );

osg::ref_ptr<osg::Geode> geodeBack = new osg::Geode;
geodeBack->addDrawable( quad.get() );

osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setCullingActive( false );
camera->setClearMask( 0 );
camera->setAllowEventFocus( false );
camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF );
camera->setRenderOrder( osg::Camera::POST_RENDER );
camera->setProjectionMatrix( osg::Matrix::ortho2D( 0.0, 1.0, 0.0, 1.0) );
camera->addChild( geodeBack.get() );

osg::StateSet* ss = camera->getOrCreateStateSet(); 
ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
ss->setMode(GL_DEPTH, osg::StateAttribute::ON);
ss->setAttributeAndModes( new osg::Depth( osg::Depth::LEQUAL,0.99,1.0 ) );


// Quad geometry
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
vertices->push_back( osg::Vec3(-1.0f, 1.0f,-1.0f) );
vertices->push_back( osg::Vec3( 0.0f, 1.0f,-1.0f) );
vertices->push_back( osg::Vec3( 0.0f, 1.0f, 0.0f) );
vertices->push_back( osg::Vec3(-1.0f, 1.0f, 0.0f) );

osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
normals->push_back( osg::Vec3(0.0f,-1.0f, 0.0f) );

osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
colors->push_back( osg::Vec4(1.0f, 1.0f, 1.0f, 0.0f) );

osg::ref_ptr<osg::Geometry> quad2 = new osg::Geometry;
quad2->setVertexArray( vertices.get() );
quad2->setNormalArray( normals.get() );
quad2->setNormalBinding( osg::Geometry::BIND_OVERALL );
quad2->setColorArray( colors.get() );
quad2->setColorBinding( osg::Geometry::BIND_OVERALL );

quad2->addPrimitiveSet( new osg::DrawArrays(GL_QUADS, 0, 4) );

osg::ref_ptr<osg::Geode> geodeTransp = new osg::Geode;
geodeTransp->addDrawable( quad2.get() );


osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc;
blendFunc->setFunction( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
osg::StateSet* stateset = geodeTransp->getOrCreateStateSet();
stateset->setAttributeAndModes( blendFunc ); 

// I'd see both spheres if I uncomment this. Otherwise I'd see the blue osg default background
//stateset->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );

// Sphere 1
osg::ref_ptr<osg::ShapeDrawable> shape1 = new osg::ShapeDrawable;
shape1->setShape( new osg::Sphere(osg::Vec3(-0.3f,0.5f,-0.3f), 0.2f) );
shape1->setColor( osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f) );

// Sphere 2
osg::ref_ptr<osg::ShapeDrawable> shape2 = new osg::ShapeDrawable;
shape2->setShape( new osg::Sphere(osg::Vec3(-0.7f,1.5f,-0.7f), 0.2f) );
shape2->setColor( osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f) );

osg::ref_ptr<osg::Geode> geodeFront = new osg::Geode;
geodeFront->addDrawable( shape1.get() );
geodeFront->addDrawable( shape2.get() );

osg::ref_ptr<osg::Group> root = new osg::Group;
root->addChild( camera.get() );
root->addChild( geodeTransp.get() );
root->addChild( geodeFront.get() );

osgViewer::Viewer viewer;
viewer.setSceneData( root.get() );

viewer.setCameraManipulator(new osgGA::TrackballManipulator());
osg::Vec3d eye( -0.5, -3.0, -0.5 );
osg::Vec3d center( -0.5, 0.0, -0.5 );
osg::Vec3d up( 0.0, 0.0, 1.0 );

viewer.getCamera()->setViewMatrixAsLookAt( eye, center, up );

viewer.realize();
while(!viewer.done()) {
    viewer.frame(); 
}
return 0;
}

Заранее спасибо,

Привет, Альваро


person AVGrimaldi    schedule 21.09.2016    source источник


Ответы (1)


Если я правильно понял, что вам нужно, вы должны просто отображать в этом конкретном порядке:

  • фоновая плоскость
  • четверка "невидимок"
  • весь другой объект (т.е. две сферы и т. д.)

Так что все, что рендерится после квадрацикла, будет замаскировано им, если окажется за ним. В OSG вы можете добиться этого, явно назначив рендербин для использования для разных (групп) узлов в их наборе состояний:

osg::StateSet* stateset = backgroundNode->getOrCreateStateSet();
stateset->setRenderBinDetails(1, "RenderBin");
// and increasing the number for the other nodes...
person rickyviking    schedule 22.09.2016
comment
Привет, rickyviking, спасибо за быстрый ответ! Действительно ценю это. Но даже устанавливая порядок рендеринга, который вы мне сказали, со мной постоянно происходит следующее: 1. Если предоставить подсказку рендеринга TRANSPARENT_BIN: визуализируются обе сферы, а не только ближайшая. 2. Если я этого не сделаю, то я увижу синий фон OSG по умолчанию через поверхность квадроцикла вместо моего фиксированного фона. ----- (Может быть, какой-либо вид рендеринга сплошного четырехугольника + обновление его состояния до прозрачного после рендеринга сферы (сфер)? И в последнее время рендеринг фона ..?) - person AVGrimaldi; 22.09.2016
comment
Извините @AVGrimaldi, но здесь задействовано слишком много понятий, которые нельзя прояснить в одном вопросе. Порядок рендеринга, который я упомянул в своем ответе, должен дать вам правильный результат. Но вам нужно лучше знать osg: TRANSPARENT_BIN будет сортировать объекты, которые вам не нужны, а набор состояний нельзя изменить при рендеринге одного кадра. Проверьте архивы osg и примеры для правильного использования - person rickyviking; 22.09.2016
comment
Отлично, обязательно сделаю! Хотя я все еще застрял ... так как ваш ответ также приводит к четвертому стиранию фона! (Даже без использования Transparent_bin в любом случае, как вы хорошо объяснили), поэтому должно быть что-то отсутствующее, чтобы сохранить фоновое пользовательское изображение нетронутым... - person AVGrimaldi; 22.09.2016