源码下载地址:文件下载-奶牛快传 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。文章来源:https://www.toymoban.com/news/detail-776500.html
完整函数(最好定义全局,放在VECTOR3D类后面):文章来源地址https://www.toymoban.com/news/detail-776500.html
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;
}
到了这里,关于C语言伪3D制作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!