1.实验目的:
了解背向面消隐的基本原理,利用VC实现三棱锥的消隐处理。
2.实验内容:
(1) 阅读教材P139页了解背向面消隐的基本原理;
(2) 阅读教材P194页了解矢量的点积与叉积;
(3) 运行示范代码,了解背向面消隐的实现。
3.实验代码:
完整代码下载:/Files/opengl/BackfaceCull.rar
核心代码如下:
void CBackfaceCullView::OnDraw(CDC* pDC)
{
CBackfaceCullDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CRect rect;
GetClientRect(&rect);
pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);
mT.p[3][0] = lx; mT.p[3][1] = ly;mT.p[3][2] = lz;
mRx.p[1][1] = cos(alpha); mRx.p[2][1] = -sin(alpha);mRx.p[1][2] = sin(alpha); mRx.p[2][2] = cos(alpha);
mRy.p[0][0] = cos(phi); mRy.p[0][2] = -sin(phi); mRy.p[2][0] = sin(phi); mRy.p[2][2] = cos(phi);
mP.p[2][2] = 0;
//mP.p[2][3] = -1/d;
//mP.p[2][3] = 0;
mTemp = Multiply(mT, mRy);
mTemp = Multiply(mTemp, mRx);
mA = Multiply(mTemp, mP);
PyramidProject();
DrawPyramid(pDC);
}
void CBackfaceCullView::DrawPyramid(CDC* pDC)
{
int ptIdx[3];
for(int face=0;face<4;face++)
{
int num =fInfo[face].num;//面的总顶点数
for(int i=0;i<num;i++)//循环
{
ptIdx[i] = GetPtIdx(fInfo[face], i);//面的顶点号
}
bool bDraw = true;
if(m_bHide)
{
//计算面的外法向量
/*
| i j k |
|x2-x1 y2-y1 z2-z1 |
|x3-x2 y3-y2 z3-z2 |
*/
double x1 = m_tmpPt[ptIdx[0]].x;
double y1 = m_tmpPt[ptIdx[0]].y;
double z1 = m_tmpPt[ptIdx[0]].z;
double x2 = m_tmpPt[ptIdx[1]].x;
double y2 = m_tmpPt[ptIdx[1]].y;
double z2 = m_tmpPt[ptIdx[1]].z;
double x3 = m_tmpPt[ptIdx[2]].x;
double y3 = m_tmpPt[ptIdx[2]].y;
double z3 = m_tmpPt[ptIdx[2]].z;
double xn,yn,zn,vn;
xn = (y2 - y1)*(z3-z2) - (y3-y2)*(z2-z1);
yn = -(x2-x1)*(z3-z2) + (x3-x2)*(z2-z1);
zn = (x2-x1)*(y3-y2) - (x3-x2)*(y2-y1); //计算每个面的法矢
vn = sqrt(xn*xn + yn*yn + zn*zn);
xn = xn/vn; yn = yn/vn; zn = zn/vn; //视点方向在(0,0,-1)处
if(zn < 0.0) //视线方向与Z轴同向,当法矢的Z方向分量大于0时,与实现方向成小于90度的角,面可见
{
bDraw = false;
}
}
if(bDraw)
{
for(int j=0; j<3; j++)
{
int idx0 = ptIdx[j];
int idx1 = ((j== 2) ? ptIdx[0]:ptIdx[j+1]);
pDC->MoveTo(m_Pt2d[idx0].x, m_Pt2d[idx0].y);
pDC->LineTo(m_Pt2d[idx1].x, m_Pt2d[idx1].y);
}
}
}
}
4.代码说明:
(1)ReadPoint:定义三棱锥的4个顶点,每个顶点用三维坐标表示;
(2)ReadFace:定义三棱锥的4个面的顶点信息,顶点顺序为逆时针以保证该面的法线向外;
(3)对每个面,读出三个顶点,使用(V2-V1)╳(V3-V2)计算外法向量N;
(4)采用正面投影显示三棱锥,即z’=0;视线方向向量S为(0,0,-1);
(5)未消隐处理下,不计算视向量S与法向量N的点积,直接绘制;
(6)消隐处理下,计算视向量S与法向量N的点积为-zn,如果-zn>0即zn<0为背向面,不绘制面;否则绘制;
(7)设置键盘的上下左右键用于调整三棱锥的显示角度;
(8)三棱锥示意图: