|
|
May 29 装了gb 2.2 之后又安装了 gb2.3 而启动2.3 的场景编辑器之后 2.2 就不能启动了。因为这两个程序用的配置文件放入了相同的目录,并且有相同的名字,这样2.2 加载时发现版本不对,就会启动失败。 删除文件 C:\Documents and Settings\你的用户名\Local Settings\Application Data\Emergent Game Technologies\Gamebryo Scene Designer\tool.settings C:\Documents and Settings\All users\Local Settings\Application Data\Emergent Game Technologies\Gamebryo Scene Designer\tool.settings
开始还以为是.net 框架打补丁影响了。一通狂卸载、最后vc2005、office 2007 都卸掉了,熬到了3点。看来得补习c#了。如果能熟练应用它,调试一下就可以更早发现这个问题 May 21 BOOL IsDebuggerPresent() { _asm { mov eax, dword ptr fs:[0x18] mov eax,[eax+0x30] movzx eax,byte ptr[eax+0x2] } } May 20 转载请注明出处 http://topameng.spaces.live.com 通过坐标变换将3D空间的图元转换成2D图元的过程:主要为世界变换->视图变换->投影变换->视口变换 3D场景中的任何物体,都是由一个一个三角形组成的。而三角形位置信息的就是其各个顶点的三维坐标。这是用来在模型中存储的,而要把物体显示在屏幕上,还需要将它们转换成显示器上的二维坐标。这就需要对每个点实施一套 3D to 2D 的转换公式,在Direct3D中叫做“几何流水线”(Geometry Pipeline)。 一般创建的mesh处于自己的局部坐标系。基本是屏幕正中放置。 世界矩阵:而游戏需要先放入世界坐标系。世界坐标系主要3大功能:平移、旋转、缩放 平移: D3DXMatrixTranslation() 位于矩阵第四行 1 0 0 0 0 1 0 0 0 0 1 0 Tx Ty Tz 1
旋转: D3DXMatrixRotationX() 延 x 轴旋转 1 0 0 0 0 cos sin 0 0 -sin cos 0 0 0 0 1 D3DXMatrixRotationY() 延 y 轴旋转 cos 0 -sin 0 0 1 0 0 sin 0 cos 0 0 0 0 1 D3DXMatrixRotationZ() 延 z 轴旋转 cos sin 0 0 -sin cos 0 0 0 0 1 0 0 0 0 1 缩放: D3DXMatrixScaling
顺序如先旋转R在缩放S 则矩阵为 R*S 。对于行向量(dx默认为行向量)复合矩阵视觉效果为从左到右的顺序各单独矩阵效果的组合。对于列向量则相反: 复合矩阵应为 S * R.视觉效果从右到左(这是opengl 采用的)
观察矩阵:函数 D3DXMatrixLookAtLH() 不要被这个函数吓倒。其实观察矩阵作用和世界矩阵差不多,只是起到旋转、平移的作用。而且是把世界坐标系的物体映射到观察坐标系。只要用摄像机当前世界变换矩阵的逆就好了 矩阵基本组成 M = T*Rz*Ry*Rz 。 T 平移。 Rz 延z旋转。Ry 延Y旋转 Rx 延X轴旋转 实际上可以先获得摄像机的世界坐标 p,和摄像机坐标系轴在世界坐标中的矢量D(看向),U(上),R(右)。然后要把世界坐标的摄像机位置点换算到摄像机局部坐标系中。 (-D * p, - U * p, - R * p) 计算-p 在(D,U,R)矢量上的投影转换为p1. Dx, Ux, Rx, 0 Dy, Uy, Ry, 0 Dz, Uz, Rz, 0 p1x,p1yp1z, 1 对于D,U,R 其实就是摄像机的世界坐标旋转变换的逆矩阵。如下: Dx,Dy,Dz Ux,Uy,Uz Rx,Ry,Rz 旋转矩阵(还有镜像矩阵)为正交矩阵(参考3D数学基础中的矩阵正交化章节)。对于一个正交矩阵他的逆矩阵等于转置矩阵
这些不会影响mesh 的顶点和法线关系 使用shader时。如计算顶点和法线的点积,没必要映射到观察坐标系.在 direct3d 游戏编程基础的 shader 章节里。顶点法线和光线矢量都映射到了视图空间。其实是没有必要的
而世界变化和观察变换是可以和到一起组成世界-视图变换矩阵
投影变换:把3d 投影到2d平面。(似乎说映射[-1,-1,0(opengl 为-1)] 到[1,1,1]的立方体更好一些。但透视投影相当于3D变换成2D,近大远小的变换就在这个时刻)分为透视投影和正交投影。正交投影不会随物体远近影响物体投影的大小。而透视则z值影响,物体越远成像越小。 投影变换涉及缩放和平移操作。对于正交投影矩阵缩放和z值无关。对于透视投影缩放和z值相关。 对于dx 左手坐标系函数如下: 正交投影函数: D3DXMatrixOrthoLH() 这个是以屏幕中心为坐标原点的。 如果设置2d坐标系。 可以考虑使用 D3DXMatrixOrthoOffCenterLH 函数 D3DXMatrixOrthoOffCenterLH(&m_matProj,0,(float)m_iWidth,(float)m_iHeight,0,0.0f,1.0f); 这样左上角为坐标(0,0). 右下角为(width,height) 透视投影: D3DXMatrixPerspectiveFovLH() 对于Opengl经过投影变换x,y,z映射到范围[-1,1]. x,y 还保持原来的符号。对于z 最远面 f 映射为1,最近面 n 映射为 -1. 但directx z 值略有差异。z 映射范围为[0,1]。最远面映射为1。最近面映射为0. 对于z值都是以 1/z 映射到 [0,1]或者[-1,1] 范围。因为一般要求近处z值判断要精细一些。而远处精度要小一些。所以用1/z来判断更好。 一个dx 投影矩阵如下: w,h 为 zn 面的宽度和高度。zn 近表面距离。zf 为远表面。 2*zn/w 0 0 0
0 2*zn/h 0 0
0 0 zf/(zf-zn) 1
0 0 zn*zf/(zn-zf) 0
其次坐标一个点p(px,py,pz,1) 经过这个变化成为(x'pz,y'pz,z'pz,pz)
dx 一直透视投影函数一直默认了中心点为[0,0] (摄像机坐标x,y). 如果视景截头体不以[0,0]为中心则需要自己生成投影矩阵。 如对于zn平面,左l 右 r 上 t 下 b.这样 w = r - l h = t - b .建立的非对称投影矩阵如下(相对于dx左手坐标,对于opengl略有不同) 2*zn/r-l 0 0 0
0 2*zn/t-b 0 0
r+l/r-l t+b/t-b zf/(zf-zn) 1
0 0 zn*zf/(zn-zf) 0
dx 采用的是行向量,对于一个矢量 v 变换相当于 v * T. 而不是 T * v opengl 采用的是列向量, 对于矢量变化为 T * v
左手坐标系和右手坐标系平移、缩放矩阵是相同的。 对于旋转矩阵,输入角度时有变化: 从轴的负端向正端看,左手坐标系 逆时针为正方向。即逆时针延z旋转旋转30 度。输入正数30 到旋转矩阵. 而右手坐标系相反,逆时针为负方向。即逆时针延z旋转30度。输入-30 到旋转矩阵
用U0 U1 U2 表示变换矩阵, 对于矩阵 R(U0 | U1 | U2) 对于右手坐标 U0 = U1 X U2 U1 = U2 X U0 U2 = U0 X U1 对于左手坐标 U0 = U2 X U1 U1 = U0 X U2 U2 = U1 X U0
而有些系统如gamebryo 采用右手坐标系,但是Gamebryo矩阵旋转方向和默认右手坐标系相反,我日。gb 延旋转轴顺时针为正。好处换成左手不用修改矩阵了。
尽管有这些左右顺序问题。 但很多放在内存中矩阵结构是一样的。这是为了方便使用intel SSE加速指令。 dx 矩阵存放结构 struct { float _11, _12, _13, _14; float _21, _22, _23, _24; float _31, _32, _33, _34; float _41, _42, _43, _44; };
quake3 对于ui,客户端执行渲染命令都是先写入rendercmd列表: backEndData[tr.smpFrame]->commands 等全部写入完毕后 从这个列表获得渲染数据 把顶点、颜色、法线等数据写入本地数据 提交渲染数据 看似多走了几步,浪费效率。 1 写入渲染列表可以使图形渲染和客户端,UI分开。这样测试各个模块效率才能更准确。 2 统一提交顶点颜色法线等数据能够提高效率,减少和显卡通信次数 3 封装性更强,把渲染细节同UI客户端分离. 缺点: 难于调试,因为先填充列表而没有直接draw.难于拦截draw特定图像或者mesh的位置。
可以在游戏引擎完善时加入这个特性。 May 14 出现Incorrect version of Direct3D and/or D3DX 错误 在nvidia 使用的dxut.lib 中有针对dx编译版本与运行版本的比较。 D3DXCheckVersion(D3D_SDK_VERSION, D3DX_SDK_VERSION) 只需要重新编译LIBS\src\DXUT工程即可 May 13 最早的概念差不多来自ID吧,quake.exe 就是引擎。而客户端只是玩法逻辑部分,现在随着时代发展似乎在悄悄的变化。很多引擎现在只提供库,并没有winmain函数。而很多人认为winmain属于客户端的范畴。 winmain所在的项目可以起一个Fade的概念。q3 是这样,renderer 功能是图形lib, quake3 工程导出了renderer 和 quake3 工程中的资源管理部分函数,给其他工程使用,这样减少了耦合,UI、renderer 和 game 工程都只和quake3工程单线联系。这似乎比客户端概念多了点东西 想到把这个概念引入到后面项目中。 领导认为这样会导致大量重复代码? 如果需求多导出接口会过多. 当时没仔细想,毕竟工程没有开始,这方面不好意思跟领导吹牛。 想想quake3 的导出函数也不是很多,很多图形相关的主要就2个函数:如shader registershader () drawshader() (不是q3函数,类似名字) 模型和场景类也差不多。 而shader非常复杂。接口却很少,其实很简单,那就是配置文件,注册的名字在配置文件中,而配置文件描述了这个名字对应的shader的各个技术特性,如果这些特性也导出函数接口,将是非常复杂的工程。 看来开放mod是非常有好处的。要考虑给各个档次的人使用。 相关的图形导出函数简直少的可怜(10,20还是30,懒得数了所有接口的也就100左右,还包含众多资源函数控制台cvar,甚至ping之类的),却能实现异常复杂的功能。 尽管q3引擎已经落伍了,但看它的代码还是能有非常多的收获的。可惜就是应用太窄了(室内引擎不太适合网络游戏),其实quake完全可是胜任室外,以前光从表面看,有些认知错误
gamebryo 也是建议开发者修改NiApplication.这样的话NiApplication 工程相当与引擎主工程有整个进程起点winmain。而客户端逻辑相对放入dll。 quake3 shader 和 现在d9 的 shader 概念是不太一样的。请勿对号入座 May 09 使用vc2003 编译gamebryo教程时,因为有dx 10 不能通过编译. 在 d3d10.h 中加入:
#pragma warning( disable: 4049 ) /* more than 64k source lines */ //加入这后面的内容 #define __out /**/ #define __in /**/ #define __inout
#define __in_opt /**/ #define __out_opt /**/ #define __inout_opt /**/
#define __in_ecount(THING) /**/ #define __in_ecount_opt(THING) /**/ #define __out_ecount(THING) /**/ #define __out_ecount_opt(THING) /**/ #define __inout_ecount(THING) /**/ #define __inout_ecount_opt(THING) /**/
#define __in_bcount_opt(THING) /**/ #define __out_bcount_opt(THING) /**/ #define __inout_bcount_opt(THING) /**/
#define WINAPI_INLINE WINAPI 或者下载 Windows Server 2003 R2 Platform SDK from March 2006,这个sdk就有点大了
引擎好像没有renderstate 切换管理,搞得用dx debug 调试输出了很多warning,很是不爽(太多了难免影响调试,尽管这个不怎么影响效率),想dx改似乎不太现实。突然想起那句:凡人的智慧啊。还能要求什么,三流的引擎唉!
更正:gamebryo 没有quake3那样的renderstate 切换,但系统还是有一个Renderstate 重复设置相同值的判断设置的,至于debug输出的重复设置,应该是第一次设置的renderstate值和显卡内部默认值相同了。这个应该是resetdevice时设置的。影响不大 May 08 简介 在当今的计算机中,随着电源管理技术越来越普遍地使用,一种用来获得高分辨率时钟的通用方法 —— RDTSC指令可能无法如按预期地工作了①。本文建议使用一种更精确、更可靠的方法 —— QueryPerformanceCounter和QueryPerformanceFrequency两个Winodws API函数。 背景 自从x86 P5指令集引入以来,很多游戏开发者一直在使用RDTSC指令来完成高分辨率计时。对于声音和视频处理来说,Windows多媒体计时器已经足够精确了,但是对于小于等于12毫秒的帧时间,它们无法提供时间增量(delta-time)信息。鉴于RDTSC的局限性, Windows API通过函数QueryPerformanceCounter和QueryPerformanceFrequency揭示了一种更正确的方法来实现这个功能。 这种RDTSC风格的计时方式存在三个基本问题: 使用RDTSC直接默认了线程运行在同一个处理器上。多处理器系统和双核系统不担保每个核间循环计数器的同步。当结合现代电源管理技术时,这个现象会加剧,因为现代电源管理技术会在不同的时间闲置(idle)或恢复(restore)不同的核,这通常会导致各个核失去同步。对于应用程序来说,这通常会引起干扰或潜在的崩溃,因为线程在不同的处理器之间跳动执行,其取得的时间值由于处理器之间的不同步而不同,这要么引起大增量、负增量,要么引起计时中断。 RDTSC使得应用程序请求的计时信息完全依赖于处理器的循环计数器。很多年以来,这是得到高精度计时信息的最佳方法,但是现在新一代的主板贡献了一些计时设备,这些设备能提供高分辨率且没有RDTSC那些缺点的计时信息。 以前总是假设在程序的生命期内,CPU的频率是固定的。然而,有了现代电源管理技术,这成了一个不正确的假设。起初这种技术只用在膝上、移动计算机上,但是现在它正积极地被用到很多高端台式PC上,而且禁止使用它通常是无法让用户接收的。 建议 游戏需要精确的计时信息,但是也需要以某种方式实现计时代码,这种方式必须避免与RDTSC使用相关的问题。在实现高分辨率计时之时,应该采取以下几步: 用QueryPerformanceCounter 和QueryPerformanceFrequency 两个API函数来取代RDTSC 指令。 这些API或许会使用RDTSC,但也可能使用能提供高分辨率计时信息的主板计时芯片或其他一些系统服务来代替。但是,RDTSC比QueryPerformanceCounter快多了,因为后者是一个API调用,尽管如此,QueryPerformanceCounter还是可以在每帧中被调用几百次而没有明显地影响。在每一帧中,游戏应试着尽量少地调用QueryPerformanceCounter来避免性能损失。 在计算增量的时候,增量值应被控制在确保计时误差不会引起崩溃或时间相关计算(time-related computation)的不稳定的程度。控制范围应从0(以防止产生负增量)到某个合理的基于最低期望帧率的值。注意:在调试应用程序的时候,这个控制可能不需要,但是如果在进行性能分析或运行游戏于某些非优化模式中时,必须使用它。 因为QueryPerformanceCounter / QueryPerformanceFrequency两个API是支持多处理器的,所以线程从一个处理器移向另一个的时候,BIOS或主板驱动程序中的Bug可能会导致这些函数返回不同的值。我们建议所有的游戏计时都在单个线程上计算,并且用SetThreadAffinityMask这个Windows API来让该线程始终运行于单个处理器上。通常这个是游戏的主线程。所有其他线程应被设计成不收集和使用它们自己的计时器数据。我们不建议使用“工作线程(worker thread)”来计算计时,因为这会编程同步瓶颈。建议工作线程设计成从主线程读取时间戳。因为工作线程仅读取时间戳,所以没有必要使用临界区了。我们同样不建议让多线程来计算计时并将每个线程与一个特定的处理器关联,因为这将大大降低多核系统的吞吐量。 系统运行时,QueryPerformanceFrequency这个API不会改变频率,所以它只需被调用一次。 应用程序兼容性解决方案 很多游戏开发人员使用对RDTSC的假设很多年了,因此当他们现存的应用程序在多处理器 / 多核系统上运行时,有计时实现方法的原因,很可能会出现问题。这通常表现为小故障或慢动作移动。缺少电源管理意识是没有简单的补救措施的,但是有一种现存的缓解方法,那就是强迫应用程序总是运行在单个处理器上,即使是在多处理器系统中。
微软游戏技术组软件设计工程师 Chuck Walbourn
Beware of QueryPerformanceCounter()
When it comes to high-precision timing on Windows, many have gotten used to using the CPU's time stamp counter (TSC). The time stamp counter is a 64-bit counter that was added to most x86 CPUs starting around the Pentium era, and which counts up at the clock rate of the CPU. The TSC is generally readable via the RDTSC instruction from user mode, making it the fastest, easiest, and most precise time base available on modern machines.
Alas, it is rather unsafe to use.
The first problem you quickly run into is that there is no easy way to accurately and reliably determine the clock speed of the CPU, short of perhaps doing calibration over a longish period of time. Sometimes you don't need super accuracy or only need to deal with timing ratios, in which this doesn't matter. However, you're still screwed when you discover that on CPUs with speed switching, the speed at which the TSC counts will change when the CPU speeds up or slows down, which makes the TSC's rate swing all over the place. And if this weren't enough, the TSC is not always synchronized on dual-core or SMP systems, meaning that the reading from the TSC will jump back and forth by as much as 0.2ms as the kernel moves your thread back and forth across the CPUs. Programs which do not have adequate safety protection may be surprised when time momentarily runs backwards.
For reasons like these, Microsoft now recommends that you use QueryPerformanceCounter() to do high-precision timing. What they don't tell you, though, is that QPC() is equally broken.
The documentation for QueryPerformanceFrequency() says that not all systems have a high-performance counter. Truth be told, I've never seen a system that didn't support QPF/QPC, including ones running Windows 98, NT4, and XP. However, the timer that is used can vary widely between systems. On Win9x systems that I've seen, QPF() returns 1193181 -- which looks suspiciously like the clock rate of the venerable 8253/8254 timer. On a PIII-based Windows 2000 system, I got 3549545, which happens to be the frequency of the NTSC color subcarrier, but is probably just a factor of a common clock crystal used by some chipset timer. And I've also seen the CPU clock speed show up, or CPU clock divided by 3.
Some of these timers used for QPC also have bugs.
When I was looking at some anomalous capture logs from one of my systems, I noticed that the global_clock values from the capture subsystem, which were recorded in the capture log, occasionally jumped forward or backward by a few seconds compared to the video capture clock. (While video capture drivers are notoriously flaky, there were no gaps in the video and I'm pretty sure my PlayStation 2 didn't burp for three seconds.) When I tried Windows XP x64 Edition, the HAL used the CPU TSC for QueryPerformanceCounter() without realizing that Cool & Quiet would cause it to run at half normal speed. And recently, I've had the pleasure of seeing a dual-core system where use of the TSC exposed QPC-based programs to the same CPU-mismatch bug that RDTSC incurred. So, realistically, using QPC() actually exposes you to all of the existing problems of the time stamp counter AND some other bugs.
So, what to do?
I switched VirtualDub's capture subsystem from QueryPerformanceCounter() to timeGetTime(). I had to give up microsecond precision for only millisecond, but it's more reliable. If you don't really need high precision, you can use GetTickCount(), which has terrible precision on Win9x (55ms), but it's reliable, and it's fast, since it just reads a counter in memory. If you're a user suffering from this problem, you can try fixing the problem by adding /usepmtimer to the end of the boot.ini entry, which switches QPC() to use an alternate timer (usual disclaimers apply; back up data before trying; no purchase necessary; void where prohibited). May 07 软考室的烟味弥漫 坐满了程序员 室里面的监考官 系分 已三年 出上午试题的老师 练cpu 耍单片机 硬件功夫最擅长 还会逻辑门三极管 他们学生我习惯 从小就耳濡目染 什么软件跟网络我都耍的有摸有样 什么语言最喜欢 c++面向对象 想要去英伦美帝 学图灵诺伊曼 怎么编 怎么编 离散数学是关键 怎么编 怎么编 数值分析也较难 怎么编 怎么编 数据结构最重要 算法不学莫后悔 死的难看 一段代码写好 一个左子树 右子树 一句不会递归有危险 不停调用 一个优秀的库函 一用好多年 拷贝好带身边 怎么编 怎么编 我学会动态规划 怎么编怎么编 分支限界的难关 怎么编怎么编 已被我一脚踢开 哼 快使用c语言 哼哼哈兮 快使用c语言 哼哼哈兮 编程之人切记 np无敌 是谁在练汇编 背指令集 快使用c语言 哼哼哈兮 快使用c语言 哼哼哈兮 如果我会分治 快速解题 熟用堆栈队列 系统分析 快使用c语言 哼 我用vb描述 哼 万能的回溯法 呵呵,不是科班出身。有些只是听说,寒!老贴了,居然今天才看到。蓦然回首才发现不逛论坛很多年。
推荐一个blog . 这年头写程序员的文章太少了。 http://blog.csdn.net/hitetoshi May 05 用了dx9的多流,在nvida 8600gt 上确实能提高效率,不过不是很明显,高10%多点吧,可能我画的顶点还少,只有900个左右。 在nvida mx400上比没有使用流的差了很多(这个也不是dx9显卡,可能支持的不好),只有1半的fps,不过奇怪的是切换到全屏,fps就差不太多了,还是略低。 在nvida 6200 上窗口模式使用流fps 略低。但全屏时能高10%左右。 奇怪即使窗口不能独占设备,也不能相差这么大啊。 或许多流这个东西到了dx10显卡才被很好的支持吧。 越看越像opengl的机制. opengl1.0 开始的颜色、顶点、法线缓冲区都是分开的。 May 04 函数: //采用32*32像素矩形图片。 //hotx,hoty 为点击的热点,即判断游标是否点中的点。 m_pDevice9->SetCursorProperties(hotx,hoty,surface); m_pDevice9->ShowCursor(TRUE); 检测是否支持: if(m_Caps.CursorCaps & D3DCURSORCAPS_COLOR) { //_T("...支持高分辨率游标400\n") } else if(m_Caps.CursorCaps & D3DCURSORCAPS_LOWRES) { //T("...支持高分辨率游标\n"); } 在dx2006 中不需要调用 SetCursorPosition 函数.dx会自动更新数据 注意事项: 1 传递给SetCursorProperties函数的 LPDIRECT3DSURFACE9 参数必须是 default a8r8b8g8资源 : LPDIRECT3DSURFACE9 surface; m_pDevice9->CreateOffscreenPlainSurface(32,32,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&surface,NULL); 2 当使用dinput鼠标时不能设置独占模式 DISCL_EXCLUSIVE , 否则不能显示游标. 3 不管源图片多大最终是以32*32大小呈现 4 不需要修改 WM_SETCURSOR 消息。return false 就好。只需要在win32 和 dinput控制切换的时候调用 SetCursor(NULL); m_pDevice9->ShowCursor(TRUE); 好处: 当硬件支持高分辨率鼠标时(基本都支持)。鼠标刷新不受图像刷新速度影响,即使你的图形fps<5,游标一样能快速移动。就像windows操作系统即使挂掉了,鼠标还是能移动
|