实验八 真实感图形

28
实实实 实实实实实 . 实实实实实实实实实实实实实实实实实实实实 实实实实实 实实实实实实实实实实实实 、、, 实实实实实实实实实 实实实 实实实实实 实 体体 实实实实实实实实实 实实实实实实实实实实实实实实 实实实实实实实实实 实 ,。, 实实实实实实实实实实实实实实

Upload: york

Post on 05-Jan-2016

148 views

Category:

Documents


2 download

DESCRIPTION

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

TRANSCRIPT

Page 1: 实验八      真实感图形

实验八 真实感图形

一 . 概述:

本实验是根据真实感图形生成的光照技术、消影技术、几何纹理映射等相关理论,编程实现具有三维立体感的立体图形的绘制 。

由于本实验难度较大,所以对本科不要求必须完成求。故仅作为附加实验,给能力较强的同学们提供锻炼机会。

Page 2: 实验八      真实感图形

二.实验的主要目的:

1 、检查学生对真实感图形生成相关技术的掌握情况;2 、培养学生根据真实感图形生成的光照技术、消影技术、

几何纹理映射等等相关技术之一,具有编程实现三维立体感图形的能力;

3 、培养学生根据相关理论,能借助计算机分析解决实际问题的能力。

注:对于本科生来说,此实验难度稍大。所以不要求必须完成,仅作锻炼与参考。

Page 3: 实验八      真实感图形

三.实验步骤:

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

Page 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;

}

Page 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); // 画线到一点

}

Page 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); // 移动到某点

}

Page 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;}

Page 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];}

Page 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;

}

Page 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);

}

Page 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);

}

Page 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);

}

Page 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;}

Page 14: 实验八      真实感图形

void CMyView::Mydraw(){

RedrawWindow();ReadVertics();ReadFaces();// 绘出透视投影下的凸多面体图形VisionPoint(); // 给出视点位置

DrawObject(); // 画出立体的图形}

Page 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;

}}

Page 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);}

Page 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;

Page 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_yzw=z; xw=x;x=zw*cos(thy)-xw*sin(thy);z=zw*sin(thy)+xw*cos(thy);//x=x+r1/2*d;

Page 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 persx=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;

}

Page 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;

Page 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;

} }

}

Page 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);

Page 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();}

Page 24: 实验八      真实感图形

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

Page 25: 实验八      真实感图形
Page 26: 实验八      真实感图形
Page 27: 实验八      真实感图形

光照示例 ( 程序略 ) :

Page 28: 实验八      真实感图形