|
课程名称 | 计算机图形学 | 班级 | 1320541 | 实验日期 | 2015年6月11日星期四 |
姓 名 | 刘 | 学号 | 37 | 实验成绩 |
|
实验名称 | 实验五 光照球 | ||||
实 验 目 的 及 要 求 | 1) 理解球边表和面表算法 2) 理解双缓冲的算法 3) 理解mfc作用原理 4) 理解光照球算法 | ||||
实 验 环 境 | VS2013基于MFC | ||||
实 验 内 容 | 利用mfc绘制光照球球 | ||||
算
法
描
述
及
实
验
步
骤 | 部分重要代码截图:
(用适当的形式表达算法设计思想与算法实现步骤) | ||||
调
试
过
程
及
实
验
结
果 | 实验过程中没有出现太大的问题 实验结果展示如下: 双光源光照地理球
(详细记录在调试过程中出现的问题及解决方法。记录实验运行结果) | ||||
总
结 | 1) 通过本次实验,了解到了mfc的最基本知识,发现自己学习mfc任重而道远,在前行的路上还有很多学习的地方。 2) 实践是检验真理的唯一标准 3) 动手能力需要再次提高 4) 算法思想要与时俱进,要多学习算法 (对实验结果进行分析,实验心得体会及改进意见) | ||||
附
录
附
录
附
录
附
录
附
录
附
录
附
录
附
录 | CDrawBallView::CDrawBallView() : N(NULL) , F(NULL), N1(0) , N2(0) , Alpha(0) , Beta(0) , V(NULL) { // TODO: 在此处添加构造代码 V = NULL; F = NULL; R = 1000.0, d = 800.0, Phi = 90.0, Theta = 0.0;//视点位于正前方 Near = 200.0, Far = 1200.0;//近剪切面与远剪切面 LightNum = 2;//光源个数 pLight = new CLighting(LightNum);//一维光源动态数组 pLight->Light[0].SetPosition(-800, 800, 800);//设置光源位置坐标 pLight->Light[1].SetPosition(800, 800, 800);//设置光源位置坐标 for (int i = 0; i<LightNum; i++) { pLight->Light[i].L_Diffuse = CRGB(1.0, 1.0, 1.0);//光源的漫反射颜色 pLight->Light[i].L_Specular = CRGB(1.0, 1.0, 1.0);//光源镜面高光颜色 pLight->Light[i].L_C0 = 1.0;//常数衰减系数 pLight->Light[i].L_C1 = 0.0000001;//线性衰减系数 pLight->Light[i].L_C2 = 0.00000001;//二次衰减系数 pLight->Light[i].L_OnOff = TRUE;//光源开启 } pMaterial = new CMaterial;//一维材质动态数组 pMaterial->SetAmbient(CRGB(0.175, 0.012, 0.012));//材质对环境光光的反射率 pMaterial->SetDiffuse(CRGB(0.614, 0.041, 0.041));//材质对漫反射光的反射率 pMaterial->SetSpecular(CRGB(1.0, 1.0, 1.0));//材质对镜面反射光的反射率 pMaterial->SetEmit(CRGB(0.2, 0.2, 0.4));//材质自身发散的颜色 pMaterial->SetExp(30);//高光指数 }
// CDrawBallView 绘制
void CDrawBallView::OnDraw(CDC* pDC) { CDrawBallDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代 pDC = GetDC(); CRect rect; GetClientRect(&rect); //pDC->Rectangle(0, 0, rect.Width(), rect.Height()); //pDC->FillSolidRect(&rect, RGB(0, 0, 0)); pDC->SetTextColor(RGB(255, 0, 0)); pDC->TextOutW(200, 200, _T("光源位置为:X:-800,Y:800,Z:800")); pDC->TextOutW(920, 200, _T("光源位置为:X:800,Y:800,Z:800")); DoubleBuffer(); pDC->TextOutW(200, 200, _T("光源位置为:X:-800,Y:800,Z:800")); pDC->TextOutW(920, 200, _T("光源位置为:X:800,Y:800,Z:800")); }
// CDrawBallView 打印
BOOL CDrawBallView::OnPreparePrinting(CPrintInfo* pInfo) { // 默认准备 return DoPreparePrinting(pInfo); }
void CDrawBallView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: 添加额外的打印前进行的初始化过程 }
void CDrawBallView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: 添加打印后进行的清理过程 }
// CDrawBallView 诊断
#ifdef _DEBUG void CDrawBallView::AssertValid() const { CView::AssertValid(); }
void CDrawBallView::Dump(CDumpContext& dc) const { CView::Dump(dc); }
CDrawBallDoc* CDrawBallView::GetDocument() const // 非调试版本是内联的 { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(Cliuchuang46_DrawBallDoc))); return (Cliuchuang46_DrawBallDoc*)m_pDocument; } #endif //_DEBUG
// CDrawBallView 消息处理程序 void CDrawBallView::InitParameter() { k[1] = sin(PI*Theta / 180); k[2] = sin(PI*Phi / 180); k[3] = cos(PI*Theta / 180); k[4] = cos(PI*Phi / 180); k[5] = k[2] * k[3]; k[6] = k[2] * k[1]; k[7] = k[4] * k[3]; k[8] = k[4] * k[1]; ViewPoint.x = R*k[6]; ViewPoint.y = R*k[4]; ViewPoint.z = R*k[5]; }
void CDrawBallView::PerProject(CP3 P) { CP3 ViewP; ViewP.x = P.x*k[3] - P.z*k[1];//观察坐标系三维坐标 ViewP.y = -P.x*k[8] + P.y*k[2] - P.z*k[7]; ViewP.z = -P.x*k[6] - P.y*k[4] - P.z*k[5] + R; ViewP.c = P.c; ScreenP.x = d*ViewP.x / ViewP.z;//屏幕坐标系三维坐标 ScreenP.y = Round(d*ViewP.y / ViewP.z); ScreenP.z = Far*(1 - Near / ViewP.z) / (Far - Near); ScreenP.c = ViewP.c; }
void CDrawBallView::ReadVertex()//读入顶点 { int gAlpha = 5, gBeta = 5;//面片夹角 N1 = 180 / gAlpha; N2 = 360 / gBeta;//N1为纬度区域,N2为经度区域 V = new CP3[(N1 - 1)*N2 + 2];//V为球的顶点 //纬度方向除南北极点外有"N1-1"个点,"2"代表南北极两个点 double gAlpha1, gBeta1, r = 300;//r为球体半径 //计算北极点坐标 V[0].x = 0, V[0].y = r, V[0].z = 0; //按行循环计算球体上的点坐标 for (int i = 0; i<N1 - 1; i++) { gAlpha1 = (i + 1)*gAlpha*PI / 180; for (int j = 0; j<N2; j++) { gBeta1 = j*gBeta*PI / 180; V[i*N2 + j + 1].x = r*sin(gAlpha1)*sin(gBeta1); V[i*N2 + j + 1].y = r*cos(gAlpha1); V[i*N2 + j + 1].z = r*sin(gAlpha1)*cos(gBeta1); } } //计算南极点坐标 V[(N1 - 1)*N2 + 1].x = 0, V[(N1 - 1)*N2 + 1].y = -r, V[(N1 - 1)*N2 + 1].z = 0; }
void CDrawBallView::ReadFace()//读入面表 { //设置二维动态数组 F = new CFace *[N1];//设置行 for (int n = 0; n<N1; n++) F[n] = new CFace[N2];//设置列 for (int j = 0; j<N2; j++)//构造北极三角形面片 { int tempj = j + 1; if (tempj == N2) tempj = 0;//面片的首尾连接 int NorthIndex[3];//北极三角形面片索引号数组 NorthIndex[0] = 0; NorthIndex[1] = j + 1; NorthIndex[2] = tempj + 1; F[0][j].SetNum(3); for (int k = 0; k<F[0][j].vN; k++) F[0][j].vI[k] = NorthIndex[k]; } for (int i = 1; i<N1 - 1; i++)//构造球面四边形面片 { for (int j = 0; j<N2; j++) { int tempi = i + 1; int tempj = j + 1; if (tempj == N2) tempj = 0; int BodyIndex[4];//球面四边形面片索引号数组 BodyIndex[0] = (i - 1)*N2 + j + 1; BodyIndex[1] = (tempi - 1)*N2 + j + 1; BodyIndex[2] = (tempi - 1)*N2 + tempj + 1; BodyIndex[3] = (i - 1)*N2 + tempj + 1; F[i][j].SetNum(4); for (int k = 0; k<F[i][j].vN; k++) F[i][j].vI[k] = BodyIndex[k]; } } for (int j = 0; j<N2; j++)//构造南极三角形面片 { int tempj = j + 1; if (tempj == N2) tempj = 0; int SouthIndex[3];//南极三角形面片索引号数组 SouthIndex[0] = (N1 - 2)*N2 + j + 1; SouthIndex[1] = (N1 - 1)*N2 + 1; SouthIndex[2] = (N1 - 2)*N2 + tempj + 1; F[N1 - 1][j].SetNum(3); for (int k = 0; k<F[N1 - 1][j].vN; k++) F[N1 - 1][j].vI[k] = SouthIndex[k]; } }
void CDrawBallView::DoubleBuffer() { CDC* pDC = GetDC(); CRect rect;//定义客户区 GetClientRect(&rect);//获得客户区的大小 pDC->SetMapMode(MM_ANISOTROPIC);//pDC自定义坐标系 pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口范围 pDC->SetViewportExt(rect.Width(), -rect.Height());//x轴水平向右,y轴垂直向上 pDC->SetViewportOrg(rect.Width() / 2, rect.Height() / 2);//屏幕中心为原点 CDC MemDC;//内存DC CBitmap NewBitmap, *pOldBitmap;//内存中承载图像的临时位图 MemDC.CreateCompatibleDC(pDC);//建立与屏幕pDC兼容的MemDC NewBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());//创建兼容位图 pOldBitmap = MemDC.SelectObject(&NewBitmap); //将兼容位图选入MemDC //MemDC.FillSolidRect(&rect, pDC->GetBkColor());//按原来背景填充客户区,否则是黑色 MemDC.SetMapMode(MM_ANISOTROPIC);//MemDC自定义坐标系 MemDC.SetWindowExt(rect.Width(), rect.Height()); MemDC.SetViewportExt(rect.Width(), -rect.Height()); MemDC.SetViewportOrg(rect.Width() / 2, rect.Height() / 2); DrawObject(&MemDC); pDC->BitBlt(-rect.Width() / 2, -rect.Height() / 2, rect.Width(), rect.Height(), &MemDC, -rect.Width() / 2, -rect.Height() / 2, SRCCOPY);//将内存位图拷贝到屏幕 MemDC.SelectObject(pOldBitmap);//恢复位图 NewBitmap.DeleteObject();//删除位图
ReleaseDC(pDC);//释放DC }
void CDrawBallView::CalVertexColor()//计算顶点颜色 { for (int nVertex = 0; nVertex<(N1 - 1)*N2 + 2; nVertex++)//遍历所有点 { CVector VNormal(V[nVertex]);//点的位置矢量代表共享该点的所有面的平均法矢量 V[nVertex].c = pLight->Lighting(ViewPoint, V[nVertex], VNormal, pMaterial);//调用光照函数 } }
void CDrawBallView::DrawObject(CDC* pDC) { CalVertexColor(); CZBuffer *zbuf = new CZBuffer;//申请内存 zbuf->InitDeepBuffer(800, 800, 1000);//初始化深度缓冲器 CPi3 Point3[3];//南北极顶点数组 CPi3 Point4[4];//球体顶点数组 for (int i = 0; i<N1; i++) { for (int j = 0; j<N2; j++) { CVector ViewVector(V[F[i][j].vI[0]], ViewPoint);//面的视矢量 ViewVector = ViewVector.Normalize();//单位化视矢量 F[i][j].SetFaceNormal(V[F[i][j].vI[0]], V[F[i][j].vI[1]], V[F[i][j].vI[2]]); F[i][j].fNormal.Normalize();//单位化法矢量 if (Dot(ViewVector, F[i][j].fNormal) >= 0)//背面剔除 { if (3 == F[i][j].vN)//三角形面片 { for (int m = 0; m<F[i][j].vN; m++) { PerProject(V[F[i][j].vI[m]]); Point3[m] = ScreenP; } zbuf->SetPoint(Point3, 3);//设置顶点 zbuf->CreateBucket();//建立桶表 zbuf->CreateEdge();//建立边表 zbuf->Gouraud(pDC);//填充三角形 zbuf->ClearMemory();//内存清理 } else//四边形面片 { for (int m = 0; m<F[i][j].vN; m++) { PerProject(V[F[i][j].vI[m]]); Point4[m] = ScreenP; } zbuf->SetPoint(Point4, 4);//设置顶点 zbuf->CreateBucket();//建立桶表 zbuf->CreateEdge();//建立边表 zbuf->Gouraud(pDC);//填充四边形 zbuf->ClearMemory();//内存清理 } } } } delete zbuf;//释放内存
}
void C_DrawBallView::OnInitialUpdate() {
ReadVertex(); ReadFace(); tran.SetMat(V, (N1 - 1)*N2 + 2); InitParameter(); }
void CDrawBallView::OnDrawView() { // TODO: 在此添加命令处理程序代码 SetTimer(1, 100, NULL); }
void Cliuchuang46_DrawBallView::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值
CView::OnTimer(nIDEvent); Alpha = 5; Beta = 5; tran.RotateX(Alpha); tran.RotateY(Beta); Invalidate(FALSE); }
void CDrawBallView::OnExit() { // TODO: 在此添加命令处理程序代码 exit(1);
}
void CDrawBallView::OnPause() { // TODO: 在此添加命令处理程序代码 KillTimer(1); }
int CDrawBallView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1;
// TODO: 在此添加您专用的创建代码 return 0; }
BOOL CDrawBallView::OnEraseBkgnd(CDC* pDC) { // TODO: 在此添加消息处理程序代码和/或调用默认值 /*CBrush brush(RGB(0, 0, 0)); CBrush* pOldOne = pDC->SelectObject(&brush); CRect rc; pDC->GetClipBox(&rc); pDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATCOPY); pDC->SelectObject(pOldOne);*/ return TRUE;
}
BOOL CDrawBallView::PreCreateWindow(CREATESTRUCT& cs) {
return CView::PreCreateWindow(cs);
} |