使用旋转组件在3D空间中投射光线

时间:2016-09-15 03:31:29

标签: java math 3d raytracing

我目前正在研究基于CPU的简单光线跟踪器,以将几个三角形渲染为项目。除了生成实际光线外,我对它的每个方面都没关系。我不希望将世界坐标投影到屏幕空间,但实际上根据摄像机在3D坐标中的位置创建光线。

现在,我有一个相当不错的算法,它允许我为屏幕上的每个像素生成一条光线,用于围绕Y轴的任何旋转,并且它也尝试合并X轴,给出一些和向下看功能,但是当用户向上或向下查看时,图像会变形。

这是我到目前为止所做的工作:

Ray ray = new Ray(Camera.position, 
                new Vector3(
                        Math.sin(Camera.rotation.y+(x*2/Main.renderSize.width)/2) * Math.cos(Camera.rotation.x+(y*2/Main.renderSize.height)/2),
                        Math.sin(Camera.rotation.x+(-y*2/Main.renderSize.height)/2),
                        Math.cos(Camera.rotation.y+(x*2/Main.renderSize.width)/2) * Math.cos(Camera.rotation.x-(y*2/Main.renderSize.height)/2)
                        ));

当相机未朝向任何向上或向下方向时,这为我提供了良好的观看投影。

相机前进时的投影图像:

img

相机略微向上看时的投影图像

img

如果有人可以帮助我使用算法或指向一个新的或一个好的来源,我将不胜感激。速度是必要的,因为它是全部实时的。谢谢。

1 个答案:

答案 0 :(得分:0)

可能会有更多的事情发生,然后只是错误的光线方向。所以在这里要更清楚的是我的评论更详细的含义:

ray

因此,假设所有东西都在相机空间坐标系中。因此屏幕在平面z=0上,中间像素为(0,0,0)。焦点位于focus=(0,0,-f),其中f是投影的焦距。现在您需要为每个像素投射光线(或更多),使其位置和方向为:

pos = (x,y,0);
dir = pos-focus = (x,y,f);
// most likely you should also normalize it so
dir = dir / |dir|;

当您的x,y坐标不是世界单位而是像素时,您应该相应地重新缩放它们。因此,让屏幕分辨率为xs,ys,我们希望在xFOVx = 60.0deg中设置视野,然后您需要更改此内容:

// pixel size
sz = f*tan(0.5*FOVx)/(0.5*xs);
// x,y screen position [pixels] -> xx,yy [world units]
xx=(x-(0.5*xs))*sz;
yy=(y-(0.5*ys))*sz;
// ray
pos = (xx,yy,0);
dir = pos-focus = (xx,yy,f);
dir = dir / |dir|;

现在进入transformation matrix。设M为表示屏幕的变换矩阵。原点设置为屏幕中间,x,y轴向量对应于屏幕轴。您还需要M0矩阵,该矩阵是M的副本,但原点设置为(0,0,0)

如果您想在世界全球坐标系 GCS 中制作所有内容,那么从屏幕空间转换为世界:

world_position  = M *screen_position;
world_direction = M0*screen_direction;

但如果在上面的链接中使用了不同的矩阵元素和操作数顺序约定,这可能会略有不同。

所以现在世界 GCS 中的光线将是:

// pixel size
sz = f*tan(0.5*FOVx)/(0.5*xs);
// x,y screen position [pixels] -> xx,yy [world units]
xx=(x-(0.5*xs))*sz;
yy=(y-(0.5*ys))*sz;
// ray
pos = (xx,yy,0);
dir = pos-focus = (xx,yy,f);
// convert to world GCS
pos = M *pos;
dir = M0*dir;
// normalize
dir = dir / |dir|;

通常你可以从M作为单位矩阵开始,然后通过关键笔划的旋转和平移来加倍,以处理视图移动和旋转。在每次渲染之前,您可以计算M0=M,然后只需将保持原点的3个元素设置为零。