1 / 28

实验八 真实感图形

实验八 真实感图形. 一 . 概述:. 本实验是根据真实感图形生成的光照技术、消影技术、几何纹理映射等相关理论,编程实现具有三维立体感的立体图形的绘制 。 由于本实验难度较大,所以对本科不要求必须完成求。故仅作为附加实验,给能力较强的同学们提供锻炼机会。. 二.实验的主要目的:. 1 、检查学生对真实感图形生成相关技术的掌握情况; 2 、培养学生根据真实感图形生成的光照技术、消影技术、几何纹理映射等等相关技术之一,具有编程实现三维立体感图形的能力; 3 、培养学生根据相关理论,能借助计算机分析解决实际问题的能力。

york
Télécharger la présentation

实验八 真实感图形

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 实验八 真实感图形 一. 概述: 本实验是根据真实感图形生成的光照技术、消影技术、几何纹理映射等相关理论,编程实现具有三维立体感的立体图形的绘制 。 由于本实验难度较大,所以对本科不要求必须完成求。故仅作为附加实验,给能力较强的同学们提供锻炼机会。

  2. 二.实验的主要目的: 1、检查学生对真实感图形生成相关技术的掌握情况; 2、培养学生根据真实感图形生成的光照技术、消影技术、几何纹理映射等等相关技术之一,具有编程实现三维立体感图形的能力; 3、培养学生根据相关理论,能借助计算机分析解决实际问题的能力。 注:对于本科生来说,此实验难度稍大。所以不要求必须完成,仅作锻炼与参考。

  3. 三.实验步骤: 1.建立project; 2.选择欲创建的文档类型; 3.根据真实感图形生成中的消隐技术、或光照技术、图形反走样技术、或阴影生成技术,设计出一个具有真实感图形的程序; 4.编译、调试、运行,并检查是否得到预期结果; 5.按要求书写并提交试验报告。

  4. 附录: 下面仅对消影技术的实现进行编程演示: 实验步骤和方法与前面的实验一相同,区别仅在于: 是在“。。。View.cpp”文件之后,按要求添加如下代码: void CMyView::Project(float X, float Y, float Z)// 此函数求点的平行投影和透视投影坐标值 { XObs = -X * Aux1 + Y * Aux3; YObs = -X * Aux5 - Y * Aux6 + Z * Aux4; // 求透视投影坐标值 ZObs = -X * Aux7 - Y * Aux8 - Z * Aux2 + Rol; XProj = DE * XObs / ZObs; YProj = DE * YObs / ZObs; }

  5. void CMyView::WLineTo(float X, float Y, float Z,CDC*pDC)// 用三维点坐标直接从当前点画线到一点的函数 { Project(X, Y, Z); // 将三维点作投影 XScreen = floor(0.5 + XProj * Scale +400); // 圆整(立体在屏幕上初始的X坐标位置) YScreen = floor(0.5 + 300 - YProj); // 圆整(立体在屏幕上初始的Y坐标位置) pDC->LineTo(XScreen, YScreen); // 画线到一点 }

  6. void CMyView::WMoveTo(float X, float Y, float Z,CDC*pDC)// 三维坐标下直接将当前点移动到某点的函数 { Project (X, Y, Z); // 将三维点作投影 XScreen = floor(0.5 + XProj * Scale + 400); //// 圆整(立体在屏幕上初始的X坐标位置) YScreen = floor(0.5 + 300 - YProj); // 圆整(立体在屏幕上初始的Y坐标位置) pDC->MoveTo(XScreen, YScreen); //移动到某点 }

  7. void CMyView::ReadVertics()// 此函数用来给数组St的元素赋顶点坐标值 { St[1][1] = 40; St[1][2] = 154; St[1][3] =-20; St[2][1] = 40; St[2][2] = 154; St[2][3] = 0; St[3][1] = 40; St[3][2] =46; St[3][3] = 0; St[4][1] = 40; St[4][2] =46; St[4][3] =-20; St[5][1] =-40; St[5][2] =46; St[5][3] =-20; St[6][1] =-40; St[6][2] = 154; St[6][3] =-20; St[7][1] =-40; St[7][2] = 154; St[7][3] = 0; St[8][1] = 0; St[8][2] = 134; St[8][3] = 40; St[9][1] = 0; St[9][2] =66; St[9][3] = 40; St[10][1] =-40; St[10][2] =46; St[10][3] = 0; }

  8. void CMyView::ReadFaces()// 此函数给数组Fc的元素赋表面有关的数据值 { NF= 9; Fc[1][0]=4; Fc[1][1]=1; Fc[1][2]=2; Fc[1][3]=3; Fc[1][4]=4; Fc[2][0]=4; Fc[2][1]=1; Fc[2][2]=6; Fc[2][3]=7; Fc[2][4]=2; Fc[3][0]=3; Fc[3][1]=2; Fc[3][2]=7; Fc[3][3]=8; Fc[4][0]=4; Fc[4][1]=2; Fc[4][2]=8; Fc[4][3]=9; Fc[4][4]=3; Fc[5][0]=4; Fc[5][1]=1; Fc[5][2]=4; Fc[5][3]=5; Fc[5][4]=6; Fc[6][0]=4; Fc[6][1]=7; Fc[6][2]=10; Fc[6][3]=9; Fc[6][4]=8; Fc[7][0]=3; Fc[7][1]=3; Fc[7][2]=9; Fc[7][3]=10; Fc[8][0]=4; Fc[8][1]=10; Fc[8][2]=5; Fc[8][3]=4; Fc[8][4]=3; Fc[9][0]=4; Fc[9][1]=5; Fc[9][2]=10; Fc[9][3]=7; Fc[9][4]=6; } void CMyView::VisionVector(int St1) /* 该函数用于求观察方向矢量 St1 is the first point of a face. */ { v1=O1-St[St1][1]; v2=O2-St[St1][2]; v3=O3-St[St1][3]; }

  9. void CMyView::NormalVector(int St1, int St2, int St3)// 此函数用表面三个顶点调用求该表面的法矢 // St_i is the i_th point of a face. { float P1, P2, P3, Q1, Q2, Q3; // 求一个向量 P1 = St[St2][1] - St[St1][1]; P2 = St[St2][2] - St[St1][2]; P3 = St[St2][3] - St[St1][3]; // 求另一个向量 Q1 = St[St3][1] - St[St1][1]; Q2 = St[St3][2] - St[St1][2]; Q3 = St[St3][3] - St[St1][3]; //用向量积求法向量 n1 = P2 * Q3 - Q2 * P3; n2 = P3 * Q1 - Q3 * P1; n3 = P1 * Q2 - Q1 * P2; }

  10. float CMyView::ScaleProduct(float v1, float v2, float v3, float n1, float n2, float n3)// 此函数用于求观察方向矢量与表面法矢的数量积 { float SProduct; SProduct = v1 * n1 + v2 * n2 + v3 * n3; return(SProduct); }

  11. void CMyView::DrawFace(CDC*pDC)// 画出立体上的平面 { int S, NS, No; float X, Y, Z, X0, Y0, Z0; NS = Fc[F][0]; for ( S = 1; S<= NS; S++ ) { No = Fc[F][S]; X = St[No][1]; Y = St[No][2]; Z = St[No][3]; if ( S == 1 ) { WMoveTo(X, Y, Z,pDC); X0 = X; Y0 = Y; Z0 = Z; } else WLineTo(X, Y, Z,pDC); } WLineTo (X0, Y0, Z0,pDC); }

  12. void CMyView::DrawObject()// 此函数用于绘出消隐立体图 { int St1, St2, St3; CDC*pDC=GetDC(); CPen pen1(PS_SOLID,1,(COLORREF)1),pen2(PS_DOT,1,(COLORREF)1); CPen *pOldPen=pDC->SelectObject(&pen1); for ( F = 1; F<= NF; F++ ){ St1 = Fc[F][1]; St2 = Fc[F][2]; St3 = Fc[F][3]; VisionVector(St1); // 求观察方向矢量 NormalVector(St1, St2, St3); // 求表面法矢 if ( ScaleProduct( v1,v2,v3,n1,n2,n3 ) > 0 ) // 判断数量积正否 { pDC->SelectObject(&pen1); DrawFace(pDC); // 数量积大于零,表面可见,画出此表面 } else; } pDC->SelectObject(pOldPen); ReleaseDC(pDC); }

  13. void CMyView::VisionPoint()// 此函数用于给出视点位置 { // 投影时初始值即正弦值和余弦值及其乘积的计算、赋值 float Th, Ph; Th = 3.1415926 * Theta / 180; Ph = 3.1415926 * Phi / 180; Aux1 = sin(Th); Aux2 = sin(Ph); Aux3 = cos(Th); Aux4 = cos(Ph); Aux5 = Aux3 * Aux2; Aux6 = Aux1 * Aux2; Aux7 = Aux3 * Aux4; Aux8 = Aux1 * Aux4; //给出视点位置 O1 = Rol * Aux7; O2 = Rol * Aux8; O3 = Rol * Aux2; }

  14. void CMyView::Mydraw() { RedrawWindow(); ReadVertics(); ReadFaces(); // 绘出透视投影下的凸多面体图形 VisionPoint(); // 给出视点位置 DrawObject(); // 画出立体的图形 }

  15. void CMyView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {//此函数用来利用上下左右键移动视点角度位置,C键切换投影类型. switch(nChar){ case VK_UP: /上下左右键选择 Phi=Phi-IncAng; Mydraw(); break; case VK_DOWN: Phi=Phi+IncAng; Mydraw(); break; case VK_RIGHT: Theta=Theta+IncAng; Mydraw(); break; case VK_LEFT: Theta=Theta-IncAng; Mydraw(); break; default: break; } }

  16. void CMyView::OnTumianti() {//透视投影赋初值 Rol = 600.0; S=1; Theta = 60; Phi = 135; DE = 1000; Mydraw(); CDC*pDC=GetDC(); //指出控制旋转防向键 pDC->TextOut(10,10,"按下键盘上的“↑”、“↓”、“←”、“→”箭头可从各方位观看图形"); ReleaseDC(pDC); }

  17. void CMyView::OnYuanjin() { CClientDC *pdc=new CClientDC(this); CPen *pen1=new CPen(PS_SOLID,1,RGB(0,0XFF,0)); CPen *pen2=new CPen(PS_SOLID,1,RGB(255,0,0)); CPen *OldPen=pdc->SelectObject(pen1); CBrush brush; brush.CreateSolidBrush(RGB(0,0,0)); CBrush *oldbrush=(CBrush*)pdc->SelectObject(&brush); int flag,k1,k2,r1,r2,n,d,m,p; int xs1,xs2,xs3,xs4,ys1,ys2,ys3,ys4,i,j,lastp; double x,y,z,thx,th1,th3,yw,zw,xw,thy,th2; double PI,ed,od,eh,zzw,ppw; double xs[50][17],zs[50][17],ys[50][17],zc[50][17],x1,y1; int zz[850],pp[850]; r1=100;r2=40;k1=20;k2=16;ed=1500; eh=0;od=0; n=0;PI=3.14159;th3=1;thx=0.9;

  18. //计算顶点坐标值 for(d=-1;d<=1;d+=2){ for(th1=0; th1<=2*PI+0.1;th1+=2*PI/k1){ n=n+1; m=0; for(th2=0;th2<=2*PI+0.1;th2+=2*PI/k2){ m=m+1; x=r1+r2*cos(th2); y=r2*sin(th2); z=0; thy=th1; //Call rot_y zw=z; xw=x; x=zw*cos(thy)-xw*sin(thy); z=zw*sin(thy)+xw*cos(thy); // x=x+r1/2*d;

  19. if(d==1) { yw=y; zw=z; y=yw*cos(PI/2)-zw*sin(PI/2); z=yw*sin(PI/2)+zw*cos(PI/2); } thy=th3; //Call rot_y zw=z; xw=x; x=zw*cos(thy)-xw*sin(thy); z=zw*sin(thy)+xw*cos(thy); // Call rot_x: yw=y; zw=z; y=yw*cos(thx)-zw*sin(thx); z=yw*sin(thx)+zw*cos(thx); //Call pers x=x*ed/(ed-od-z); y=(y*ed-eh*(od+z))/(ed-od-z); xs[n][m]=x; ys[n][m]=y; zs[n][m]=z; }

  20. //next th2 flag=0; //Next th1 } flag=0; //Next d } //计算center值 p=0; for(n=1;n<=k1;n+=1){ for(m=1;m<=k2;m+=1){ zc[n][m]=int((zs[n][m]+zs[n+1][m+1])/2); zz[p]=zc[n][m]; pp[p]=p; p=p+1; //Next m //Next n } } lastp=p-1;

  21. //排序 for(i=2;i<=lastp;i+=1){ for(j=i-1;j>=0;j+=-1){ if(zz[j]>zz[j+1]) { zzw=zz[j]; zz[j]=zz[j+1]; zz[j+1]=zzw; ppw=pp[j]; pp[j]=pp[j+1]; pp[j+1]=ppw; } } }

  22. //绘图 for(p=0;p<=lastp;p+=1){ n=int(pp[p]/k2)+1; m=pp[p]%k2+1; if(n!=(k1+1)){ xs1=int(xs[n][m]); ys1=int(ys[n][m]); xs2=int(xs[n+1][m]); ys2=int(ys[n+1][m]); xs3=int(xs[n+1][m+1]); ys3=int(ys[n+1][m+1]); xs4=int(xs[n][m+1]); ys4=int(ys[n][m+1]); //} if (abs(ys1*(xs2-xs3)+ys2*(xs3-xs1)+ys3*(xs1-xs2))>80){ pdc->MoveTo(xs1+320,ys1+200); pdc->SelectObject(pen1); pdc->LineTo(xs2+320,ys2+200); pdc->LineTo(xs3+320,ys3+200); pdc->LineTo(xs4+320,ys4+200); pdc->LineTo(xs1+320,ys1+200);

  23. //paint x=(xs[n][m]+xs[n+1][m+1])/2; y=(ys[n][m]+ys[n+1][m+1])/2; x1=int(x+320); y1=int(y+200); pdc->ExtFloodFill(x1,y1,RGB(0,255,0),0); //endif } pdc->MoveTo(xs1+320,ys1+200); pdc->SelectObject(pen2); pdc->LineTo(xs2+320,ys2+200); pdc->LineTo(xs3+320,ys3+200); pdc->LineTo(xs4+320,ys4+200); pdc->LineTo(xs1+320,ys1+200); } } pdc->SelectObject(OldPen); delete pen1; delete pen2; pdc->DeleteDC(); }

  24. 其运行结果如下: 用“↑”、“↓”、“←”、“→”键控制图形的旋转,以观察消隐效果。

  25. 光照示例(程序略):

  26. 本实验讲解完毕 谢谢!

More Related