好久没有更新了,现在正在忙着做一个基于OpenCasCade和OGRE的项目,希望能够开发一套基建筑物建模和渲染的平台。等时间成熟,放些代码和截图和大家共享讨论。
前两天编程序用到了C++ 的multimap表。multimap可以实现同一键的多次存储纪录。本来我想通过下面的代码实现将键值为2的所有记录复制一份,并以键值为3的方式插入到mulitmap表中,结果出现了错误。代码如下:
typedef multimap<int, SelfClass*> MultiMapTable;
typedef MultiMapTable::iterator MultiMapIter;
typedef pair<MultiMapIter, MultiMapIter> EqualRangeIter
MultiMapTable multiMapTable;
......
//复制插入操作
EqualRangeIter eqaulIter = multiMapTable.equal_range(2);
for(; equalIter.first!=equalIter.second; equalIter.first++)
multiMapTable.insert(MultiMapTable::value_type<3, equalIter.first.second>));
代码看似没有问题,后来调试发现,for循环语句进入了死循环状态。简单分析了一下,感觉是以下原因:
当时multiMapTable中记录了key=1和key=2的纪录若干条。且key=2的所有记录是于key=1的记录之后插入到map表中的。这就导致了multiMapTable.end()与equalIter.second指向了同一个地址。而multiMapTable.insert语句的调用则会不停的修改multiMapTable.end()的指针。从而导致了equalIter.first!=equalIter.second语句始终为true;
修改方式:通过multiMapTable.count(2)计算key=2的纪录iCount条,在for循环中iCount--,在判断条件中添加iCount>=0。通过此方法可以获得正确结果。
由于key值不一样,觉得通过简单的copy无法实现,不过没有尝试过。
posted @ 2008-09-09 19:23 soaroc 阅读(596) 评论(5)
编辑
常见的光照模型(无论是局部光照模型还是全局光照模型)基本上都是基于几何光学的,对于大尺寸几何体和表面粗糙度较大的物体来说,还可以达到逼真的效果。对于几何尺寸和表面粗糙度接近于可见光波长的物体来说,由于会产生衍射(Diffraction)现象,就必须要考虑到光的波动性了。Stam Jos在其论文《Diffraction Shaders》中对衍射模型做了非常细致的推导,感兴趣的同学不妨去啃一啃。在这里只做一个简单的介绍。
根据惠更斯原理我们知道,介质中任一波面上的各点,都可以看作是发射子波的波源。这就是为什么水波穿过细缝时不是成射线状,而是呈球面状的原因。此外,费涅耳在研究光波衍射时提出:衍射场中各点的强度由各子波在该点的相干叠加决定,因此在不同的视线角度,看到的相干图样有所不同。有了这两个定理就可以展开介绍了。下面就是一个简单的示意图:

其中L是光源方向,V是视线方向,光线照射到表面之后在表面产生无数的子波,将子波看作是新的光源,最后传递到眼中形成干涉条纹。干涉条纹产生的条件是:d*(sin@1-sin@2)为光线波长的整数倍,这样就会在眼点出产生极大值的光线叠加。
使用shader实现Diffraction时的关键在于光程差的求解和形成干涉的波长的光线颜色的确定。在GPU Gems I中,前者是通过将光源和视点形成的半角矢量投影到顶点的切线空间获取的,而后者则是通过将颜色设定为波长的二次抛物线关系来计算的。下面就是使用这种方法,在添加了基于Cube Mapping的Reflection之后的CD 衍射效果图。

实际拿张光盘看了一下,发现有个问题,无论怎么运动,彩色衍射条纹始终是成直线型的,而实际的衍射条纹则会出现弯曲,原因我分析可能是在构建CD Mesh是,径向顶点的切线是一样的,这样产生的衍射颜色就一致的,如果对其中远端顶点的切线作同一个方向的随机扰动,估计可能会好一些。
总结:原理很简单,实现起来也不困难,不过从Stam Jos发表了这篇文章之后,并没有引起很大的反响,搜了一下ACM的数据库,发现这方面的研究也不是很多,可能是实际应用的需求还不是很大吧。
posted @ 2007-11-17 15:31 soaroc 阅读(372) 评论(1)
编辑
好久没有更新了,都快要长草了,呵呵!
学习Cg编程有两个多月了,收获还是蛮大的。前一段时间动手编写了几个程序,一通修改之后,整个程序变得面目全非了,有时自己都不清楚程序的运行流程了。于是痛下决心,尝试着自己编写一个小型的实验平台。用了两个多星期,基本的框架总算搭建起来了。由于主要是用于实践各种Cg特效技术,我尽量的使用了目前网上已有的一些开源的库,下面就是我这个框架中用到的一些库
1) libpng - 1.3.0 读取png格式纹理图片,貌似DevIL也可以做
2) zlib - 1.2.3 读取压缩文件
3) DevIL - 1.6.8 读取各种格式的图片,用作纹理贴图
4) mathgl++ - 0.5.2 向量,矩阵计算
5) lib3ds - 1.3.0 读取3ds模型
6) glew - 1.4.0 OpenGL扩展检查
开发平台用的是.NET,使用glut作为OpenGL的运行环境管理,就是GUI管理差了一点,还好GUI用的不是太多
下面是一个Demo,读取3ds模型,并简单的实现了一个Projective Mapping

对于这个Table和Rose,想必大家不陌生吧,考虑到以后Table和Rose可能会用于实现不同的特效,这两个模型是分别导入的,相对位置不是太精确。都是一些很简单的技术,大家表BS我啊。
学习GPU编程,完全是我个人兴趣。老板项目催的紧,学这个也是断断续续的,不知道有没有用,很多时候都有放弃的念头了。哪知前几天老板带我国展看一个公司的VR演示系统,里面有一个海洋的Demo,用了Normal Texture Mapping,跟那个做演示的老外胡乱瞎侃。回来之后,老板竟让我做个讲座,给他们普及普及GPU编程的知识。哈哈,终于可以"名正言顺"的学习GPU编程了。
posted @ 2007-11-10 12:14 soaroc 阅读(776) 评论(7)
编辑
《Cg Tutorial》的第四章介绍了场景转换的一些基本概念,并就此给出了一个程序例子,演示了在Cg顶点程序中执行从模型空间到剪切空间的转换。由于顶点程序的模型视点投影距阵参数是uniform类型,因此是通过在应用程序中先手动计算各矩阵(包括平移、旋转、视点以及投影距阵),然后按照转换空间的顺序相乘,最后在传递给顶点程序的顺序来完成的。程序实现时,完全是通过传递参数,然后自己来构造相应的矩阵,这种办法虽然可行,但必须要对各种矩阵的构造原理十分的了解。考虑到OpenGL中,可以使用状态函数glGetFloatv来获取指定的矩阵,因此可以先执行相应的操作,让OpenGL来计算最终的合成矩阵,而我们则可以直接通过状态获取函数来得到最终的矩阵。下面就是基于这种方法的实现:
void getModelViewProjMatrix(float outModelViewProjMatix[16],
float fovy,float aspect,float zNear,float ZFar, /* The Projection Parameter*/
double eyex,double eyey,double eyez, /* The Eye Position */
double centerx,double centery,double centerz, /* The Center Position*/
double upx,double upy,double upz, /* The Up Vector*/
void (*transformOp)(void) /* The transform Operation*/)
{
float projMatrix[16];
// Get the projection matrix
getProjectMatrix(projMatrix,fovy,aspect,zNear,ZFar);
// ModelMatrix = Translate * Rotation * ...
// ModelViewMatrix = ViewMatrix * ModelMatrix
// ModelViewProjectionMatrix = ProjectionMatrix * ModelViewMatrix
// In OpenGL,the order of matrix multiplication is REVERSE to the order of function call
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// Multiple the modelview matrix by projection matrix
glMultMatrixf(projMatrix);
//do the transformation operation and camera setting
gluLookAt(eyex,eyey,eyez,centerx,centery,centerz,upx,upy,upz);
transformOp();
//get the modelview matrix
glGetFloatv(GL_MODELVIEW_MATRIX,outModelViewProjMatix);
glPopMatrix();
}
此函数用来获取模型视点矩阵与投影矩阵相乘的结果,这个结果就是传递给顶点程序的值。其中(fovy,aspect,zNear,ZFar)调用gluPerspectiv()函数,获取投影矩阵;(eyex, eyey,eyez
centerx,centery,centerz, upx,upy,upz)则用来调用gluLookAt()函数,设置视点矩阵。由于平移、旋转的操作顺序和次数不定,因此在这里是通过函数指针的形式指定。在这个函数中指定的具体的平移和旋转操作。
使用这种方法时,需要考虑到两个问题:
1、 从模型空间到剪切空间的转换顺序:

2、 在OpenGL中,矩阵相乘的顺序与函数调用的顺序相反:
例如:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(N);
glMultMatrixf(M);
glMultMatrixf(L);
glBegin(GL_POINTs);
glVertex3f(v);
glEnd();
在上述代码中,当前矩阵依次为I、N、NM、NML。变换后的顶点为NMLv。
3、 在OpenGL中,使用一维数组存储矩阵时,默认的方式是按列存储的,因此在使用Cg程序时,需要使用cgSetMatrixParameter{f,d}c来传递矩阵参数。
在所有参数设置相同时,试验的结果与书上的结果有一些出入,主要体现在物体在空间的位置不同。为了验证真实的情况,我在只使用OpenGL,不是用Cg程序的条件下绘制,绘制结果同我的一样。下面是在这三种方法下的最终结果:从左到右依次为使用上面方法渲染结果、使用纯OpenGL渲染结果以及书中自带结果

不知道这是我的方法有问题,还是书上程序有问题。
posted @ 2007-09-14 14:58 soaroc 阅读(938) 评论(5)
编辑
前一段时间开始接触OGRE开源引擎,下载了一个1.4.2版本的OGRE[开发代号为Eihort]。没想到安装特别的麻烦,从安装补丁到最后编译成功,竟然耗了一整天,怎一个"汗"字了得啊!
安装前也曾到网上搜过一些安装说明,可是没有一个成功的,后来是自己慢慢摸索着才成功的,个人感受不敢独享,下面详细的介绍我自己的安装步骤:
1、软件包下载准备:WindowsXP SP1补丁、OGRE安装程序包(我下载的是Source版本的,SDK版本没有源代码)及补丁(针对vc7和vc8有不同的补丁程序)、Cg Toolkit开发包(用于Cg语言编程的,可选)、DirectX SDK开发包(用于D3D编程,推荐)。
2、安装WindowsXP SP1补丁:WindowsXP SP1补丁号称是史上最BT的补丁了,安装前保证系统盘预留3G的空间,并且安装时要有足够的耐心,据说有人安装了3个多小时,我的内存是1G的,用了一个多小时。下面是一个注册表文件,需要先运行这个注册表文件再安装补丁。
reg export HKLM"Software"Policies"Microsoft"Windows"Installer installer.reg
reg add HKLM"Software"Policies"Microsoft"Windows"Installer /v MaxPatchCacheSize /t REG_DWORD /d 0 /f
net stop msiserver
start /wait VS80sp1-KB926604-X86-CHS.exe
reg delete HKLM"Software"Policies"Microsoft"Windows"Installer /v MaxPatchCacheSize /f
reg import installer.reg
net stop msiserver
del /q installer.reg 2>nul
其实前面的部分不过是照着微软官方网站的说明,翻译成注册表操作语言罢了。先导出注册表,存为install.reg。然后将安全策略中的对应键值由0改为1。然后安装SP1补丁(这里要求补丁程序位于.."wait下面),之后就是导入installer.reg文件。完成之后删除。(中间有一个net命令,用于隔断主机与域的网络连接)。
3、安装Cg Toolkit以及DirectX SDK开发包,最后解压缩OGRE的安装包。SDK版本的有安装导向,可以很方便的完成安装,但不提供源代码。Source版本的解压缩之后会生成一个ogrenew的文件夹,里面就是一大堆的工程文件和源代码。
4、解压缩之后需要先完整的编译一遍才可以使用,编译OGRE工程文件之前,先将OGRE的补丁解压缩,并将Dependencies文件夹拷贝到OGRE的工程文件夹目录下。
5、可以开始编译了,第一次编译大约需要二十多分钟,中间可能会出现N多的警告,都不用理会。
posted @ 2007-09-07 11:15 soaroc 阅读(2068) 评论(4)
编辑