2006年12月23日

Shadow Volume详解(3)

事隔几个月之后,终于有时间把代码贴上来了。代码下载
今天在搞Hardware shadow map,有一点小进展,但是还是有不少距离。期待写shadow map系列















1.先说一下3ds文件的结构吧,只说跟投影有关的东西,就是它是包含多个object的,读进来的模型也是包含多个object的。
// 模型信息结构体

struct t3DModel
{
UINT texture[MAX_TEXTURES];
int numOfObjects; // 模型中对象的数目
int numOfMaterials; // 模型中材质的数目
std::vector <tMaterialInfo> pMaterials;// 材质链表信息
std::vector <t3DObject> pObject; // 模型中对象链表信息
};
2.首先执行阴影的初始化工作
//载入模型
g_model.Import3DS(fileName);
// 初始化阴影
g_modelShadow.Init(g_model.GetModel(), g_lightPos);
以下是ModelShadow::Init的定义

bool ModelShadow::Init(const t3DModel &model,const float *lightPos)
{
// 获取object的数目
objNum_ = model.numOfObjects;
objInfoTable_.resize(objNum_);
for(int objIndex = 0 ; objIndex < objNum_ ; objIndex++ )
{
....
}
glClearStencil(0);
....
SetConnectivity(); // 设置三角形之间的链接关系
CalcPlane(); // 计算每个三角形的平面方程
....
}
3.初始化之后就可以渲染了
// 绘制模型,阴影
// 重设光源位置,如果光源位置不便可以忽略
g_modelShadow.ResetLightPos(g_lightPos);
// 这里获取当前的model view matrix(MVM)
g_modelShadow.GetCurMatrix();
glPushMatrix();
// 放置物体
glTranslatef(g_modelPos[0], g_modelPos[1], g_modelPos[2]);
// 这里又获取了一次model view matrix
g_model.Draw();
g_modelShadow.Draw();
glPopMatrix();
通过两次获得的矩阵的差异就可以算出中间做了那些变换,比如(glTranslatef(g_modelPos[0], g_modelPos[1], g_modelPos[2]); )
现在看一下ModelShadow::Draw的实现
void ModelShadow::Draw() const
{
glClear(GL_STENCIL_BUFFER_BIT);

GLfloat objMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, objMatrix);

// 求逆矩阵,这四条语句就是在求物体的局部坐标系里灯的坐标

InverseMatrix16(objMatrix);
MultiplyMatrix16(objMatrix, curMatrix_);
memcpy(lightPos_, orignLightPos_, 4 * sizeof(float));
Mtx16MultVect4(objMatrix, lightPos_);

//Cast the shadow
CastShadow();
}
再看ModelShadow::castShadow

void ModelShadow::CastShadow() const
{
SetVisibility(); // 设置每个三角形的可见性
....
// 第一趟渲染,通过模板测试的话模版值增一
glFrontFace(GL_CCW);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
DoShadowPass();

// 第二趟渲染,通过模板测试的话模版值减一
glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
DoShadowPass();
....
glStencilFunc(GL_NOTEQUAL, 0, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

//在全屏幕混合一张图
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0, 0, 0, 0.3f);
....
}
有一些问题,我在(2)里说错了的
glLoadIdentity();
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(-0.1f, 0.1f, -0.10f);
glVertex3f(-0.1f, -0.1f, -0.10f);
glVertex3f( 0.1f, 0.1f, -0.10f);
glVertex3f( 0.1f, -0.1f, -0.10f);
glEnd();
这个覆盖全屏真是投机取巧
gluPerspective(45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0);
如果那个角度比45.0f大就无法覆盖了
正确的做法是改用正投影。

Pictures of Blizzard Art Contest

孤独的兽人战士,半兽人?
貌似是巫妖王,嘴巴好夸张啊呵呵。
For the lich king.













Warrior of the night, assemble.


copyright
BLIZZARD-ART

One of blizzard's christmas flash


蛮温暖的呵,苦工老弟都开始玩了。

2006年12月14日

Words on:图形程序开发人员指南(一)

书的英文名是《Michael Abrash's classic Graphics Programming Black Book》。Michael Abrash是图形学的先驱者之一,《DOOM启示录》也有描述。云风的书(《游戏之旅-我的编程感悟》)上也多次提到了这本书。我摘录了一些,但是是非技术的。以后多贴点技术的。
在东校区图书馆无意间发现的,大家要到东校区借书的话来找我。:D

[Michael Abrash]        我想说的是我们现在日益进入一个紧密互联,高度逼真的空间,我希望那些人意识到3D编程的难度和潜能实际上比以前更大。关键在于要沉溺于已经实现的技术,必须不断奋斗,力争"用不同的方式,用更少的代码,编写出更好的程序。"不断学习,改变并尝试新的方法,直至生命的终结,这样就能为将来留下自己的烙印。
        当说到这种乐趣是我生活的目的时,我认为我并没有言过其实(当然也许有一点点),我很高兴这么多读者都有这种热情。
        要敢于尝试不可能的事情,知道什么是不可以的也是有用的知识-一些意想不到的成功可能会让你顿悟:多数不可能的事情其实是可能的。
        这十年是微机程序员的十年,我庆幸自己不仅能成为其中的一员,而且能够在历史的发展中留下自己的痕迹。但愿未来的十年依然充满兴奋和喜悦。

[John carmack]编程不是一个零和的游戏,教给你的同行一些东西并不会丢失它们,我与人分享我能够做到的一切时感到很高兴,因为我深深的热爱编程。一辆法拉利小轿车不过时一种物质享受,但做人最重要的是真诚

2006年12月1日

我为何而生

这是个很麻烦的题目了,但是是必须要思考的。跟家里人的想法有点不大一样,一冲动就写了。
罗素有一篇这个题目的经典文章:
[William Russell]对爱情的渴望,对知识的追求,对人类苦难不可遏制的同情,是支配我一生的单纯而强烈的三种感情。这些感情如阵阵飓风,吹拂在我动荡不定的生涯中,有时甚至吹过深沉痛苦的海洋,直抵绝望的边缘。
像我的Blog的题目一样,《伊尔的理想》,我是为理想而存在的吧。
以前是不想这些事情的,整天上学上学,不思考。改变我高中生活的是一本让我懂得思考的杂志。改变我的大学生活的是盖茨的那句话:
[Bill gates]每天清晨当你醒来时,都会为技术进步及其为人类生活带来的发展和改进而激动不已。
我希望可以用技术改变人们的生活,这是我来做技术的原因。不是为了变得更强,也不是为了生活。为了这个也失去了一些的。空余时间,课程成绩等等。但是那些付出在我看来是值得的,我能感觉到自己的存在,未来的一天,我可以让这个世界更美好。至于做图形,是因为我想做游戏,这跟我的经历有关。还有很重要的是,同时也有了伙伴。(跟我爱罗不一样wo,有存在的理由,有伙伴。:D)
Live for ideal,not just live for living.