我目前正在开发一个关于3D渲染的项目,我正在尝试制作一个简单的程序,可以显示一个简单的3D房间(静态着色,没有玩家移动,只有旋转)和pygame
到目前为止,我已经完成了这个理论:
虽然看起来很简单,但将3D坐标转换为屏幕上的2D点的过程证明我很难理解。
谷歌搜索这个主题到目前为止只有这些方程式:
screenX = (worldX/worldZ)
screenY = (worldY/worldZ)
这对我来说似乎有缺陷,因为如果任何Z坐标为0,你会得到除零误差。
所以如果有人能帮忙解释一下,我会非常感激。
答案 0 :(得分:0)
那么
screenX = (worldX/worldZ)
screenY = (worldY/worldZ)
不仅仅是z
透视除法的全部内容,也不适用于DOOM或Wolfenstein技术。
好在末日中只有单一的观察角度(你可以向左/向右转,但不能只向上/向下看鸭子或跳跃,这是不一样的)。所以我们需要知道我们的球员位置和方向px,py,pz,pangle
。只有当您想要实现z轴移动/寻找时才需要z
如果您正在寻找一条直线(红色),那么在3D中穿过该线的所有物体将被投射到播放器屏幕中的单个x坐标...
因此,如果我们正在查看某个方向(红色),任何物体/点交叉/触摸此红线将位于屏幕的中心(x
轴)。剩下的东西将在左侧呈现,同样右侧的内容也将在右侧呈现......
透视我们需要定义我们获得的视角大小......
这限制了我们的视野,因此任何点都会触及绿线将投射到视图的边缘(x
轴)。我们可以直接计算任意点x
的屏幕sx
坐标(x,y,z)
:
// angle of point relative to player direction
sx = point_ang - pangle;
if (sx<-M_PI) sx+=2.0*M_PI;
if (sx>+M_PI) sx-=2.0*M_PI;
// scale to pixels
sx = screen_size_x/2 + sx*screen_size_x/FOVx
其中screen_size_x
是我们视区的分辨率,而点ang是相对于原点x,y,z
的点px,py,pz
的角度。您可以这样计算:
point_ang = atan2(y-py,x-px)
但是如果你真的做了 DOOM 光线投射,那么你已经有了这个角度。
现在我们需要计算屏幕y
坐标sy
,这取决于玩家和墙壁大小的距离。我们可以利用三角相似性。
这样:
sy = screen_size_y/2 (+/-) wall_height*focal_length/distance
焦距是指100%高度的墙壁将覆盖y
轴的整个屏幕的距离。正如你所看到的,我们除以距离可能为零。必须避免这种状态,因此如果直接站在细胞边界上,您需要确保在下一个细胞中评估您的光线。此外,我们需要选择焦距,以便将方形墙投影为方形。
这里是来自我的Doom引擎的一段代码(全部放在一起):
double divide(double x,double y)
{
if ((y>=-1e-30)&&(y<=+1e-30)) return 0.0;
return x/y;
}
bool Doom3D::cell2screen(int &sx,int &sy,double x,double y,double z)
{
double a,l;
// x,y relative to player
x-=plrx;
y-=plry;
// convert z from [cell] to units
z*=_Doom3D_cell_size;
// angle -> sx
a=atan2(y,x)-plra;
if (a<-pi) a+=pi2;
if (a>+pi) a-=pi2;
sx=double(sxs2)*(1.0+(2.0*a/view_ang));
// perpendicular distance -> sy
l=sqrt((x*x)+(y*y))*cos(a);
sy=sys2+divide((double(plrz+_Doom3D_cell_size)-z-z)*wall,l);
// in front of player?
return (fabs(a)<=0.5*pi);
}
其中:
_Doom3D_cell_size=100; // [units] cell cube size
view_ang=60.0*deg; // FOVx
focus=0.25; // [cells] view focal length (uncorrected)
wall=double(sxs)*(1.25+(0.288*a)+(2.04*a*a))*focus/double(_Doom3D_cell_size); // [px] projected wall size ratio size = height*wall/distance
sxs,sys = screen resolution
sxs2,sys2 = screen half resolution
pi=M_PI, pi2=2.0*M_PI
不要忘记使用垂直距离(乘以cos(a)
),否则会出现严重的鱼眼效应。有关详细信息,请参阅: