📄 tutorial_44.htm
字号:
<p>现在你在头脑里应该有了一个大慨地图像了吧。我们来说说何时我们应该绘制光晕,一般来说平时我们是看不见这些光晕的,只有当我们对准光源的时候才能看见这些。所以我们首先要获得视景体的数据,下面的函数可以帮我们完成这个功能。</p>
</td>
<td class="r"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="bl"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="bc" width="100%"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="br"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<pre><span class="theme">// 获得当前视景体的6个平面方程的参数</span><br>void glCamera::UpdateFrustum()<br>{<br> GLfloat clip[16];<br> GLfloat proj[16];<br> GLfloat modl[16];<br> GLfloat t;</pre>
<p> <span class="theme">//返回投影矩阵</span><br>
glGetFloatv( GL_PROJECTION_MATRIX, proj );</p>
<p> <span class="theme">//返回模型变换矩阵</span><br>
glGetFloatv( GL_MODELVIEW_MATRIX, modl );</p>
<p> <span class="theme">//计算剪切矩阵,即上面两个矩阵的乘积</span><br>
clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] +
modl[ 3] * proj[12];<br>
clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] +
modl[ 3] * proj[13];<br>
clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] +
modl[ 3] * proj[14];<br>
clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] +
modl[ 3] * proj[15];</p>
<p> clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8]
+ modl[ 7] * proj[12];<br>
clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] +
modl[ 7] * proj[13];<br>
clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] +
modl[ 7] * proj[14];<br>
clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] +
modl[ 7] * proj[15];</p>
<p> clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8]
+ modl[11] * proj[12];<br>
clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] +
modl[11] * proj[13];<br>
clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] +
modl[11] * proj[14];<br>
clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] +
modl[11] * proj[15];</p>
<p> clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8]
+ modl[15] * proj[12];<br>
clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] +
modl[15] * proj[13];<br>
clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] +
modl[15] * proj[14];<br>
clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] +
modl[15] * proj[15];</p>
<p> <span class="theme">//提取右面的平面方程系数</span><br>
m_Frustum[0][0] = clip[ 3] - clip[ 0];<br>
m_Frustum[0][1] = clip[ 7] - clip[ 4];<br>
m_Frustum[0][2] = clip[11] - clip[ 8];<br>
m_Frustum[0][3] = clip[15] - clip[12];<br>
t = GLfloat(sqrt( m_Frustum[0][0] * m_Frustum[0][0] + m_Frustum[0][1] * m_Frustum[0][1]
+ m_Frustum[0][2] * m_Frustum[0][2] ));<br>
m_Frustum[0][0] /= t;<br>
m_Frustum[0][1] /= t;<br>
m_Frustum[0][2] /= t;<br>
m_Frustum[0][3] /= t;</p>
<p> <span class="theme">//提取左面的平面方程系数</span><br>
m_Frustum[1][0] = clip[ 3] + clip[ 0];<br>
m_Frustum[1][1] = clip[ 7] + clip[ 4];<br>
m_Frustum[1][2] = clip[11] + clip[ 8];<br>
m_Frustum[1][3] = clip[15] + clip[12];<br>
t = GLfloat(sqrt( m_Frustum[1][0] * m_Frustum[1][0] + m_Frustum[1][1] * m_Frustum[1][1]
+ m_Frustum[1][2] * m_Frustum[1][2] ));<br>
m_Frustum[1][0] /= t;<br>
m_Frustum[1][1] /= t;<br>
m_Frustum[1][2] /= t;<br>
m_Frustum[1][3] /= t;</p>
<p> <span class="theme">//提取下面的平面方程系数</span><br>
m_Frustum[2][0] = clip[ 3] + clip[ 1];<br>
m_Frustum[2][1] = clip[ 7] + clip[ 5];<br>
m_Frustum[2][2] = clip[11] + clip[ 9];<br>
m_Frustum[2][3] = clip[15] + clip[13];<br>
t = GLfloat(sqrt( m_Frustum[2][0] * m_Frustum[2][0] + m_Frustum[2][1] * m_Frustum[2][1]
+ m_Frustum[2][2] * m_Frustum[2][2] ));<br>
m_Frustum[2][0] /= t;<br>
m_Frustum[2][1] /= t;<br>
m_Frustum[2][2] /= t;<br>
m_Frustum[2][3] /= t;</p>
<p> <span class="theme">//提取上面的平面方程系数</span><br>
m_Frustum[3][0] = clip[ 3] - clip[ 1];<br>
m_Frustum[3][1] = clip[ 7] - clip[ 5];<br>
m_Frustum[3][2] = clip[11] - clip[ 9];<br>
m_Frustum[3][3] = clip[15] - clip[13];<br>
t = GLfloat(sqrt( m_Frustum[3][0] * m_Frustum[3][0] + m_Frustum[3][1] * m_Frustum[3][1]
+ m_Frustum[3][2] * m_Frustum[3][2] ));<br>
m_Frustum[3][0] /= t;<br>
m_Frustum[3][1] /= t;<br>
m_Frustum[3][2] /= t;<br>
m_Frustum[3][3] /= t;</p>
<p> <span class="theme">//提取远面的平面方程系数</span><br>
m_Frustum[4][0] = clip[ 3] - clip[ 2];<br>
m_Frustum[4][1] = clip[ 7] - clip[ 6];<br>
m_Frustum[4][2] = clip[11] - clip[10];<br>
m_Frustum[4][3] = clip[15] - clip[14];<br>
t = GLfloat(sqrt( m_Frustum[4][0] * m_Frustum[4][0] + m_Frustum[4][1] * m_Frustum[4][1]
+ m_Frustum[4][2] * m_Frustum[4][2] ));<br>
m_Frustum[4][0] /= t;<br>
m_Frustum[4][1] /= t;<br>
m_Frustum[4][2] /= t;<br>
m_Frustum[4][3] /= t;</p>
<p> <span class="theme">//提取近面的平面方程系数</span><br>
m_Frustum[5][0] = clip[ 3] + clip[ 2];<br>
m_Frustum[5][1] = clip[ 7] + clip[ 6];<br>
m_Frustum[5][2] = clip[11] + clip[10];<br>
m_Frustum[5][3] = clip[15] + clip[14];<br>
t = GLfloat(sqrt( m_Frustum[5][0] * m_Frustum[5][0] + m_Frustum[5][1] * m_Frustum[5][1]
+ m_Frustum[5][2] * m_Frustum[5][2] ));<br>
m_Frustum[5][0] /= t;<br>
m_Frustum[5][1] /= t;<br>
m_Frustum[5][2] /= t;<br>
m_Frustum[5][3] /= t;<br>
}</p>
<p></p>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="tl"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="tc" width="100%"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="100%"></td>
<td class="tr"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="l"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="back3" valign="top" width="100%">现在我们可以测试一个点或圆是否在视景体内了。下面的函数可以测试一个点是否在视景体内。</td>
<td class="r"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="bl"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="bc" width="100%"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="br"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<pre>BOOL glCamera::PointInFrustum(glPoint p)<br>{<br> int i;<br><br> for(i = 0; i < 6; i++)<br> {<br> if(m_Frustum[i][0] * p.x + m_Frustum[i][1] * p.y + m_Frustum[i][2] * p.z + m_Frustum[i][3] <= 0)<br> {<br> return(FALSE);<br> }<br> }<br> return(TRUE);<br>}</pre>
<p></p>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="tl"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="tc" width="100%"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="100%"></td>
<td class="tr"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="l"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="back3" valign="top" width="100%"><p>下面的函数用来测试某个点是否位于当前场景物体的前面: </p>
</td>
<td class="r"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="bl"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="bc" width="100%"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="br"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<pre>bool glCamera::IsOccluded(glPoint p)<br>{<br> GLint viewport[4]; <br> GLdouble mvmatrix[16], projmatrix[16]; <br> GLdouble winx, winy, winz; <br> GLdouble flareZ; <br> GLfloat bufferZ; </pre>
<p> glGetIntegerv (GL_VIEWPORT, viewport); <br>
glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix); <br>
glGetDoublev (GL_PROJECTION_MATRIX, projmatrix); </p>
<p> <span class="theme">// 返回顶点p在单位立方体中的位置</span><br>
gluProject(p.x, p.y, p.z, mvmatrix, projmatrix, viewport, &winx, &winy,
&winz);<br>
flareZ = winz;</p>
<p> <span class="theme">// 读取点(winx,winy)的深度坐标</span><br>
glReadPixels(winx, winy,1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &bufferZ);</p>
<p> <span class="theme">// 如果深度坐标小于点的坐标,则返回true</span><br>
if (bufferZ < flareZ)<br>
return true;<br>
<span class="theme">//否则返回false</span><br>
else<br>
return false;<br>
}</p>
<p></p>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="tl"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="tc" width="100%"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="100%"></td>
<td class="tr"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="l"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="back3" valign="top" width="100%">我
们通过检测光源是否正对我们的视线来决定是否绘制光晕,但如果你的视点超过了光源的位置,则会发生看不见光晕的现象。为了避免这种现象,我们在移动视点的
使用,也相应的移动我们的光源。为了在视点和光源之间绘制多个光晕,我们需要计算之间的向量,下面的代码完成这个功能:</td>
<td class="r"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="bl"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="bc" width="100%"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="br"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<pre><span class="theme">//下面的函数完成具体的渲染光晕的任务</span><br>void glCamera::RenderLensFlare()<br>{<br> GLfloat Length = 0.0f;</pre>
<p> <span class="theme">// 如果我们的光源在我们的视线范围内,则绘制它</span><br>
if(SphereInFrustum(m_LightSourcePos, 1.0f) == TRUE)<br>
{<br>
vLightSourceToCamera = m_Position - m_LightSourcePos; <span class="theme">//
计算光源到我们视线的距离</span><br>
Length = vLightSourceToCamera.Magnitude(); </p>
<p> <span class="theme">//下面三个函数计算光源位置到光晕结束位置之间的向量</span><br>
ptIntersect = m_DirectionVector * Length; <br>
ptIntersect += m_Position;<br>
vLightSourceToIntersect = ptIntersect - m_LightSourcePos; <br>
Length = vLightSourceToIntersect.Magnitude(); <br>
vLightSourceToIntersect.Normalize(); <br>
<br>
glEnable(GL_BLEND); <br>
glBlendFunc(GL_SRC_ALPHA, GL_ONE); <br>
glDisable(GL_DEPTH_TEST); <br>
glEnable(GL_TEXTURE_2D);</p>
<pre>
</pre>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="tl"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="tc" width="100%"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="100%"></td>
<td class="tr"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="l"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="back3" valign="top" width="100%">
<p>首先我们需要找到光源位置和视点位置之间的向量,接下来我们需要在视线的方向设置一个插值点,这个点的距离必须和光源位置和视点位置之间的距离相等。完成以后,我们找出可以产生光晕的方向,即下图红线的方向,在这个线上我们可以绘制我们的光晕。</p>
<p>
</p><center>
<img src="Tutorial_44_files/illustration.jpg" height="512" width="512">
</center>
<br>
<p></p>
</td>
<td class="r"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="bl"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="bc" width="100%"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td>
<td class="br"><img alt="" src="Tutorial_44_files/blank1.gif" height="28" width="28"></td></tr></tbody></table>
<pre> if (!IsOccluded(m_LightSourcePos)) <span class="theme">//如果光晕可见</span><br> {<br> <span class="theme">// 渲染中间的光晕</span><br> RenderBigGlow(0.60f, 0.60f, 0.8f, 1.0f, m_LightSourcePos, 16.0f);<br> RenderStreaks(0.60f, 0.60f, 0.8f, 1.0f, m_LightSourcePos, 16.0f);<br> RenderGlow(0.8f, 0.8f, 1.0f, 0.5f, m_LightSourcePos, 3.5f);</pre>
<p> <span class="theme">//绘制到光晕结束位置的0.1处的光晕</span><br>
pt = vLightSourceToIntersect * (Length * 0.1f); <br>
pt += m_LightSourcePos; <br>
RenderGlow(0.9f, 0.6f, 0.4f, 0.5f, pt, 0.6f); </p>
<p> <span class="theme">//绘制到光晕结束位置的0.15处的光晕</span><br>
pt = vLightSourceToIntersect * (Length * 0.15f); <br>
pt += m_LightSourcePos; <br>
RenderHalo(0.8f, 0.5f, 0.6f, 0.5f, pt, 1.7f); <br>
<br>
<span class="theme">//绘制到光晕结束位置的0.175处的光晕</span><br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -