三维空间⾥的简单的长⽅体透视变换
好啦,啰嗦的话yogurt就不多说了,最近在W3school上⾯⾃学Java和CSS有点⼉⼼累,不过还是要给⼤家良⼼推荐这个学习⽹站,真⼼不错哦!
// 3Dchange.cpp : 定义控制台应⽤程序的⼊⼝点。
//
#include "stdafx.h"
#include"Graph.h"
圣佛山#include"math.h"
#define PI 3.1415926
typedef double matrix[4][4];
typedef struct
{
double x;
double y;
double z;
}point;
//叉乘
void Cross_Product(double pa[3], double pb[3], double pc[3])
{
pc[0] = pa[1] * pb[2] - pa[2] * pb[1];
pc[1] = pa[2] * pb[0] - pa[0] * pb[2];
pc[2] = pa[0] * pb[1] - pa[1] * pb[0];
return;
}
//点乘
double Dot_Product(double pa[3], double pb[3])
{
double p = 0;
for (int i = 0; i < 3; i++)
{
p += pa[i] * pb[i];
}
if (p < 1e-6)//当结果太⼩时,取0
return0;
el
return p;
}
//单位化
void unit(double p[3])
{
double k = sqrt(pow(p[0], 2) + pow(p[1], 2) + pow(p[2], 2));
for (int i = 0; i < 3; i++)
p[i] /= k;
return;
}
//求⽤户坐标系到观察坐标系变换矩阵
void transform(point a, double t1[4][4])
{
double pn[3] = { a.x - 0, a.y - 0, a.z - 0 };
unit(pn);
double pf[3] = { 0, 0, 1 };
double pu[3], pv[3];
Cross_Product(pf, pn, pu);
unit(pu);
Cross_Product(pn, pu, pv);
unit(pv);
double p[3] = { a.x, a.y, a.z };
double m[3] = { 0, 0, 0 };
m[0] = -Dot_Product(p, pu);
m[1] = -Dot_Product(p, pv);
m[2] = -Dot_Product(p, pn);
for (int i = 0; i < 3; i++)
t1[i][0] = pu[i];
for (int i = 0; i < 3; i++)
t1[i][1] = pv[i];
for (int i = 0; i < 3; i++)
t1[i][2] = pn[i];
for (int i = 0; i <3; i++)
t1[i][3] = 0;
for (int i = 0; i < 3; i++)
t1[3][i] = m[i];
for (int i = 0; i < 3; i++)
t1[i][3] = 0;
t1[3][3] = 1;抓饭的做法
//得到⽤户坐标系到观察坐标系的转换矩阵t1[4][4]
return;
}
//求透视投影变换矩阵
void perspective_Tran(point a, double ty[4][4])
{
//观察窗⼝--------------------------------------------------------------double wwidth = getWindowWidth(), hheight = getWindowHeight(); double d = wwidth / hheight;//横纵⽐
double heightt = 10 * tan(PI / 6);//半个窗⼝⾼
六年级的作文
double height = 2 * heightt;
double width = height*d;//窗⼝⾼和窗⼝宽
//规范化变换矩阵--------------------------------------------------------
//不需要进⾏投影中⼼和错切的变换
double k = (double)10 / 1000;
简笔画杯子
double a211 = (2 / width)*k;
double a222 = (2 / height)*k;
double a233 = 1 / 1000.0;
double t2[4][4] = { a211 / 2.0, 0, 0, 0,
0, a222 / 2.0, 0, 0,
0, 0, a233, 0,
0, 0, 0, 1 }; //⽐例变换
double f = (double)10 / 1000;
double a333 = 1 / (1 - f);
double a343 = -f / (1 - f);
double t3[4][4] = { 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, a333, 1,
0, 0, a343, 0 }; //变为平⾏投影的规范化观察空间
for (int i = 0; i < 4; i++){
for (int j = 0; j < 4; j++)
{
ty[i][j] = 0;
for (int w = 0; w < 4; w++)
ty[i][j] += t2[i][w] * t3[w][j];
}
}//得到透视投影变换矩阵ty[4][4]
眼球充血怎么办
int tmp = 0;
return;
}
//得到平移等变换矩阵
void command(double(*p)[4], char order)
{
switch (order)
{
ca'y':
printf("X、Y、Z平移量(形如:1,1,1):");
scanf("%lf,%lf,%lf", p[3], p[3] + 1, p[3] + 2);
break;
ca'f':
printf("X、Y、Z变化⽐例(形如:1,1,1):");
scanf("%lf,%lf,%lf", p[0], p[1] + 1, p[2] + 2);
break;
ca'a':
printf("绕X轴旋转⾓度(如:30°输⼊30):");
double angle_a;
scanf("%lf", &angle_a);
angle_a /= PI;
*(p[1] + 1) = (double)cos(angle_a);
*(p[1] + 2) = (double)sin(angle_a);
*(p[2] + 1) = -(double)sin(angle_a);
*(p[2] + 2) = (double)cos(angle_a);
break;
ca'b':
printf("绕Y轴旋转⾓度:");
double angle_b;
scanf("%lf", &angle_b);
angle_b /= PI;
*(p[0] + 0) = (double)cos(angle_b);
*(p[0] + 2) = -(double)sin(angle_b);
*(p[2] + 0) = (double)sin(angle_b);
*(p[2] + 2) = (double)cos(angle_b);
break;
ca'c':
printf("绕Z轴旋转⾓度:");
double angle_c;
scanf("%lf", &angle_c);
angle_c /= PI;
*(p[0] + 0) = (double)cos(angle_c);
*(p[0] + 1) = (double)sin(angle_c);
*(p[1] + 0) = -(double)sin(angle_c);
*(p[1] + 1) = (double)cos(angle_c);
break;
}
getchar();
return;
}
//矩阵乘法
void change(double cuboid[8][4], double t[4][4], double new_cuboid[8][4]) {
for (int i = 0; i < 8; i++)
for (int j = 0; j < 4; j++)
{
new_cuboid[i][j] = 0;
for (int w = 0; w < 4; w++)
new_cuboid[i][j] += cuboid[i][w] * t[w][j];
}
return;
}
//三维转⼆维,便于在⼆维空间画图
void Tran3DTo2D(double(*rectangle)[4], double(*cuboid)[4]) {
for (int i = 0; i < 8; i++)
{
rectangle[i][0] = cuboid[i][0] / cuboid[i][3];
rectangle[i][1] = cuboid[i][1] / cuboid[i][3];
刘嘉龙
rectangle[i][2] = cuboid[i][2] / cuboid[i][3];
rectangle[i][3] = cuboid[i][3] / cuboid[i][3];
} //三维转⼆维(x,y,z,w)-->(x/w,y/w,z/w,w/w)
return;
}
//画图
void draw(double(*tu)[4])
{
double new_tu[8][2];
double w = getWindowWidth();//屏幕宽
for (int i = 0; i < 8; i++)
{
new_tu[i][0] = (*tu[i] + 1)*w / 2;
new_tu[i][1] = (*(tu[i] + 1) + 1)*w / 2;
}
tOrig(0, 0);
moveTo(new_tu[0][0], new_tu[0][1]);
lineTo(new_tu[1][0], new_tu[1][1]);
lineTo(new_tu[2][0], new_tu[2][1]);
lineTo(new_tu[3][0], new_tu[3][1]);
lineTo(new_tu[0][0], new_tu[0][1]);
lineTo(new_tu[4][0], new_tu[4][1]);
lineTo(new_tu[5][0], new_tu[5][1]);
lineTo(new_tu[6][0], new_tu[6][1]);
lineTo(new_tu[7][0], new_tu[7][1]);
lineTo(new_tu[4][0], new_tu[4][1]);
for (int i = 1; i < 4; i++)
{
moveTo(new_tu[i][0], new_tu[i][1]);
lineTo(new_tu[i + 4][0], new_tu[i + 4][1]);
}
return;
}
int _tmain(int argc, _TCHAR* argv[])
{
double cuboid[8][4] = { 0, 0, 0, 1,
300, 0, 0, 1,
300, 200,0, 1,
0, 200, 0, 1,
0, 0, 100, 1,
300,0, 100, 1,
300, 200, 100, 1,
0, 200, 100, 1 };
point a;//⽤户坐标系中的坐标
char viewpoint;
printf("是否开始/继续改变视点(y,n):");
scanf("%c", &viewpoint);
getchar();
while (viewpoint == 'y')
{
printf("请输⼊观察参考点在⽤户坐标系中的坐标(x,y,z):");
scanf("%lf,%lf,%lf", &a.x, &a.y, &a.z);
getchar();
matrix t1 = { 0 };//⽤户坐标系-->观察坐标系的转换矩阵
matrix ty = { 0 };//在观察坐标系中的透视投影变换矩阵
transform(a, t1);
perspective_Tran(a, ty);
double new1_cuboid[8][4], new2_cuboid[8][4];
change(cuboid, t1, new1_cuboid);//⽤户坐标系-->观察坐标系中的坐标
change(new1_cuboid, ty, new2_cuboid);//在观察坐标系中做透视投影后的坐标
double rectangle[8][4];
Tran3DTo2D(rectangle, new2_cuboid);
draw(rectangle); //未经过平移等变换的长⽅体
梦妆护肤品怎么样double commandmand[4][4] = { 1, 0, 0, 0,归还世界给你剧情介绍
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 };
char code, order;;
printf("是否开始/继续变换(y,n):");
scanf("%c", &code);
getchar();
while (code == 'y')
{
printf("请输⼊平移(y)、放缩⽐例(f)、旋转x轴y轴z轴(a、b、c):");
scanf("%c", &order);
getchar();
command(commandmand, order); //修改三维变换命令矩阵commandmand
double new3_cuboid[8][4];
change(cuboid, commandmand, new1_cuboid); //⽤户坐标系中先按命令三维坐标变换进⾏变换
change(new1_cuboid, t1, new2_cuboid);
change(new2_cuboid, ty, new3_cuboid);
Tran3DTo2D(rectangle, new3_cuboid);
clearWindow();
draw(rectangle);
printf("是否开始/继续变换(y,n):");
scanf("%c", &code);
}
printf("是否开始/继续改变视点(y,n):");
scanf("%c", &viewpoint);
}
return0;
}
View Code
程序的稳定性还有⼀些⼩问题,在输⼊输出的如getchar上⾯还有待调试。哎呀不要在意细节,具体我们能够完成透视变换就已经棒棒哒啦!也欢迎⼩伙伴⼀起调试给出意见和建议哦!