OGRE中级教程七 Render to texture (RTT)

英语水平有限,欢迎大家批评指正微笑

本文并没有将原文全部翻译,只是将其中的一些知识点翻译总结了一下,想要查看详细讲解的话,可以到原文处看一下,附上英文原文地址:http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Intermediate+Tutorial+7&structure=Tutorials

Introduction

   本教程中我们将学习渲染到纹理的基本知识,该技术对很多特效特别是与着色器一起制作的特效是很重要的。渲染到纹理RTT的思想很简单,你只需要把场景的渲染输出数据发送给一个纹理,而不是把它发送给你的渲染窗口。然后这个纹理就可以像一张普通的纹理一样被硬件驱动使用了。

Render to texture

Creating the render textures

   首先创建一个纹理:

Ogre::TexturePtr rtt_texture = Ogre::TextureManager::getSingleton().createManual("RttTex", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mWindow->getWidth(), mWindow->getHeight(), 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);

   mWindow是你的Ogre::RenderWindow的指针)

   createManual()的第一个参数是纹理的名字,通常命名为RttTex。第二个参数指定了资源组,第三个参数为纹理类型,第四、五个参数为纹理的宽和高。你还需要传递mip maps的个数以及纹理的格式和一个使用标记(usage flag)。有很多不同的纹理格式,最简单的是PF_R8G8B8,它可以创建一个24为的RBG纹理。如果你需要一个alpha通道,那么应该用PF_R8G8B8A8格式。现在我们需要获取纹理的渲染目标,以设置一些参数并且稍后加一个RenderTargetListener

Ogre::RenderTexture *renderTexture = rtt_texture->getBuffer()->getRenderTarget();

renderTexture->addViewport(mCamera);

renderTexture->getViewport(0)->setClearEveryFrame(true);

renderTexture->getViewport(0)->setBackgroundColour(Ogre::ColourValue::Black);

renderTexture->getViewport(0)->setOverlaysEnabled(false);

   得到渲染纹理后,我们需要给他添加一个视口。该视口将被渲染纹理所填充。每帧视口都要clear自己,设背景色为黑色并使所有overlays不可用。

Write texture to file

   现在我们要把我们创建的渲染纹理(RenderTexture)的内容保存到一个文件中,RenderTextures继承自RenderTarget,并有一个函数能将渲染纹理(RenderTexture)的内容保存到文件中(我们也可以用RenderWindwos来做)。但在保存内容到文件之前,你得更新你的渲染纹理(RenderTexture)。你可以手动的通过update()函数来更新渲染纹理(RenderTexture)或让程序通过调用setAutoUpdata()函数自动更新渲染纹理(RenderTexture)。

   // Either this way

renderTexture->setAutoUpdated(true);

// or this way

renderTexture->update();

// Now save the contents

renderTexture->writeContentsToFile("start.png");

   运行程序后,你会在你的exe程序所在的文件夹中找到一个a.png文件。

Implementing a mini screen

General

   现在我们要在程序窗口的右下角添加一个小窗口,为此我们添加一个以我们的渲染纹理(RenderTexture)作为纹理的2D矩形(Rectangle2D)到场景中。我们场景将被显示两次:一次渲染到渲染唱k,另一次作为我们的2D矩形(Rectangle2D)的纹理。

   用这个方法还可以做一个TV屏幕(或CCTV摄像机等),你可以通过放置一个摄像机,创建一个渲染纹理(RenderTexture)并显示到TV屏幕上,来显示场景的其他部分。

Setting up the rectangle

   创建一个Ogre::Rectangle2D

Ogre::Rectangle2D *mMiniScreen = new Ogre::Rectangle2D(true);

mMiniScreen->setCorners(0.5f, -0.5f, 1.0f, -1.0f);

mMiniScreen->setBoundingBox(Ogre::AxisAlignedBox(-100000.0f*      Ogre::Vector3::UNIT_SCALE, 100000.0f * Ogre::Vector3::UNIT_SCALE));

   第一行设参数为true来生成纹理坐标,后面用于将纹理绘制到矩形上。第二行指定矩形的角,左为-1.0、右为+1.0、上为+1.0、下为-1.0。这样我们的矩形就正好在程序窗口的右下角。我们还给矩形一个很大的绑定盒以防止它被剔除,当我们没有面向他的场景节点时。你还可以用AxisAlignedBox::setInfinite(),而不用手动设置绑定盒的大小,但过去这会有点问题,所以手动设置绑定盒是最快的方法。

   现在我们已经创建了矩形,然后需要把它绑定到一个场景节点上。

Ogre::SceneNode*miniScreenNode= mSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode");

miniScreenNode->attachObject(mMiniScreen);

   现在运行你的程序,你会看到在程序窗口的右下角有一个白色的矩形。

Creating a material from scratch

   下面要显示我们前面在矩形上创建的渲染纹理(RenderTexture),我们得为他创建一个材质。我们可以写一个材质脚本或直接在运行时的代码中来创建材质。

Ogre::MaterialPtr renderMaterial = Ogre::MaterialManager::getSingleton().create("RttMat",                      Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

Ogre::Technique* matTechnique = renderMaterial->createTechnique();

matTechnique->createPass();

renderMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false);

renderMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex");

   第一行创建一个空的材质,后面两行添加一个technique和一个pass,第三行我们使光源不可用以防止我们小屏幕比纹理还要暗,最后一行我们通过传送我们前面创建的渲染纹理(RenderTexture)创建了一个新的TextureUnitState

   现在我们可以将这个材质用到我们的小屏幕上了:

   mMiniScreen->setMaterial("RttMat");

   运行程序你会看到一个不是你想要的效果:小屏幕自己有一个小屏幕。要解决这个问题,OGRE引进了RenderTargetListener

Usage of Render TargetListener

General

   很多情况下只有场景中的某些对象需要RTT,例如我们只需要一个包含了不带小屏幕的程序窗口输出数据的纹理,这个纹理是用于我们的小屏幕的。所有每次在窗口输出数据保存到纹理前,我们得把小屏幕隐藏起来。这也是RenderTargetListener插入(come in)的地方。该侦听器有两个重要的函数:preRenderTargetUnpdate()postRenderTargetUpdate()。正如其名,第一个函数是在渲染纹理(RenderTexture)被填充时被该侦听器自动调用的(这里我们可以隐藏小窗口),第二个函数是在渲染纹理(RenderTexture)被填充完后被该侦听器自动调用的(这里我们再次显示小窗口)。

Implementing a RenderTargetListener

   写一个RenderTargetListener很简单,首先让我们的程序的类继承RenderTargetListener让它成为自己的侦听器。然后我们只要在preRenderTargetUnpdate()postRenderTargetUpdate()函数中隐藏和显示我们的小屏幕就行了。所有你的程序的类应该如下所示:

IntermediateTutorial7.h

class IntermediateTutorial7 : public BaseApplication, public Ogre::RenderTargetListener

{

public:

    IntermediateTutorial7(void);

    virtual ~IntermediateTutorial7(void);

protected:

    virtual void createScene(void);

       virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);

       virtual void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);

       virtual void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);

       Ogre::MovablePlane* mPlane;

       Ogre::Entity* mPlaneEnt;

       Ogre::SceneNode* mPlaneNode;

        //This should be taken out of the createScene member and brought here

       Ogre::Rectangle2D* mMiniScreen;

};

IntermediateTutorial7.cpp

void IntermediateTutorial7::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)

{

       mMiniScreen->setVisible(false);

}

void IntermediateTutorial7::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)

{

       mMiniScreen->setVisible(true);

}

   最后一步给渲染纹理(RenderTexture)添加侦听器,因为程序的类继承自RenderTargetListener,所有我们只把this指针作为参数在createScene函数的最后传给addListener函数:

   renderTexture->addListener(this);

   运行程序,现在就可以看到你的程序中有一个小屏幕了。

RTTs and shaders

Passing a RTT to a shader

   因为RTTs和着色器(shader)经常一起使用,所有你需要知道如何把渲染纹理(RenderTexture)传给着色器(shader)。最简单的例子就是,运行时你不需要为着色器修改纹理。如果不需要,你只需要告诉材质脚本运行时创建的纹理的名字,本例中是TttTex。所有你的texture_unit如下所示:

texture_unit

{

     texture RttTex

}

   如果运行时着色器要使用的纹理要改变,添加如下代码:

Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName("Sepia"); material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("OtherRttTex");

   第一行获取一个指向材质的指针,第二行将纹理改成所想要的名字。现在你可以用这两种方法之一在材质脚本中设置正确的纹理名,然后你可以用下面的代码在cg着色器中获取纹理了:

  uniform sampler2D SceneSampler : register(s0)

   编译运行你的程序!

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值