魔域如何到达地图上横坐标 纵坐标为1纵坐标为6的地方?截张…

科洛偌斯·幻宠师
308,448
科洛诺斯研究所
科洛偌斯·幻宠师
311,448
科洛诺斯研究所
爱德·科洛诺斯
幻兽幻化
科洛诺斯研究所 .教授
315,448
科洛诺斯研究所
奥维莉娅
幻兽幻生
科洛偌斯·幻宠师
320,445
科洛诺斯研究所
经验球使用、装备兑换换圣兽魔晶 经验魔导士
323,444
蓝袍议会
幻兽评分 334,448
蓝袍议会
神器技师
339,448
王国直属
科洛偌斯·幻宠师
344,448
科洛诺斯研究所
黑圣石幻兽营
幻兽孵化师
345,458
科洛诺斯研究所
幻兽蛋批量孵化
幻化师 345,464
科洛诺斯研究所
天晴猪宝贝
普通NPC
290,438
普通NPC
王国家族统领官
281,482
王国直属
塔蕾莉娜
王国抽奖监督员
292,455
王国直属
科洛偌斯·幻宠师
287,465
圣·欧斯商会
茉莉·星见
VIP商店 炼金师
284,470
王国直属
光之霍因海姆
魔石卡领取NPC
284,474
王国直属
市场商人
赫而墨斯商会 .商人
284,478
赫而墨斯商会
灵魂换经验
近卫军执行官
281,482
皇家近卫团
维德尼娜
幻兽商人
286,486
王国直属
积分兑换师
281,501
王国直属
积分出售
积分售卖师
281,504
王国直属
卷轴兑换魔石
281,507
圣·欧斯商会
装备兑换使者
装备兑换师
274,478
王国直属
经验兑换使者
经验兑换师
269,478
王国直属
希丝蒂娜
外套兑换使者
外套兑换师
263,478
王国直属
幻兽道具兑换使者
幻兽兑换师
258,478
王国直属
幻兽兑换使者
幻兽兑换师
252,476
王国直属
米娅蕾斯
鲜花兑换使者
鲜花兑换师
249,481
王国直属
双倍经验领取NPC
249,488
卡诺萨教廷
庆典卡兑换使者
庆典卡兑换师
249,494
王国直属
VIP专享服务
248,499
王国直属
小礼物兑换使者 礼物兑换师
252,506
王国直属
VIP幻兽管理员 幻兽管理员
254,506
王国直属
艾德里安
鉴定装备
331,501
蓝袍议会
道格拉斯
武器开洞
纳邦德学院·造型师
326,501
锻造工会
+9以上高级魔魂锻造
【锻造工会】高级魔魂师
326,515
锻造工会
安德罗妮
等级锻造
【锻造工会】升级师
316,501
锻造工会
云·雷娜
魔魂锻造
工会】魔魂师
321,509
锻造工会
特修NPC
321.501
锻造工会
普通修理
【锻造工会】高级修理师
331.515
锻造工会
亚特·查尔斯
宝石融合
314,515
锻造工会
贝鲁特·米特亚
品质锻造
【锻造工会】品质师
306,507
锻造工会
结婚NPC
卡诺萨教廷大祭祀
295,539
卡诺萨教廷
纳邦德学院·造型师
308,558
纳邦德尔
308,564
圣·欧斯商会
幻兽孵化栏任务NPC 任务NPC
285,553 47
杰克.海因莱因
王国任务发布官(发布各种教程、功勋等任务)
王国任务发布官
285,558
王国直属
库鲁司.里昂
任务记录员 (用来查询战绩积分) 任务记录员
285,563
王国直属
塞巴斯蒂安
传送练功场
卡诺萨练功场守卫官
285,571
皇家近卫团
254,605 圣·欧斯商会
蕾亚莉·罗兰德
领奖NPC
女王特使 .【领奖处】
215,629
王国直属
塔蕾莉娜 抽奖NPC
王国抽奖监督员
224,629
王国直属
游戏资料
游戏介绍
职业技能
道具介绍
异能装备
战士装备
法师装备
地图指引
新手任务
入门任务
教程任务
日常任务
副本任务
其他任务    
官方信息
· 游戏类型:MMORPG
· 运营公司:网龙
· 研发公司:天晴数码
· 官方站点:
· ******:0591-87085777
· 邮编:350001
·***邮箱:tqmy@tqdigital.com
·游戏配置:
·友情提示:拒绝魔域外挂
抵制魔域私服
2001-2011
建议意见:
 商务合作:
广告专线:0591-87878497 17173******:0591-87826743魔域最新推出的吸血鬼职业你是怎么看待这个角色的
活动推荐
魔域带给大家很多快乐,说说你们游戏过程中的美好往事
腾讯微博
编辑推荐
综合资料查询
综合资料查询
新手上路
魔域BOSS地图资料
魔域视频
魔域视频
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
[06-14]
大概玩这个游戏的很多人都有过找bo 的想法...
异能者明天就要公测了,我也就现在官方现在...
1.在环保练功之前给幻兽批量孵化器里放些宝...
[08-05]
[08-05]
[08-05]
[08-04]
[08-04]
[08-04]
[08-04]
[08-03]
[08-03]
[08-03]
·游戏状态:公测
·游戏类型:3D幻想武侠
·研发公司:网龙
·运营公司:91.COM
·官方网站:
·官方专区:
·官方记论坛:放飞梦想, 只因游戏
( Wed, 14 May 2008 10:44:47 +0800 )
Description: loom, Fake HDR, True HDR概念
HDR在我旧网上有说过原理,主要是参考了gamedev上的文章.现在把这几个放一起解释一下.
这些后期处理技术都是为了实现发光特效(glow effect)
HDR, 指高动态光范围,类似于暴光的效果,由于rgb分量在计算机显示
时超出255范围的就被丢弃,所以暴光效果表示不太出来,于是使用了一些
方法来得到这样的效果, 一般常用方法就是把高光找出来模糊后加色混合原场景.
bloom 和 Fake HDR(伪HDR), True HDR(真HDR)原理都差不多,主要是在实现
方法上的不同, 如下所示实现方法:
1. bloom的实现: 只渲染发出的光芒到一贴图上(例如关掉灯光只渲染自发光物件的光芒) 然后blur这张贴图 最后把它用加色混到场景上
2. True HDR的实现: 读取hdr文件 将颜色转到64位浮点原贴图中 将原贴图以1/4大小渲染到dow ample贴图中(只取高光,丢弃LDR.即亮度低于1的被过滤掉) 对dow ample进行横向blur然后再纵向blur 最后将blur与原贴图加色合成并进行tone ma ing(调整亮度和乘上暴光指数)就是最终的贴图了. 提示: 什么是tone ma ing: tone ma ing指的是对那个可能过亮或过黑image进行rbg值缩放调整(因为最终输出 的rbg值是不能超出计算机显示范围). 具体参见hdr教程参见(非常简单,有源码): 3. Fake HDR的实现: 由于真HDR需要SM3.0的浮点纹理支持,所以有人在dx8下作出了伪HDR, 作法是 将hdr浮点格式转换成16位整形到一整形贴图上,然后再把发光部分抽出来渲染到另一贴图上, 对它进行blur, 然后用加色方式与第一张贴图混合. 参考(在fake hdr和true hdr): 说白了这种唬人的技术可以用非常简单的方法来实现, 具体可参考dxsdk后期处理例子 有bloom, glow等效果, 而且可以自己组合(有点象3dsmax那个后期合成), 不过由于多 遍渲染及相关计算等处理会使速度变慢. dx的例子在: Microsoft DirectX SDK (December 2006)\Samples\C++\Direct3D\PostProce \ 这里有我对该程序的分析: http://blog.csdn.net/flipcode/archive/2008/03/18/2194994.a x 另外HDR相关可参考phoenixzz的Something about HDR解释也比较容易懂: 他的网站: 他的解释: HDR(High dynamic range) 光照技术是一种近期十分热门的技术,很多最新的DEMO与商业游戏都使用了这种技术,如近期比较流行的帝国时代三与Half-Life2等。由于传统图形学中的纹理颜色表示范围在[0,1]之间,而现实生活中光的范围远远超过[0,1],因此超出范围的光信息就会丢失。由于DX9支持了浮点纹理格式,因此可以支持更大范围的颜色,HDR得以实现。
说到底,HDR实现的根本技术在于浮点纹理格式与浮点绘制表面,A16B16G16R16F 的纹理格式已经足够。其实整数格式的纹理也可以实现HDR,只是需要多费一些事,需要将浮点数表示为整数格式压进整数格式的纹理中。
渲染技术其实很简单,首先将像素结果乘以一个曝光度(一般大于1),这个结果一般会超过[0,1]这个范围,将小于1的部分保存为一个普通的LDR纹理(可以是R8G8B8格式),将超过1的部分保存为HDR纹理(A16R16G16B16F格式);然后对HDR纹理进行BLUR(先水平方向再垂直方向,而且进行BLUR的纹理大小可以是原大小的1/2或1/4,也可以BLUR多遍),最后将LDR纹理与BLUR的结果相加即得到最终的结果。
至于得到特殊的效果,需要仔细调整曝光度以及一些参数。
( Thu, 10 Apr 2008 17:11:26 +0800 )
Description: 哈哈.. 今天终于拿到了ShaderX系列的书籍,一拿到手上,马上翻阅一下,果然是经典的著作啊! 很多实用并且绚丽的效果在里面都有提到! 总共借了3本,ShaderX2的自己已经有电子书了,就不借了,以后打算每天一节.努力把这几本书都看完. ( Sat, 5 Apr 2008 15:56:31 +0800 )
Description:
  * 地形纹理
  大概分两种类型:rts型和f 型
  **第一种:rts型。
  和二维做法差不多,把地图分为很多Block,每块Block可能又由m*n个Tile组成。每块Block使用一张纹理。适合rts等俯视类型游戏,《魔兽3》、《魔域帝国》用到。
  优点:图像精细,适合表现细致的场景。
  缺点:渲染时纹理切换频繁。没法做大面积LOD(Level of Detail),LOD被限制在Block内。由于Block边缘顶点纹理坐标问题,导致Block间没法共用顶点。
  地貌间过渡处理: 如草地过渡到土地,简单的方法是让美术做好所有可能用到的不同地貌过渡的图片,程序计算拼接。复杂点的做法是程序计算纹理融合,在渲染是用多层纹理来解决过渡问题,《Empire Earth》,《C&am C将军》使用类似做法。
  特效处理:
  水深效果:使用顶点色形成水下体积雾效果。
  **第二种:f 型。
  整个地形用一张基本纹理(如:1024*1024)铺满,这张纹理是由程序计算生成(Terrain Texture Generation)。适合室外大场景游戏,如室外f ,飞行模拟。《Battle Field 1942》用到。
  优点:任意的LOD范围。无纹理切换问题。可以把计算好的地形LightMap融入基本纹理,一次渲染。
  缺点:图像精度不够,解决方法是在渲染时上面加一层细节贴图,如:BumpMap,《Ground Control》用到。
  *下面是一些常见的问题
  **纹理生成计算方法
  基本纹理每点像素由所处的海拔高度和坡度约束计算而得。可以理解为有一张横坐标为高度,纵坐标为坡度的纹理表,每点像素查表而来。资料见后。
  **地形LightMap
  明暗(Shading):首先计算每个顶点的平均法向量,注意是共点平面的平均法向量,而不是某个面的法向量,然后用你的光照模型计算公式计算该点光照强度,如:I = co lt;light,normal*Isun + ambient。顶点间光照用插值计算,如法向插值phong算法。
  阴影(Shadow):没看到太好的算法,一般光线求交算法速度太慢,目前我的想法是用硬件
  作ShadowVolume,渲染到一张纹理,然后保存。如果你有好的方法请告诉我。
  **物体阴影
  对静态物体,如房屋可事先渲染好融入Terrain LightMap。
  对动态物体,可用Projection Shadow,简单说就是从光源方向把物体影子渲染到一张纹理,然后通过使用纹理坐标生成(TexCoordGen)和修改相应Texture Coordinates Matrix,把这张图贴到地面渲染。
  **地形渲染
  用Indexed方式按块渲染,注意顶点提交顺序,增加GPU Vertex Cache命中率。如果有LOD,因为每次顶点数据是变化的,d3d实现时用Dynamic Vertex Buffer,把顶点放入AGP内存。
  **LOD(Level of Detail)
  ROAM算法不适合现代硬件加速显卡,不要用。
  可以看一下GeomMipMap LOD和T-Strip LOD。网址见后。
  **射线与地形求交算法
  把射线垂直投影到2d地面网格,顺着射线方向检测经过的每个格子,如果光线在格子里面的最低处大于格子四个顶点的最高处,则不可能有交点。
  资料:
  T-Strip LOD:
  GeoMipMap LOD:
  TerrainTextureGenerator(Full Source Code):http://www.i anesoftware.de/index.php?page=freetools/terrain.php
  my email:
( Sat, 5 Apr 2008 00:28:03 +0800 )
Description: 一种基于几何多重映射的地形绘制优化算法
李均(四川师范大学 计算机学院,四川成都 610066) 摘 要 为了使地形绘制算法更好适应现代图形卡的硬件架构,达到CPU和GPU的均匀负载,提出一种基于几何多重映射的地形绘制优化算法。该算法利用线性插值的方法改善了几何多重映射算法中由于网格分辨率变化引起的图像突变,经实验数据证明,优化后的算法绘制速度得到极大提高,并且分辨率不同的网格间过渡自然,图像质量得以提高。 关键词 地形绘制;线性插值;LOD 1 引言 地形绘制在3D游戏、GIS、计算机仿真中应用很多,关于这方面的算法也一直是计算机图形学领域研究的热点。地形的绘制需要很多数据参与,对系统资源消耗巨大。加上早期图形卡的数据吞吐能力相当有限,缺乏计算功能,因此当时对地形绘制算法的研究主要集中简化网格模型,减小绘制多边形数目,以期减轻图形卡的数据负载,达到实时渲染大地形的目的。在二十世纪九十年代中后期,出现的Progre ive meshes[1],ROAM[2],Continues LOD[3],以及相关的改进算法都称为LOD(Level of detail)算法,其基本思想都是根据视点的位置和地形几何复杂度实时产生细节分辨率不同的网格简化模型。即离视点近或总体起伏较大的模型用高精度的网格来绘制,离视点较远或起伏不很明显的模型用相对低精度的网格绘制。很显然,这中间需要实时计算很多评价参数,需要实时构建全部的地形网格,CPU工作量极大。 随着图形卡数据吞吐能力的不断提高,每秒钟处理上亿个三角形已不再困难。很多计算,比如几何变换和光栅处理都可以交给GPU去计算。所以在GPU数据吞吐量很大的情况下,如果一个算法在剔除渲染顶点的过程中占用了太多CPU资源,出现GPU等待CPU的情况,那么即使算法在剔除多余顶点方面做的很好,但总体绘制效率也不是高效的。而传统的LOD算法都存在这方面的缺陷。并且,受硬件带宽的限制,频繁的传输量巨大的顶点数据,使得时间集中消耗在数据“迁移”过程中。过多的DP(Draw Primitive)也使得图形卡不能发挥最大功效,造成资源极大浪费。所以要适应现代图形卡的硬件架构,算法必须改进,几何多重映射(Geometrical Mipma ing)[4]等算法由此产生。 本文在GeoMipMap(Geometrical Mipma ing)算法的基础上,改进了原算法抑制不同细节分辨率模型之间突变的处理方法,使得在提高绘制效率的同时,保证了绘制图形的质量。通过使用查表法的分块网格顶点数据组织方式,使得CPU的工作进一步减轻。此外,本文还利用了现代图形卡的存储功能来优化地形的绘制。
2 GeoMipMap 算法
2.1 基本思想 GeoMipMap算法是Willem根据纹理多重映射的概念提出的,他把整个地形场景在xz平面上进行分块(block),比如用33×33的block把1025×1025的地形表示为32×32个block。每个分块可用不同分辨率的网格模型来描述。在同一分块内,网格模型的分辨率相同。采用隔行采样的方式生成不同分辨率的网格。整个地形的模型表示和组织如图1所示。 不同的block之间互相拼接时,如果分辨率不同则可能产生裂缝。为了消除裂缝,在较高分辨率的block边界上,忽略一些点作为网格顶点,如图2所示。 每个block分辨率是通过屏幕空间误差[4]来决定的。在地形数据预处理阶段,对每个block的每个分辨率模型,都取一个屏幕误差阀值ε(一般取4个像素),预先计算出当ε等于4个像素时,视点到block的距离d,并保存在查找表中。当实时绘制时,根据视点到每个block的距离查找表中的d,从而决定该block的网格分辨率。
2.2 优点和不足 GeoMipMap算法的网格生成方式显然和ROAM算法以及基于四叉树的连续性LOD算法大不一样。以基于四叉树的连续性LOD算法为例,他是通过自顶向下的方式用四叉树递归地将地形分成一个个小地形块,越往下细分,地形块的大小越小,直至不能细分。当视点发生改变时,所有的顶点都必须重新参与细分的递归运算,这种算法能根据实际情况最大程度确定整个地形的网格分辨率,但计算量很大,并且递归层次很多。而对于GeoMipMap算法来说,当视点改变时,只需要判断可见的每一个block的网格分辨率应该是多少,block内部的顶点并不参与计算。虽然这种做法不能最大化减少进入渲染管道的顶点,减少三角形面片,但是增加的这些渲染顶点对现代图形卡来说是不会影响绘制速度的。相反,由于他减小了实时绘制时模型简化的计算复杂度,速度得到极大提高,所以他是符合现代图形卡硬件架构的地形绘制算法。此外GeoMiaMap相对固定的三角形面片组织方式,也使得进入固定渲染管线的顶点能更好的组织成三角形带,大大减少传入图形卡的顶点个数。 但是,这种算法由于不是连续的LOD算法,也就是说LOD的粒度比较粗放,因此在block的网格分辨率发生改变时,会产生网格形状的突变,使得在地形漫游时,图形过渡不自然。虽然通过屏幕投影误差来选择block的网格分辨率可以使突变的效果有所减轻,但对用户来说比较明显。本文通过线性插值的思想,使层次过渡由突变转为逐步递进,极大减小了这方面的不足。
3 地形绘制优化算法
3.1 地形数据的总体组织和表示 我们首先读入一个场景的DEM数据(高程数据),保存在一个顶点线性表中,然后把这个场景在xz平面上划分成均匀大小的多个block。block的大小按需求而定,其边长满足 ,如9×9,17×17,33×33等。如果地势总体比较平坦,我们可以选得大一点,如果对地形的细节要求较高我们可以选得小一点。本文以19×19作为block的大小。 block通过顶点索引所组成的三角形带描述他负责的一片小的区域。整个场景用一棵完全四叉树把这些blocks组织起来。实时渲染时完全四叉树负责场景的裁剪,决定哪些blocks应该绘制,然后计算可见block的网格分辨率,从而得到整个地形要渲染的三角形面片。其数据组织如图3所示。 当地形是超大地形绘制时,我们采用文献[5]的方法,用多线程机制加上场景缓冲的方法实现大地形数据实时动态调入和管理。每一个场景作为动态加载单元,用一个缓冲区来管理,用单独线程来调度。
3.2 Block多分辨率网格模型的构造和数据组织 Willem在他的论文中指出当细节层次不同时block的顶点取舍方法,以及为了避免出现T型裂缝,block的边界顶点应该怎么调整。本文试着在他的思想基础上,提出一种基于查找表的block三角形带生成方法。 我们把block的中心地带和边界分开对待。在预处理阶段就生成五个顶点索引表。如图4所示。
中心地带索引表负责生成block中心的三角形条带,其索引参数就是自身的网格分辨率。 边界索引表负责生成与其他block相邻区域的三角形带(防止T型裂缝)。索引参数有三个:自身的网格分辨率,相邻的方向,相邻block的网格分辨率。 网格都使用三角形带(Triangle Strip)的方式生成,有些地方需要生成一些退化三角形,用于三角形带的连接。运用三角形带的方式比三角形扇和纯粹三角形方式更能减少顶点个数,提高绘制效率。 这五个索引表一起能够描述任何一个block中组成网格的所有顶点的相对位置(在block区域内的位置)。在实时渲染的时候,针对一个特定的block,我们可以根据这个block在场景中的起始位置,他的网格分辨率,和他四周block的网格分辨率,直接查表得到这个block完整的三角形带顶点索引,减少了CPU的判断和计算量。内存中只保存一个block网格顶点的相对索引,不是整个场景的所有block的顶点索引都保存,因此不会造成什么内存消耗。
3.3 利用线性插值逐步过渡不同分辨率的网格模型 当block的网格分辨率次发生变化时,其网格模型可能变化较大,由于变化是在瞬间完成的,极易被观察者察觉。但如果我们把这种变化由突变改为渐变,用户就不易察觉,其视觉影响也就可以忽略不计。 我们在预处理阶段已经得到一个合适的查找表,可以查出block的网格分辨率c与block到视点的距离d之间的对应关系。我们假设d=1000m时 c=n+1,d=2000m时c=n。 如果现在d=1500m,则网格的分辨率正处在n 和n+1的过渡阶段。我们取网格顶点为c=n+1时的索引,他比c=n时多出一些细节顶点,对这些多出的细节顶点,我们对其高度进行线性插值,使其缓慢在分辨率n+1和分辨率n之间过渡。如图5,v3为高分辨率时出现的细节顶点,v4为模型在低分辨率时v3的初始点。随着网格向高分辨率过渡,v4逐步过渡到v3。v’的Y坐标由下面的公式决定: 如图5所示。 采用这种插值的手段后,只增加了很少的计算,视觉效果上却得到了很大提高。
3.4 利用显存保存地形的顶点表 现代图形卡已经支持把一定大小经常使用的数据直接保存在显存中,所以如果我们把经常使用不频繁变动的数据保存在显存中,可以避免大量数据在渲染时频繁从内存传输到显存。在实验中通过OpenGL的VBO(Vertex Buffer Object)方式把顶点线性表数据保存在显卡中,经比较渲染速度大幅提高。
3.5 描述算法的流程 预处理阶段: (1) 载入地形数据,初始化顶点线性表。 (2) 初始化所有分辨率的block模型所对应的三角形带顶点索引表(见2.2),此表保存的是组成三角形带的相对顶点索引。生成描述整个地形场景的block数组,每个block记录自身在场景中的绝对位置。 (3) 构造完全四叉树,每个子节点对应管理一片区域(一个或多个block),设置包围球半径。每个叶子节点都对应一个block索引。 实时绘制阶段: (1) 遍历完全四叉树,根据视锥体裁剪算法,得到可见block的索引。 (2) 计算这些block的网格分辨率,根据分辨率和网格的三角形带索引表,顶点表,可以得到组成地形网格的所有三角形带顶点的完整信息。 (3) 根据3.3介绍的线性插值方法,调整相关顶点的高度信息。 (4) 送入渲染管道绘制。 (5) 重复(1)。
4 测试结果 我们使用大小为2049×2049的高程图作为实验数据,以Athlon2500+,DDR 512M,ATI 9500,126M显存作为硬件环境对上述算法进行测试。程序用VC+OpenGL在windows平台上完成。其中分块大小为33×33,共分5个细节分辨率,图6是场景绘制的网格形式截图。
图6 地形场景绘制截图
表1 地形绘制测试结果 不使用简
化模型
基于四叉树的LOD算法
新算法
三角形个数
210FPS 从表1中的技术参数统计来看,新算法的渲染效率有很大提高,能满足大规模地型的渲染要求。
5 结论 本文在GeoMipMap算法的基础上,提出了一种生成分块网格模型的方案。用查找表方式生成三角形带来表示分块模型,大大减少CPU计算,减少了传入渲染管道的顶点个数。此外,用插值法把网格模型的分辨率突变转换为逐步递进,改善了渲染图像质量。把常用的顶点保存在显存中,缓解了传输的带宽压力,极大提高了渲染速度。
参考文献
Ho e H. View-dependent Refinement of Progre ive Meshes[C]. Proceedings of the ACM SIGGRAPH Conference on Computer Graphics. Los Angeles:ACM Pre ,1997:189-198
[2] Duchaineau Mark A,Woli ky Murray,Sigeti David E,ROAMing Terrain:Real-time Optimally Adapting Meshes [C]. IEEE Visualization 1997.Los Alamitos: IEEE Computer Society Pre ,1997:81-88
[3] Rottger S,Heidrich W,Slusallek P. Real-time Generation of Continuous Levels of Detail for Height Fields [C]. Winter School in Computer Graphics(WSCG'98).Plzen:Science Pre ,1998:315-322
[4] Willem H de Boer . Fast Terrain rendering using geomtrical mipma ing.(2000) http://www.flipcode.com/ tutorials/geomipma .pdf
[5] 胡斌,江南. 基于粗粒度分页和细粒度分片的大地形动态调度机制研究[J]. 计算机应用,2006,26(6):3-5 收稿日期:9月24日 修改日期:10月6日 作者简介:李均(1980-),男(汉族),四川成都人,硕士,研究方向为图形图像,
( Fri, 4 Apr 2008 22:57:28 +0800 )
Description: 这几天因为比较忙, 所以没有怎么去设计大话梦游这个游戏, 只是简单设计了界面而已, 这里简单说说界面的设计, 界面主要是采用滚轮式的菜单效果! 看看下面截图先: 由于界面没有怎么设计, 所以看起来比较简陋.. 随着游戏的进展, 将会增加比较好看的效果进去!
下面说说界面的实现细节, 其实比较简单, 就是给定一个圆的原点, 然后根据图片的多少(也就是菜单项的多少)计算 一个偏移的角度, 比如上面5张照片的话, 那就是360/5 = 72度. 然后根据偏移的角度, 移动一个圆的半径Radian, 在那个位置blit图片, 旋转的效果, 大家应该也可以想象出来把, 可以给定一个Rotation角度, 每一次递增到72度, 然后判断现在的Rotation的大小, 比如Rotation初始是-90,这时显示的是第一张图片, 那么-18时就会显示第二张图片, 为什么选择Rotation初始为-90, 是因为 x = sin(), y = cos(), pygame的屏幕原点,也就是(0,0)是在左上角的.
( Fri, 4 Apr 2008 20:02:38 +0800 )
Description: 学习了pygame几天了,发觉pygame并不是很实用,它的局限性在于占内存太高了,不管你是否进行了优化,比如使用 rite.renderupdate避免重绘屏幕.并且在图片之间的融合不是很好,假如有两张图片想融合在一起,融合的模式是RGBA的叠加,好像1.8版本的时候blit有一个参数可以选择这个功能, 不过之后的版本没有了,大概是有其他的函数实现了这个功能,不过我找了半天,也实验了半天都没有发现这样的函数,晕死我 之后考虑用OpenGL来实现,也就是pyOpenGL了, 不过看了几个别人写的程序之后,就觉得OpenGL与Python融合得不好,比如鼠标响应之类的处理,很麻烦.不过还是觉得比pygame更养眼, ^_^ 毕竟自己很喜欢使用OpenGL来开发程序. 之后就想了想到底做一个如何的游戏呢? 哈哈..发觉自己很喜欢整天幻想, 没准哪天写程序写累了,可以去策划游戏了! huhu.. 不说废话了, 说说自己设想的游戏吧! 游戏的名称还没有想,只是大概构思了游戏, 这个游戏是射击类型的3D网络对战游戏, 游戏屏幕采用分屏,支持两个玩家,或者VS电脑, 游戏场景是一个3D的场景, 大概 -100 = (x,y,z) = 100. 这个是场景的大小. 为什么选这样一个空间呢,待会再解释. 两个玩家, 游戏一开始会随机在场景中的一个位置(当然是在场景的某个角落里面), 游戏场景里面有一些小兵或者bo (姑且用立方体来表示吧), 你可以打败这些小兵来得到积分,经验, 这样你可以升级, 学会技能. 游戏的胜利条件是打败对方的玩家, 当然你可以直接去挑掉对方, 或者升级之后才去打对方, 这个有点类似魔兽! 刚才说游戏的场景是一个 -100 = (x,y,z) = 100的立方体. 这样选择的原因是场景里面有天空盒(这个天空盒我就不多说了, 学过3D的都知道,就是天空),以及游戏里面,玩家有一个立方体的雷达, 玩家以及小兵等的位置都可以在这个立方体里面看到, 选择一个固定的空间,这样才比较好映射到这个立方体里面. 当然也可以无限场景, 不过如果有一方想逃跑, 估计你可能再也追不到了 今天把以前设计的一个camera类改成python类,这样可以在场景里面漫游!
游戏的实现细节: 语言支持: Pygame + PyOpenGL 游戏角色: GameObject类实现, 属性 Position, Area( 攻击范围以及当你进去这个范围内敌人会攻击你).. 其他还细节还没有想好. 我简单做一个样板, 截个图给你们看看
( Mon, 24 Mar 2008 00:05:31 +0800 )
Description: 如有转载,请注明 上星期听老大说要做一个mini游戏的时候,便开始想着如何做一个游戏,做一个怎样的游戏,当天(星期一)晚上回到宿舍,百无聊赖的看着网页的时候,刚好看到大话3的游戏背景(
)里面的灵石诞生那一章: 三界众生各自修行,这一切却在500年前被突然打破,东胜神州花果山的一块巨石仰天地日月之光,竟化生出一只灵猴,后又习得一身武艺,上天入地,无所不能。他不甘于在水帘洞闲度一生,恰巧遇到了私自下凡的紫霞仙子,一场凄美的旷世恋情开幕,石猴才明白原来仙界有如此之多的束缚,于是打上天庭,寻求自由之路。三界遂都入战,之前的格局逐渐被打破.... 突然我灵机一动,想到了如何设计我那个游戏了 ^_^ mini游戏有三个,一个是球类游戏,一个棋牌游戏,最后一个是射击游戏. 一般射击游戏, 都基本上是采用通关式的, 当时我想到, 孙悟空在水帘洞里面应该是非常无聊的吧, 空有一身的本事,而无处得以施展. 那为什么我不能帮他一下呢. 况且每一次看到有关孙悟空的连续剧(西游记),或者是小说. 孙悟空都是被如来给打败, 那么我何不帮帮他, 让他打败一下如来, 尝一次胜利的喜悦也好. 正好, 灵感来了...设计一款射击游戏, 通关式的游戏, 通关的过程,有一关的bo 或者大bo 是如来. 也许你会问, 这样的游戏也没有什么啊? 当然我的创意是结合大话3这款游戏的,并且增加了一些战斗模式的创意进去. 详细请看下面的游戏剧情设计:
类型: 横版射击游戏
1 游戏名称: 大话西游3前传(小插曲)之
大话梦游 大话西游
大话梦游
2 游戏设计语言:Pygame(Python SDL)
游戏剧情
: ......(大话西游3的剧情背景:灵石诞生),故事从孙悟空(灵猴)破石而出, 习得一身武艺开始。话说孙悟空终日闲来无事,有天突发奇想:究竟俺老孙与玉皇大帝(设定其为天地人三界最大),孰强孰弱? 于是乎决定上天界挑战玉皇大帝。孙悟空过五关斩六将之后,终于打败了玉皇大帝,在欣喜之际,打了一个哈欠。发现自己原来是在做梦,叹了一口气之后,心想还是下山闯闯天下吧。之后巧遇了私自下凡的紫霞仙子,一场凄美的旷世恋情开幕........(大话西游3的剧情)
4 美工设计及游戏音乐等: 风格为Q版, 其它略..(这里不写出来了, 按照北方的说话,就是留点念想.呵呵 估计被电影天下第二毒害了)
5 游戏关卡设计:(可增加) 1 南天门 bo :四大天王 2 广寒宫 bo :嫦娥 3 天河 bo :天篷元帅 4 瑶池 bo :瑶池圣母 5 兜率宫 bo :太上老君 (可选择关卡) 6 凌霄宝殿 bo :玉皇大帝 (隐藏bo 如来)
注意:太上老君为bo 的关卡中,太上老君其主要的作用是为了帮助孙悟空 太上老君为bo :很容易被打败,并且太上老君假意被打败之后,孙悟空可以学习到新的技能或者得到新的武器。(忠于西游记原著, 呵呵, 这个要多亏坐在我隔壁的李GG. 跟我吹了整天的道佛神仙, 发现原来"老太"(太上老君) 实在太牛叉了, 比如来还强,化过胡. 估计只是菜过鸿钧而已
5 创意设计 5.1
大话模式
: 方案1:当游戏角色孙悟空连续射击敌人,得到一定分数。并且期间没有被敌方击中,这时将会启动“大话模式”,如果你不知道所谓的“大话模式“ 是什么,你总该看过星爷的《九品芝麻官》里面对着大海骂人的场景吧。“大话模式”的灵感取决于此。在”大话模式“下(人物头会变得很大),给定3秒内,你可以随意敲键盘,敲键盘的key数目越多,种类越多,越复杂(比如需要同时按住shift的符号键),这时孙悟空将会发出一连串”#◎¥%※¥%◎#!“的口水冲击波对敌方的伤害就会越大。 好多口水哦... 方案2:当游戏角色孙悟空连续射击敌人,得到一定分数。并且期间没有被敌方击中,这时将会启动“大话模式”,在”大话模式“下,给定一串方向键的字符,比如“↑↑→←↓”,当你在一定时间内(2,3秒)敲对这串字符,将会放出攻击波,对敌方造成大的伤害。这次应该不是口水了 5.2 七十二变模式
: 设计方案1: 该模式无需任何条件,但是需要注意的地方是七十二变是随机变化的,有可能变化成庞然大物,攻击力虽然提高,但是跟容易被敌方打到;或者有可能变化成小小的动物,以此来躲过敌方的攻击。 设计方案2: 该模式无需任何条件,该模式启动之后,3秒内孙悟空为不可见,既是隐身了,通过这样,孙悟空可以躲过敌方的耳目,但是将导致会有很长的一段时间内无法再次使用该模式。 5.3 五行相生相克系统
:采用五行相生相克的原理。五行:水火风土雷。水克火,火克雷,雷克风,风克土。土克水。子弹的属性分为水火风土雷。根据五行相克的道理对于敌方造成不同的伤害。 ( Mon, 10 Dec 2007 10:03:51 +0800 )
Description:
William Do elly
University of Waterloo
翻译:netghost(
) 欢迎转载,转载请注明出处
由于本人水平有限,不准确的地方请大家参考原文
Blog:http://netghost.c logs.com/
在这一章中,我们介绍距离映射(distance ma ing),一种在pixel shader中添加小规模位移映射的技术。我们把位移映射视为一个光线跟踪问题,开始于基础表面的纹理坐标,然后计算观察光线和位移表面的交点的纹理坐标。由于这个原因,我们预先计算一个提供了空间点和位移表面之间距离量度的3维的距离映射。这个距离映射给我们提供快速计算光线与表面交点的全部所需要的信息。我们的算法显著的增加了场景中的感知物体的复杂性,但是却维持了实时的性能。
8.1 简介
Cook (1984)提出了位移映射作为增加表面小规模细节的方法。与凹凸映射之影响表面的明暗不同,位移映射调整表面元素的位置。这就导致凹凸映射不可能的效果,例如:表面之间的遮蔽(occlude)特性和非多边形轮廓。图8-1显示了石头表面的渲染效果,表面之间的遮蔽特性对深度感觉有很大的贡献。
位移映射的通常实现是迭代细分(te ellates)一个基本的表面,把顶点沿着基本表面的法向量方向推出去,这样一直继续下去,直到生成的多边形的大小接近单一像素的大小。Michael Bu ell在本书的第七章中提出了这种方法,“Adaptive Te ellation of Subdivision Surfaces with Di lacement Ma ing.”
虽然看起来在渲染管线的顶点着色阶段(vertex shading stage)实现位移映射是更合理的,但是这是不可能的,因为顶点着色不能产生新的顶点。这使得我们考虑依赖于像素着色(pixel shader)的技术。因为以下的原因使用像素着色是个好的想法:
●当前的GPUs的像素处理能力比顶点处理能力更强大。举例来说:GeForce 6800 Ultra有16个像素渲染管线,而顶点染管线只有6个。另外,一个单独的像素渲染管线在一个时钟周期内通常比单独顶点渲染管线执行更多的操作。
●像素着色器更适合访问纹理。许多GPUs在像素着色阶段不允许访问纹理;正是由于这个原因,访问模式是受限制的,会带来性能上的开销。
●带有距离的像素处理的规模。顶点着色总是在模型的每个顶点上执行一次,但是像素着色确是在屏幕的每个像素上执行一次。这意味着工作集中在临近的目标,这也是最需要的。
使用像素着色的缺点是我们不能在shader内部改变像素的屏幕坐标。这意味着与基于细分的方法不同,使用像素着色的方法不能被使用在任意大的位移。可是这并不是严格的限制,因为在实际中位移几乎总是有限制的。
8.2 之前的工作 视差映射(Parallax ma ing)是一种增加凹凸映射来包含视差效果的简单的方法(Kaneko et al. 2001).视差映射使用表面上单一点的高度信息来向观察者或者远离观察者偏移纹理坐标。虽然这是一种仅在平稳变化的高度场上才有效的粗糙的近似,但是却得到了好的令人惊讶的结果,尤其是它可以仅在三个额外的shader指令中实现。不幸运的是,因为这种技术所固有的假设,它不能处理巨大的位移,高频的特征或者遮蔽特性
浮雕映射(Relief ma ing)是由Policarpo (2004)提出的,它在高度映射(height map)上使用一种根查找的方法。它开始于把观察实现变换到纹理空间。然后执行一个线性的查找来定位与表面的交点,跟随着二分查找的是找到一个精确的交点。不幸运的是线性查找需要确定的步幅大小。这意味着为了解决小的细节,必需增加步幅的数目,强迫用户在精确性和性能之间做出权衡。
视点相关的位移映射(Wang et al. 2003)和它的扩展,通用的位移映射(Wang et al. 2004),把位移映射看作是光线跟踪问题。它在5维映射中保存了所有可能的光线交点查询的结果的3维体积,这个5维的映射是以3维位置坐标和两个角度坐标为索引的。这个映射然后使用奇异值***压缩,在运行时使用像素着色解压缩。因为数据是5维的,需要大量的预处理和存储器。
我们这里提出的位移渲染得算法是基于球体跟踪(Hart 1996)的,一种为了加速隐式表面的光线跟踪而开发的技术。虽然在概念上是相同的,但是不在隐式表面的光线跟踪上应用这个算法,而是在GPU上渲染位移映射是应用它。
8.3 距离映射算法
假设我们想在一个平面上应用位移映射。我们可以想象表面被轴对齐的包围盒包围。传统的位移映射算法将渲染包围盒的底面,并把顶点推向上。我们的算法改为替换包围盒的上表面。然后在shader内部,我们将得到位移表面上的那个点是观察者实际看到的。
在场景中,我们将处理与传统的位移映射相反的问题。位移映射询问的是“对于几何体的片元,将被映射到图像中的那个像素?”,而我们算法询问的是,图像中的这个像素,“我们将看到哪个几何体片元?”第一个方法被光栅算法使用,第二个方法被光线跟踪算法使用。因此我们把距离映射视为一个光线跟踪问题。
一个普通的光线跟踪方法在单位间隔位置的高度映射(height map)上采样,来测试视线是否与表面相交。不幸运的是,我们将面临下面的问题:只要我们的采样间隔大于单一纹理元素,我们不能保证没有遗漏在我们的采样之间的交点。这个问题在图8-2中说明。这些“过辐射(overshoots)”会造成渲染得几何体上存在缝隙,结果导致严重的走样。这样我们有两个选择:我们或者接受这种低采样下的古董,或者我们必须为沿着视线的每个纹理元素采样。图8-3显示了我们的算法可以以很好的细节渲染物体而几何体上没有任何的走样或者空隙。
我们可以从前面的例子中得出两个结论:
1. 我们不能简单的以固定的间隔查询高度映射。它要么造成低采样的,要么就会产生难以处理的算法的结果。
2. 在处理中我们需要比高度场更多的信息;我们需要知道在任何的给定区域,我们的采样到什么程度而不会产生过辐射表面。
为了解决这些问题,我们定义了表面的距离映射。对于纹理空间的任何的给定点p 和表面S,我们定义一个函数dist(p, S) = min{d(p, q) : q in S}. 换句话说,dist(p, S)是p 到表面 S 的上最近点的最短距离。S 的距离映射就是简单的3D纹理,为每个点p 保存了dist(p, S)的值。图8-4显示了一个1维高度映射和它对应的距离映射的例子。
这个距离映射给我们提供了需要的选择采样位置的正确的信息。假设我们有一个起点在p0,方向为向量d的光线,d已经规格化为单位长度。我们定义一个新的点p1 = p0 + dist( p0, S) × d.这个新点的重要特性就是p0 在表面的外侧,p1 也在表面的外侧。然后我们通过定义p2 = p1 + dist(p1, S) × d应用相同的操作,等等。每个连续的点都更接近表面一些。这样,要是我们做了足够的采样,我们的点汇聚在光线与表面的最近焦点上。图8-5说明了这个算法的效力。
距离函数不应用到高度映射上是没有任何意义的。实际上,距离映射可以表示任意的voxelized的数据。这意味着渲染带有复杂布局的小规模细节是有可能的。例如:chain mail 可以以这种方式渲染。
8.3.1任意的网格
到现在为止,我们仅仅讨论在平面上应用距离映射。我们很愿通常意在网格上应用距离映射。我们通过假设表面是局部平坦的来这样做。基于这个假设,我们可以使用局部的切线框架,像平面的情形执行相同的计算。我们使用局部表面的切线来变换观察向量到切线空间,正像我们将要变化光向量到切空间法向映射。一旦我们将观察光线变化到切空间,算法就会像平面情形一样正确执行。
既然我们知道怎样使用距离映射进行光线跟踪,我们需要知道怎样有效的为任意的高度场计算距离映射。
8.4 计算距离映射
计算距离变换是一个已经仔细研究过的问题。Daniel on (1980)提出了一个O(n)时间的算法,这里的n 是映射中像素的数目。想法是创建一个3维的映射,映射的每个像素保存一个到达表面最近点的3维的位移向量。算法然后执行一个3维范围的很小的连续交换,基于临近的位移向量更新每个像素的位移向量。一旦位移被计算完成,每个像素的距离使用大量的位移计算。这个算法的实现在本书的CD中。
当距离变化算法完成,我们已经计算了距离映射中每个像素到表面最近点的距离,使用像素衡量。为了使距离在范围[0, 1]之间,我们把每个距离除以3D纹理中像素的深度。
8.5 The Shaders 8.5.1顶点着色
距离映射的顶点着色程序,如Listing 8-1所示,与切空间的法向映射十分的相似,但是有两个显著的不同。第一个是除了把光源向量变换到切空间,我们还把视线方向变换到切空间。这个切空间的视点向量被用在顶点着色中作为在纹理空间中被跟踪的光线的方向。第二个不同是我们以感知深度的反比例来加入一个额外的因子。这使得我们交互的调整位移的比例。
8.5.2片断着色
现在,我们已经有了我们所需的开始光线进展的全部信息:我们拥有一个开始点(从顶点着色向下传递的基本的纹理坐标)和一个方向(切空间的视线方向)。
片断着色要做的第一件事就是单位化方向向量。注意存贮在距离映射中的距离是以对像素的单位比例来衡量的;方向向量是以纹理坐标的为单位来衡量的。通常,距离映射比它的深处更高,更宽,因此这两种距离的度量是完全不同的。为了确保我们的向量是使用距离映射中的距离度量来规格化的,我们首先规格化方向向量,然后把规格化向量和额外的标准因子(depth/width, depth/height, 1)相乘。
Listing 8-1. The Vertex Shader
v2fCo ector distanceVertex(a2vCo ector a2v,
uniform float4x4 modelViewProj,
uniform float3 eyeCoord,
uniform float3 lightCoord,
uniform float invBumpDepth)
v2fCo ector v2f;
// Project position into screen ace
// and pa through texture coordinate
v2f.projCoord = mul(modelViewProj, float4(a2v.objCoord, 1));
v2f.texCoord = float3(a2v.texCoord, 1);
// Tra form the eye vector into tangent ace.
// Adjust the slope in tangent ace based on bump depth
float3 eyeVec = eyeCoord - a2v.objCoord;
float3 tanEyeVec;
tanEyeVec.x = dot(a2v.objTangent, eyeVec);
tanEyeVec.y = dot(a2v.objBinormal, eyeVec);
tanEyeVec.z = -invBumpDepth * dot(a2v.objNormal, eyeVec);
v2f.tanEyeVec = tanEyeVec;
// Tra form the light vector into tangent ace.
// We will use this later for tangent- ace normal ma ing
float3 lightVec = lightCoord - a2v.objCoord;
float3 tanLightVec;
tanLightVec.x = dot(a2v.objTangent, lightVec);
tanLightVec.y = dot(a2v.objBinormal, lightVec);
tanLightVec.z = dot(a2v.objNormal, lightVec);
v2f.tanLightVec = tanLightVec;
return v2f;
现在可以开始我们的光线迭代过程了。开始查询距离映射,得到一个与表面不相交的保守的距离估计,我们可以沿着光线向前。然后,我们可以使用那个距离使我们当前的位置向前来得到表面外的另一个点。我们可以以这种方式继续下去生成汇聚在位移表面的一系列的点。最后,一旦我们得到交点的纹理坐标,我们在切空间计算法向映射的照明。Listing 8-2显示了片断着色。
Listing 8-2. The Fragment Shader
f2fCo ector distanceFragment(v2fCo ector v2f,
uniform sampler2D colorTex,
uniform sampler2D normalTex,
uniform sampler3D distanceTex,
uniform float3 normalizationFactor)
f2fCo ector f2f;
// Normalize the offset vector in texture ace.
// The normalization factor e ures we are normalized with re ect
// to a distance which is defined in terms of pixels.
float3 offset = normalize(v2f.tanEyeVec);
offset *= normalizationFactor;
float3 texCoord = v2f.texCoord;
// March a ray
for (int i = 0; i NUM_ITERATIONS; i++) {
float distance = f1tex3D(distanceTex, texCoord);
texCoord += distance * offset;
// Compute derivatives of u erturbed texcoords.
// This is because the offset texcoords will have discontinuities
// which lead to incorrect filtering.
float2 dx = ddx(v2f.texCoord.xy);
float2 dy = ddy(v2f.texCoord.xy);
// Do bump-ma ed lighting in tangent ace.
// ‘normalTex’ stores tangent- ace normals rema ed
// into the range [0, 1].
float3 tanNormal = 2 * f3tex2D(normalTex, texCoord.xy, dx, dy) - 1;
float3 tanLightVec = normalize(v2f.tanLightVec);
float diffuse = dot(tanNormal, tanLightVec);
// Multiply diffuse lighting by texture color
f2f.COL.rgb = diffuse * f3tex2D(colorTex, texCoord.xy, dx, dy);
f2f.COL.a = 1;
return f2f;
8.5.3过滤的说明
当采样纹理时,我们必须注意怎样指定纹理查找的派生(derivatives),通常,位移纹理坐标是不连续的(例如:由于sectio of the texture that are occluded)当分级细化纹理(mipma ing)或者各向异性的过滤打开的时候,GPU需要纹理坐标的派生信息。因为GPU近似的从有限的微分派生,派生在间断处会有不正确的值。这导致不正确的分级细化纹理层次的选择,反过来导致在不连续处可见的接缝。
不使用位移纹理映射坐标的派生,我们使用基本纹理坐标来代替派生。因为位移纹理坐标始终是连续的,所以这是可行的,它们在基本纹理坐标的相同比率上近似的有所不同。因为我们没有使用GPU的机制来决定分级细化纹理层次,可能会产生纹理的走样。在实际中,这并不是个大问题,因为基本纹理坐标的派生是位移纹理坐标的派生的很好的近似。
注意关于分级细化纹理层次的相同的参数同样被应用在距离映射的查找中。因为纹理坐标在特征边缘的周围可能是不连续的,纹理单元可能会访问能过于粗糙的分级细化纹理层次。这反过来导致不正确的距离值。我们的解决办法是不使用分级细化纹理,线性的过滤距离映射。因为距离映射的值不会直接的显示,这里就不会产生缺少分级细化纹理的走样。
8.6 结论
我们使用OpenGL,Cg 和Sh (http://www.li h.org)实现了距离映射算法。本章中的图片是使用Sh的实现创建的,在附带的CD中提供。因为依赖大量的纹理读取和使用派生指令,这个实现只在GeForce FX 和GeForce 6系列的GPUs上可以工作。
本章的所有例子中,我们使用一个大小为256×256×16的3D纹理,但是这个选择是高度数据相关的。我们同样在一个512×512×32大小的映射上试验更复杂的数据集。在我们的例子中,设定NUM_ITERATIONS的值为16次迭代。在大多数情况下,这是足够的了,使用8次迭代就可以满足光滑的数据集。
我们的片断着色程序,假定16次迭代,为GeForce FX编译48条指令。每次循环迭代有两条指令:一条纹理查找,跟随着一条多重加法。GeForce FX 和GeForce 6系列的GPUs上可以在一个时钟周期内执行这两条指令,意味着每次迭代只占用一个时钟周期。应该注意的是每次纹理查找依赖于前一次;在有限制的纹理操作的GPUs上,这个shader需要被拆成多遍(multiple pa es)执行。
我们在GeForce FX 5950 Ultra 和GeForce 6800 GT上使用不同的数据集测试了我们的距离映射的实现。在图8-6所示的数据集上,在GeForce FX 5950 Ultra,我们可以渲染1024×768分辨率的照明近似的在每秒30帧。如果我们把迭代次数减少到8,我们在相同的分辨率下大约得到每秒75帧。在GeForce 6800 GT上,甚至使用16次迭代,照明1280×1024分辨率像素,我们可以恒定的运行在每秒70帧。
8.7 Conclusion
8.7 结论
我们已经介绍了距离映射,一个基于隐式表面的光线跟踪的位移映射的快速迭代的技术。我们展示了距离函数包含的内容,使得我们在光线与表面很远时采用较大的步幅,而不会大到以至于在渲染的集合体上产生缝隙的程度。实现的结果是非常高效的;它包含了少数的迭代,并且每次迭代仅仅花费GeForce FX 和GeForce 6系列的GPUs上的一个时钟周期。
将来,我们将使用Shader Model 3 GPUs的动态分支的能力来提高我们的技术的性能,对像素使用“early outs”使得会聚更快。这使得我们增加技术的质量,关注于更强的像素的计算能力…
我们也十分愿意使我们的技术适合于曲面。虽然我们的算法可以被使用在任何代有适当的切向量的模型中,但是可能会在高度弯曲的区域导致扭曲变形。在实际中,通常的位移映射(Wang et al. 2004)使用一类四面体的投影来考虑曲面,而且这个方法同要可以被应用到我们的算法中。这种四面体投影可以在顶点着色中完成(Wylie et al. 2002)。
8.8 References
Cook, Robert L. 1984. “Shade Trees.” In Computer Graphics (Proceedings of SIGGRAPH84) 18(3), . 223–231.
Daniel on, Per-Erik. 1980. “Euclidean Distance Ma ing.” Computer Graphics and Image Proce ing 14, . 227–248.
Hart, John C. 1996. “Sphere Tracing: A Geometric Method for the Antialiased Ray Tracing of Implicit Surfaces.” The Visual Computer 12(10), . 527–545.
Kaneko, Tomomichi, Toshiyuki Takahei, Masahiko Inami, Naoki Kawakami, Yasuyuki Yanagida, Taro Maeda, and Susumu Tachi. 2001. “Detailed Shape Representation with Parallax Ma ing.” In Proceedings of the ICAT 2001 (The 11th International Conference on Artificial Reality and Telexistence), Tokyo, December 2001, . 205–208.
Policarpo, Fabio. 2004. “Relief Ma ing in a Pixel Shader Using Binary Search.”
http://www.paralelo.com.br/arquivos/ReliefMa ing.pdf
Wang, Lifeng, Xi Wang, Xin Tong, Stephen Lin, Shimin Hu, Baining Guo, and Heung-Yeung Shum. 2003. “View-Dependent Di lacement Ma ing.” ACM Tra actio on Graphics (Proceedings of SIGGRAPH 2003) 22(3), . 334–339.
Wang, Xi, Xin Tong, Stephen Lin, Shimin Hu, Baining Guo, and Heung-Yeung Shum.2004. “Generalized Di lacement Ma .” In Eurographics Symposium on Rendering 2004, . 227–234.
Wylie, Brian, Ke eth Moreland, Lee A Fisk, and Patricia Cro o. 2002. “Tetrahedral Projection Using Vertex Shaders.” In Proceedings of IEEE Volume Visualization and Graphics Symposium 2002, October 2002, . 7–12. Special thanks to Stefanus Du Toit for his help implementing the distance tra form and writing the Sh implementation.
( Mon, 10 Dec 2007 10:02:32 +0800 )
Description:
最近在研究水面渲染,眼看马上要毕业交论文了,还什么都没有弄,大意了~~~。Te endorf 2001发表的那篇论文真是影响深远,无论FFT还是顶点纹理的实现方法,本质上都是波纹叠加。简单对比了两种实现的demo,顶点纹理的实现CPU占用率确实很少,用任务管理器看大概就30%左右,而FFT的demo只要一开就是100%。不过顶点纹理只有GeForce 6以上的显卡能跑,而且ATI的卡似乎不支持顶点纹理,应该算是它最大的局限性。另外,对LOD的实现来说,也是方法多多,看了几篇论文,实现都不一样,还在研究中-_-#。 这段时间慢慢把看的文章都翻译整理出来,下面这篇是《GPU Gems 2》中的第18章,讨论了如何使用顶点纹理置换来渲染水面。个人觉得这篇文章讲的不太细致,而且很多问题,比如如何表现水面的深浅、纹理映射,都没有讲,对于法线生成的方法也只是大概提了一下。当然,总的来说,还是值得一看的,特别是文中使用了一种特别的LOD处理,比较有趣。
Using Vertex Texture Di lacement for Realistic Water Rendering(上) 此教程版权归我所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。
由于本人水平有限,难免出错,不清楚的地方请大家以原著为准。也欢迎大家和我多多交流。
翻译:clayman
Blog:http://blog.csdn.net/soilwork 水面在计算机图形学,特别是游戏中,是一种常见的效果。它是增加场景真实性的重要元素之一。但要模拟真实的水面,却是一个难题,因为水面的运动和光学效果都相当复杂。这篇文章描述了游戏Pacific Fighters中,用来渲染水面的技术。 支持DirectX Shader Model 3.0的硬件提供了许多相当有用的特性,可以用来帮助渲染水面。下面,我们就将讨论如何使用顶点纹理(Vertex Texture)来渲染真实的水面。此外,我们还使用了braching技术来提高渲染效率。
最终的结果,左图使用了di lacement ma ing,右图则没有
1.1水体模型
对水面动画和渲染来说,已经发展出多种方法。其中,最出名也是效果最真实的,就是基于流体动力学和快速傅立叶的方法(FFTs)(比如Te endorf 2001中描述的)。这些方法可以提供非常真实的渲染效果,但不幸的是他们需要相当大的计算量,因此,不适合于交互式的实时渲染。
此外,现在大多数游戏使用的都是相当简单的模型,大部分方法仅仅是通过改变水面法线创建水面效果。使用这些方法渲染水面,虽然相当高效,但真实度很低,而且并没有真正在水面产生任何波纹。
因此,我需要一种综合了两种方法优点的技术来渲染水面。
1.2 实现 我们的实现中,水面渲染将依赖于法线图(normal map)来进行光照计算。因为法线图可以忠实的重现高频率波形下的所有细节。此外,使用低频率、高振幅的波对水面网格进行扰动。
1.2.1 水面模型 我们的水面模型基于多张,在空间和时间上都进行了分割(tiled)的高度图(height map)的重叠。每张纹理都代表了频谱( ectrum)中的一个“谐波(harmonic)”或者“倍频程(octave)”,和那些使用FFT的方法一样,将把这些纹理叠加到一起。这些纹理就是高度图,每个像素元代表了对应位置的水平高度。 对于艺术家来说,创建高度图是很简单的:创建它们就和绘制一张简单的灰度图一样。使用高度图,艺术家只需分别绘制单个波纹的形状,就可以可以很容易的控制水面动画。把高度图当作顶点纹理来使用也是很方便的:使用它来置换(di lace)顶点的垂直位置是很有效的。
一张用来置换水面位置的高度图 使用不同的空间和时间缩放比例,混合多张高度图,我们可以获得相当复杂的水面动画效果: 为了实现真实可信的水面,应该合理的选择参数A、B和i的值,以最小化波纹的重复效果。对于Pacific Fighters来说,我们混合了4张高度图来进行光照计算,其中比例尺较大的两张还将用作置换贴图。这样,我们可以模拟比例尺从10cm到40km大小的水面。
1.2.2实现细节 可以把所有需要进行的运算分为两类:几何体置换计算和光照计算。因为水面镶嵌(te ellated)良好,因此,可以把光照计算放到片断(fragment)程序中,而把置换映射放到顶点程序里。当然,把光照计算放到顶点处理阶段也是可以的,特别是对于远处的顶点来说。 在写这篇文章时,唯一支持顶点纹理的硬件就是GeForce 6系列以及最新的Quadro FX GPU。在这些硬件上,使用顶点纹理有一些特别的限制,只能使用32bit的浮点纹理,只能使用nearest filtering。
1.2.3采样高度图 我们的实现中,对高度图中的每个顶点进行采样,在顶点程序中计算置换值。对于采样来说,使用了一个放射状的网格,它的中心位于摄像机所在位置。按照这个样子镶嵌的网格,可以让靠近观察者的地方提供更多细节。
下面的公式说明了如何计算放射网格中的顶点位置:
这里i = [ 0….N-1], j = [ 0…..M-1]。我们选择
r0 = a0 = 10cm
rN-1 = a0 + a1( N – 1)4 = 40km 这种基于距离的镶嵌,提供了一种相当简洁的LOD方法。当然,这里也可以使用其他的地形渲染算法来实现LOD,比如ROAM或者SOAR,但这就需要占用一定的CPU资源进行计算,这完全违背了使用顶点纹理的初衷。 下面的代码显示了如何在vertex shader中,使用放射形网格对一张高度图进行采样:
float4 main(float4 position: POSITION, uniform sampler2D tex0, uniform float4x4 ModelViewProj, uniform float4 DMParameters, // di lacement map parameters uniform float4 VOFs) :POSITION
{ //read vertex packed as (cos(),sin(),j) float4 INP = positio //tra form to radial grid vertex INP.xy = INP.xy * (pow(INP.z,4) * VOFs.z); //find di lacement map texture coordinates //VOFs.xy ,DMParameters.x - height texture offset and scale float2 t = (INP.sy + VOFs.xy) * DMParameters.x; //fetch di lacement value form texture (lod 0) float vDi = tex2d(tex0, t).x; //scale fetched value form 0...1 //DMParameters.y - water level //DMParameters.z - wavy amplitude INP.z = DMParameters.y + (vDi - 0.5) * DMParameters.z; //di lace current position with water height and project it return mul(ModelViewProj,INP);
} 1.2.4质量改进和优化 Packing Heights for Bilinear Filtering 顶点纹理拾取(fetch)是相当耗费资源的操作。在GeForce 6系列的硬件上,可以在顶点程序中引入一个顶点纹理拾取器。我们必须最小化在顶点程序中进行纹理拾取的次数。此外,对纹理中的值进行过滤(filtering)也是必须的,否则视觉效果将会大打折扣。 一般来说,最常见的过滤方法就是双线性过滤和三线性过滤。双线性过滤将对最靠近纹理选取坐标位置处的四个像素元(texels)进行均值计算。三线性过滤则需要对邻近mip层次中的双线性过滤结果进行均值计算,同时根据不同的LOD层次选择每个层次的混合权重。 由于当前的图形卡无法对顶点纹理中的值进行任何形式的过滤,我们不得不在shader中直接使用数学运算指令来模拟过滤。对于不好的实现来说,即使是最简单的双线性过滤也需要通过通过四次纹理查找来计算一个过滤值,而三线过滤的查找次数更是翻了两倍。 为了减少过滤时的纹理拾取次数,我们用一种特殊的方法来创建纹理,让一个像素元就包含了一次双线性纹理查找所需要的所有数据。这是一个相当可行的方法,因为高度图本质上就是一张单通道(one-component)的纹理,我们可以把4张高度图打包为一张每个像素元四通道的纹理: 这里i = [ 0….N-1], j = [ 0…..M-1]。H表示高度图的值,F是过滤函数,A则是打包好的输出纹理。 下面的代码实现了对顶点纹理进行双线性查找
float tex2D_bilinear4x(uniform sampler2D tex, float4 t, float2 Scales)
{ float size = Scales.x; float scale = Scales.y; float4 tAB0 = tex2Dbisa(tex, t); float2 f = frac(t.xy * size) float3 tAB = lerp(tAB0.xy, tAB0.yw, f.x); return lerp(tAB.x, tAB.y, f.y);
} 我们可以把这个方法扩展为三线性过滤。因为三线性过滤需要局部LOD的值,因此,我们把顶点到摄像机的距离作为LOD的近似值。下面的代码实现了对打包之后的顶点纹理进行三线性查找:
float tex2D_trilinear(uniform sampler2D tex float4 t, float4 Scales)
{ float fr = frac(t.z); t.z -= fr; // floor(r.zw) float Re if(fr 0.30) Res = tex2D_bilinear4x ( tex, t.xyzz, Scales); else if (fr 0.70) Res = tex2Dbilinear4x(tex, t.xyzz + float4(0,0,1,1), Scales * float2(0.5,2); else { Res = tex2D_bilinear4x(tex, t.xyzz, Scales); float Res1 = tex2D_bilinear4x(tex, t.xyzz + float4(0,0,1,1), Scales * float2(0.5,2)); fr = saturate ( ( fr – 0.30) * ( 1 / ( 0.70 – 0.30))); Res = Res1 * fr + Res * (-fr) } return Re } 注意,这里我们进一步对三线性纹理选取进行了优化,只对影响较大的两个mip层次区域进行纹理查找。对其他区域来说,直接把他们的LOD值设置为最相邻mip层次的值,从而节约纹理带宽。(未完待续ing~~~)
Using Vertex Texture Di lacement for Realistic Water Rendering(下)
作者: Yuri Kryachko
本文版权归原作者所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。
由于本人水平有限,难免出错,不清楚的地方请大家以原著为准。也欢迎大家和我多多交流。
翻译:clayman
Blog:http://blog.csdn.net/soilwork
使用Branching避免不需要的计算 即使优化了纹理拾取方式,渲染水面时的纹理拾取次数还是很高,将严重影响性能。虽然我们能减少需要渲染的顶点数量,但这会影响视觉效果,并且带来锯齿。 由于我们渲染了大片的水面,因此有些三角形有可能一直延伸到了屏幕之外。但即使是这些三角形,顶点程序仍然对他们进行了渲染,浪费了宝贵的计算资源。如果我们渲染时跳过那些摄像机视见体(frustum)之外的三角形,则可以节省许多计算量。 由于顶点程序同一时刻只能处理一个顶点,无法访问拓扑信息,因此,我们只能在顶点层次进行优化,而无法在三角形层次优化。虽然,当三角形中的某些顶点被挑过了,而其他顶点没有时,可能出会一些问题。但是在实践中,我们发现,如果三角形以及顶点纹理置换的位置足够小时,这种效果就不太明显。 下面的伪代码描述了这个思想:
float4 ClipPos = mul ( ModelViewProj, INP)
float3 b0 = a (ClipPos.xyz) (ClipPos.www * C0 + C 1) if ( all (b0))
{ // vertex belongs to visible triangle, //perform texture sampling and di lace vertex accordingly
} 这段伪代码里,我们使用裁减空间的顶点纹理来判断当前顶点是否在视见体之内,之后,对于所需要的顶点,再进行余下复杂的计算操作。 这里C0和C1是特殊的裁减常量,控制了三角形延伸出摄像机视见体多少距离将会触发裁减。这样,就能避免由于裁减了那些顶点在视见体外,但三角形还在视见体内的顶点,而导致的问题。出于效率的考虑,我们的“裁剪”视见体只需比摄像机视见体稍微宽一点就可以了,以保证延屏幕边缘有一定的“安全区域(guard-band)”。因为我们的水体表面镶嵌良好,同时顶点纹理置换也很合理,所以这个简单的方法在实践中效果很好。 使用渲染到纹理(Using Render-to-Texture) 可以先使用一个单独的pa ,把多张高度图混合为一张浮点纹理,从而进一步提高程序的速度。这样就不必在vertex shader中多次执行昂贵的拾取操作。此外,使用高度压缩的16-bit浮点纹理格式储存原来的高度图。另外,使用3D纹理,我们还可以储存一系列的高度图动画序列帧(a sequence of animated height ma ),让水面动画更加平滑。 使用这种优化,需要把渲染循环分为两个pa :
1. 用一个单独的pixel shader把多张高度图混合为一张32-bit的浮点纹理。这张纹理中的象素元对应了放射状mesh中的顶点。
2. 使用前面描述的方法,置换顶点位置。 Back Sides of Waves 由于在pixar shader中进行的光照计算假设水面是平坦(flat),因此在某些特定的情况下,这种近似会导致一些问题。 如下图所示,即使背对着观察者的波纹,也会被看到,而实际上,这些波应该是不可见的。这种效果将会对波峰较亮部分产生影响。 为了减轻这种效果,需要对用于光照计算的法线进行调整,让它朝观察者的方向“倾斜(tileing)”一点,这样,他们就会靠近波纹的前面。可以在源码中找到具体代码。以下是使用本章所介绍的技术,渲染的一张水面效果图。 1.2.5渲染局部波纹扰动(Rendering Local Perturbatio ) 有时候,需要渲染由于物体漂浮或者落入水中,所引起的局部波纹扰动。特别是对游戏来说,这是很有用的,我们通常需要产生爆炸效果,船航行时的轨迹,等等。对基于高度图的水面模型来说,很难引入物理上正确的扰动实现方法,我们将讨论一种简单的方法。 形变模型分析(Analytical Deformation Model) 实现局部波纹的扰动,最简单的方法就是根据分析结果,再次改变置换之后的顶点位置,在vertex shader中把重新计算的顶点位置和置换之后的位置进行加和。例如,对于爆炸效果来说,可以使用以下公式: 这里,r表示水平面上的点到爆炸中心的距离,b是抽样常量(decimation co tant)。I0、w和k的值则根据给定的爆炸参数来确定。 至于渲染,同样可以使用前面渲染水面时,所用的放射状网格,但网格的中心必须是爆炸点。 动态置换贴图(Dynamic Di lacement Ma ing) 另一种选择是,把局部产生的偏移值直接渲染到顶点纹理中,实际上就是在GPU上实现通用编程(general-purose programming on the GPU)(GPGPU)的方法。使用这种方法,先在第一个pa 中产生一张顶点纹理,随后的pa 中用它来进行实际渲染。对高度图进行过滤,在pixel shader中,再把所有波形加和到一起,可以大大减少vertex shader的工作量。 为了计算偏移值,可以使用上面提到的分析模型,也可以使用一钟细胞自动机(cellular-automata)的方法,逐帧展开(evolving)局部偏移。沿着一定的方向对纹理进行模糊处理,还可以实现风吹过水面的效果。 但是,对于大小为1km,分辨率为50cm的水面来说,意味着纹理尺寸为2048x2048,这将给纹理内存和shader的执行速度都带来极大压力。此外,想要快速改变观察点也很成问题。 然而,我们仍然鼓励读者去尝试一下这些方法。 泡沫生成(Foam Generation) 在波涛汹涌的水面上,我们可以生成一些泡沫来进一步增加真实感。最简单的方法就是对于高度超过值H0的顶点,使用一张预处理过的泡沫纹理进行混合。根据以下公式来计算泡沫的透明度: Hmax表示可能出现泡沫的最高位置,H0为基准高度,H表示当前高度。 泡沫纹理可以是动态的,以表现泡沫的生成和消失。这些动画纹理序列可以由艺术家手动创建,也可以用纹理生成。 1.3 结论 略
( Mon, 10 Dec 2007 10:01:18 +0800 )
Description:
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
1) 并行设备的硬件寄存器(如:状态寄存器)
2) 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3) 多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。搞嵌入式的家伙们经常同硬件、中断、RTOS等等打交道,所有这些都要求用到volatile变量。不懂得volatile的内容将会带来灾难。假设被面试者正确地回答了这是问题(嗯,怀疑是否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。
1)一个参数既可以是co t还可以是volatile吗?解释为什么。
2); 一个指针可以是volatile 吗?解释为什么。
3); 下面的函数有什么错误:
int square(volatile int *ptr)
return *ptr * *ptr;
下面是***:
1)是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是co t因为程序不应该试图去修改它。
2); 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
3) 这段代码有点变态。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)
int a, a = *ptr;
b = *ptr;
return a * }
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
a = *ptr;
return a * a;
( Mon, 10 Dec 2007 10:00:29 +0800 )
Description:
c++中的explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有"显式"那么必然就有"隐式",那么什么是显示而什么又是隐式的呢?
如果c++类的构造函数有一个参数,那么在编译的时候就会有一个缺省的转换操作:将该构造函数对应数据类型的数据转换为该类对象,如下面所示:
cla MyCla {
public:
MyCla ( int num );
MyCla obj = 10; //ok,convert int to MyCla 在上面的代码中编译器自动将整型转换为MyCla 类对象,实际上等同于下面的操作:
MyCla temp(10);
MyCla obj = tem 上面的所有的操作即是所谓的"隐式转换"。
如果要避免这种自动转换的功能,我们该怎么做呢?嘿嘿这就是关键字explicit的作用了,将类的构造函数声明为"显示",也就是在声明构造函数的时候前面添加上explicit即可,这样就可以防止这种自动的转换操作,如果我们修改上面的MyCla 类的构造函数为显示的,那么下面的代码就不能够编译通过了,如下所示:
cla MyCla {
public:
explicit MyCla ( int num );
( Mon, 10 Dec 2007 09:53:59 +0800 )
Description:
最近在搞这个在MFC框架上显示OGRE渲染, 开发环境是VS2005.
如何嵌入呢,其实不难. 主要是要把MFC主窗口的句柄传给OGRE的渲染系统RenderSystem,并且程序结束时要清理渲染窗口. 1)不再使用OGRE默认的配置窗口来初始化RenderSystem,自己来进行初始化。首先设置配置文件路径,然后轮询可用的RenderSystem。这里使用OpenGL Render System,当然你也可以使用Direct3D9 Render System。 // 和原来一样设置插件、资源路径,对资源进行加载. //设置过后就可以轮讯可用的RenderSystem了 etupResources(); // 指定使用OpenGL Render System渲染子系统
Ogre::RenderSystemList::iterator pRend = mRoot-getAvailableRenderers()-> egin(); while (pRend != mRoot-getAvailableRenderers()-end()) { //////if((*pRend)-getName().find("Direct3D9")) break; Ogre::String rName = (*pRend)-getName(); if (rName == "OpenGL Rendering Su ystem") reak; Rend++; }
Ogre::RenderSystem *rsys = *pRend; // 配置框中的选项需要手动设置。
rsys-> etConfigOption("Colour Depth", "32" ); rsys-> etConfigOption( "Full Screen", "No" ); rsys-> etConfigOption( "VSync", "No" ); rsys-> etConfigOption( "Video Mode", "800 x 600" ); rsys-> etConfigOption( "Di lay Frequency", "60" ); // 起用 mRoot-> etRenderSystem( rsys );
2)剩下的初始化过程和ExampleA lication基本一致,只不过现在不需要由OGRE自动创建窗体,应该将MFC视图的句柄传过去初始化。 // 初始化,传入false表示不需要OGRE自动创建窗口 mRoot-initialise( false ); // 手动创建渲染窗口,在这里我们将MFC视图的句柄传入 NamevaluePairList miscParam miscParams["externalWindowHandle"] = StringConverter::toString( ( ize_t )mWnd ); mWindow = mRoot-createRenderWindow( "View", 640, 480, false, am miscParam ); 到次初始化过程已经完毕,这时候运行程序就得到一个漆黑的MFC窗口。
3)因为现在使用是视图的WndProc,我们必须自己处理更新和触发FrameStart事件. // 触发FrameStart, FrameEnd事件 void update( void ) { mRoot-_fireFrameStarted(); mWindow-update(); mRoot-_fireFrameEnded(); } //在视图的OnDraw时间里,调用update void CMFCRenderView::OnDraw(CDC* /*pDC*/) { CMFCRenderDoc* Doc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) retur // TODO: 在此处为本机数据添加绘制代码 update(); } 这样还不够,WM_PAINT事件并不由我们控制,当窗体静静的趟在那的时候是不会触发的,因此我们通过设置一个timer来模拟没帧的更新, // 20ms触发一次, SetTimer()可以放在OnCreate()或者OnDraw()里面, 只需初始化一次就可以了 SetTimer( 100, 20, 0 ); void CMFCRenderView::OnTimer(UINT IDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 update(); __super::OnTimer(nIDEvent); } *******须注意的地方:
1......初始化可以在OnDraw(CDC* pDC)的第一次执行时候进行,而不能在PreCreateWindow(CREATESTRUCT&am cs) 或者COgreMFCView( )或者OnCreate()这个CView的子类初始化的时候进行因为这个时候,View对应的HWND实际上还没初始化出来呢...
2......Ogre嵌入到MFC里面, 将会导致NEW等操作符的重载冲突, 你必须选择让Ogre或者MFC进行内存管理.
(1) 使用Ogre自己的MemoryManager,并且禁止调用MFC的DEBUG_NEW,这需要先 找到c 中的以下行 #ifdef _DEBUG #define new DEBUG_NEW #endif
并用 #define OGRE_DEBUG_MEMORY_MANAGER 1代替 这样Ogre中会使用自己的new/delete,而不是调用vccrt中的_heap_alloc_debug . (2) 使用MFC. 可以参考
具体设置如下:
i) in the General tab, switch "Use
in a shared DLL" to "Use Standard Windows Libraries"
ii) in the C/C++/Preproce or tab, add _AFXDLL to the preproce or definitio iii) in the Linker/I ut tab, add mfc80d.lib anywhere before OgreMain_d.lib 3.....在实际的编程中,你的view类将会需要重载cwnd类的OnTimer,OnDraw / OnPaint等函数, VS2005里面是没有像VC6.0里面的CLASS WIZZARD,这使得我们在重载的过程中,需要自己手动添加消息映射.
如重载OnTimer类, 这时你的View类里面有该函数 afx_msg void OnTimer(UINT_PTR nIDEvent);
这时你需要在view的c 里面找到
BEGIN_MESSAGE_MAP(COgreMfcView, CView) // 标准打印命令 ON_WM_TIMER() ON_COMMAND(ID_FILE_PRINT, &am CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, &am CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, &am CView::OnFilePrintPreview)
END_MESSAGE_MAP()
并且添加ON_WM_TIMER(), 这时你的定时器函数才会响应,被调用到.
4......ROOT根对象的删除须在你的wina 里面, 如果你在view类的ondestroy()里面删除根对象,或者在析构函数里面删除它, 这对导致你在关闭程序后,弹出错误. 其原因可能是由于删除root的时机不对! 就说这么多了, 想到再补充! (上面内容是通过本人总结以及网上牛人的文章而写的)

参考资料

 

随机推荐