﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-清源游民的网络笔记本-随笔分类-OGRE</title><link>http://www.cppblog.com/yuanyajie/category/3706.html</link><description>记录所思所想，收藏所见所闻�?
</description><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 13:01:23 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 13:01:23 GMT</pubDate><ttl>60</ttl><item><title>Ogre3D嵌入Qt框架 之　小结</title><link>http://www.cppblog.com/yuanyajie/archive/2007/05/21/24528.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Mon, 21 May 2007 03:57:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/05/21/24528.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/24528.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/05/21/24528.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/24528.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/24528.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/yuanyajie/archive/2007/05/21/24528.html'>阅读全文</a><img src ="http://www.cppblog.com/yuanyajie/aggbug/24528.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-05-21 11:57 <a href="http://www.cppblog.com/yuanyajie/archive/2007/05/21/24528.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ogre3D嵌入Qt框架 之　秀图</title><link>http://www.cppblog.com/yuanyajie/archive/2007/05/21/24506.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Sun, 20 May 2007 17:26:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/05/21/24506.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/24506.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/05/21/24506.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/24506.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/24506.html</trackback:ping><description><![CDATA[<p>环境：WindowsXp Pro SP2, VS2003.NET, Ogre1.4.1(Eihort), Qt 4.2.2 开源版<br>参考：ShowMesh,MAGE,两款工具源码<br>先把图秀出来，有时间文字总结一下，难度虽然不高，但也折腾不少时间,也算近来学习Qt与Ogre的一个小结。<br><br><img height=480 alt="" src="http://www.cppblog.com/images/cppblog_com/yuanyajie/2865/r_ShowOgreEmbedInQt.jpg" width=612 border=0><br></p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/24506.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-05-21 01:26 <a href="http://www.cppblog.com/yuanyajie/archive/2007/05/21/24506.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》读书笔记 之 第十一章 动态阴影</title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/21/20302.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Wed, 21 Mar 2007 09:07:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/21/20302.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/20302.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/21/20302.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/20302.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/20302.html</trackback:ping><description><![CDATA[
		<p>清源游民　　gameogre@gmail.com<br /><br /><font color="#0000ff">阴影技术</font><br />Ogre支持两种主流的动态阴影技术，模板(stencil)阴影与纹理(texture)阴影,每一种都有两个变体：modulative 与additive。这四种技术完全兼容固定函数图形流水线，因此不需要可编程GPU支持。然而，可利用GPU程序进行加速。在场景中只有使用一种阴影技术，应该在场景渲染这前进行阴影技术相关设置（最好是在创建场景管理器之间）。通过调用SceneManager::setShadowTechnique()来设置技术，参数指定技术的具体类型。阴影技术缺省情况下被关闭。对于物体，投射与接收阴影可以在材质中控制，也可以控制物体自己对自己投射。由于模板阴影算法的本质特征，透明半透明的物体要么全部投射实心阴影要么根本不投影影，不可能得到半透明的阴影。而使用纹理阴影技术则可以。灯不能用来投射阴影。<br /><font color="#0000ff">模板阴影算法<br /></font>模板阴影算法原理上来讲比较简单：从光源的角度看一个可以投射阴影的物体，可以看到物体最外轮廓的<br />形状，把这个轮廓沿光的方向延伸，形成一个空间体，就是所谓的阴影锥(shadow volume),很显然，如果一<br />个物体被这个阴影锥包围，那么这个物体就处于前面那个物体所投射的阴影中了。既然阴影锥是通过延伸的方式来增长的，那么可以在延伸方向对锥体的延伸范围作出控制。在延伸方向上，有一端不能延伸，另外一端的延伸范围控制按照下面两个规则。第一，如果使用可编程图形硬件，顶点程序可以对顶点进行无限延伸。第二，如果使用固定函数图形流水线，延伸的范围由光线衰减设置(点光源和聚光灯）或使用<br />SceneManager::setShadowDirectionalLightExtrusionDistance()来控制。在不使用加速图形硬件的情况下，应该尽量避免物体离光源过近，这样会产生过于宽的阴影锥，导致不正确的阴影效果。根据算法原理，产生的阴影边界非常明显：一个像素要么在阴影中，要么不在。这带来的好处是，即使阴影锥的延伸距离很大，也不会影响精度。可以讲这种技术产生的阴影是一种“硬阴影"。纹理阴影技术可以”软化“阴影。使用模板阴影技术需要边列表(edge lists),标准的转换工具在产生二进制mesh文件时会创建边列表，如果没有，在程序中也可以用Mesh::buildEdgeList()来产生。因为有时候，我们会代码的方式来生成mesh,如果这时我们想使用模板阴影技术，那么就要确保产生出边列表数据。如果边列表数据不存在，那么ogre会认为你不希望这个物体投射阴影。<br /><font color="#0000ff">模板阴影优化<br /></font>Ogre能进行一些一般的优化。例如可使用硬件加速，可能通过光的方向与范围来检测它是否会对平截头体<br />(frustum)产生影响，从面避免了计算那些不必要的阴影几何体。ogre支持双面模板，stencil-wrapping扩展，<br />这些都能阻止不必要的原型安装(primitive setup)与驱动过载(driver overhead)。ogre使用相对廉价的Z-pass算法代替Z-Fail算法（当Z－Fail算法不必要时，假如相机处于一个阴影锥中，使用Z-pass算法会有问题，这种情况下应该使用Z-fail算法）。<br />阴影锥不受封闭几何的影响。在下图中，<br /><img src="http://www.cppblog.com/images/cppblog_com/yuanyajie/2865/r_shadowVolumeJPG.JPG" /><br />卫兵投射到地板上，投射的范围内有个封闭的箱子（此例中设定箱子不投射阴影）。根据现实世界的经验，箱子上会有卫兵投射的阴影，如图中所示。但光线经过箱子阻挡后应该不再前进，也就是说阴影锥经过箱子阻挡后不应该延伸了，于是箱子后面的地板上不应该再出现卫兵的阴影（真实世界中出现箱子的阴影，但是此例设定箱子不产生阴影)。图中的地板上出现了卫兵投射的阴影，这说明了阴影不会受到延伸方向上物体的影响。<br />在屏幕上看不到的物体也可以把阴影投影到可视的平截头体(view frustum)中。虽然看不到，但是这些物体<br />也必须得被渲染，渲染他们纯粹是为了得到产生阴影的相关数据。在不使用硬件加速的情况下，尽量避免物体离光源过近。<br /><font color="#0000ff">纹理阴影</font><br />纹理阴影算法的基本原理是：首先从光源的角度观察场景，把观察到结果渲染到一个纹理，纹理中只保存<br />深度值（深度缓冲中的值）。这样做的意义是，在纹理中保存了场景中的物体与光源之间的最短距离。然后从相机的角度进行正常渲染场景，计算每个像素与光源的距离,并与纹理对应的值进行比较，如果大于，那么说明它不是光线方向上离光源的最近的，会有阴影产生<font color="#008000">。/*可以有点疑惑，每个需要测试的像素如何与纹理中的像素一一对应呢？还是按照生成纹理图的原理，需要把测试顶点的位置坐标，转换到光源为视点的空间，也就是说从光源的角度，看看顶点应该在哪里。这样就可以一一对应比较了。当然这仅仅是为了比较的目的，真正渲染时顶点还是要先转换到视空间中(从相机角度看)*/</font>。<br />纹理阴影速度上要比模板阴影算法快，但因为阴影被渲染到纹理中，而纹理具有确定的解析度，因此当阴影被扩展，拉伸时，效果会较差，如产生锯齿边等。<br />因为使用了纹理内存，因此它的尺寸决定了纹理阴影数的上限。ogre中可以管理一帧中可以使用的阴影纹理数：SceneManager::setShadowTextureCount()。每个光源都需要一个纹理。假如指定的纹理数少于光源数，ogre采用”先来先服务“的原则分配纹理。假如不能增加纹理尺寸来提高视觉效果，最好减小投射阴影的距离。阴影不会突然终结，ogre会淡化纹理阴影的边缘阻止有阴影与无阴影之间剧烈过渡。可以控制淡化半径。<br /><font color="#0000ff">Modulative阴影混合<br /></font>正常场景渲染的颜色与阴影的颜色相乘来创建暗的、表示阴影的颜色。这种方法有从已经渲染的场景中”减去“光照影响的效果。阴影区域一律变暗，与进入阴影区的光线数无关。当有多个光源产生的阴影区<br />重叠时，阴影会非常暗，视觉效果很差。<br /><font color="#0000ff">Additive Shadow Masking<br /></font>Modulative的方法是通过影响阴影区实现的。而Additive方法是只对处于光照中的区域有影响，对阴影区没<br />有影响。这样阴影区会受到别的光源的影响而变得稍亮，而相互重叠的阴影区也不会更暗。<br />ogre会把一个通道分为三个通道.<br />Ambietn,应用环境光到场景中，在这个通道没有纹理被渲染。<br /> Diffuse and specular, 这个通道对每个灯都渲染一次，当前灯产生的阴影区域不受影响。其余的区域与场景进行混合。同样也不使用任何贴花纹理。<br />Decal。纹理被应用到前面累积的颜色上。</p>
		<p>
				<br /> </p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/20302.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-21 17:07 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/21/20302.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》读书笔记 之 第十章 布告板与粒子　第二部分 </title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/20/20227.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Tue, 20 Mar 2007 10:04:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/20/20227.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/20227.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/20/20227.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/20227.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/20227.html</trackback:ping><description><![CDATA[清源游民　　<a href="mailto:gameogre@gmail.com">gameogre@gmail.com</a><br /><br /><font color="#0000ff">粒子系统<br /></font>ogre中的粒子系统既可用脚本描述，也可用代码完成。用粒子脚本定义的粒子系统实际上是个模板，因此它定义的粒子系统可在程序中方便地重用。<br /><font color="#0000ff">粒子系统与场景</font><br />粒子系统会被挂到场景结点上，因此，结点的平移，缩放，旋转会关联到粒子系统，影响粒子反射的向。<br />粒子会被发射到世界空间中，这意味着当场景移动时，它会牵连到发射器，但已经发射出去的粒子不受影响。假如需要这些粒子受结点的影响，可以把粒子发射到本地空间(local space)中。粒子系统不能无限制的发射粒子，它有一个限额（quota)。一旦到达限额，粒子系统不会再发射粒子，直到已经存在的粒子消亡。缺省的限额是10。<br /><font color="#0000ff">粒子系统约束(Bounds)</font><br />粒子系统的动态特征意味着它们的绑定盒必须规律地被重新计算。缺省情况下，ogre会在10秒之后，停止<br />更新绑定盒。可以用ParticleSystem::setBoundsAutoUpdated(  bool  autoUpdate,  Real  stopIn = 0.0f )来改变缺省行为。stopIn这个参数告诉ogre多长时间后停止更新。假如有个粒子系统，可以知道它的增长不会超过某个范围，可以事先用ParticleSystem::setBounds()设置绑定盒尺寸。这样做效率很高，如果无法事先确定粒子系统的增长情况，可先用setBounds()设定一个初始尺寸，而用setBoundsAutoUpdated()让它在一段时间之后更新。<br /><font color="#0000ff">粒子系统更新<br /></font>对于粒子系统的更新，ogre采用适度启发式的策略。举例来说，当粒子系统不在视锥体之内，ogre仍会对粒子系统进行更新，这是考虑到不久之后，粒子系统有可能会重新进入视锥体之内。这就避免了这种情况下的视觉上的不和谐。但是出于性能上的考虑，当粒子系统退出视锥体一段时间之后，粒子确实会停止更新。这又会碰到上面的问题：被冻结的粒子系统突然重新进入视锥体的情况。ogre提供了一个所谓的<br />"fast-forward"机制，允许粒子系统在被冻结之后，快速超越当前状态。这种特性也可以用在刚创建的粒子系统，使它们状态提前一段时间，使用的方法是ParticleSystem::fastForward ();<br /><font color="#0000ff">粒子系统排序<br /></font>可以指示ogre根据与相机之间的距离，对粒子进行排序。虽然这会影响性能，但有时不得不用。在烟的<br />例子中，不使用排序的结果是，从烟的顶部依然清晰地看到火苗，而使用了排序之后火苗被烟雾模糊掉了。显然后者更加真实。<br /><font color="#0000ff">发射器<br /></font>点发射器从空间中单一点发射粒子。box发射器可以从规则四方体的任何位置发射粒子。cylinder定义了一个圆柱体。ellipsoid定义了一个椭球体。hollow elipsoid只是椭球体的外壳。ring只出平面圆环的边发射。被发射粒子的速度，方向也可以配置。粒子系统会被挂到场景结点上，因此发射器与父结点有一个相对的位置。粒子通常不会沿直线发射，它们在发射器方向的一个锥内发射，有一个angle参数来定义。假如希望沿直线发射，angle应该设为0,假如希望全方向发射，angle设为180, 90表示会在方向向量的半球内随机发射。<br />发射率用　粒子数/秒　表示。发射器可以按某个发射率发射，也可以使用一个范围内的随机值。粒子可<br />以有固定的生命期，也可以从一个范围随机指定。颜色也一样，固定值，随机值都可以。也可以在运动时，以插件的形式提供定制发射器，这是扩展ogre粒子系统最简单的方法。<br /><font color="#0000ff">影响器<br /></font>粒子一旦被发射到世界中，影响器可被用来影响粒子的运动路径与生命期。<br /><font color="#ff1493">LinearForce</font>:加一个力到粒子上，力是一个向量，有方向与大小（模）。<br /><font color="#ff1493">ColourFader</font>:用于改变粒子颜色。表示每秒减少的值，是一个绝对值。<br /><font color="#ff1493">ColorFader2</font>:与ColourFader相似，但是粒子生命到到达其生命期的某个阶段时，可以转换到另一个褪色函数。<br /><font color="#ff1493">ColourInterpolator</font>:与上面两个相似，但是它最多可以有6个阶段，分别对每个阶段的时间与颜色进行定义，然后不同阶段之间进行插值，这与关键帧动画的思想有点像。<br /><font color="#ff1493">Scaler</font>:用来缩放粒子尺寸，以时间为函数来定义一个缩放因子。<br /><font color="#ff1493">Rotator</font>:通过一组随机数量，或是随机速率来旋转粒子的纹理，这些被定义在某个范围之内。<br /><font color="#ff1493">colourImage</font>:从图像中攻取颜色,方向从左到右，适合一维纹理 。<br /><img src ="http://www.cppblog.com/yuanyajie/aggbug/20227.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-20 18:04 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/20/20227.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》读书笔记 之 第十章 布告板与粒子　第一部分 </title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/20/20216.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Tue, 20 Mar 2007 07:31:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/20/20216.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/20216.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/20/20216.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/20216.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/20216.html</trackback:ping><description><![CDATA[
		<p>清源游民　gameogre@gmail.com<br /><br /><font color="#0000ff">布告板(Billboard)</font><br />Ogre中的布告板简单的来讲就是场景中的一个四边形，但它的朝向与相机有关。通常布告板随着相机的视方向旋转以便与相机的视线方向对齐。把布告板放在场景的任何地方，它将会朝向相机。为了效率考虑，布告板与相机的视线方向对齐，而不是与从布告板到相机的向量对齐。大部分情况下两者没有明显的区别。如果想使用后一种的对齐形式，也可以办到，但在性能会有所降低。<br /><font color="#0000ff">布告板集(Billboard Sets)</font><br />布告板不能独立存在，他们也不能自我渲染。他们必须属于某个布告板集。布告板集可认为是一组布告板<br />的管理器，布告板集内的所有布告板有相同的尺寸，使用相同的材质。相同的尺寸，相同的纹理会带来计算与渲染效率的提升。可以在一个布告板集内单独改变某个公告板的尺寸，但这样做会导致性能下降ogre<br />认为一个布告板集是一个操作的单位，它们要么都不渲染，要么全部进行渲染，换句话说，它们以同样的<br />方式进行剔除处理，也可以对集合的个体进行单独剔除，但最好不要这么做，同样这也是出于效率的虑。在大范围的应用布告板集来模拟草的例子中，就有可能出现在布告板集内的许多布告板落在视角之外的情况，在这种情况下也许会想到用单独剔除的方式，但这样做同样不可避免地会影响性能。更好的做法是使用多个布告板集而不是在一个巨大的布告板集进行单独剔除。布告板集内的布告板是相对于布告板集attached到的场景结点进行定位的。既然，布告板集内的布告板使用相同的材质，那么它们会在同一batch进行渲染。<br /><font color="#0000ff">布告板创建<br /></font>布告板可以用与本布告板集的中心的偏移与尺寸（宽，高）来描述。它的方向是它到相机向量的函数。缺省，创建的布告板是所谓的point布告板。这种布告板总是完全地面对相机而且垂直。布告板的原点缺省位置是它的中心，可以在九个规范的位置范围内改变原点位置。第二种类型的布告板是oriented布告板，它即可以沿各自的Y轴旋转，也可沿共同的轴（通常是Y轴）旋转。第三种是perpendicular布告板，它与方向向量（布告板与相机之间的向量）垂直。这个方向向量可以是共享的向量（通常是Z轴），也可以是各自的Z轴。这种类型的布告板也需要一个上方向辅助定位。<br />point布告板相对于其他类型的布告板有一些优点。一般，ogre为每个布告板产生一个quad(四个顶点，每个<br />顶点都有位置，纹理坐标），并把生成的几何体送入GPU进行渲染。对于point 布告板，可以废除其中的三个，让GPU挑选，以及决定如何进行基于点绘制纹理属性的渲染。进行硬件点渲染有一些限制：只支持<br />point布告板，其中只限于以中心为原点的那一类。尺寸与外观在材质中定义，不在布告板集，尺寸是有限<br />的，不可能与软件创建的一样大。不支持单独的布告板旋转与改变大小，但可以对纹理单元旋转。<br /><font color="#0000ff">布告板池</font><br />创建布告板时需要告诉布告板集中布告板的数量。布告板被分别放在active与free列表中，这使得定位非常快。当创建的布告板的数量超过了布告板池的尺寸，池的尺寸会增加一倍。最好事先确定池的大小，避免在使用中使池的大小不合理地增长。<br /><font color="#0000ff">布告板纹理坐标</font><br />支持非全范围的纹理坐标分配。举个例子，假如你有个纹理，它包含几个子纹理。每个纹理都包含一个<br />英文字母。这时，你想创建几个公告板，每个公告板上显示不同的字母，当然它们都来自同一个纹理。<br />可以先创建一个包含纹理坐标的数组，然后把这个数组提供给布告板集。当利用布告板集创建布告板时，<br />可以给这个布告板一个存放纹理坐标的数组的索引。图片与代码如下：<br /><img src="http://www.cppblog.com/images/cppblog_com/yuanyajie/2865/r_abcd.JPG" /><br /><font color="#008000">// create a new billboard set with a pool of 4 billboards<br /></font>BillboardSet* bbset = sceneMgr-&gt;createBillboardSet("BBSet", 4);<br /><font color="#008000">// create a texture coordinate array to address the texture</font><br />FloatRect texCoordArray[] = {<br />FloatRect(0.0, 0.0, 0.5, 0.5), // address the "A"<br />FloatRect(0.5, 0.0, 1.0, 0.5), // address the "B"<br />FloatRect(0.0, 0.5, 0.5, 1.0), // address the "C"<br />FloatRect(0.5, 0.5, 1.0, 1.0), // address the "D"<br />};<br /><font color="#008000">// provide this array to the billboard set<br /></font>bbset-&gt;setTextureCoords(texCoordArray, 4);<br />// now create a billboard to display the "D"; this<br /><font color="#008000">// is the fourth entry in the array, index=3<br /></font>Billboard* bb = bbset-&gt;createBillboard(Vector3(0, 0, 0));<br />bb-&gt;setTexcoordIndex(3);<br />也可以直接对纹理坐标进行赋值<br />FloatRect coords(0.5, 0.5, 1.0, 1.0);<br />bb-&gt;setTexcoordRect(coords);<br />布告板使用的材质脚本与可以包括正常材质脚本中的所有东西，而且可以使用布告板与点纹理特有的一些<br />指令与参数。<br /><font color="#0000ff">布告板链与丝带跟踪（Ribbon Trails）<br /></font>布告板链一组前后相联结的一组布告板（可以联想“老鹰抓小鸡”的游戏中小鸡们的组织结构）。ogre<br />提供了一个ribbon-trail引用类，它使用了布告板链，可以追逐场景中的结点，并留下一条尾巴。布告板链可以分多个节，因此可以很好来模拟灯的效果　。布告板链的缺点是必须手动更新。可以为布告板链的每个节的尾部添加项，每个节有最大的长度，假如超过了那个长度，尾部项被移除，重新做为节的头。<br />ribbon trail有类似的行为，从尾部移除项作为头来增长，从头到尾颜色逐渐褪化。图片与代码如下：<br /><img src="http://www.cppblog.com/images/cppblog_com/yuanyajie/2865/r_Snap5.jpg" /><br /><br />void setupTrailLights(void)<br />{<br />NameValuePairList pairList;<br />pairList["numberOfChains"] = "2";<br />pairList["maxElements"] = "80";<br />RibbonTrail* trail = static_cast&lt;RibbonTrail*&gt;(<br />mSceneMgr-&gt;createMovableObject("1", "RibbonTrail", &amp;pairList));<br />trail-&gt;setMaterialName("Examples/LightRibbonTrail");<br />trail-&gt;setTrailLength(400);<br />mSceneMgr-&gt;getRootSceneNode()-&gt;<br />createChildSceneNode()-&gt;attachObject(trail);<br /><font color="#008000">// Create nodes for trail to follow</font><br />SceneNode* animNode = mSceneMgr-&gt;getRootSceneNode()-&gt;<br />createChildSceneNode();<br />animNode-&gt;setPosition(50,30,0);<br />Animation* anim = mSceneMgr-&gt;createAnimation("an1", 14);<br />anim-&gt;setInterpolationMode(Animation::IM_SPLINE);<br />NodeAnimationTrack* track = anim-&gt;createNodeTrack(1, animNode);<br />TransformKeyFrame* kf = track-&gt;createNodeKeyFrame(0);<br />kf-&gt;setTranslate(Vector3(50,30,0));<br />kf = track-&gt;createNodeKeyFrame(2);<br />kf-&gt;setTranslate(Vector3(100, -30, 0));<br />kf = track-&gt;createNodeKeyFrame(4);<br />kf-&gt;setTranslate(Vector3(120, -100, 150));<br />kf = track-&gt;createNodeKeyFrame(6);<br />kf-&gt;setTranslate(Vector3(30, -100, 50));<br />kf = track-&gt;createNodeKeyFrame(8);<br />kf-&gt;setTranslate(Vector3(-50, 30, -50));<br />kf = track-&gt;createNodeKeyFrame(10);<br />kf-&gt;setTranslate(Vector3(-150, -20, -100));<br />kf = track-&gt;createNodeKeyFrame(12);<br />kf-&gt;setTranslate(Vector3(-50, -30, 0));<br />kf = track-&gt;createNodeKeyFrame(14);<br />kf-&gt;setTranslate(Vector3(50,30,0));<br />AnimationState* animState = mSceneMgr-&gt;createAnimationState("an1");<br />animState-&gt;setEnabled(true);<br />mAnimStateList.push_back(animState);<br />trail-&gt;setInitialColour(0, 1.0, 0.8, 0);<br />trail-&gt;setColourChange(0, 0.5, 0.5, 0.5, 0.5);<br />trail-&gt;setInitialWidth(0, 5);<br />trail-&gt;addNode(animNode);<br /><font color="#008000">// Add light<br /></font>Light* l2 = mSceneMgr-&gt;createLight("l2");<br />l2-&gt;setDiffuseColour(trail-&gt;getInitialColour(0));<br />animNode-&gt;attachObject(l2);<br /><font color="#008000">// Add billboard</font><br />BillboardSet* bbs = mSceneMgr-&gt;createBillboardSet("bb", 1);<br />bbs-&gt;createBillboard(Vector3::ZERO, trail-&gt;getInitialColour(0));<br />bbs-&gt;setMaterialName("Examples/Flare");<br />animNode-&gt;attachObject(bbs);</p>
		<p>}<br />首先，RibbonTrail创建了两个链，每个最多包括80个元素，尾巴长400个世界单位。创建了一个结点animNoade。为这个结点创建了一个动画,使得这个结点可以根据关键帧的设计在场景中不断变化位置。并把一个RibbonTrail与这个结点联结起来，于是RibbonTrail可与animNode一起运动。又创建了一个灯，并联结到这个结点，灯随结点也一起运动，于是怪物头会有明暗变化。最后用一个布告板来形象表示刚创建的灯，因为灯在场景中是不可见的。因为灯被挂到animNode结点上，所以布告板bbs也挂到同样的结点上。当然别忘了使用了动画状态来推进动画。</p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/20216.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-20 15:31 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/20/20216.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第九章 动画 第一部分 </title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/16/19974.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Fri, 16 Mar 2007 09:33:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/16/19974.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19974.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/16/19974.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19974.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19974.html</trackback:ping><description><![CDATA[清源游民　<a href="mailto:gameogre@gmail.com">gameogre@gmail.com</a><br /><font color="#0000ff">概述</font><br />动画，总的来讲，在计算机发展的各个阶段，与艺术家们快速浏览一系列彼此稍微不同的图片从而产生运动的幻觉的行为没有什么不同。1872年，Eadweard Muybridge给奔跑的马拍了一组连续的照片，从而证明了马在奔跑时会四脚同时离地。这是一系列的图片流可以产生运动幻觉的最早的文档化的记录。<br />现在在Ogre中，不必小题大作地装配一些设备来创造这种运动幻觉了。只需要每帧少量地移动或变形场景中的数据，幻觉就产生了。它确实只是幻觉。ogre不跟踪对象的速度，加速度，或是角色的胳膊是在抬起<br />或是叉着腰。ogre逐帧来处理位置与朝向。ogre能为你做的是帮你重新播放这些动画。这些动画可以是用离线工具制作的，或是运行时产生的，或仅是为了实现相机漫游而填充了一系列位置的曲线。<br />场景的每帧都会被重画，两帧之间没有什么会被保存下来。ogre中的动画仅仅是根据关于任意变量（通常<br />是时间）的函数，来定位与定向角色。每一帧，在ogre动画系统的控制之下，场景中的实体与动画被稍稍<br />移动或产生变形，然后场景被重画。这种产生动画的方式，与华纳兄弟的动画团队做卡通动画没什么同。<br />一行画24个卡通兔，彼此稍微不同，然后在1秒钟的时间连续播放。<br /><font color="#0000ff">Ogre中的动画类型</font><br />根据控制物体的不同方式分为两种：基于关键帧的动画，控制器。<br />抽象地来看，ogre中的动画是相关tracks的集合。track是作为时间函数存储的一组数据值。一对“track值”与"时间点“，构成了关键帧(keyframe)，更好的一种说法是，在时间轴线上对对象全部或部分的位置，朝向，缩放，进行采样。根据动画的类型，ogre支持好几种关键帧。"关键帧”这个名称来源于手工制作动画的时代（像上面提到的制作卡通兔动画），首席艺术家会给他的下级提供一组关键的帧。这些帧给出了场景中角色的位置，然后下级艺术家们根据这些画出帧之间角色的位置。在ogre中，你就是首席艺术家，需要提供这些关键帧，ogre是你的下级，它帮你完成帧之间的过渡。<br />ogre中支持的track有下面这几种类型（一个track中的所有关键帧必须有一致的类型）:<br /><font color="#ff1493">NumericAnimaitonTrack(NumericKeyFrame):<br /></font>关键帧包含一个AnyNumeric类型的标量值。Any是ogre中定义的结构，和COM中的variant　类型一样，允许数据类型的多态化。AnyNumeric限定了可能的数据类型只能是数字的(实数，整数)。<br /><font color="#ff1493">NodeAnimationTrack(TransformKeyFrame):<br /></font>关键帧包含两个3维向量，一个四元数，分别表示结点的位置，缩放与朝向。<br /><font color="#ff1493">VertexAnimationTrack(VertexMorphKeyFrame,VertexPoseKeyFrame):<br /></font>关键帧包含或是引用在一个特定时间点上（在pose 动画中）顶点位置和混合权重(VertexPoseKeyFrame)。<br /><font color="#0000ff">动画状态<br /></font>程序与ogre中的动画主要的交互是通过动画状态来完成的(animation state)。在建模工具中，可以为骨骼或顶点网格沿时间轴线定义多个动画，导出时每个动画都可以定义一个名字，通过这个名字来定位Entity中同的动画。通过动画状态可以访问动画的许多属性：长度，当前位置,动画名，是否循环，有否有效，权重（用于混合动画）。权重根据混合动画的类型进行不同的处理。<br /><font color="#ff1493">混合权平均：</font><br />告诉ogre做这种混合时，所有权重之和为1。如果不是1，ogre会进行正规化处理，使得它们的总和为1。这种方式只对骨骼动画有效，它也是默认的混合方式。<br /><font color="#ff1493">混合权累积：</font><br />ogre只是简单地把所有引用权重的效果进行累加，不会再平衡。这种方式只对顶点动画有效（pose, morph),用到骨骼动画时也可以。<br />动画状态也是也给动画“加时间”推动它向前变化的地方。基本上总是给一个时间增量，意味着从上次调用到现在增长了的时间。本质上，加一个时间增量与直接设定时间位置没有什么不同。<br /><font color="#0000ff">骨骼动画<br /></font>骨骼动画是最常用的动画类型。网格(mesh)中的顶点被绑定到骨骼上，如同我们身体的肌肉绑定到骨上。<br />不同的是，计算机动画中的“骨头”不是真实存在的。它们用一些（无对应实体）变换来表示骨头的位置，朝向与缩放，经常是用矩阵来表示。骨骼动画的关键帧，仅是相对于骨骼恢复位置的偏移。它们被组合起来形成了沿着时间轴线上某一给定点的骨骼。<br />Ogre中的骨骼是有层次关系的，如脚骨与胫骨相连，胫骨又与膝盖骨相连。在这种层次关系下，除了root外，每个骨头都有父亲。但并不限于只有一个root,这种层次关系仅仅是用来传递转换(自上而下)。改变一根骨头会影响它所有孩子的位置。反向的运动ogre不支持：当一个骨头运动时，它不会影响父辈。<br /><font color="#0000ff">顶点绑定<br /></font>顶点被绑定到骨骼时会指定一个权重，权重说明了骨头运动对顶点的影响效果。典型的是把一个顶点绑<br />定到多个骨头，赋于不同的权重。ogre仅支持每顶点四个骨头，但每个骨头可以与任意多个顶点关联。<br /><font color="#0000ff">顶点动画<br /></font>与通过计算动画骨骼，再根据骨骼位置计算顶点位置的动画方式不同。顶点动画直接对顶点进行动画操作。它是资源密集型的解决方案，对于每个动画位置都要转送完整的顶点数据的拷贝。有时这种方式是维一的办法，例如实现逼真的面部表情动画。<br />顶点动画在动画track这个层次上被管理、操纵。这意味着我们可以对角色的头，脸部分使用复杂的pose动画，而角色的剩余部分使用相对简单的morph动画。但是不能对相同的顶点使用不同的动画类型。顶点动画在引用一组顶点集时，要么全部引用，要么一个也不引用。这意味着，在网格级别上来看，所有的共享几何(shared geometry)构成了顶点动画的顶点数据。在子网格级别上来看，所有子网格的顶点构成了顶点动画的顶点数据。举例来讲，一个子网格的某些顶点参与morph动画，而剩余顶点参与pose动画，这种情况是不允许的。<br /><font color="#ff1493">变形动画(Morph Animation)<br /></font>变形动画是两种顶点动画技术中最简单最直观的一种。实际的顶点位置做为"快照"被保存。这与前面说到<br />的卡通兔动画的过程是一样的。这种方法比较消耗资源，但是计算效率最高。关键之间数据通过插值得。<br />主要的缺点是不能混合多个变形动画，因为他们保存的是顶点的绝对位置。当然，如果有两个动画，它们<br />影响的顶点没有交集，那么确实可以对这两个动画进行混合。<br /><font color="#0000ff"><font color="#ff1493">姿势动画(Pose Animation)</font><br /></font>模型的各种姿势被保存在动画tracks中。这些姿势可以被混合来创建更复杂的动画。顶点的位置是相对于<br />复原位置的偏移量，而不是顶点的绝对位置。而且只有变化的数据才被保存。因此，它不仅更灵活，而且<br />对资源使用也更高效。<br />pose动画的关键帧引用一个或多个pose tracks，每个引用对姿势有一个影响权重。权重决定了当pose被混合时每个顶点偏移对最终的顶点位置产生多大的影响。不必在每一帧都引用一个pose。在实践中，pose混合会碰到一些限制：每个附加的pose需要更多的处理时间。<br /><font color="#0000ff">混合动画</font><br />不能混合pose与morph动画到一起，也不能混合多个morph动画。<br />当混合骨骼动画与顶点动画时，ogre将首先计算/混合顶点动画，然后应用骨骼变形到混合顶点上。<br />规范的pose与骨骼动画混合的程序,会混合全身体的骨骼动画与复杂的面部表情。例如，可以对角色的面部顶点使用pose动画，而角色的剩余部分(包括头)使用相对简单的骨骼动画。<br />混合两个骨骼动画对于动画之间的切换是最有用的。例如角色可能在循环地执行"跑步"这个动画，一会儿<br />他可能要停下来（执行"idle"动画），那么这时需要对两个动画进行混合。<br />Morph与骨骼动画的混合，对于给骨骼动画的角色增加"外皮"网格变形是很合适的。例如,将一个衣服动画与角色实际的骨骼运动动画混合，这样就避免了对衣服进行实时模拟的高额代价。<br /><font color="#0000ff">硬件vs软件<br /></font>应用硬件加速时最应该记住的是：硬件动画网格数据不能被CPU使用。这相当重要！假如你依赖网格数据<br />进行别的计算(体积阴影计算，物理模拟），一旦顶点变形计算被移到GPU中，顶点就永远消失了，不在代码中使用了，假如需要变形之后的顶点数据，那么你还得用CPU进行与GPU同样的计算！这确实也可以做到,告诉ogre做吧：　Entity::addSoftwareAnimationRequest()。<br />硬件加速的骨骼动画与顶点动画混合，会在顶点程序中执行混合。假如你刚才还没有注意到上面曾经提到<br />过的执行顺序的话，现在又有机会让你意识到这点：先顶点，然后骨骼。这同样也意味着，所有的动画技术都应该是基于硬件加速的，不能让硬件加速的骨骼动画与基于软件的顶点动画混合。<br />使用GPU加速<font color="#ff1493">骨骼动画</font>时，应该考虑到：骨骼动画算法的本质上要求，在计算每个顶点时，骨架中所有骨头的数据必须都被提供。老旧的硬件仅仅支持24　bones或更少的skinning通道。这时应把mesh分为几段，在多个通道中skin它们。ogre只会把submesh引用到的bones发送到skinning shader,而不是骨骼中所有的bones,这使得多个skinnig pass成为可能。<br />在CPU中对<font color="#ff1493">morph动画</font>顶点进行插值的主要优点是利用了GPU并行计算的本质。morph计算起来也不复杂，<br />主要的输入是两个顶点位置与一个插值因子，顶点程序产生插值后的顶点位置做为输出。<br /><font color="#ff1493">pose动画</font>与morph类似，而且有与骨骼动画类似的限制：它提供给程序的pose数目如何进行传递。<br /><font color="#0000ff">标签点<br /></font>标签本身不是动画的一部分，但它们常被用于联结任意对象（例如武器）到存在的动画模型上。标签点<br />的概念比较简单：它是骨架中一块特殊的骨头，它能在运行时，控制绑定对象的位置与朝向。不必事先<br />创建标签点，可以在运动期attched一个可移动对象到骨架中一个命名的骨头上。Entity有这样一个方法：<br />attachObjectToBone();一旦物体被绑到骨头上，它就会随着标签点移动。需要知道的是，对象并不是真正<br />地被attched到标签点上。它被attched到用那个骨骼的Entity上。<br /><font color="#0000ff">动画与控制器</font><br />两者都是基于一个一维的变量来控制对象的状态，把变量输入一个函数产生输出。对于动画来说，输入变量是时间，而对于控制器来说，输入变量是任何你想要的东西。<br /><font color="#ff1493">动画的特点：</font><br />通过插值函数计算给定时间点上track值来产生输出，从而改变顶点位置。<br />动画被认为是个封闭的系统：你设置输入值，ogre 使用它来更新相关对象的属性。<br />插值函数较为固定：要么线值，要么三次样条插值。<br />动画有ogre提供的许多工具的支持。<br /><font color="#ff1493">控制器的特点</font>：<br />对于输出的计算更为灵活，工作函数需要提供，因此有更多选择。<br />控制器可以形成一个链，一个输出可作为另一个输入。<br />控制器自己不移动任何东西，对于输出可以不做任何事情。ogre用控制器来驱动纹理动画。<br />控制器自动逐帧更新，然而必须手工添加代码使每帧的动画向前变化。<img src ="http://www.cppblog.com/yuanyajie/aggbug/19974.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-16 17:33 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/16/19974.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第八章 渲染对象</title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/15/19910.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Thu, 15 Mar 2007 09:25:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/15/19910.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19910.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/15/19910.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19910.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19910.html</trackback:ping><description><![CDATA[
		<p>清源游民　gameogre@gmail.com<br /><br /><font color="#0000ff">OGRE渲染对象</font><br />Ogre中的render target 只是共享AGP内存或显存的某个区域的抽象，这个区域中保存着全部或部分场景2D渲染结果。最普通的render target是主渲染窗口，这是应用程序的主窗口。使用这个render target不需要做太多另外的努力，ogre可以帮我们创建它。还可以把场景中的全部或部分（甚至是场景中不可见的部分）渲染到一个纹理，这个纹理可以被场景中的其他多边形使用。目标硬件缓冲在ogre中抽象为render target,它的物理显示可以为主渲染窗口，也可以是副窗口，也可以是非可视的：纹理。<br />渲染对象也是事件源，假如程序注册了这事件，ogre会在pre- 和 postrender时通知程序，这给程序改变设置，做出响应的机会。甚至在视口(viewport)级别上pre-,post- 渲染时也有上述通知机制。ogre提供了计算渲染状态信息的功能,如多长时间渲染一帧，渲染对象上有多少三角形等。<br /><font color="#0000ff">渲染窗口</font><br />窗口是由渲染系统的具体实现创建与维护的（D3D9下是个标准的Win32 Window)。Ogre允许对渲染窗口进行很少的配置，限于尺寸，标题栏文字等。假如希望开发的程序有菜单，工具栏等，把ogre的渲染输出到<br />窗口的客户区，这是可能的。ogre可以提供你系统相关的窗口句柄给渲染窗口，也允许你提供句柄给父窗口。第一个创建的ogre渲染窗口称为主窗口。另外创建的是副窗口。窗口不像主窗口那么重要。假如在程序中有三个窗口，那么为了正确的进行资源清理，必须在销毁主窗口前把另外两个副窗口销毁。<br /><font color="#0000ff">视口<br /></font>渲染窗口包含一个或多个视口。视口是一个长方形区域，场景管理器把从一个相机中看到的场景可见内容<br />的透视图渲染到这个区域中。视口创建时会引用一个相机，但这不是视口的静态属性，可以随时改变用于<br />渲染视口的相机。每个视口拥有一个z序数，z序高的位于Z序低之上。z序0，总是被一个能覆盖整个渲染对象的视口所拥有。缺省，ogre会清理视口的颜色与深度缓冲。然而，可以关闭这些缓冲清理。视口是渲染对象（也就是特定的渲染系统，如OpenGL)与相机（也就是特定场景管理器与它的内容）之间的唯一交互点。视口不必占用整个渲染对象的表面。3D渲染相机不是真正的相机，所有的几何LoD计算是以相机的位置算的，因此不能简单的改变相机的焦点属性来达到“更近”的渲染效果。<br /><font color="#0000ff">渲染到纹理<br /></font>使用步骤是：创建一个纹理渲染对象，配置它的渲染属性，加纹理到渲染对象列表，设置纹理到被使用的材质。纹理对象先于其他渲染对象类型更新，这就保证了使用了渲染纹理的对象正确地被渲染。渲染纹理可以像其他普通纹理一样被处理。对于那些不需要每帧都更新的渲染纹理，可以关闭自动逐帧更新而采用手动更新。从底层看，纹理对象就是一块硬件缓冲。为了性能考虑，认为它们是只写与静态的。渲染到纹理会渲染场景中的几何，需要一些时间执行，会降低应用程序帧率。但是很多有用的技术现在离不开渲染到纹理的使用。实时阴影，实时反射等。ogre支持渲染到多个纹理，唯一的限制是它们就具有相同的寸。<br /><font color="#0000ff">渲染对象类<br /></font>RenderTarget是RenderWindow,MultiRenderTarget,与RenderTexture的基类。<br />RenderWindow通过子类化来实现：D3D9RenderWindow,GLXWindow等。在windows操作系统中，由于可以使用Direct3D 9或是OpenGL,于是可以分别使用D3D9RenderWindow，Win32Window。<br />RenderSystem::createRenderWindow()来创建窗口。<br />virtual RenderWindow* Ogre::RenderSystem::createRenderWindow  (  const String &amp;  name,  <br />  unsigned int  width,  <br />  unsigned int  height,  <br />  bool  fullScreen,  <br />  const NameValuePairList *  miscParams = 0 <br /> )  <br />通过最后一个参数，可以设置窗口的一些属性。<br />将渲染窗口嵌入外部窗口的代码<br />NameValuePairList params; <font color="#008000">// is just a typedef std::map&lt;std::string, std::string&gt;<br /></font><font color="#008000">// set external window handle -- assume that you have<br />// already created a window to embed the Ogre render window, and its handle is<br />// stored in an integer variable called "mParent"<br /></font>params["externalWindowHandle"] = StringConverter::toString(mParent);<br /><font color="#008000">// window can be resized later to fit within parent client area if needed<br /></font>RenderWindow* window = createRenderWindow("MyWindow", 800, 600, false, &amp;params);<br /><font color="#0000ff">渲染到纹理Demo</font><br />demo在原点创建了一个倾斜的平面，设置相机，把场景（场景由一个魔鬼脑袋与几个环面纽结组成）<br />相对于平面的倒影渲染到纹理中。渲染纹理与平面已经应用的静态纹理混合，这样就实现了反射效果。<br /><font color="#ff1493">创建渲染纹理:<br /></font>TexturePtr texture = TextureManager::getSingleton().createManual( "RttTex", <br />                               ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, <br />                              512, 512, 0, PF_R8G8B8, TU_RENDERTARGET );<br /><font color="#ff1493">创建相机与视口用于渲染到纹理:</font><br />             mReflectCam = mSceneMgr-&gt;createCamera("ReflectCam");<br />            mReflectCam-&gt;setNearClipDistance(mCamera-&gt;getNearClipDistance());<br />            mReflectCam-&gt;setFarClipDistance(mCamera-&gt;getFarClipDistance());<br />            mReflectCam-&gt;setAspectRatio(<br />                (Real)mWindow-&gt;getViewport(0)-&gt;getActualWidth() / <br />                (Real)mWindow-&gt;getViewport(0)-&gt;getActualHeight());<br />            Viewport *v = rttTex-&gt;addViewport( mReflectCam );<br />            v-&gt;setClearEveryFrame( true );<br />            v-&gt;setBackgroundColour( ColourValue::Black );<br /><font color="#ff1493">创建使用渲染纹理的材质</font><font color="#ff1493">：</font><br />MaterialPtr mat = MaterialManager::getSingleton().create("RttMat",<br />                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);<br />            TextureUnitState* t = mat-&gt;getTechnique(0)-&gt;getPass(0)-&gt;createTextureUnitState("RustedMetal.jpg");<br />            t = mat-&gt;getTechnique(0)-&gt;getPass(0)-&gt;createTextureUnitState("RttTex");<br />           <font color="#008000"> // Blend with base texture<br /></font>            t-&gt;setColourOperationEx(LBX_BLEND_MANUAL, LBS_TEXTURE, LBS_CURRENT, ColourValue::White, <br />                ColourValue::White, 0.25);<br />            t-&gt;setTextureAddressingMode(TextureUnitState::TAM_CLAMP);<br />            t-&gt;setProjectiveTexturing(true, mReflectCam);<br />            rttTex-&gt;addListener(this);<br />材质名为RttMat,包含一个技术，后者有一个通道。通道有两个纹理单元,一个为静态纹理(RustedMetal.jpg)<br />,另一个纹理单元为渲染纹理,两个纹理按比例混合。设置了合适的纹理寻址模式，开启了透视纹理支持。<br />并为渲染纹理（它是渲染对象）注册了侦听器。<br /><font color="#ff1493">相机倒置使用材质:</font><br />            <font color="#008000">// set up linked reflection<br /></font>            mReflectCam-&gt;enableReflection(mPlane);<br />            <font color="#008000">// Also clip</font><br />            mReflectCam-&gt;enableCustomNearClipPlane(mPlane);<br />        }<br />          <font color="#008000"> // Give the plane a texture</font><br />           mPlaneEnt-&gt;setMaterialName("RttMat");<br />相机这样设置后，渲染出的将是场景的倒影，这是以指定平面为参照的。定制最近裁剪平面的作用是：<br />那些低于反射面的对象将不会再被渲染。渲染纹理时，并不想把平面也渲染进去，可以在上边已经注册<br /><font color="#ff1493">侦听器做点手脚</font>：<br />void preRenderTargetUpdate(const RenderTargetEvent&amp; evt)<br />    {<br />       <font color="#008000"> // Hide plane <br /></font>        mPlaneEnt-&gt;setVisible(false);</p>
		<p>    }<br />    void postRenderTargetUpdate(const RenderTargetEvent&amp; evt)<br />    {<br />        <font color="#008000">// Show plane <br /></font>        mPlaneEnt-&gt;setVisible(true);<br />    }<br />最后要提的是，在每一帧，都要使两个相机的位置，朝向保持一致:<br /><font color="#ff1493">frameStarted:<br /></font> mReflectCam-&gt;setOrientation(mCamera-&gt;getOrientation());<br />  mReflectCam-&gt;setPosition(mCamera-&gt;getPosition());</p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/19910.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-15 17:25 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/15/19910.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第七章 资源管理  第一部分</title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/14/19827.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Wed, 14 Mar 2007 09:09:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/14/19827.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19827.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/14/19827.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19827.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19827.html</trackback:ping><description><![CDATA[
		<p>清源游民　　gameogre@gmail.com<br /><br /><font color="#0000ff">资源组</font><br />命名组可以作为一个整体加载与卸载。在加载，卸载，初始化时把把组中的所有资源作为一个执行单位来<br />看待，而不是逐个进行处理。资源组管理纯粹是了为了管理上的方便，是否使用组的方式与性能无关。假<br />如向资源组管理器中加入了资源位置而没有指定组名，那么这些资源位置被放入"General"组中。<br /><font color="#0000ff">资源组与世界几何<br /></font>缺省情况下，ogre把加载的世界几何放入"General"组。也可以覆盖(override)这种方式，使得对世界几何的管理像其他资源的管理方式一样。统一的场景管理器可以提供关于装载世界总步骤的线索，这样就可以在关卡加载时，提供精确的以进度条显示的反馈信息。<br /><font color="#0000ff">资源位置(location)</font><br />资源位置是ogre去查找资源进行索引的地方。索引指的是在某个位置的所有资源通过它们的名字被映射，这样可以方便进行更快的查找资源。可以在程序的任何时候添加或删除资源位置,不必事先对所以可能用到的进行定义。资源位置在ogre中实际上是个archive,它的意思就是“文件的集合”。磁盘上的文件系统是<br />archive的一种类型。另外一种是zip archive。可以自定义archive格式。这通过改写archive类实现来完成,必须支持对命名的leaf文件进行枚举操作，必须支持通配符，支持结点递归，给ogre提供一个流访问archive中文件的数据。ogre中的archive是只读的。ogre资源管理器利用archive枚举特性来索引archive的内容，当ogre对archive进行索引时，不会实际加载任何资源。<br /><font color="#0000ff">资源生命周期</font><br />资源有四种状态,各状态之间的转换关系如下图：<br /><img src="http://www.cppblog.com/images/cppblog_com/yuanyajie/2865/r_Resource.JPG" /><br /><font color="#ff1493">Undefined:</font>这是程序开始时，所有资源的缺省状态。除非它们被声明，ogre对程序用到的资源一无所知，手工调用代码 ResourceGroupManager::declareResource()或在脚本中被解析之后，资源的状态变为Declared<br /><font color="#ff1493">Declared:</font>声明就是告诉ogre想要加载某些资源。ResourceGroupManager::declareResource()总是有效的，包括在渲染系统初始之前，这与ResourceManager::create()不同，因为后者依赖于渲染系统。<br /><font color="#ff1493">Unloaded</font>:通过调用ResourceGroupManager::initialiseAllResourceGroup(), ResourceGroupManager::<br />initialiseResourceGroup(),或Root::initialise()(它会初始化在此调用之前所有声明的资源)，资源状态进入到Unloaded,资源会占用一点内存来保存它的定义的实例，但是资源本身还没有加载到内存。从另一角度看(从Loaded到Unloaded),引起状态变化的调用有：ResourceManager::unload(),ResourceManager::unloadAll(), ResourceManager::unloadAllUnreferencedResources(),ResourceGroupManager::unloadResourceGroup(), or Resource::unload().所有这些调用仍会保存资源实例，但真正的资源数据会从内存中卸载。<br /><font color="#ff1493">Loaded:</font> 这种状态下，所有数据都变得有效。与此状态有关的调用有Resource::load(), Resource::reload(),<br />ResourceManager::load(), ResourceManager::reload(), ResourceManager::reloadAll(),<br />ResourceManager::reloadAllUnreferencedResources(), and ResourceGroupManager::<br />loadResourceGroup().<br /><font color="#0000ff">逻辑资源管理<br /></font>资源以命名组的形式组织，每组可以包括任何类型的资源，每种资源都有自己的资源管理器，后者负责加载与卸载特定类型的资源。ogre对它的资源没有实现特定的内存管理方案，如果你需要对某种资源实“最近最少使用算法”方案来进行管理，那么需要自己的代码来实现。值的一提的是，现在的大多数显卡驱动，对于大多数重要的资源已经实现了这种LRU算法管理。<br /><font color="#0000ff">资源加载<br /></font>假如没有预加载，当资源被访问时会进行加载。实际的加载，卸载是资源自己的责任。<br /><font color="#0000ff">手动加载资源</font><br />资源管理层不负责实际的加载与卸载。通常，不必担心资源是否存在于易失性媒介。然而，手工方式时需要考虑。手工资源加载器必须在任何时候准备好重新加载资源。假如某个资源是通过程序生成的，那么手工资源加载器必须内存中缓冲这些资源，或者是当资源管理加载时重新创建它。ogre认为手工加载与自动加载没有区别。<br /><font color="#0000ff">后台资源管理<br /></font>缺省，ogre不是线程安全的。假如在OgreConfig.h中 #define OGRE_THREAD_SUPPORT 1 ,那么资源管理<br />代码的线程同步功能变得有效，我们就可以在包含Root实例的线程之外，开启新的线程对资源管理类与方法进行操作,从而实现灵活的资源加载方案。　<br /><font color="#0000ff">非后台资源管理<br /></font>Ogre中大量使用了Observer模式,资源管理系统也不例外。ResourceGroupListene 回调接口包含了几个方法<br />允许对资源加载过程进行细粒度的监听。<br /><font color="#0000ff">资源卸载</font><br />资源被加载后总存在于内存中，直到被应用程序强行卸载(通过资源组管理器或是被资源直接释放)。资源管理组管理会把组中所有的资源都卸载掉。在资源被引用时不能强行卸载。<br /><font color="#0000ff">Resource Locations<br /></font><font color="#008000">// 配置文件方式<br /></font>ConfigFile cf;<br />cf.load("resources.cfg");<br /><font color="#008000">// Go through all sections &amp; settings in the file<br /></font>ConfigFile::SectionIterator seci = cf.getSectionIterator();<br />String secName, typeName, archName;<br />while (seci.hasMoreElements())<br />{<br />secName = seci.peekNextKey();<br />ConfigFile::SettingsMultiMap *settings = seci.getNext();<br />ConfigFile::SettingsMultiMap::iterator i;<br />for (i = settings-&gt;begin(); i != settings-&gt;end(); ++i)<br />{<br />typeName = i-&gt;first;<br />archName = i-&gt;second;<br />ResourceGroupManager::getSingleton().addResourceLocation(<br />archName, typeName, secName);<br />}<br />}<br /><font color="#008000">//硬编码方式<br /></font>ResourceGroupManager *rgm = ResourceGroupManager::getSingletonPtr();<br />rgm-&gt;addResourceLocation("../../media/packs/OgreCore.zip", "Zip", "Bootstrap");<br />rgm-&gt;addResourceLocation("../../media", "FileSystem", "General");<br />rgm-&gt;addResourceLocation("../../media/fonts", "FileSystem", "General");</p>
		<p>
				<font color="#0000ff">初始化</font>
				<br />在初始化之前，必须创建至少一个渲染窗口。因为在分析脚本时可能会创建GPU资源，而后者需要渲染<br />上下文。<br /><font color="#008000">// initialize all of the previously defined resource groups</font><br />ResourceGroupManager::getSingleton().initialiseAllResourceGroups();<br /><font color="#008000">// or, alternately, initialize the defined resource groups one at a time<br /></font>ResourceGroupManager::getSingleton().initialiseResourceGroup("General");<br />ResourceGroupManager::getSingleton().initialiseResourceGroup("Bootstrap");<br /><font color="#0000ff">卸载</font><br />可以在任何时候卸载资源（以组或单个的方式）,正在使用的资源不会被卸载。<br /><font color="#0000ff">以组的方式卸载</font><br />ResourceGroupManager::getSingleton().unloadResourceGroup("Bootstrap", true);<br />ResourceGroupManager::getSingleton().<br />unloadUnreferencedResourcesInGroup("Bootstrap", true);<br />true表示只卸载资源数据，不删除资源实例，它可以被reloaded。有些资源在创建时被标为<br />"nonreloadable",这种类型的资源不能使用上述方法卸载。<br /><font color="#0000ff">清理或销毁资源组</font><br />清理仅是卸载资源与分离资源索引，销毁不仅做清理的工作，还包括从资源组中把自己移除。<br />ResourceGroupManager::geSingleton().clearResourceGroup("Bootstrap");<br />ResourceGroupManager::geSingleton().destroyResourceGroup("Bootstrap");<br /><font color="#0000ff">以个体方式卸载</font><br /><font color="#008000">// assume that pEntity is a valid pointer to an instance of Entity</font><br />MeshPtr meshPtr = pEntity-&gt;getMesh();<br />meshPtr-&gt;unload();<br /><font color="#0000ff">加载/重载资源组</font><br />ResourceGroupManager::getSingleton().loadResourceGroup("Bootstrap", false, true)<br />二个布尔变量不同资源类型资源加载开关，一针对"Normal"资源，二针对"World geometry"<br /><font color="#0000ff">资源组加载通知<br /><font color="#000000"><font color="#0000ff">class</font> LoadingProgressListener : <font color="#0000ff">public</font> ResourceGroupListener<br /></font>{<br />   public: <br />       </font><font color="#000000"><font color="#008000"> // fired when a group begins parsing scripts</font><br />                void resourceGroupScriptingStarted(const String&amp; groupName,<br />                                                                        size_t scriptCount) {}<br />       <font color="#008000">// fired when a script is about to be parsed<br /></font>               void scriptParseStarted(const String&amp; scriptName) {}<br />       <font color="#008000">// fired when the script has been parsed<br /></font>               void scriptParseEnded() {}<br />       <font color="#008000">// fired when all scripts in the group have been parsed</font><br />              void resourceGroupScriptingEnded(const String&amp; groupName) {}<br />      <font color="#008000">//还有一些接口<br /></font>}<br /><font color="#008000">//实现之后，进行注册<br /></font>LoadingProgressListener listener(m_progressMeter);<br />ResourceGroupManager::getSingleton().addResourceGroupListener(&amp;listener);</font></p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/19827.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-14 17:09 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/14/19827.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第六章 材质　材质复制 </title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/13/19754.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Tue, 13 Mar 2007 07:57:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/13/19754.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19754.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/13/19754.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19754.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19754.html</trackback:ping><description><![CDATA[
		<p>清源游民　gameogre@gmail.com<br /><br /><font color="#0000ff">材质复制</font><br />如果新的脚本只是对某个已经存在的脚本进行小部分的变化，那么可进行从旧脚本复制，而不是C＆P。新材质可以修改特定technique,pass,texture,或是添加新项。<br />格式: material &lt;NewUniqueChildName&gt; : &lt;ReferanceParentMaterial&gt;<br />当材质脚本被加载到ogre中，这种继承关系不再维系，假如父材质在运行时被修改，不会影响到子材质。如果在一个technique中有5个pass,而我们只想修改第5个pass,我们可以用pass指定或是它的索引(从0计）<br />meterial test2: test1<br />{<br />  technique 0<br />    {<br />      pass 4<br />        {<br />          ambient 0.5 0.7 0.3 1.0<br />        }<br />    }<br />}<br />加入一个新的technique或pass到material中，可以通过赋于它们新的名称来实现，新名称必须在父材质中没有出现过。指定新索引也一样。新technique或pass会被加载到父材质相应technique或pass末尾.<br />material BumpMap2 : BumpMap1<br />{<br />  technique ati8500<br />  {<br />    pass 0<br />    {<br />      texture_unit NormalMap<br />      {<br />        texture BumpyMetalNM.png<br />      }<br />    }<br />  }<br />}<br />在上面的例子中，如果texture_unit的名称NormalMap在父材质中指定过，那么现在的行为表示override,如果它是一个新的名字，那么表示在pass的最后新加一个texture unit。　</p>
		<p>
				<font color="#0000ff">纹理别名</font>
				<br />
				<br />在源材质被clone时，每个texture unit可以被赋于一个Texture alias(别名）。可以用这个别名来指定使用什么纹理。格式： texture_alias &lt;name&gt; 缺省： texutre_unit &lt;name&gt;( 纹理单元的名字)<br />texture_unit DiffuseTex<br />{<br />  texture diffuse.jpg<br />}<br />在这种情况下，texture_alias为DiffuseTex.<br />material TSNormalSpecMapping<br />{ <br />  <font color="#0000ff">technique </font><font color="#000000">GLSL<br /></font>  { <br />    pass <br />    { <br />      texture_unit <font color="#ff1493">NormalMap<br /></font>      {<br />        texture defaultNM.png<br />        tex_coord_set 0<br />        filtering trilinear<br />      }</p>
		<p>       texture_unit <font color="#ff1493">DiffuseMap</font><br />      {<br />        texture defaultDiff.png<br />        filtering trilinear<br />        tex_coord_set 1<br />      }</p>
		<p>        texture_unit <font color="#ff1493">SpecMap</font><br />      {<br />        texture defaultSpec.png<br />        filtering trilinear<br />        tex_coord_set 2<br />      }<br />    } <br />  } </p>
		<p> <font color="#0000ff"> technique </font><font color="#000000">HLSL_DX9</font><br />  { <br />    pass <br />    { <br />        texture_unit <br />      {<br />        texture_alias <font color="#ff1493">NormalMap</font><br />        texture defaultNM.png<br />        tex_coord_set 0<br />        filtering trilinear<br />      }</p>
		<p>      texture_unit <br />      {<br />        texture_alias <font color="#ff1493">DiffuseMap</font><br />        texture defaultDiff.png<br />        filtering trilinear<br />        tex_coord_set 1<br />      }</p>
		<p>      texture_unit<br />      {<br />        texture_alias <font color="#ff1493">SpecMap</font><br />        texture defaultSpec.png<br />        filtering trilinear<br />        tex_coord_set 2<br />      }<br />    } <br />  } <br />}<br />例子中有两个技术，都使用相同的纹理,第一个技术使用缺省的方式定义了纹理别名，第二个技术显式地指定纹理别名。两者都有相对应的同样的纹理别名。如果想定义一个材质只是想使用不同的纹理,那么copy父材质时可以使用set_texture_alias来重新指定新纹理。<br />material fxTest : TSNormalSpecMapping<br />{<br />  set_texture_alias <font color="#ff1493">NormalMap</font> fxTestNMap.png<br />  set_texture_alias <font color="#ff1493">DiffuseMap</font> fxTestDiff.png<br />  set_texture_alias <font color="#ff1493">SpecMap</font> fxTestMap.png<br />}<br />上面代码就对拥有指定别名的texture unit所使用的纹理图片进行了重新指定。<br /></p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/19754.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-13 15:57 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/13/19754.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第六章 材质　概念</title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/13/19703.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Tue, 13 Mar 2007 03:31:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/13/19703.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19703.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/13/19703.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19703.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19703.html</trackback:ping><description><![CDATA[
		<font color="#0000ff">基本对象着色<br /></font>材质，简单的来讲就是定义了被赋于此材质的对象如何反射光。ogre中的光照采用局部光照模型，这意味着，对计算有影响的因素有：光照的角度与光的颜色，相机的视角，对象的材质。ogre支持四种类型用来描述材质的颜色,表述了光照对它的影响：环境光，漫反射，发散，镜面反射。环境光是对全局光照的近似，漫反射是指当物体被光照射后在物体各方向上反射的光的颜色。发散指物体本身自发光的颜色。镜面反射，指的是在某个视角看到的被光反射出的“高光”。镜面高光有两个参数可以控power,shininess.power用来控制“加亮点”的尺寸(影响的范围越大)。而shininess值越大的表面，高光越容易聚集。<br /><font color="#0000ff">纹理映射<br /></font>通过纹理坐标，用一张2D图片给3D对象着色的技术。<br /><font color="#0000ff">可编程着色</font><br />通过写高级或低级的顶点程序，片段程序代替固定管线的功能。支持可编程图形硬件也可以当做固定函数流水线硬件来用。可编程硬件允许更灵活的计算顶点的的颜色，位置等。纹理也可用于可编程硬件。纹理中包含的数据，不仅仅可以表示颜色，也可以表示任何其他程序员知道如何处理的数据。<br /><font color="#0000ff">Batching<br /></font>材质与mesh之间的关系所带来的最大影响是渲染状态的改变。ogre中的渲染单元大多数情况下指的是renderable,它是SubEntity的父类。渲染单元这个概念的重要性在于，正是在这里，ogre将调用显卡驱动开始并且会结束“画操作”。一次画操作（batch),指的是清除颜料（color,texture,etc)与材料（vertexof display lists)，从头开始一组新的操作的过程。就像一个画家每次在画板上做画时会洗净他的调色板一样。对于3D硬件来讲，这个过程包括发送新的顶点列表与数据索引到GPU(或者引用还存在的），用纹理，颜色，以及光栅化这些顶点组成的面需要的一些元数据来设置GPU。因此，最有效率的做法是一次尽可能多的把<br />使用同样渲染数据的顶点发送到GPU进行处理。ogre会尽量减小状态改变带来的影响，但它遵重你如何构成一个renderable的决定。假如你有一个模型它有20个块组成，它们都使用相同的材质，这时应该把他们整合到相同的renderable中去，而不是分20次batch发送到显卡。每帧的batch数会有个上限。<br /><font color="#0000ff">材质克隆<br /></font>ogre中的材质是共享的。当你从材质管理器获得一个指针，它与从使用这种材质的其他对象所拥有的材质<br />指针是相同的。因此改变一处会影响其他，为了避免影响其他应该克隆材质。<br /><font color="#000080"><font color="#0000ff">Technique &amp; Scheme</font><br /></font>Technique允许针对不同的硬件平台定制不同的材质。Scheme允许对特定一组技术进行更一般化的描述。Ogre选择技术时有明确的顺序。首先，它寻找属于某个命名Scheme中的技术。然后在选好的scheme中查找那些应用了特定材质lod的技术。最后在这些技术列表中，选择最能适应当前硬件设置的技术。缺省，所有的技术属于细节级别0,它对应最高细节级别。<br /><font color="#0000ff">Material LoD</font><br />层次细节这个术语常用来讨论随场景中的物体的几何复杂性是相机与物体之间距离的函数。类似的概念被应用到材质定义上。ogre提供了在哪个层次细节上使用特定技术的手段。可以在材质中定义层次细节发生变化时的距离，赋于材质中的每个技术一个细节索引。每个细节索引也可以有多个技术，用来支持scheme或是硬件能力fallback。<br /><font color="#0000ff">材质组成<br /></font>一个materail由一个或多个technique组成，后者又由一个或多个pass组成，一个时刻只有一个technique是活动的。pass对于在GPU上执行画操作的renderable来讲，是完整的原子渲染状态。假如选择的技术有三pass，那么每帧会对renderable进行三次画操作。pass可以引用纹理单元定义，而不必包含任何纹理单元定义。<br /><font color="#0000ff">纹理单元<br /></font>ogre materail中的纹理单元实际引用GPU上的texture sampler.多数现代图形硬件有多个texture sampler,<br />ogre支持的硬件至少有一个有效的texture sampler。纹理单元包括一个纹理的引用，可以来自一个磁盘文件，或是运行时渲染，或是来自外部视频流。可以在每个pass中指定多个纹理单元。ogre会检测硬件支持的能力，必要时把一个pass折分成多个pass。举例来说，假设pass中指定6个纹理单元，而硬件只支持4个，那么ogre会把这个pass拆分成两个，对这两个pass执行纹理混合以达到相同的设计功能。纹理通常保存在video memory中，直到它们不再需要。ogre不会每次需要时都通过总线传输纹理，除非纹理经常地从<br />video memory中剔除。（这时发生了纹理震荡，原因是有太多或太大的纹理同时存在于vedio memory中）。<br /><font color="#0000ff">纹理压缩<br /></font>现代图形硬件支持压缩纹理。ogre只是简单地把纹理按原样传送他们到图形硬件中去，它不会压缩纹理。<br />对于那些压缩过的纹理，也不必事先处理它，如果硬件不支持压缩纹理，ogre会在运行时解压缩。<br /><font color="#0000ff">实体<br /></font>在渲染期间，Entity主要作为subentities的容器来用，subentities是实际的渲染单元（renderable）。<br />subentity与submesh有一一对应的关系，后者提供原始的材质引用。概念上来讲，entity(subentity)提供了对象的渲染属性，而mesh(submesh)提供了对象的结构属性。<img src ="http://www.cppblog.com/yuanyajie/aggbug/19703.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-13 11:31 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/13/19703.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第五章 场景管理　场景查询</title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/11/19573.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Sun, 11 Mar 2007 09:24:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/11/19573.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19573.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/11/19573.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19573.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19573.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#0000ff">场景查询<br /></font>创建查询的代价比较大，而执行不是。SceneQueryResualt只定义了两种成员：movables与worldFragments.<br />掩码也需要自己定义，自己解释。在一个轴对齐盒子中查询灯光的例子如下：<br />const unsigned int LIGHT_QUERY_MASK = 0x00000001;　//掩码定义<br />Light* light1 = mSceneMgr-&gt;createLight("Light1");<br />Light* light2 = mSceneMgr-&gt;createLight("Light2");<br />light1-&gt;setPosition(12, 12, 12);<br />light2-&gt;setPosition(5, 5, 5);<br />light1-&gt;setQueryFlags(LIGHT_QUERY_MASK);<br />light2-&gt;setQueryFlags(LIGHT_QUERY_MASK);<br />AxisAlignedBoxSceneQuery* lightQuery =<br />mSceneMgr-&gt;createAABBQuery(<br />AxisAlignedBox(0, 0, 0, 10, 10, 10), LIGHT_QUERY_MASK);<br /><font color="#008000">// sometime later in the application's code, find out what lights are in the box<br /></font>SceneQueryResult&amp; results = lightQuery-&gt;execute(); //查询<br /><font color="#008000">// iterate through the list of items returned; there should only be one, and it<br />// should be light2 created above. The list iterator is MovableObject type.<br /></font>SceneQueryResultMovableList::iterator it = results.movables.begin();<br />for (; it != results.movables.end(); it++)<br />{<br /><font color="#008000">// act only on the lights, which should be all we have <br /></font>assert ((*it)-&gt;getQueryFlags() &amp; LIGHT_QUERY_MASK) != 0);<br /><font color="#008000">// do whatever it was we needed to do with the lights<br /></font>}<br /><font color="#008000">// destroy the query when we are done with it<br /></font>mSceneMgr-&gt;destroyQuery(lightQuery);</p>
		<p>我们知道地形总是起伏不平的，当主角在上面行走时需要根据地形的高度调整，可以光线查询来实现。<br />原理比较简单：向主角脚下执行光线查询，与地形有一个交点，根据交点的高度调整主角位置。<br /><font color="#0000ff">Terrain Clamping<br /></font>void Entity::clampToTerrain() {<br />static Ogre::Ray updateRay;<br />updateRay.setOrigin(m_controlledNode-&gt;getPosition() + Ogre::Vector3(0, 15, 0));<br />updateRay.setDirection(Ogre::Vector3::NEGATIVE_UNIT_Y);<br />m_raySceneQuery-&gt;setRay(updateRay);<br />Ogre::RaySceneQueryResult&amp; qryResult = m_raySceneQuery-&gt;execute();<br />if (qryResult.size() == 0) {<br /><font color="#008000">// then we are under the terrain and need to pop above it<br /></font>updateRay.setOrigin(m_controlledNode-&gt;getPosition());<br />updateRay.setDirection(Ogre::Vector3::UNIT_Y);<br />m_raySceneQuery-&gt;setRay(updateRay);<br />}<br />qryResult = m_raySceneQuery-&gt;execute();<br />Ogre::RaySceneQueryResult::iterator i = qryResult.begin();<br />if (i != qryResult.end() &amp;&amp; i-&gt;worldFragment)<br />{<br />Ogre::SceneQuery::WorldFragment* wf = i-&gt;worldFragment;<br />m_controlledNode-&gt;setPosition(m_controlledNode-&gt;getPosition().x,<br />i-&gt;worldFragment-&gt;singleIntersection.y,<br />m_controlledNode-&gt;getPosition().z);<br />}<br />}<br />void Entity::init()<br />{<br /><font color="#008000">// lots of other irrelevant entity init stuff goes here</font><br />m_raySceneQuery = sm-&gt;createRayQuery(<br />Ogre::Ray(m_controlledNode-&gt;getPosition(),<br />Ogre::Vector3::NEGATIVE_UNIT_Y));<br /><font color="#008000">// move this node is such a way that it is above the terrain</font><br />clampToTerrain();<br />}</p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/19573.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-11 17:24 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/11/19573.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第五章 场景管理　地形</title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/09/19504.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Fri, 09 Mar 2007 09:25:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/09/19504.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19504.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/09/19504.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19504.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19504.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#0000ff" size="5">Ogre中的地形<br /></font>
				<br />
				<font color="#0000ff">使用terrain.cfg</font>
				<br />WorldTexture=terrain_texture.jpg  <font color="#008000">//地形纹理<br /></font>DetailTexture=terrain_detail.jpg  <font color="#008000">//细节纹理<br /></font>DetailTile=3                     <font color="#008000"> //细节纹理在一个地形小块中的平铺数<br /></font>PageSource=Heightmap             <font color="#008000"> //高度图数据源<br /></font>Heightmap.image=terrain.png      <font color="#008000"> //高度图名称,符合2^n+1<br /></font>PageSize=513                     <font color="#008000"> //高度图大小<br /></font>TileSize=65                      <font color="#008000"> //地形小块大小<br /></font>MaxPixelError=3                  <font color="#008000"> //决定使用层次细节时充许误差<br /></font>PageWorldX=1500                   <font color="#008000">//地形在世界中的范围x方向<br /></font>PageWorldZ=1500                 <font color="#008000">  //z方向<br /></font>MaxHeight=100                   <font color="#008000">  //世界中地形最大映射高度<br /></font>MaxMipMapLevel=5                <font color="#008000">  //层次细节上限<br /></font>#VertexNormals=yes                <font color="#008000">//在缓冲中计算顶点法线，计算机光照或GPU程序用到时打开<br /></font>#VertexColors=yes　　　　　　　　 <font color="#008000">//在缓冲中设置顶点颜色，假如有GPU程序需要时打开</font><br />#UseTriStrips=yes                <font color="#008000"> //对于现在的硬件，建议关掉<br /></font>VertexProgramMorph=yes　　　     <font color="#008000"> //使用顶点程序进行LOD融合处理<br /></font>LODMorphStart=0.2                <font color="#008000"> //LOD融合开始点：高，低LOD之间距离之比</font></p>
		<p>下列参数用于提供自己的着色程序时使用，这会提供自己定义的material，那么先前定义的<br />WorldTexture 与 DetailTexture的设置不再用到，多余的了。</p>
		<p>MorphLODFactorParamName=morphFactor　<br /><font color="#008000">//假设VertexProgramMorph被设为yes,定制的material中包括一个高级顶点程序。它指定了一个顶点<br />//程序的参数名，这个参数用于融合LOD,参数值从0－1，0表示不调整，1表示完全调整到下一级LOD</font><br />MorphLODFactorParamIndex        <font color="#008000"> //用于materail中包含低级顶点程序的情况，意义同上<br /></font>CustomMaterialName              <font color="#008000"> //指定的materail名字</font></p>
		<p>上述配置文件定义了基于高度图的地形。这些参数定义可概括为两类：Ogre使用第一类从高度图产生地形<br />mesh与材质。第二类是定制材质与GPU顶点程序，这可以代替ogre自动产生的着色程序。<br /><font color="#ff1493">另外的说明：</font><br />TerrainScenceManager会把高度图分为向个pages,每个page由几个tiles组成.而它们也不过是个方便的名字，<br />它们都定义了在产生的mesh中一组构成正方形的顶点集。<br />WorldTexture定义的纹理不必与目标地形一样大。<br />PageWorldX，PageWorldZ可以缩放世界中的地形。<br />MaxHeight 在Y方向缩放地形。<br />DetailTexture 只使用一个纹理，如使用多层纹理，应该使用自定义materail。<br /><br /><font color="#0000ff">从程序加载地形</font><br />setWorldGeometry()有重载形式，一种用于加载配置文件，另一种我们可在程序中使用，以<br />达到手工加载的功能。这里，SceneData被 typedef 为std:map,它存储了如我们在terrain.cfg<br />中看到那些值对。假设我们已经从某个二进制文件读入我们想要的内容到SceneData中。我们要做<br />的就是把读入的内容转换成setWorldGeometry()需要的类型。先看一下函数原型：<br />Ogre::SceneManager::setWorldGeometry (  DataStreamPtr &amp;  stream,  <br />  const String &amp;  typeName = StringUtil::BLANK <br /> )  <br />DataStreamPtr是一个智能指针,因此从局部变量中返回是安全的,程序相当直观，不再多说了。</p>
		<p>Ogre::DataStreamPtr Process_Loader::getSceneDataStream(SceneData &amp;data) {<br /><font color="#008000">// create what looks like a config file for the edification of Ogre</font><br />std::string mem;<br />SceneData::iterator it;<br />for (it=data.begin(); it!=data.end(); it++) {<br />mem += it-&gt;first;<br />mem += "=";<br />mem += it-&gt;second;<br />mem += "\n";<br />}<br />void *pMem = (void *)new unsigned char[mem.length()+1];<br />memset(pMem, 0, mem.length()+1);<br />memcpy(pMem, mem.c_str(), mem.length() + 1);<br /><font color="#008000">// stuff this into a MemoryDataStream<br /></font>Ogre::DataStreamPtr pStr(new Ogre::MemoryDataStream(pMem, mem.length() + 1));<br />return pStr;<br />}<br /><font color="#008000">// and then elsewhere in the world loader:</font><br />Ogre::DataStreamPtr pStr = getSceneDataStream(terrainDef);<br />m_sceneMgr-&gt;setWorldGeometry(pStr);<br /></p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/19504.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-09 17:25 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/09/19504.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第五章 场景管理 第二部分 </title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/09/19496.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Fri, 09 Mar 2007 06:25:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/09/19496.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19496.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/09/19496.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19496.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19496.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#0000ff">场景对象创建<br /></font>场景中的所有对象，包括可移动与不可移动的：lights, cameras, entities,particle system,<br />billboards, skyboxes, static geometry , world geometry.都由场景管理器来创建。场景中的<br />任何东西都由场景管理器来管理。任何通过场景管理器得到的东西，都必须由场景管理器来销毁。<br />用户不能delete通过由场景管理器得到的指针。<br />场景结点只有一个父结点，可能有多个子结点。可以随意的attach 和 detach 这些场景中的结点。<br />在明确告诉场景管理器销毁这些结点前，它们总是存在。如果不想渲染场景中的某些结点上的内容，<br />我们可以很方便地对她们进行detach.场景中总是存在一个Root结点。可以把多个内容对象attach到<br />同一个结点上。不能同时把一个实例对象挂到两个场景结点上，一个场景结点也不能有两个父结点。<br />总是场景结点在执行空间操作（平移，旋转，缩放）而不是实体对象。<br /><font color="#0000ff">场景查询</font><br />场景管理器的第二个最常用的功能是进行场景查询。包括射线查询，球查询，绑定盒查询，绑定平面<br />查询，相交查询。Terrain clamping：在崎岖不平的路上，勇敢地向下发射一束光，不管你告诉我你有<br />多高，我永远把你踩在脚下..（是不是不太像笔记？^_^)。所有这些查询都是 maskble的，这表明可<br />以在查询时过滤掉不关心的对象类型。如球查询时，只想看看它包含了多少lights,其他的对象即使包含<br />在球里也不必返回，实际上根本不用计算。<br /><font color="#0000ff">空间关系与3D变换<br /></font>world , parent , local世界空间中的变换是相对于全局坐标系的源点(0,0,0),这也是root scene node的位置。因此可以认为世界空间中的变换是相对于Root scene node的。父空间中的变换是相对于场点结点的父结点的，本地空间的变换是相对于物体所挂接的结点的。大多数情况下，我们会在父空间中做平移，在本地空间中做旋转，ogre中的这些操作，都是在上述的这种方式下。<br />object space<br />从模型导出的顶点数据与它的源点之间的关系是不变的，当它被挂到场景结点上，这个结点就是认为是<br />它的源点。建模时与导出时不假设测量单位，以世界单位导出（也就是无单位）。<br />ogre平移与设置位置不同：平移可以有多个参照点（world,local,parent space),而用setPosition()<br />时，总是相对于parent-space　坐标系的。<br /><font color="#0000ff">可移动的场景对象</font><br />基于资源的对象：最普通的是mesh(陪伴着skeleton)，这种类型的对象被资源管理系统管理。<br />场景管理器不负责实际的装载，它调用Ogreuq资源管理器来完成。<br />基于四边形的对象：粒子系统，公告板，ribbon trail,overlay,天空盒。它们通常是面向相机的，<br />使用动态材质。它们的主要资源是脚本，这些脚本定义了如何映射材质，以及它们的生命期（对于粒子系统与ribbon trail来说)。天空盒直接用场景管理器来定义。<br /><font color="#0000ff">skyplane,skydome,skybox</font><br />主要的相似点是它们与相机保持一个常量的距离。它们可以在场景中其它对象<br />之前或是之后渲染。它们使用普通的ogre material,因此纹理动画与其他纹理没有什么不同。它们可以<br />被场景管理器打开或关闭，与相机的距离也可以设置。<br />skyplane 是一个平面。用距离和法线定义它与相机的位置关系。可以弯曲，可以分多个段，可对纹理进行多次平铺。skydome由五个平面组成，底部空。使用改变纹理坐标的方式来达到外观上的曲率变化。有一个值用来调节，值越低，曲率越柔和，值越高，越陡峭。skybox 像skydome,但他不能“弯曲”材质坐标。它可以使用立方材质。可使用硬件加速功能达到很好渲染效率。<br /><font color="#0000ff">光</font><br />使用光的限制：单个通道通常最大支持8个灯。使用更多的灯，通过多通道。<br />光与物体之间的距离，决定光对物体实际的影响。Ogre支持点光源，平等光，聚光灯。<br /><font color="#0000ff">世界几何</font><br />当创建基于mesh的景物或关卡，应该分成较小的部分，以便于裁减。Paging Scene Manager提供了这样的工具。<br /><font color="#0000ff">空间分割方案<br /></font>Ogre是基于硬件加速渲染引擎，因此以最大化几何体batching的方式会比基于实际多边形进行空间分割<br />效果要好的多<font color="#ff1493">。Modern GPUs prefer to render a few large batches　of geometry instead of <br />many small batches.<br /></font><font color="#ff1493">The more visible geometry you can render in a single batch, the better your application’s<br />performance is likely to be (within reason, of course; other classic issues such as fillrate and<br />overdraw can still take over if you just blindly blast polygons at the GPU, batched or not).</font><br /><font color="#0000ff">静态几何使用注意</font>：<br />静态几何在使用之间必须被建立。<br />使用相同材质的几何体将被放到同一渲染操作中(batch):<font color="#ff1493">different materials still require a separate batch.<br /></font>努力的方向是，最大化一个调用的三角形数，最小化调用的次数。<br />不能移动被包含在static geometry中的对象。只有一个世界转换应用到完整的static geometry对象上.<br />比同样规模的movable geometry占用更多的内存。<br />假如组中的任何东西在视锥之内，那么组中的所有对象都将被渲染。</p>
		<p> </p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/19496.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-09 14:25 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/09/19496.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第五章 场景管理 第一部分</title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/08/19427.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Thu, 08 Mar 2007 07:08:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/08/19427.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19427.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/08/19427.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19427.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19427.html</trackback:ping><description><![CDATA[
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" color="#0000ff">
						<font size="5">Ogre 场景管理</font>
						<br />
				</font>
				<br />每个3D引擎都会用scene graph 来组织它的可渲染对象。scene graph　总是会为了更快地搜索与查询做<br />优化，提供给用户查找目标对象附近特定对象的功能，允许查找，排序，剔除多边形，以实现更高效的渲染。偶尔，scene graph也用于碰撞检测。有时，一个单独的scene graph可被用于程序中的所有子系统，包括<br />音效与物理。<br />Ogre使用插件机制来实现场景管理功能。ScenceManager只是接口，他可以有很多具体的实现。Ogre允许<br />在同一时刻同一场景中使用多个Scene Manager,这样在不同的场景类型切换时带来好处。<br /><br /><font color="#ff1493">场景管理器的责任<br /></font>1，创建，放置场景中的可移动对象，light,camera，并可以在图形遍历中有效地访问它们。<br />2，加载，装配world geometry(它通常很大，向四处延伸，不可移动）<br />3，完成场景查询，例如可以回答这样的问题：在世界空间的特定点画一个球体，它会包含哪些对象？<br />4，剔除不可见对象，把可见对象放入渲染队列进行渲染<br />5，从当前可渲染的透视图中组织，拣选各方向光照<br />6，设置，渲染场景中的所有阴影<br />7　设置，渲染场景中的其他对象（如背景，天空盒）<br />8　传递组织良好的内容到渲染系统进行渲染</p>
		<p>
				<font color="#0000ff">场景管理器类型<br /></font>
				<br />以分析源码的方式讨论一下插件的加载机制与特定场景管理器是如何进行运用的。<br />上一章提到了以手工的方式初始化ogre,包括手工加载场景管理器：<br />root-&gt;loadPlugin("Plugin_OctreeSceneManager");<br />其实所谓的自动方式下，Root:Root()中也会间接调用到loadPlugin()方法，这已在前面的笔记<br />(配置文件Plugins.cfg )中提到过。既然特定管理器以插件的形式（dll文件）给出，下面先看如何<br />加载dll. 进入源码：标号表明执行顺序。<br />void Root::loadPlugin(const String&amp; pluginName)<br /> {<br /><font color="#9acd32"><font color="#006400"> </font><font color="#008000">// Load plugin library</font><br /></font>　　　 DynLib* lib = DynLibManager::getSingleton().load( pluginName ); <font color="#ff0000">//(1)<br /></font><font color="#008000">  // Store for later unload<br /></font> mPluginLibs.push_back(lib); <font color="#ff0000">//(4)<br /></font> <font color="#008000">// Call startup function<br /></font>　　　　DLL_START_PLUGIN pFunc = (DLL_START_PLUGIN)lib-&gt;getSymbol("dllStartPlugin"); <font color="#ff0000">//(5)<br /></font><font color="#008000"> // This must call installPlugin<br /></font> pFunc(); <font color="#ff0000">//(6)</font></p>
		<p> }<br />DynLib* DynLibManager::load( const String&amp; filename)  <font color="#ff0000">//(2)<br /></font>{<br />        DynLib* pLib = new DynLib(filename);<br /> pLib-&gt;load();        <br />        mLibList[filename] = pLib;<br /> return pLib;<br />}<br />void DynLib::load() <font color="#ff0000">//(3)<br /></font>{<br />m_hInst = (DYNLIB_HANDLE)DYNLIB_LOAD( name.c_str() );<br />}<br />第<font color="#ff0000">(3)</font>中的宏定义如下：<br />#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32<br />#    define DYNLIB_HANDLE hInstance<br />#    define DYNLIB_LOAD( a ) LoadLibrary( a )<br />到此，DLL被加载到内存,第<font color="#ff0000">(4)</font>步，mPluginLibs是个STL容器，它存放动态库指针。<br />第<font color="#ff0000">(5)</font>步，进入源码可以看到<br />void* DynLib::getSymbol( const String&amp; strName ) const throw()<br />    {<br />        return (void*)DYNLIB_GETSYM( m_hInst, strName.c_str() );<br />    }<br />其中宏定义：define DYNLIB_GETSYM( a, b ) GetProcAddress( a, b )，很显然，它取得一个名为<br />dllStartPlugin的函数指针：不防再看看宏定义： typedef void (*DLL_START_PLUGIN)(void);<br />说明DLL_START_PLUGIN为参数为空，返回值为空的函数指针。<br />每个注册到ogre的dll都实现了这个约定函数。对于我们当前讨论的场景管理器Plugin_OctreeSceneManager<br />来讲，我们可以找到其相应的定义:它在第<font color="#ff0000">(6)</font>步中执行</p>
		<p>OctreePlugin* octreePlugin;<br />extern "C" void _OgreOctreePluginExport dllStartPlugin( void )<br />{<br /> <font color="#008000">   // Create new scene manager<br /></font>    octreePlugin = new OctreePlugin();　<font color="#ff0000">//(6-1)</font></p>
		<p> <font color="#008000">   // Register<br /></font>    Root::getSingleton().installPlugin(octreePlugin); <font color="#ff0000">//(6-2)</font></p>
		<p>}<br />程序执行到<font color="#ff0000">(6-1)</font>步，new 来一个OctreePlugin,我们看一下它的定义：<br />class OctreePlugin : public Plugin<br />{<br /> public:<br />  OctreePlugin();<br />  const String&amp; getName() const;<br />  void install();<br />   void initialise();<br />   void shutdown();<br />   void uninstall();<br /> protected:<br />  OctreeSceneManagerFactory* mOctreeSMFactory;<br />  TerrainSceneManagerFactory* mTerrainSMFactory;<br />  TerrainPageSourceListenerManager* mTerrainPSListenerManager;</p>
		<p>};</p>
		<p>我们会注意到它包含两个工厂类指针:OctreeSceneManagerFactory,TerrainSceneManagerFactory<br />他们就是用来生产特定ScenManager的，稍后讨论。先看<font color="#ff0000">(6-2)</font>步：<br />void Root::installPlugin(Plugin* plugin)<br />{<br /> mPlugins.push_back(plugin);　　<font color="#ff0000">//(6-2-1)<br /></font> plugin-&gt;install();             <font color="#ff0000">//(6-2-2)<br /></font> // if rendersystem is already initialised, call rendersystem init too<br /> if (mIsInitialised)<br /> {<br /> plugin-&gt;initialise();         <font color="#ff0000">//(6-2-3)<br /></font> }<br />}<br />//<font color="#ff0000">(6-2-1)</font>步把插件放到容器中。看看<font color="#ff0000">(6-2-2)</font>做了什么：<br />void OctreePlugin::install()<br /> {<br />  // Create objects<br />  mOctreeSMFactory = new OctreeSceneManagerFactory();<br />  mTerrainSMFactory = new TerrainSceneManagerFactory();<br />  mTerrainPSListenerManager = new TerrainPageSourceListenerManager();</p>
		<p> }<br />呵，刚才还说两个工厂类指针，现在把两个工厂建起来，以后可以用来生产东西了。<br />继续看看<font color="#ff0000">(6-2-3):<br /></font>void OctreePlugin::initialise()<br /> {<br />  // Register<br />  Root::getSingleton().addSceneManagerFactory(mOctreeSMFactory);<br />  Root::getSingleton().addSceneManagerFactory(mTerrainSMFactory);<br /> }<br />哦，把这两个工厂注册到Root中，让Root可以使用它们。啊这句话有点问题，Root只是间接的用到，<br />直接雇主是 SceneManagerEnumerator* mSceneManagerEnum;它被包含在Root中。于是我们可以看到<br />void Root::addSceneManagerFactory(SceneManagerFactory* fact) <font color="#ff0000">//(6-2-3-1)</font><br /> {<br />  mSceneManagerEnum-&gt;addFactory(fact);<br /> }</p>
		<p>工厂已经有了，我们如何利用这个工厂生产出我们想到的东西(SceneManager)呢？<br />回忆上一章的手工初始化过程中，我们一般用以下语句来创建SceneManager:<br />  SceneManager *sceneMgr = root-&gt;createSceneManager(ST_GENERIC); <font color="#ff0000">//(A)<br /></font>也可以这样用<br />  sceneMgr = ogre-&gt;createSceneManager("OctreeSceneManager"); <font color="#ff0000">//(B)<br /></font>每个工厂类都用一个字符串表示其类型。上面说的两个工厂分别使用的字符串为：“TerrainSceneManager”，"OctreeSceneManager"<br />(A)语句肯定会调用工厂类的方法来产生实际的SceneManager,下面看源码验证一下：<br />SceneManager* Root::createSceneManager(const String&amp; typeName, <br />  const String&amp; instanceName)<br /> {<br />  return mSceneManagerEnum-&gt;createSceneManager(typeName, instanceName);<br /> }<br />继续挖：<br />SceneManager* SceneManagerEnumerator::createSceneManager(<br />  const String&amp; typeName, const String&amp; instanceName)<br /> {<br />  SceneManager* inst = 0;<br />  for(Factories::iterator i = mFactories.begin(); i != mFactories.end(); ++i)<br />  {<br />   if ((*i)-&gt;getMetaData().typeName == typeName)<br />   {<br />    if (instanceName.empty())<br />    {<br />     // generate a name<br />     StringUtil::StrStreamType s;<br />     s &lt;&lt; "SceneManagerInstance" &lt;&lt; ++mInstanceCreateCount;<br />     inst = (*i)-&gt;createInstance(s.str());<br />    }<br />    else<br />    {<br />     inst = (*i)-&gt;createInstance(instanceName);<br />    }<br />    break;<br />   }<br />  }<br /> }<br />上述代码很简单：因为执行<font color="#ff0000">(6-2-3-1)</font>已经过实际工厂类实例进行了注册。于是遍历每个工厂实例，<br />找到类型相符的。找到之后，如果没有传场景管理器实例的名字，就起个名字。然后用这个名字<br />生产出一个实例来。CreateInstance没干什么，new　呗。<br />SceneManager* OctreeSceneManagerFactory::createInstance(<br /> const String&amp; instanceName)<br />{<br /> return new OctreeSceneManager(instanceName);<br />}<br />就是这样。OctreeSceneManager and TerrainSceneManager 的功能都是由一个DLL提供的。它们的关系是：class _OgreOctreePluginExport TerrainSceneManager : public OctreeSceneManager，按照一般的类关系逻辑，<br />我们知道派生类一般功能都比父类强大，父类应用于一般场景，子类针对特定场景。这个逻辑在这里是对的。本来是写读书笔记，跑题了，打住。</p>
		<p> </p>
		<p> </p>
		<p> </p>
		<p> </p>
		<p> </p>
		<p> </p>
		<p> </p>
		<p> </p>
		<p> </p>
		<p> </p>
		<p> </p>
		<p> </p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/19427.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-08 15:08 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/08/19427.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第四章 开始使用OGRE</title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/07/19361.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Wed, 07 Mar 2007 06:14:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/07/19361.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19361.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/07/19361.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19361.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19361.html</trackback:ping><description><![CDATA[
		<p>清源游民　<a href="mailto:gameogre@gmail.com">gameogre@gmail.com</a><br /><font color="#0000ff">日志系统</font>：<br />日志记录了基于ogre的程序每次运行时的所有事件，系统初始化，状态，性能信息。输出的内容被放在磁盘文件上，文件缺省名是ogre.log。也可以手动显示创建日志系统,这需要在创建Root对象之前实施。<br /><font color="#008000">// create an instance of LogManager prior to using LogManager::getSingleton()<br /></font>LogManager* logMgr = new LogManager;<br />Log *log = LogManager::getSingleton().createLog("mylog.log", true, true, false);<br /><font color="#008000">// third param is not used since we already created a log in the previous step<br /></font>Root *root = new Root("", "");<br />可以用Ogre LogManager注册一个Log Listener, 以任何方式重定向log data。可以用这种方式来屏蔽任何日志信息。然后还一个更简单的方法达到上述目的：在实例化Root之前，当实例化一个LogManager后，不调用createLog()方法。<br />以下是实现日志信息截流的代码片断：<br />class MyLogListener : public LogListener<br />{<br />public:<br />void write (const String&amp; name, const String&amp; message,<br />LogMessageLevel level, bool maskDebug)<br />{<br /><font color="#008000">// redirect log output here as needed<br /></font>};<br />MyLogListener *myListener = new MyLogListener;<br /><font color="#008000">// this is the same as calling LogManager::getSingletonPtr() after the<br />// LogManager has first been instanced; the same pointer value is returned<br /></font>LogManager *logMgr = new LogManager;<br />LogMgr-&gt;addListener(myListener);<br />logMgr-&gt;createLog("mylog.log", true, false, true);<br />logMgr-&gt;setLogDetail(LL_NORMAL);<br />Root *root = new Root("", "", "mylog.log");<br /><font color="#0000ff">Ogre手动初始化</font><br />int main(int argc, char *argv[]) <br />{</p>
		<p>
				<font color="#008000"> // tell Root not to load from any plugins or settings file<br /></font> Root *root = new Root("", "");</p>
		<p>
				<font color="#008000"> // Load feature plugins. Scene managers will register <br /> // themselves for all scene types they support<br /></font> root-&gt;loadPlugin("Plugin_CgProgramManager");<br /> root-&gt;loadPlugin("Plugin_OctreeSceneManager");</p>
		<p>
				<font color="#008000"> // load rendersystem plugin(s). The order is important in that GL<br /> // should be available on on platforms, while D3D9 would be available <br /> // only on Windows -- the try/catch will intercept the exception in this<br /> // case where D3D9 is not available and continue gracefully</font>.<br /> try {<br />  root-&gt;loadPlugin("RenderSystem_GL");<br />  root-&gt;loadPlugin("RenderSystem_Direct3D9");<br /> }<br /> catch (...) {}</p>
		<p> try {<br /><font color="#008000">  // We'll simulate the selection of a rendersystem on an arbirtary basis; normally<br />  // you would have your own code to present the user with options and select the<br />  // rendersystem on that basis. Since a GUI is beyond the scope of this example, we'll<br />  // just assume the user selected OpenGL.<br /></font>  RenderSystemList *rList = root-&gt;getAvailableRenderers();<br />  RenderSystemList::iterator it = rList-&gt;begin();<br />  RenderSystem *rSys = 0;</p>
		<p>  while (it != rList-&gt;end()) {<br />   <br />   rSys = *(it++);<br />   if (rSys-&gt;getName().find("OpenGL")) {<br />   <br />    root-&gt;setRenderSystem(rSys);<br />    break;<br />   }<br />  }</p>
		<p>
				<font color="#008000">  // check to see if a render system was selected; if we reached the end of the list<br />  // without selecting a render system then none was found</font>.<br />  if (rSys == 0) {<br />   delete root;<br />   std::cerr &lt;&lt; "No RenderSystem available, exiting..." &lt;&lt; std::endl;<br />   return -1;<br />  }</p>
		<p>  <font color="#008000">// We can initialize Root here if we want. "false" tells Root NOT to create<br />  // a render window for us<br /></font>  root-&gt;initialise(false);</p>
		<p>
				<font color="#008000">  // set up the render window with all default params<br /></font>  RenderWindow *window = rSys-&gt;createRenderWindow(<br />   "Manual Ogre Window", // window title<br />   800,     // window width, in pixels<br />   600,     // window height, in pixels<br />   false,     // fullscreen or not <br />   0);      // use defaults for all other values</p>
		<p>  <font color="#008000">// from here you can set up your camera and viewports as normal<br />  // get a pointer to the default base scene manager -- sufficient for our purposes</font><br />  SceneManager *sceneMgr = root-&gt;createSceneManager(ST_GENERIC);</p>
		<p>
				<font color="#008000">  // create a single camera, and a viewport that takes up the whole window (default behavior)<br /></font>  Camera *camera = sceneMgr-&gt;createCamera("MainCam");<br />  Viewport *vp = window-&gt;addViewport(camera);<br />  vp-&gt;setDimensions(0.0f, 0.0f, 1.0f, 1.0f);<br />  camera-&gt;setAspectRatio((float)vp-&gt;getActualWidth() / (float) vp-&gt;getActualHeight());<br />  camera-&gt;setFarClipDistance(1000.0f);<br />  camera-&gt;setNearClipDistance(5.0f);</p>
		<p>
				<font color="#008000">  // Run the manual render loop. Since we are not using a frame listener in this case, we<br />  // will count to 15 seconds and then instead of exiting, we'll change the render window settings <br />  // and re-initialize it.<br /></font>  bool renderLoop = true;<br />  Timer *timer = Ogre::PlatformManager::getSingleton().createTimer();<br />  timer-&gt;reset();<br />  float s = 0.0f;</p>
		<p>  while (renderLoop &amp;&amp; window-&gt;isActive()) {</p>
		<p>   renderLoop = root-&gt;renderOneFrame();</p>
		<p>   // accumulate total elapsed time<br />   s += (float)timer-&gt;getMilliseconds() / 1000.0f;</p>
		<p>   // if greater than 15 seconds, break out of the loop<br />   if (s &gt;= 15.0f)<br />    renderLoop = false;</p>
		<p>
				<font color="#008000">   // we must call the windowing system's message pump each frame to <br />   // allow Ogre to process messages <br /></font>   //PlatformManager::getSingleton().messagePump();<br />  }<br /> }<br /> catch (Exception &amp;e) {<br />  std::cerr &lt;&lt; e.getFullDescription() &lt;&lt; std::endl;<br /> }</p>
		<p> delete root;<br /> return 0;<br />}<br /></p>
		<p>
				<font color="#0000ff">视口<br /></font>通过视口上的一点与相机的原点产生世界空间中的一条光线<br />// x and y are in "normalized" (0.0 to 1.0) screen coordinates<br />Ray getCameraToViewportRay(Real x, Real y) const;</p>
		<p>视口,创建多个视口，通过Z序（越高越在上）　确定覆盖效果，每个视口可以有不同的背景。<br /><font color="#008000">// assume window is a valid pointer to an existing render window, and<br />// a valid pointer to an existing camera instance<br /></font>Viewport *vpTop, *vpBottom;<br /><font color="#008000">// second parameter is z-order, remaining params are position and size,<br /></font>vpBottom = window-&gt;addViewport(camera, 0);<br /><font color="#008000">// create a smaller viewport on top, in the center, 25% of main vp size<br /></font>vpTop = window-&gt;addViewport(camera, 1,<br />0.375f, 0.375f,<br />0.25, 0.25);<br /><font color="#008000">// set the background of the top window to blue (the default is black<br />// need to set the bottom window explicitly)<br /></font>vpTop-&gt;setBackgroundColour(ColourValue(0.0f, 0.0f, 1.0f));<br /><font color="#008000">// an alternate way to set the color is to use the manifest constant<br />// vpTop-&gt;setBackgroundColour(ColourValue::Blue);</font><br />在多视口情况下，overlay缺省在每个视口中渲染。可以关掉。Skybox, Shadow也是如此。<br />vpTop-&gt;setOverlaysEnabled(false);<br />vpTop-&gt;setSkiesEnabled(false);<br />vpTop-&gt;setShadowsEnabled(true);<br /></p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/19361.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-07 14:14 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/07/19361.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第三章 设计概要 第二部分</title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/06/19280.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Tue, 06 Mar 2007 03:18:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/06/19280.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19280.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/06/19280.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19280.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19280.html</trackback:ping><description><![CDATA[
		<p>清源游民　 <a href="mailto:gameogre@gmail.com">mailto:gameogre@gmail.com</a></p>
		<p>
				<font color="#0000ff">子系统概览</font>
				<br />
				<font color="#000000">Root Object <br />Root 是程序进入点，它是一个façade 类，提供了访问子系统的方便的方法。通过它可以开启ogre,也可能通过它关闭ogre。</font>
				<br />
				<font color="#ff1493">资源管理</font>
				<br />在渲染场景中使用的任何东西都被视为资源。所有的资源最终都被一个单个类对象管理：ResourceGroupManager，它负责定位资源，初始化资源（不真正装载）。 <br />在缺省情况下，Ogre认识以下类型的资源： <br />Mesh: 二进制格式，它也可包含 morph 和　pose 动画数据 <br />Skeleton: 　可以被Mesh文件引用，也可单独使用，包含骨骼层次结构信息，关键帧信息。 <br />Material: 　定义了渲染一组几何体时的渲染状态，可以被mesh文件引用，也可以手工使用。 <br />GPU 程序：.program 支持HLSL, GLSL,Cg 与低级的 .asm ，这些文件会在任何.material之间被剖析，因此在一个material之中被引用的Gpu程序总是有效的。 <br />Compositor: 与Material很相似，扩展名不同. <br />Font: 用字体定义文件去定义在overlay中使用的字体，扩展名 .fontdef <br />每种资源都有自己的特定的ResourceManager,如，MaterialManager, FontManager。ResourceGroupManager负责通过名字查找资源，它不负责实际的内存管理任务。这些任务是由ResourceManager基类来完成的。ResourceGroupManager允许通过组名来加载，释放整组资源。 <br />默认情况下，Ogre认为资源以一个磁盘文件的形式存在。然而，有些类型的资源可以手工管理，当前只有mesh, font 有手工资源加载的实现。其他类型的可以自己实现，Ogre已经在它的框架中保留了这种功能。 <br /><font color="#ff1493">场景管理</font><br />所有的具体实现都从SceneManager派生而来，程序中常与此类交互。，可以有多个活动的SceneManager。它们用来管理SceneNode, SceneNode可以在场景中被移动。SceneNode也可以有层次结构。 <br />场景实际内容经常也Entity实例的形式存在。它们被Scene Manager创建，MovableObject实现。一个有效的Entity可以被attach 到SceneNode上面。Entity 经常从磁盘上以 mesh文件加载。然后也可以手工创建内容对象，如plane.当Entity被attach到SceneNode上时，进行移动等操作是针对SceneNode的，而不是内容对象。 <br />也可以把非内容对象(灯，相机等)attach 到SceneNode上面。 <br />渲染系统与渲染对象 <br />RenderSystem 是Ogre与底层API的接口, RenderTarget 是　渲染窗口与渲染纹理的概括。 <br />Ogre 扶持多个渲染窗口。窗口可以通过Root对象自动、手动地创建，也可能通过RenderSystem创建。 </p>
		<p>
				<font color="#0000ff">Ogre 管理器</font>
				<br />Manager 是一个可以访问相关类型对象，管理其生命周期的类。例如，ArchiveManager管理Archive实现的创建与注册，访问注册的Archive实现实例。Root对象创建的副作用之一就是初始化所有ogre Manager对象。 <br />LogManager : 发送日志信息到输出流。 <br />ControllerManager: 管理 controllers,后者是基于各种输入，为别的类产生状态值以供使用。 <br />DynLibManager: 　管理动态链接库 <br />PlatformManager: 把抽象的访问转换成底层硬件与操作系统相关的细节。 <br />CompositorManager: 访问管理　Compoitor framework. <br />ArchiveManager: 　文件系统目录，ZIP文件 <br />ParticleSystemManager: 粒子系统，发射器，影响器（affector） <br />SkeletonManager:  允许同名的skeleton对象重用 <br />MeshManager :  管理mesh, 允许同名mesh重用 <br />HighLevelGpuProgramManager: 维护，加载，编译高级GPU程序 <br />GpuProgramManager: 维护低级GPU程序，把编译的高级GPU程序转为汇编 <br />ExternalTextureSourceManager:  管理外部纹理源类实例，如视频流 <br />FontManager:  管理Overlay中使用的字体 <br />ResourceGroupManager: 加载，生命期管理，所有注册的程序资源 <br />OverlayManager: 加载，创建，2D Overlay 类实例 <br />HardwareBufferManager: 管理共享硬件缓冲，　顶点缓冲，像素缓冲，索引缓冲等。 <br />TextureManager: 管理纹理 <br />总结： 这一章无意覆盖关于Ogre的所有东西，只说明了一些普遍需要的Ogre对象，和一些不太常打交道的ogre 对象。 </p>
		<p> </p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/19280.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-06 11:18 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/06/19280.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Pro Ogre 3D Programming》 读书笔记 之 第三章 设计概要　　第一部分</title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/05/19264.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Mon, 05 Mar 2007 15:22:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/05/19264.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/19264.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/05/19264.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/19264.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/19264.html</trackback:ping><description><![CDATA[
		<p>清源游民　 <a href="mailto:gameogre@gmail.com">gameogre@gmail.com</a></p>
		<p>
				<font color="#0000ff">设计哲学</font>
				<br />传统上，使用 Direct3D 或 OpenGL 来渲染场景和对象，需要遵循一系列程序处理流的步骤：调用 API 设置渲染状态，调用 API 发送几何体信息，通知 API 或 GPU 去渲染几何体。对每个几何体都是如此返复，直到当前帧被完全渲染。在一下帧同样如此。 <br />使用面向对象的方法来渲染几何体简化了上述过程。通过处理组成场景的各种对象而不是原始的几何体。这些对象包括：可运动对象，静态对象（构成世界布局），光，相机等。那些 3D API 则不再需要：只是把这些对象放到场景中， Ogre 负责处理琐碎的细节。而且，可以用更加直观的方法来操纵对象，而不是使用矩阵。总的说来，我们可以处理对象，它的属性，调用更直观的方法，而不再用顶点列表，三角形列表，旋转矩阵等手段来管理了。 <br />Ogre 提供了面向对象的框架，包括了对象模型中的渲染处理的所有部分。渲染系统抽象了底层 3D 　 API 的复杂性。场景图形功能被抽象成单独的接口，这样一来，各种不同的场景图形管理算法可以即插即用。在场景中的所有可渲染对象，无论是可移动的，还是静态的，都被一组公共接口抽象，这些接口提供了实际的渲染操作（例如 techniques 和它所包含的 passes ） . <br />设计亮点 <br /><font color="#ff1493">一“设计模式”的合理使用 <br /></font>Ogre 中大量使用了经典的设计模式。例如，使用“ Observer ”模式来通知应用程序特定事件的发生，在 demo 中 FrameListener 的使用使得程序可以接收　 frame-started and frame-ended 　事件通知。“ Singleton ”模式强制实现类的单实例。“ Iterator ”模式用来遍历数据结构的内容。 <br />“Visitor” 模式用来在对象上执行某种操作。 Façade 模式用来抽象底层，提供一个单一类接口。 <br />“ Factory” 　用来创建实例。 <br /><font color="#ff1493">二 场景图与内容分离 <br /></font>传统上，场景图与内容同处于同一继承体系下。它要求从场景结点子类化内容类，也就是说内容类从场景结点继承。实践证明这种设计非常糟糕。 首先， Ogre 操作场景图形在接口层 , 它不假设特定图形算法的实现。实际上， Ogre 操作场景图形仅仅通过它的签名（方法），完全忽略底层的算法实现。 <br />第二， Ogre 的图形接口只关心图形结构，不包含任何内在的访问或管理功能。后者被推到 Renderable 中，场景中的所有几何（ movable or otherwise ）都从它继承。这些 Renderalbes 的渲染属性（材质， materials ）被包含到 Entity 对象中去。 Entity 可以包含一个或多个 SubEntity 。这些子实体是实际的可渲染对象。下面是各对象的一个关系图：<br /><img src="http://www.cppblog.com/images/cppblog_com/yuanyajie/2865/r_ScenceGraph.jpg" /><br />通过这样的设计，场景管理与场景内容充分解藕。过于场景图来说，通过 Movable Object 几何，渲染属性变得有效。注意到 Movable 不是从 Scene Node 继承而来的。 Movable Object 是 attached 到 Scene Node 上去的 . 当扩展，改变，重构场景图形实现时对场景内容对象的设计与实现没有任何影响。 <br />从另一方面来说，由于场景图形不需要知道内容类的任何变化。只要实现一些简单的场景图形“确实“需要知道的一些接口。因此，我们可以任意的 attached 一些自定义的东西到场景结点上，比如声音信息等。（听说有个 OgreAL, 它包装了 OepnAL ，猜想就是这样做的吧）。 <br /><font color="#ff1493">三　插件结构</font><br />OGRe 被设计成可扩展的。 Ogre 通过“基于契约的设计 ” 来完成。 Ogre 可以被设计成一组共同工作的组件，它们通过一些已知接口来相互交流。这带来极大的灵活性，某种功能的不同实现与改变非常容易。举例来讲，由于 ogre 处理场景图元管理是在接口级，用户可以随意的选择特定算法的实现。而且，当用户创建一个新的实现，可以很容易的以插件的形式提供给 Ogre, 　实现时只要遵循 ogre 定义的一些接口 . File archives , render systems 也以插件的形式提供，粒子系统也是。 插件形式的吸引人之处是，为了加入插件，不需要重新编译 Ogre 库 . 插件可以在运行时加载。 <br /><font color="#ff1493">四　硬件加速的渲染支持</font><br />Ogre 被设计成只支持硬件加速图形渲染，直接软件渲染不是它的选项。 Ogre 使用完整的硬件加速能力，包括可编程 shaders 。 Unreal 引擎能做什么， Ogre 就能做什么！！（ ^_^, 作者说的）。引擎直接支持的全局光照 (precomputed Radiance Transfer 等 ) 还没有实现，因为这些多数用于非实时计算场合，因此不是什么问题 .Ogre 现在和未来将可能只使用 Direct3D 与 OpenGL 。 <br /><font color="#ff1493">五，灵活的渲染队列结构 <br /></font>Ogre 　采取一个新方法来解决场景中各部分渲染次序问题。粗略地看，标准过程通常如下工作：渲染地形或世界几何，渲染可移动对象，渲染各种特效，渲染 OverLay, 渲染背景或天空盒 . 然而，正如典型的实现一样（像集成电路处理模块），这个过程很难改变 . 在许多例子中， 很难改变渲染的顺序，导致难以维护与不灵活的设计的。 渲染队列的概念是： Ogre 以一次一个的方式渲染一组可以排序的队列，也已同样的方式渲染每个队列中的内容