当前位置:   article > 正文

OGRE Demo_RenderToTexture 渲染到纹理_ogre 离屏渲染,ogre当作普通纹理贴图处理

ogre 离屏渲染,ogre当作普通纹理贴图处理

Demo_RenderToTexture

       这是一个使用渲染到纹理技术的最基本的例子,代码也比较容易理解。我们首先在原点处放置一个平面,然后布置相应的摄像机把场景中的内容映射到平面所使用的材质纹理上。如图8-1所展示的结果,为了便于观察,例子中在场景里面放置了一个食人魔的头和几个麻花体的模型。最后在平面上产生了实时反射的渲染特效。整个过程不需要任何的GPU编程,并且渲染效率远远高于传统中通过光线追踪来产生反射的效果。这种实时反射效果可以自动依照视点的变化而正确的变化。在图中可能看不出来,在摄像机移动的同时,天空盒的倒影会正确的在反射表面投影出来。

 

图8-1:Ogre渲染到纹理演示程序效果

 

       在演示程序RenderToTexture.cpp文件中,RenderToTextureApplicaiton类中的createScene()方法中实现了大部分关键的操作。在这里我们重点介绍如何设置纹理渲染目标。

和创建其他对象一样,纹理的创建也有相应的工厂方法。代码8-3中展示了纹理对象的创建过程。其中PF_R8G8B8描述了一个24位无Alpha通道的颜色格式。方法返回了一个指向纹理资源的智能指针。

 

代码8-3:创建一个512x512,24-bit,名字为RttTex的纹理渲染目标

TexturePtr texture = TextureManager::getSingleton().createManual( "RttTex",

         ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D,

         512, 512, 0, PF_R8G8B8, TU_RENDERTARGET );
 

   

在代码8-4中,我们设置了一个摄象机和视口用于把场景内容渲染到目标纹理上。

 

代码8-4:创建一个摄象机和视口用来把场景内容渲染到纹理

RenderTarget *rttTex = texture->getBuffer()->getRenderTarget();

        {

            mReflectCam = mSceneMgr->createCamera("ReflectCam");

            mReflectCam->setNearClipDistance(mCamera->getNearClipDistance());

            mReflectCam->setFarClipDistance(mCamera->getFarClipDistance());

            mReflectCam->setAspectRatio(

                (Real)mWindow->getViewport(0)->getActualWidth() /

                (Real)mWindow->getViewport(0)->getActualHeight());

            Viewport *v = rttTex->addViewport( mReflectCam );

            v->setClearEveryFrame( true );

            v->setBackgroundColour( ColourValue::Black );
 

在这里我们需要注意的,为了实现反射效果,我们把反射摄像机(纹理渲染目标使用)和主摄像机(渲染整个场景使用)设置到相同的位置。我们并不需要做任何特殊的处理,只要保证两个摄像机的位置和方向相同,就能很好的在表面上实现倒影的效果。

 

       代码8-4中创建了相应的视口并设置为每帧清理。如果你忘了做每帧清理的工作,之前的渲染结果都会保留下来(听起来似乎是一种实现残影特效的方法,但这里并不需要)。视口的背景被设置为黑色,这样就能正确地在上面添加渲染结果(黑色是没有光线的颜色)。

 

       在下面代码8-5中(接着上面的代码),我们创建了相应的材质对象,这个材质之后被用在createScene()方法所创建的反射平面上。

 

代码8-5:创建使用渲染纹理的材质

MaterialPtr mat = MaterialManager::getSingleton().create("RttMat",

                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

            TextureUnitState* t = mat->getTechnique(0)->getPass(0)->createTextureUnitState("RustedMetal.jpg");

            t = mat->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex");

            // Blend with base texture

            t->setColourOperationEx(LBX_BLEND_MANUAL, LBS_TEXTURE, LBS_CURRENT,

ColourValue::White,  ColourValue::White, 0.25);

                            t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);

                            t->setProjectiveTexturing(true, mReflectCam);

            rttTex->addListener(this);
 

 

       上面代码中创建了名字为“RttMat”的材质,其中包含一个技术实现(Technique)和其中的一个渲染通路(Pass),在渲染通路中含有两个纹理单元,其中一个是静态图片(图片文件RustedMetal.jpg),而另外一个就是使用我们之前创建的纹理渲染目标“RttTex”。两层纹理单元以25%系数混合到一起(换句话说,我们的纹理渲染目标在表面上拥有25%可见度)。最后的混合效果就像前面图8-1所展示的一样。

 

       这个投影纹理可以良好的用于对世界地图的反射纹理的应用。注意在这里代码中纹理单元的寻址方式被设置为TAM_CLAMP,这可以有效的让渲染纹理附着在物体表面上。

 

在代码的后面,RenderToTextureApplication类的实例被作为一个“监听者”添加到纹理渲染目标对象上(接下来我们会讲具体的回调内容)。

 

接下来的代码8-6中,展示了这个演示程序中关键的步骤。

 

代码8-6:设置投影摄像机,并把代码-83中创建的纹理应用到平面

            // set up linked reflection

            mReflectCam->enableReflection(mPlane);

            // Also clip

            mReflectCam->enableCustomNearClipPlane(mPlane);

        }

        // Give the plane a texture

        mPlaneEnt->setMaterialName("RttMat");
 

 

       在代码8-6中,我们首先把摄像机设置为镜像状态。并且我们在参数中指定了作为“镜子” 的平面。如你所见,这个平面即用来渲染反射纹理,同时也用来作为反射表面的分界。平面会如同镜子般反射所有平面上面的内容。这种方法比较常用于模拟水面的反射,你可以想象这样一个画面,碧绿的湖面映射着周围美丽的风景。这和本演示程序的基本原理是相同的。

 

       对摄像机近截面(Near clip plane)的设置突然出现在这里可能会让人感觉有一些突兀。但是这里确实需要一个“截面”,否则你会把反射表面下面的内容(那些你不希望被反射的东西)也渲染到表面,在这里我们同样用镜面所在的平面作为近截面来截去这些物体。但是这里没有使用“用户自定义截面”,而是通过改变视截体的近截面来达到同样的效果。这是因为并不能保证“用户自定义截面”在所有硬件上都能够正 确的实现,而视截体的“近截面”可以。并且就算在能实现“用户自定义截面”的硬件上,视截体的“近截面”会有更高的渲染效率。虽然拉远近截面会让深度缓存的精度有所下降,不过在大多数时候并不会对显示效果有明显的影响(毕竟我们只是在纹理上作渲染工作)。

 

       代码8-6最后一行把我们所用平面的实体和反射材质绑定到一起。

 

       另外一部分对渲染的处理工作发生在每一帧渲染的时候。也就是在场景内容渲染到纹理的时候。请参看代码8-7。

 

代码8-7:在渲染前隐藏平面,然后在渲染结束后让它可见

// render target events

    void preRenderTargetUpdate(const RenderTargetEvent& evt)

    {

        // Hide plane

        mPlaneEnt->setVisible(false);

 

    }

    void postRenderTargetUpdate(const RenderTargetEvent& evt)

    {

        // Show plane

        mPlaneEnt->setVisible(true);

    }
 

 

       在每次纹理被渲染的时候,我们希望它能完整的反射所有场景中存在的物体,但却不希望它连自己都反射了(就如同镜子不会反射镜子本身一样)。因此,我们不得不在每次渲染反射画面的时候“关闭”镜子,然后再渲染完整个纹理的之后再“开启”它。这就是为什么之前我们要用纹理渲染目标的addListener方法的原因。RenderToTextureApplication类实现了RenderTargetListener回调接口,纹理渲染目标会在每次渲染前后调用相应的回调函数。

 

       最后需要注意的是,为了让纹理渲染出来的结果和我们的视点相同,在运行的每一帧都要用更新反射摄像机的位置。

 

  // Make sure reflection camera is updated too

        mReflectCam->setOrientation(mCamera->getOrientation());

        mReflectCam->setPosition(mCamera->getPosition());
 

 

       如果用户更新了主摄像机的位置,我们的反射摄像机也会完全的跟随,这样就能保证反射的结果对应于我们当前的视点。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/chengxu0921/archive/2009/11/03/4761387.aspx

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/134250
推荐阅读
相关标签
  

闽ICP备14008679号