如何在 ogre 中使用模板缓冲区掩码?

发布于 2024-12-19 00:17:31 字数 2319 浏览 2 评论 0原文

如何在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);

我做错了什么?有 Ogre 中如何做到这一点的例子吗?谢谢!

作为参考,我在纯 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

How to use the stencil buffer to create a mask in OGRE?

That is, some objects should be rendered first into the stencil buffer and generate a mask (say 0 is background, 0xFF is foreground); then render the scene itself, using the stencil buffer as a mask so only pixels where it is 0xFF are rendered.

I guess I should use a RenderQueueListener, but I can't make it work. Here's what I'm doing right now:

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();
   }
}

And I set the entities that should render to the stencil buffer are set with:

   entity->setRenderQueueGroup(RENDER_QUEUE_1);

What am I doing wrong? Any examples of how this is done in Ogre? Thanks!

For reference, this is how I do it in pure 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

倾听心声的旋律 2024-12-26 00:17:31

您还应该综合您在中提到的第二步

// 只渲染轮廓“内部”——我们想要重叠

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

这意味着,您应该将在 RENDER_QUEUE_1 中设置的蒙版应用到渲染的场景,就像在 gl 调用的情况下一样。默认情况下,主渲染发生在 Ogre 的 RENDER_QUEUE_MAIN 中,因此您应该将其添加到您的 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();
}

you should synthesize the second step as well, which you mentioned in

// only render "inside" the silhouette -- we want the overlap

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

This means, you should apply the mask you set in RENDER_QUEUE_1 to the rendered scene, like you do in the case of gl calls. The main rendering takes place in Ogre's RENDER_QUEUE_MAIN by default, thus you should add this to your renderQueueStarted method:

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);     
}

also, switch off the stenciling in renderQueueEnded only after main rendering is finished:

if ( queueGroupId == Ogre::RENDER_QUEUE_MAIN )
{
    Ogre::RenderSystem *rs = Ogre::Root::getSingleton().getRenderSystem();
    rs->setStencilCheckEnabled(false);
    rs->setStencilBufferParams();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文