编写立方体的一点透视投影图

一.窗口到视区的坐标变换
1.窗口:在世界坐标系中,设置一矩阵区域,来观察整幅图中的部分内容。
编写立方体的一点透视投影图_第1张图片
2.视区:窗口映射到显示器上的区域称为视区。
编写立方体的一点透视投影图_第2张图片
3.坐标变换

(xv-xv_min)/(xv_max-xv_min)=(xw-xw_min)/(xw_max-xw_min)
(yv-yv_min)/(yv_max-yv_min)=(yw-yw_min)/(yw_max-yw_min)    **[(xv,yv)为视区中的坐标]**

转化为:

xv=xv_min+(xw-xw_min)Sx
yv=yv_min+(yw-yw_min)Sy

其中缩放因子Sx,Sy:

Sx=(xv_max-xv_min)/(xw_max-xw_min)
Sy=(yv_max-yv_min)/(yw_max-yw_min)      **[当Sx=Sy,物体保持相似性]**

二.一点透视投影
1.透视投影
透视投影的视线(投影线)是从视点(观察点)出发,视线是不平行的。模拟人眼观察物体的过程。透视图是通过透视中心(视点),将空间立体投影到二维平面(投影面)所产生的图形,具有较强的立体感。

2.一点透视
不平行于投影平面的平行线汇聚的一点称为灭点,在坐标轴上的灭点叫做主灭点。主灭点数和投影平面切割坐标轴的数量相对应。一点透视即有一个主灭点Z_prp。
编写立方体的一点透视投影图_第3张图片
3.透视变换方程的推导
(1)坐标为(x,y,z)的P点到观察平面上点(xp,yp,zp)的透视投影。
编写立方体的一点透视投影图_第4张图片
这里,直线AB的参数化方程:

     x’=x-xu ①
     y’=y-yu ②
     z’=z-(z-z_prp)u ③
     u∈[0,1]

我们可通过③式得到u值求解①②:
当u=0,位于P=(x,y,z)处;u=1,位于投影参考点(0,0,z_prp)处
在观察平面上,z’=z_vp(z_vp是投影平面在Z轴的截距)

z_vp=z-(z-z_prp)u 
u=(z-z_vp)/(z-z_prp)

将u值代入x’和y’的方程,得到透视变换方程:

xp=x[(z_prp-z_vp)/(z_prp-z)]=x *dp/(z_prp-z)
yp=y[(z_prp-z_vp)/(z_prp-z)]=y *dp/(z_prp-z)

其中, dp= z_prp-z_vp是投影参考点到观察平面的距离
这里代码中直接设置z_vp =0,则

xp=x* z_prp/(z_prp-z)=x *1/( 1-z/z_prp)
yp=y* z_prp/(z_prp-z)=y *1/( 1-z/z_prp)

三.主要步骤
1.确定空间坐标系中八个点坐标(数组存放);

2.确定立方体各顶点的投影坐标(这里z_vp=0,即投影在xoy面);

xp=x* z_prp/(z_prp-z)=x *1/( 1-z/z_prp)
yp=y* z_prp/(z_prp-z)=y *1/( 1-z/z_prp)

编写立方体的一点透视投影图_第5张图片
图中红线即得到的投影区域(其中有重合点),这样得到的图形没有立体感,所以可以在最初设置x和y的平移量使之有立体感

3.将投影坐标变换到屏幕上,最后连线即可。

xv=xv_min+(xw-xw_min)Sx
yv=yv_min+(yw-yw_min)Sy
Sx=(xv_max-xv_min)/(xw_max-xw_min)
Sy=(yv_max-yv_min)/(yw_max-yw_min)

代码如下:

#include
#include

float xt,yt,d;//xt,yt为平移量,d为视点z_prp坐标 

void Perspect(float *p){	
	//确定立方体各顶点的投影坐标 
	for(int i=0;i<24;i=i+3){
		p[i]=(p[i]+xt)/(1-p[i+2]/d);
		p[i+1]=(p[i+1]+yt)/(1-p[i+2]/d);
		p[i+2]=0;
	}
	// 得到窗口中xp_min xp_max yp_min yp_max
	float xp_min=p[0];
	float xp_max=p[3];
	for(int i=0;i<24;i=i+3){
		if(p[i]<=xp_min)
			xp_min=p[i];
		else
			xp_max=p[i];
	}
	
	float yp_min=p[1];
	float yp_max=p[4];
	for(int i=1;i<24;i=i+3){
		if(p[i]<=yp_min)
			yp_min=p[i];
		else
			yp_max=p[i];
	}
	//窗口到视区的坐标变换 
	float xv_min=20;
	float xv_max=45;
	float yv_max=20;
	float yv_min=45;
	
	float Sx=(xv_max-xv_min)/(xp_max-xp_min);
	float Sy=(yv_max-yv_min)/(yp_max-yp_min);
	for(int i=0;i<24;i=i+3){
		p[i]=xv_min+(p[i]-xp_min)*Sx;
		p[i+1]=yv_min+(p[i+1]-yp_min)*Sy;
		p[i+2]=0;
	}
	for(int i=0;i<24;i++){
		p[i]=(int)p[i];
	}
	int p1[10]={p[0],p[1],p[3],p[4],p[15],p[16],p[12],p[13],p[0],p[1]};
	int p2[10]={p[6],p[7],p[9],p[10],p[21],p[22],p[18],p[19],p[6],p[7]};
	//连线 
	drawpoly(5,p1);drawpoly(5,p2);
	line(p[0],p[1],p[9],p[10]);
	line(p[3],p[4],p[6],p[7]);
	line(p[15],p[16],p[18],p[19]);
	line(p[12],p[13],p[21],p[22]);
}

int main(){
	initgraph(640,480);
	setbkcolor(BLACK);
	float p[24]={0,0,0,1,0,0,1,1,0,0,1,0,0,0,1,1,0,1,1,1,1,0,1,1};
	printf("输入平移的位置:\n");
	printf("xt= ");scanf("%f",&xt);
	printf("yt= ");scanf("%f",&yt);
	printf("输入视点z_prp:\n");
	printf("d= ");scanf("%f",&d);
	Perspect(p);
	getch();
	closegraph();
	return 0;
}

你可能感兴趣的:(计算机图形学,C语言)