📄 tutorial_27.htm
字号:
}
</pre>
</font><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_27_files/l.png"><img src="Tutorial_27_files/l.png"></td>
<td valign="top" width="100%">下面设置必要的状态来渲染阴影.<br>
首先,禁用灯光和绘制颜色,因为我们不计算光照,这样可以节约计算量.<br>
接着,设置深度缓存,深度测试还是需要的,但我们不希望我们的阴影体向实体一样具有深度,所以关闭深度缓存.<br>
最后我们启用蒙板缓存,让阴影体的位置在蒙板中被设置为1.</td>
<td background="Tutorial_27_files/r.png"><img src="Tutorial_27_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/br.png" height="28" width="28"></td></tr></tbody></table><font color="#aaffaa" size="3">
</font><pre><font color="#aaffaa" size="3"> glDisable( GL_LIGHTING ); <font color="#ffffaa">// 关闭灯光</font>
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); <font color="#ffffaa">// 关闭颜色缓存的写入</font>
glDepthFunc( GL_LEQUAL ); <font color="#ffffaa">// 设置深度比较函数</font>
glDepthMask( GL_FALSE ); <font color="#ffffaa">// 关闭深度缓存的写入</font>
glEnable( GL_STENCIL_TEST ); <font color="#ffffaa">// 使用蒙板缓存</font>
glStencilFunc( GL_ALWAYS, 1, 0xFFFFFFFFL ); <font color="#ffffaa"> // 设置蒙板函数</font>
</font></pre>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_27_files/l.png"><img src="Tutorial_27_files/l.png"></td>
<td valign="top" width="100%">现在到了阴影被实际渲染得地方了,我们使用了下面提到的doShadowPass函数,它用来绘制阴影体的边界面.我们通过两个步骤来绘制阴影体,首先使用前向面增加阴影体在蒙板缓存中的值,接着使用后向面减少阴影体在蒙板缓存中的值.</td>
<td background="Tutorial_27_files/r.png"><img src="Tutorial_27_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
</font><pre><font color="#aaffaa" size="3"> <font color="#ffffaa">// 如果是逆时针(即面向视点)的多边形,通过了蒙板和深度测试,则把蒙板的值增加1</font>
glFrontFace( GL_CCW );
glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
doShadowPass( object, lightPosition );
<font color="#ffffaa">// 如果是顺时针(即背向视点)的多边形,通过了蒙板和深度测试,则把蒙板的值减少1</font>
glFrontFace( GL_CW );
glStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
doShadowPass( object, lightPosition );
</font></pre>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_27_files/l.png"><img src="Tutorial_27_files/l.png"></td>
<td valign="top" width="100%">为了更好的理解这两个步骤,我建议你把第二步注释掉看看效果,如下所示: <font face="Tahoma,Verdana,sans-serif" size="-1"><br>
<br>
<table align="center" border="0">
<tbody><tr align="center" valign="top">
<td><img src="Tutorial_27_files/pass1.jpg" height="150" width="200"></td>
<td><img src="Tutorial_27_files/pass2.jpg" height="150" width="200"></td>
</tr>
<tr align="center" valign="top">
<td>图 1: 步骤1</td>
<td>图 2: 步骤2</td>
</tr>
</tbody></table>
<br>
<br>
</font>最后一步就是把阴影体所在的位置绘制上阴影的颜色</td>
<td background="Tutorial_27_files/r.png"><img src="Tutorial_27_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/br.png" height="28" width="28"></td></tr></tbody></table><font color="#aaffaa" size="3">
<pre> glFrontFace( GL_CCW );
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
<font color="#ffffaa">// 把阴影绘制上颜色</font>
glColor4f( 0.0f, 0.0f, 0.0f, 0.4f );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glStencilFunc( GL_NOTEQUAL, 0, 0xFFFFFFFFL );
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
glPushMatrix();
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();
glPopMatrix();
}
</pre>
</font><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_27_files/l.png"><img src="Tutorial_27_files/l.png"></td>
<td valign="top" width="100%">下面的部分我们绘制构成阴影体边界的四边形,当我们循环所有的三角形面的时候,我们检测它是否是边界边,如果是我们绘制从灯光到这个边界边的射线,并衍生它用来构成四边形.
<p>这里要用一个蛮力,我们检测物体模型中每一个三角形面,找出其边界并连接灯光到边界的直线,把直线延长出一定的距离,构成阴影体.</p>
<p>下面的代码完成这些功能,它看起来并没有想象的复杂.</p></td>
<td background="Tutorial_27_files/r.png"><img src="Tutorial_27_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/br.png" height="28" width="28"></td></tr></tbody></table>
<pre><font color="#aaffaa" size="3">void doShadowPass(glObject *o, float *lp)
{
unsigned int i, j, k, jj;
unsigned int p1, p2;
sPoint v1, v2;
<font color="#ffffaa">//对模型中的每一个面</font>
for (i=0; i<o->nPlanes;i++)
{
<font color="#ffffaa">//如果面在灯光的前面</font>
if (o->planes[i].visible)
{
<font color="#ffffaa">//对于被灯光照射的面的每一个相邻的面</font>
for (j=0;j<3;j++)
{
k = o->planes[i].neigh[j];
<font color="#ffffaa">//如果面不存在,或不被灯光照射,那么这个边是边界</font>
if ((!k) || (!o->planes[k-1].visible))
{
<font color="#ffffaa">// 获得面的两个顶点</font>
p1 = o->planes[i].p[j];
jj = (j+1)%3;
p2 = o->planes[i].p[jj];
<font color="#ffffaa">//计算边的顶点到灯光的方向,并放大100倍</font>
v1.x = (o->points[p1].x - lp[0])*100;
v1.y = (o->points[p1].y - lp[1])*100;
v1.z = (o->points[p1].z - lp[2])*100;
v2.x = (o->points[p2].x - lp[0])*100;
v2.y = (o->points[p2].y - lp[1])*100;
v2.z = (o->points[p2].z - lp[2])*100;
<font color="#ffffaa">//绘制构成阴影体边界的面</font>
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(o->points[p1].x,
o->points[p1].y,
o->points[p1].z);
glVertex3f(o->points[p1].x + v1.x,
o->points[p1].y + v1.y,
o->points[p1].z + v1.z);
glVertex3f(o->points[p2].x,
o->points[p2].y,
o->points[p2].z);
glVertex3f(o->points[p2].x + v2.x,
o->points[p2].y + v2.y,
o->points[p2].z + v2.z);
glEnd();
}
}
}
}
}
</o-></font>
</pre>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_27_files/l.png"><img src="Tutorial_27_files/l.png"></td>
<td valign="top" width="100%">既然我们已经能绘制阴影了,那么我们开始绘制我们的场景吧</td>
<td background="Tutorial_27_files/r.png"><img src="Tutorial_27_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/br.png" height="28" width="28"></td></tr></tbody></table><font color="#aaffaa" size="3">
</font><pre><font color="#aaffaa" size="3">bool drawGLScene()
{
GLmatrix16f Minv;
GLvector4f wlp, lp;
<font color="#ffffaa">// 清空缓存</font>
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glLoadIdentity(); <font color="#ffffaa">// 设置灯光,并绘制球</font>
glTranslatef(0.0f, 0.0f, -20.0f);
glLightfv(GL_LIGHT1, GL_POSITION, LightPos);
glTranslatef(SpherePos[0], SpherePos[1], SpherePos[2]);
gluSphere(q, 1.5f, 32, 16); </font></pre>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_27_files/l.png"><img src="Tutorial_27_files/l.png"></td>
<td valign="top" width="100%">下面我们计算灯光在物体坐标系中的位置</td>
<td background="Tutorial_27_files/r.png"><img src="Tutorial_27_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_27_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_27_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_27_files/br.png" height="28" width="28"></td></tr></tbody></table><font color="#aaffaa" size="3">
</font><pre><font color="#aaffaa" size="3"> glLoadIdentity();
glRotatef(-yrot, 0.0f, 1.0f, 0.0f);
glRotatef(-xrot, 1.0f, 0.0f, 0.0f);
glTranslatef(-ObjPos[0], -ObjPos[1], -ObjPos[2]);
glGetFloatv(GL_MODELVIEW_MATRIX,Minv); <font color="#ffffaa">// 计算从世界坐标系变化到物体坐标系中的坐标</font>
lp[0] = LightPos[0]; <font color="#ffffaa">// 保存灯光的位置</font>
lp[1] = LightPos[1];
lp[2] = LightPos[2];
lp[3] = LightPos[3];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -