赞
踩
源码下载地址:文件下载-奶牛快传 Download |CowTransfer
(这个程序只支持EGE图形库,请下载自带EGE的redpandaDEVC++,下载地址:文件下载-奶牛快传 Download |CowTransfer,如果使用的是easyX图形库,请根据以下内容对程序进行修改。)
成品展示:
1.眼睛的成像方式
如下图,用A表示物体,O表示晶状体的光心(因为晶状体的形状可变,所以用符号↕表示),l表示主光轴,眼睛会自动调焦,把点A反射的光线都会聚在A'上。
下面,只留线段AA',再在图上加一个屏幕,屏幕与AA'的交点为A":
之后把屏幕后面的部分去掉,A"为光源,眼睛就会改变晶状体的形状,重新聚焦,把A"的光线聚集到A",那么可以在屏幕上用点A''表示点A:
之后,创建一个3维坐标图(为适应屏幕,所以不使用右手空间直角坐标系):
由此可以得出A在屏幕上的x坐标为A.x*眼睛与屏幕z轴的差/(眼睛距屏幕距离+A与屏幕z轴的差),y坐标同理。(但是这样只能在一定的位置实现“3D”,而且眼睛可以很容易的判断屏幕距离)
2.代码(因为成品代码太复杂,所以换另外一个程序简解)
头文件引用:
- #include<stdio.h>
- #include<windows.h>
- #include<graphics.h>
- #include<math.h>
初始化:
- main()
- {
- initgraph(450,300);
- int l=500;
- int ox=(getwidth()+1)/2;
- int oy=(getheight()+1)/2;
- int oz=70;
- typedef struct cd
- {
- int x=0;
- int y=0;
- }wdot;
- wdot wpoint[8];
- VECTOR3D point[8];
- int i,j,k;
- for(i=0;i<2;i++)
- {
- for(j=0;j<2;j++)
- {
- for(k=0;k<2;k++)
- {
- point[i*4+j*2+k].x=50*pow(-1,i);
- point[i*4+j*2+k].y=50*pow(-1,j);
- point[i*4+j*2+k].z=50*pow(-1,k);
- }
- }
- }
初始化中l为眼睛距屏幕的距离, ox和oy为屏幕中心位置坐标,oz为屏幕距坐标原点的距离,wdot类用来保存各个点在屏幕上的位置,VECTOR3D类为EGE图形库提供的3d类,用于保存3d点坐标,包含x,y,z三个float变量,如果用的是easyX,请自行定义(最好定义全局),后面三个for循环用于确定point数组中各个变量的位置,组成一个正方体。
绘制:
- while(1)
- {
- for(i=0;i<8;i++)
- {
- wpoint[i].x=ox+point[i].x*l/(l+oz-point[i].z);
- wpoint[i].y=oy+point[i].y*l/(l+oz-point[i].z);
- putpixel(wpoint[i].x,wpoint[i].y,RGB(255,255,255));
- }
- line(wpoint[0].x,wpoint[0].y,wpoint[2].x,wpoint[2].y);
- line(wpoint[0].x,wpoint[0].y,wpoint[4].x,wpoint[4].y);
- line(wpoint[2].x,wpoint[2].y,wpoint[6].x,wpoint[6].y);
- line(wpoint[4].x,wpoint[4].y,wpoint[6].x,wpoint[6].y);
- line(wpoint[0].x,wpoint[0].y,wpoint[1].x,wpoint[1].y);
- line(wpoint[1].x,wpoint[1].y,wpoint[3].x,wpoint[3].y);
- line(wpoint[2].x,wpoint[2].y,wpoint[3].x,wpoint[3].y);
- line(wpoint[3].x,wpoint[3].y,wpoint[7].x,wpoint[7].y);
- line(wpoint[6].x,wpoint[6].y,wpoint[7].x,wpoint[7].y);
- line(wpoint[5].x,wpoint[5].y,wpoint[7].x,wpoint[7].y);
- line(wpoint[5].x,wpoint[5].y,wpoint[1].x,wpoint[1].y);
- line(wpoint[5].x,wpoint[5].y,wpoint[4].x,wpoint[4].y);
用wpoint储存point对应坐标在屏幕上显示的位置,再用putpixel函数绘制点,后面的12个line函数用来绘制正方体的各个边。
旋转:
这里可以使用EGE自带的rotate_point3d_x(), rotate_point3d_y(),rotate_point3d_z()三个函数,分别为绕x,y,z轴旋转,参数格式:&VECTOR结构体,旋转角度*PI/180(弧度)。
- for(i=0;i<8;i++)
- {
- rotate_point3d_z(&point[i],3);
- }
- delay_fps(10);
- cleardevice();
- }
- }
easyX中没有 rotate_point3d_x(), rotate_point3d_y(),rotate_point3d_z()这三个函数,所以可以 自制turn3d_x(),turn3d_y(),turn3d_z()三个函数,输入格式:&VECTOR3D x,旋转角度
这里拿turn3d_y()来讲解:
- int turn3d_y(VECTOR3D *x,float a)
- {
- float tx=x->x;
- float tz=x->z;
- float ta=atan2(tx,tz)/PI*180+a;
- float r=sqrt(pow(tx,2)+pow(tz,2));
- x->x=sin(ta*PI/180)*r;
- x->z=cos(ta*PI/180)*r;
- }
首先,引用VECTOR3D结构体x,旋转角度a两个参数;
然后定义tx,ty分别等于x的想坐标,x的y坐标;
之后用x的x轴,z轴和x与原点的连线构建一个二维三角形:
那么就可以用math库中的三角函数逆推函数atan2()输入角x的邻边和对边,返回弧度,需要把返回值/PI*180得到角度,保存置ta,再用ta加上旋转角度a,算出旋转后的角度(PI为EGE图形库中的定值,如果没有EGE,请自定义PI,atan2()返回后的弧度/PI*180后得到的角度可以大于90度)
然后用勾股定理a^2+b^2=c^2算出Ox,保存到r中。
再画一个半径为r的圆:
那么x旋转后的位置永远都会在圆上, 所以可以根据三角函数用旋转后的角度ta和半径r求出旋转之后的位置,公式如下:
x->x=sin(ta)*r;
x->z=cos(ta)*r;
因为math库中的sin(),cos(),tan()函数输入的是弧度,所以要把ta*PI/180。
完整函数(最好定义全局,放在VECTOR3D结构体后面):
- int turn3d_y(VECTOR3D *x,float a)
- {
- float tx=x->x;
- float tz=x->z;
- float ta=atan2(tx,tz)/PI*180+a;
- float r=sqrt(pow(tx,2)+pow(tz,2));
- x->x=sin(ta*PI/180)*r;
- x->z=cos(ta*PI/180)*r;
- }
- int turn3d_x(VECTOR3D *x,float a)
- {
- float ty=x->y;
- float tz=x->z;
- float ta=atan2(tz,ty)/PI*180+a;
- float r=sqrt(pow(ty,2)+pow(tz,2));
- x->z=sin(ta*PI/180)*r;
- x->y=cos(ta*PI/180)*r;
- }
- int turn3d_z(VECTOR3D *x,float a)
- {
- float tx=x->x;
- float ty=x->y;
- float ta=atan2(tx,ty)/PI*180+a;
- float r=sqrt(pow(ty,2)+pow(tx,2));
- x->x=sin(ta*PI/180)*r;
- x->y=cos(ta*PI/180)*r;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。