对象生存周期管理是C++工程最重要一个环节。关于此类问题《游戏编程精粹》(GPG)系列一直有文章在提。比如第三册 1.5 《基于句柄的智能指针》,第四册1.7的《弱引用和空对象》。在GPG4 1.7给出的代码中发现了一些问题。原始代码如果放入实际工程结果会很不美妙。这里提一下

原文对指针的包装做如下处理:

template <class ResourceType> class ResPtr
{

public:

     //一些构造函数

    ResPtr(const ResPtr<ResourceType> & resPtr);
    explicit ResPtr(ResourceType * pRes);
    ResPtr(ResourcePtrHolder * pHolder = NULL);

public:

   //析构
    ~ResPtr();

private:

//用这个中间层封装指针
    ResourcePtrHolder * m_pResHolder;
}

class ResourcePtrHolder
{
public:
    ResourcePtrHolder (IResource * p) : pRes(p) {}
    ~ResourcePtrHolder();

//用户对象指针放这里
    IResource * pRes;
};

 

template <class ResourceType> ResPtr<ResourceType>::ResPtr(ResourceType * pRes)
{
    m_pResHolder = new ResourcePtrHolder(pRes); //封装原生指针时,在heap生成一个新ResourcePtrHolder对象
}

template <class ResourceType> ResPtr<ResourceType>::~ResPtr()
{//空析构
}

其他ResPtr代码略,但值得一提的是没有 delete   m_pResHolder  字样...

也就是说假如直接使用ResPtr ,用一次就有一个  ResourcePtrHolder 对象泄露

 

代码提供了另外一套引用计数的指针包装版本,ResourcePtrHolder内使用了delete this 销毁内存。但依然有个问题:

 

ResourcePtrHolder::~ResourcePtrHolder()
{
    delete pRes;
}

首先IResource 对外部要管理的指针类型做出了强制性的规定。必须是从IResource派生的类。其次是在holder析构时,不由分说把一个外部传入要管理的对象指针的内容删除。这样强硬的策略我想无论放到哪里都会导致异常巨大的问题。即便是采用引用计数版本,在holder计数到0再删除自己,顺带删除管理的对象,对于外部来讲也是个黑洞。

 

1.7代码的质量让人惊诧,还不知道整本书有多少类似的

posted @ 2008-07-31 10:34 puzzy3d 阅读(133) | 评论 (0)编辑

http://www.horizon3d.com.cn/news.asp

vc7.1的 MFC project

像素的buffer使用了D3D9的frame buffer surface。主要是为了以后CPU/GPU共同光栅化/raytracing 混合渲染实验的方便

目前只支持透视校正纹理映射的三角形光栅器
只简单的支持3DS文件

图片支持使用ALT的 CImage
没有做任何优化...

代码花了两个星期的晚上。技术细节有空再写

集成了ID SOFTWARE 公司DOOM3 SDK中 idlib 代码

如果有人有兴趣把SIMD优化加上,我再弄个SVN吧.....

posted @ 2008-07-25 19:53 puzzy3d 阅读(415) | 评论 (2)编辑

多数初学者往往陷入3D API细节。认为绘制带有各种效果的三角形就是在做引擎。或者疲于把各种NV SDK或者D3D SDK的sample code加入自己的工程。当然,用orge3d这样的开源渲染器也可以做出《天龙八部》,《巨人》等商业产品,不过,想快速开发符合要求的次世代渲染器,需要大量实际工程方面的工作。针对范围很狭窄的渲染器而言,对渲染效果质量的调整,以及自行开发美术需要的效果,不是照抄fx composer或者render monkey那么简单。由于对GPU工作原理认识不深,对某些效果优化实现背后的理论基础认识不深,都会直接带来在实际工程中开发的障碍。或者导致质量下降。

按说做为图形程序员应该对3D光栅渲染的整条流水线做到倒背如流。不过3D硬件厂商加速了应用的进程。使得在屏幕上绘制三角形这件工作变得容易。也许会忽略人们对实时三维渲染的系统知识体系建立。在高级图形渲染逐渐进入更复杂光照,全局光,基于物理或模拟基于物理的技术层面之后,不对GPU工作机理做到透彻了解,在工作中会举步为艰。因为所有渲染工作逐渐移到GPU寄存器中用可编程代码进行。整条管道,从Geometry transform,clipping,vertex lighting,到pixel的shading都由程序员控制。但GPU仍然自动进行了screen space的一些工作。包括clipping,扫描线线性插值,texture sampler等。这是光栅器能够数百倍快于raytracing渲染的本质。但如果图形程序员不了解被GPU自动进行的工作,也会象C++程序员不了解缺省构造函数一样盲目。

举例,众所周知普通的shadowmap 完全不具备工程实用性。最重要的是因为出于内存限制,shadowmap texture尺寸不可能满足实际渲染精度需要。并且收到三角形在camera space中斜率影响巨大。Depth Bias问题的本质是什么。与何参数相关。目前采用的各种调节depthmap渲染精度的方法背后理论依据是什么。Perspective shadowmap,light space shadowmap等各自优化方法会遇到什么问题,各自优缺点,以及工程中如何tunning,尤其用于self-shadow的问题。基于PCF(percentage closer filter)的各种软阴影算法的应用。

在对bumpmap技术改进过程中,在tangent space使用ray-tracing的reliefmap以及relaxed cone stepping relief map,以及带有凹凸轮廓的releif map技术。以及parallax map,和其变种dynamic parallax occlusion map。如何在pixel级别用bilinear gouraud 和这些象素级别lighting进行LOD,如何改进parallax map随视角变化而产生纹理浮动的问题,如何调整线性迭代和2分查找对效率和效果的影响。甚至从本质上了解tangent space,phong shading,都要从软件光栅机理开始。

posted @ 2008-07-22 10:35 puzzy3d 阅读(369) | 评论 (9)编辑

回到20世纪90年代,PC上进入3D图形硬件光栅化时代。VOODOO取代了CPU 光栅化渲染。随后出现NVIDIA TNT。直到GEFORCE将3DFX吞并。现在GPU的演变已经8年,基于屏幕上每个象素的复杂计算已经可以让老shader程序员忽略C和HLSL的区别。

在下一代mmo 3d引擎工具平台开发之前,有必要重新回到GPU内部,关注几何与光栅管道。越来越复杂的shader效果一切均基于光栅器的运作机理。把工作从GPU搬回CPU目的为使图形开发人员打捞图形学基础,在次世代开发中更好的运用GPU功能。

softcore 是一个软件光栅器。用于从场景物体的geometry transform, clipping,lighting, texture mapping, gouraud shading,到最后光栅化显示的整个图形处理管道技术演示。此项目为了保持代码清晰,省略了所有优化。只在可以使用SIMD和MULTITHREAD的步骤做出了标记。为了便于学习,project整合了id software doom3 sdk中SIMD和数学库代码。

由于是两个星期业余时间制作,时间有限,主要目的在于演示3D加速核心算法,光栅化部分的tc,color数值计算和sampler部分仍然需要进一步tunning。需要去除溢出和浮点转整数规则调整。这些可由感兴趣人员自行修改。

 

 

softcore project

done:

* CPU soft rasterization

* Z-buffer

* Gouraud Shading

* Perspective Correct Texturemapping

* Near plane Clipping

* Back face culling(geometry)

* Directional lighting

not do:

x Phong shading/bump mapping

x Bilinear filter

x Mipmap

x Dynamic lightmap

x Vertex color export/import

x Optimization

 

 

以下是3DSMAX中场景原图。有了硬件BILINEAR效果还是不一样.....

 

后面给出技术细节

 

posted @ 2008-07-22 02:45 puzzy3d 阅读(232) | 评论 (0)编辑

透视投影,与Z BUFFER求值
   
    为什么有透视。因为眼球是个透镜。假如地球生物进化的都靠超声波探测空间,那也许眼睛就不会有变成球,而是其他形状...
为什么有人玩3D头晕?其中一个重要的作用是,眼球不完全是个透镜。所以当视野大于60度,屏幕四周投影的变形就比眼球投影视网膜利害多。而且人脑习惯了矫正眼球投影的信息。突然有个屏幕上粗糙的模拟眼球成像,大脑还真一时适应不了。

    Z BUFFER数值计算,以及PERSPECTIVE PROJECTION MATRIX设置,使用D3D或者OPENGL,可以直接让显卡完成这些工作。但是弄清Z BUFFER如何计算,以及PROJECT MATRIX的原理。对于进行各种高级图像处理,非常有用。例如shadowmap的应用。目前为了得到好的shadowmap,很多人在如何加大shadowmap精度做了很多努力(改变生成shadowmap时的perspective project matrix来生成精度更合理的shadowmap) 。比如透视空间的perspective shadow map,light空间的Light-space perspective shadow,perspective shadowmap变种Trapezoidal shadow maps,改正交投影为对数参数投影的 Logarithmic Shadow Maps。另外,Doom3中shadow volume采用的无限远平面透视矩阵绘制stencil shadow volume。都需要对perspective projection有透彻了解。


以下描述z buffer计算以及perspective projection matrix原理。

假设坐标在 world space 是
Pw = {Xw,Yw,Zw}

经过camera space transform 得到
Pe = {Xe,Ye,Ze}

然后经过project transform 转为 device space,这里假设转为 Zp 范围 [-1,1](OPENG的Z BUFFER)

Pe在near平面的投影为:
Xep = n* Xe/(-Ze) (n为近平面到eye距离).
注意这里OPENGL 右手系camera space是Z轴负方向为眼睛看的方向。当计算投影时,x,y都应该除以一个正的数值。所以Ze取负。

这么做的目的是为了让在view space中所有在视锥平截体内的点,X数值投影到近平面上,都在near平面上的left到right。
接下来是求最后在device space里x,y,z的数值,device space是坐标为-1到1的立方体。其中x/2+0.5,y/2+0.5 分别再乘以窗口长宽就是屏幕上像素的位置。那么屏幕这个像素的Z数值就可以按以下方法求出:
需要把view space中(left,right,top,bottom,near,far)的frustum转换到长宽为(-1,1)的正方体内,就是说,把Xe,Ye,Ze都映射到[-1,1]的范围内。前面已经求出了Xe在camera space near平面上的投影Xep。这个投影的数值就是在frustum平截体near平面上的位置。
把平截体near平面映射到-1,1的正方形很简单,X方向按如下映射:
Xp = (Xep - left)*2/(right-left) -1  。

当Xep在left到right变化时,Xp在-1到1变化。
因为显卡硬件(GPU)的扫描线差值都是透视矫正的,考虑投影后,顶点Xp和Yp都是 1/(-Ze) 的线性关系。那么在device单位立方体内,Zp 的范围在[-1,1]之间,Zp也就是Z BUFFER的数值。根据前面推导,要保证透视校正,Zp也是以1/(-Ze)的线性关系。即,总能找到一个公式,使得
Zp = A* 1/(-Ze) + B。

也就是说,不管A和B是什么,在Z BUFFER中的数值,总是和物体顶点在camera space中的 -1/Ze 成线性的关系。 我们要做的就是求A 和B。
求A和B,我们利用以下条件:
当Ze = far 时, Zp = 1
当Ze = near时,Zp = -1(在OPENGL下是这样。在D3D下是Zp =0)
这实际是个2元一次方程。有了两个已知解,可以求出A和B。OPENGL下,
A = 2nf/(f-n), B = (f+n)/(f-n)

这样一来,我们就知道Z BUFFER的数值如何求得。先把物体顶点世界坐标Pw变换到camera space中得到Pe。然后再经过透视投影变换,求得Ze->Zp的数值。把这个数值填入Z buffer,就是显卡用来比较哪个像素在前,哪个像素在后的依据了。
这也就是为什么near和far设置不合适的时候,很容易发生z fighting。一般情况下,离屏幕很近的一段距离,已经用掉了90%的z 浮点精度。在用于渲染视角里中远距离的场景时,深度的判别只靠剩下的10%精度来进行。
具体推导可以看看http://www.cs.kuleuven.ac.be/cwis/research/graphics/INFOTEC/viewing-in-3d/node8.html 

逐渐被D3D抛弃的W BUFFER,场景远近与W数值是线性的。即,100米的距离,在near=1 far=101时,每一米在D3D W BUFFER的表示中,就是差不多 1/100 那么大。但是在Z BUFFER中就完全不是均匀分配。

下面考虑perspective projection matrix。
根据线性代数原理,我们知道无法用一个3x3的matrix对顶点(x,y,z)进行透视映射。无法通过一个3X3的矩阵得到 x/z 的形式。进而引进齐次坐标矩阵---4x4 matrix。顶点坐标(x,y,z,w)。
齐次坐标中,顶点(x, y, z, w)相当于(x/w, y/w, z/w, 1)。 看到这个顶点坐标,我们会联想到前面我们最终求出的z buffer数值Zp和单位device space中的Xp坐标。利用矩阵乘法,可以得到一个矩阵Mp,使得(Xe,Ye,Ze,1)的顶点坐标转换为齐次坐标规一化后的 (Xp,Yp,Zp,1) 。  即:
Vp = Mp * Ve  .
Vp是单位设备坐标系的顶点坐标(Xp,Yp,Zp,1)。Ve是camera space顶点坐标(Xe,Ye,Ze,1)。

考虑
Xp = (Xep - left)*2/(right-left) -1      (Xep  = -n* Xe/Ze)
Yp = (Yep - left)*2/(right-left) -1      (Yep  = -n* Ye/Ze)
Zp = A* 1/Ze + B

为了得到4X4 MATRIX,我们需要把(Xp,Yp,Zp,1)转为齐次坐标 (-Xp*Ze, -Yp*Ye, -Zp*Ze, -Ze) 。然后由矩阵乘法公式和上面已知坐标,就可以得到PROJECTION MATRIX。

Xp*(-Ze) = M0  M1  M2  M3                  Xe
Yp*(-Ze) = M4  M5  M6  M7        x         Ye
Zp*(-Ze) = M8  M9  M10 M11                 Ze
-Ze    = M12 M13 M14 M15                   1

这里拿 M0, M1, M2, M3 的求解来举例:
M0* Xe + M1* Ye + M2* Ze + M3= (-Ze)*(-n*Xe/Ze-left )*2/(right-left) +Ze
M1 = 2n/(right-left)
M2 = 0
M3 = (right+left)/(right-left)
M4 = 0

最后得到Opengl 的 Perspective Projection Matrix:

[ 2n/(right-left)   0                                  (right+left)/(right-left)    0                            ]
[ 0                 2*near/(top-bottom)                (top+bottom)/(top-bottom)    0                            ]
[ 0                 0                                  -(far+near)/(far-near)       -2far*near/(far-near)        ]
[ 0                 0                                  -1                           0                            ]

D3D 的左手系透视投影矩阵和OPENGL有以下区别。
1, D3D device space 不是个立方体,是个扁盒子。z的区间只有[0,1] 。x,y区间还是[-1,1]
2,D3D的camera space Z轴朝向正方向,计算camera space中投影时不用 Xep = n*Xe/(-Ze), 而是 Xep = n*Xe/Ze
3,D3D中,从camera space的视椎平截体到device space的单位体(扁盒子)摄影,采用了很奇怪的作法。把frustum右上角映射为device单位体的(0,0,0)位置

请RE D3D PERSPECTIVE PROJECTION MATRIX推导过程~

后面若有时间继续 透视校正texture mapping,phong shading以及bump mapping等per-pixel processing光栅化

posted @ 2008-07-05 04:32 puzzy3d 阅读(1225) | 评论 (5)编辑
网站
http://www.horizon3d.com.cn

公司核心技术studio有很多年历史。2005年成立公司。招聘通用C++程序和图形程序员。欢迎发送简历和DEMO SRC到
hr@horizon3d.com.cn
posted @ 2008-06-28 11:21 puzzy3d 阅读(544) | 评论 (1)编辑
不挪动了
位置: http://blog.csdn.net/puzzy3d
posted @ 2008-06-28 11:15 puzzy3d 阅读(125) | 评论 (2)编辑

    《3D游戏编程大师技巧》是一本好书,宏篇巨著。所有的核心原理都掰得很碎。从理论证明到代码实现全部细致周详。而且有中文版。英文是《trick of 3d game programming gurus - advanced 3d graphics and resterization》。内容涵盖广泛。在900多页想把游戏编程,高级计算机图形学,光栅化原理和实现,线性代数与解析几何都讲清楚,野心非凡。当时邮电出版社要我翻译时,由于精力有限,这本书的厚度和广度让人望而却步。所以选了GPU GEMS来翻译。当时GPU的发展正在如火如荼,3D硬件从简单的光栅化处理器发展为可编程的专用处理器。但这本书则专门介绍3D的软件实现。和当时的趋势有些背道而驰。不过现在翻了下。感到在使用D3D GL API做硬件3D绘图之前,把光栅化所有原理和背后理论体系都搞清楚,将会使学习和开发进度成倍。涉及高级shader的技术也会进展迅速。
    大学本科的计算机图形学是门初级入门课程。只能概要的建立一个知识框架。在应用技术方面,想在图形技术领域有所收获,要往里填补的理论知识很多。读过这本书,比较强的感受是如果从一开始建立比较牢固的理论体系,之后的技术研发速度会很快。实时三维图形学只是一个旁支。图形学理论知识体系对它非常重要。
   想要更好的利用不断发展的GPU,对GPU工作原理,光栅化过程,背后的数学知识,都有深入了解的必要。这几年工作中,体会加深。
   最近偶然翻到《数值分析》对常微分方程的数值解法,这是物理引擎的积分求解理论基础。大学都教授的这门课程忘差不多了。这是在看siggraph创立physics based modeling的paper时感到吃力的原因。用GPU在shader里使用欧拉积分做布料,也是一种很简化的数值计算方法。在书店找到几本计算几何学。是物理引擎碰撞部分的理论基础。另外物理引擎涉及到的一块是理论力学的刚体动力学部分。具体计算还要使用LCP(线性互补问题)的解法。涉及到软体的物理模拟情况就更复杂一些。感觉短时间是不太容易都找补全。
用一用商业的AGEIA物理引擎可能只需要高中的数学勉强就够了。不过真要做一套,没有一些数学底子还是很困难的一件事。传闻盛大的疯狂赛车根本没用物理。当然,当初的玛利奥赛车也不用。所以说游戏制作是个很玄妙的事。。。和技术似有关似无关。。。。。。
 《3D游戏编程大师技巧》的作者是个非常专业的技术人员。并且在介绍技术时,对重要的原理和公式都有推导和论证的过程。这样的作法在技术应用书籍里其实很少。多数初等技术书籍都在讲述一个API有几个参数每个参数什么意思。这本书实际在用CPU实现一个简化GPU。作者一看就是对3D RENDERING和游戏编程每个细节都有大量实践。所以从理论知识到技术实现细节,包括优化,讲解很通透。做为大学游戏专业的教材是最适合不过。

 在查阅书中用到的数学公式时,发现另外一个堪比《REALTIME RENDERING》的经典书籍:《Mathematics.for.3D.Game.Programming.and.Computer.Graphics》。这本书比《3D ENGINE DESIGN》要平易近人得多。本着实用的角度,用浅显易懂的描述语言对游戏和计算机图形学用到的数学知识一一进行讲解和证明。比起另外一本经典著作《3D ENGINE DESIGN》,其作者是个博士,全书都用教科书般精确简练的数学语言描述3D引擎理论体系,对没有受过专门数学训练的人读起来都是颇为吃力。《MATH FOR 3D GAME AND CG》则是从实际工程技术角度出发,用高中数学课本形式的语言详细介绍了3D图形编程中所用到的数学知识,同时还保持了广度和深度。同样类型的书籍还有《PHYSICS BASED RENDERING》和《PHYSICS BASED ANIMATION》。当然知识体系更深入。

 在看全局光照时,PRT着实让数学不好的人头大。手头必须常备微积分,微分方程,概率学,傅里叶变换等一些书籍。残缺不全的知识体系很挠头。这是任凭多少技术实践也无法倒推补全的。中间发现一套非常好的微积分教程。俄国菲赫金哥尔茨的《微积分学教程》全3卷。我感觉大学要是用这个当教材我现在的日子还能过得稍微舒服一点点。

posted @ 2008-06-28 10:16 puzzy3d 阅读(425) | 评论 (3)编辑