Как использовать маску буфера трафарета в ogre?

Как использовать буфер трафарета для создания маски в OGRE?

То есть некоторые объекты должны сначала рендериться в буфер трафарета и генерировать маску (скажем, 0 — фон, 0xFF — передний план); затем визуализируйте саму сцену, используя буфер трафарета в качестве маски, поэтому визуализируются только пиксели, где он равен 0xFF.

Думаю, мне следует использовать RenderQueueListener, но я не могу заставить его работать. Вот что я делаю прямо сейчас:

void StencilOpQueueListener::renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation) {
   if (queueGroupId == Ogre::RENDER_QUEUE_1) {
      Ogre::RenderSystem *rs = Ogre::Root::getSingleton().getRenderSystem();
      rs->clearFrameBuffer(Ogre::FBT_STENCIL, Ogre::ColourValue::Black, 1.0, 0xFF);
      rs->setStencilCheckEnabled(true);
      rs->_setColourBufferWriteEnabled(false, false, false, false);
      rs->setStencilBufferParams(
         Ogre::CMPF_ALWAYS_PASS, // compare
         0x1, // refvalue
         0xFFFFFFFF, // mask
         Ogre::SOP_REPLACE, Ogre::SOP_REPLACE, // stencil fail, depth fail
         Ogre::SOP_REPLACE, // stencil pass + depth pass
         false); // two-sided operation? no
   }
}

void StencilOpQueueListener::renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation)  {
   if (queueGroupId == Ogre::RENDER_QUEUE_1)  {
      Ogre::RenderSystem *rs = Ogre::Root::getSingleton().getRenderSystem();
      rs->setStencilCheckEnabled(false);
      rs->setStencilBufferParams();
   }
}

И я устанавливаю сущности, которые должны отображаться в буфере трафарета, с помощью:

   entity->setRenderQueueGroup(RENDER_QUEUE_1);

Что я делаю неправильно? Есть примеры того, как это делается в Огре? Спасибо!

Для справки, вот как я это делаю в чистом OpenGL:

/* Enable stencil test and leave it enabled throughout */
glClearStencil(0xFF);
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glStencilFunc(GL_ALWAYS, 0x1, 0xFFFFFFFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

// render into the stencil buffer. This should render only the selector objects
renderStencil();

// restore the rendering
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);

// only render "inside" the silhouette -- we want the overlap
glStencilFunc(GL_EQUAL, 0x1, 0xFFFFFFFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

render(); // now we render objects against that mask

person brunobg    schedule 30.11.2011    source источник


Ответы (1)


вы также должны синтезировать второй шаг, о котором вы упомянули в

// рендерить только внутри силуэта -- нам нужно перекрытие

glStencilFunc(GL_EQUAL, 0x1, 0xFFFFFFFF); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

Это означает, что вы должны применить маску, установленную в RENDER_QUEUE_1, к отрендеренной сцене, как вы это делаете в случае вызовов gl. Основной рендеринг происходит в RENDER_QUEUE_MAIN Ogre по умолчанию, поэтому вы должны добавить это в свой метод renderQueueStarted:

if (queueGroupId == Ogre::RENDER_QUEUE_MAIN)
{
    Ogre::RenderSystem * rs = Ogre::Root::getSingleton().getRenderSystem();
    rs->_setColourBufferWriteEnabled(true, true, true, true);
    rs->setStencilCheckEnabled(true);
    rs->setStencilBufferParams(Ogre::CMPF_EQUAL,0x1,0xFFFFFFFF,
        Ogre::SOP_KEEP,Ogre::SOP_KEEP,Ogre::SOP_KEEP,false);     
}

также выключайте трафарет в renderQueueEnded только после завершения основного рендеринга:

if ( queueGroupId == Ogre::RENDER_QUEUE_MAIN )
{
    Ogre::RenderSystem *rs = Ogre::Root::getSingleton().getRenderSystem();
    rs->setStencilCheckEnabled(false);
    rs->setStencilBufferParams();
}
person pergy    schedule 13.04.2015
comment
Ничего себе, четыре года спустя кто-то ответил! - person brunobg; 14.04.2015