我有一个Ray-Tracing微型项目,已经开始用Java编写。
我自己实现了所有东西,没有像OpenGl这样的任何库,一切都是我从头开始实现的,例如Camera,Renderer,Image Writer等。 问题是,当我放置一个物体(例如,一个不位于屏幕中心的球体)时,它具有某种椭圆形的形状。对于(有限)圆柱体相同-由于某种原因,它会径向拉伸。
渲染过程如下: 我的相机定义了原点,方向和向上矢量,右边的矢量是叉积方向X向上。 对于视平面中的每个点,我构造从该点到相机原点的射线,并进行拍摄以找到与场景中每个几何图形的交点。对于每个几何图形,我采用最接近的交点,计算其颜色,然后将其颜色写入位于视图平面该点的像素(我从中构造了射线)。
现在,我已经阅读了很多有关Perspective Projection的文章,并且我尝试使用此链接来实现它:http://ogldev.atspace.co.uk/www/tutorial12/tutorial12.html 但未能使用它。 我已经在Transform类中实现了它,而我试图做的就是将Projection Matrix M乘以我在场景中找到的任何最接近的交点p。 不幸的是,由于某种原因,结果保持不变。
注意:M * p的乘积是一个新的向量4(v1,v2,v3,v4),因此它已转换为一个新的向量3(v1 / v4,v2 / v4,v3 / v4)。 因此,该乘法的返回值就是vector3。
为了计算视野角θ,我计算了两束光线到视平面两侧的夹角。
这里是某些代码
GitHub链接(如果太乱了):https://github.com/elyasaf755/3D-Engine
我的Transform类字段及其相关功能:
public class Transform {
private static double _zNear;
private static double _zFar;
private static double _width;//screen width
private static double _height;//screen height
private static double _fov;//field of view
private Vector3D _translation;
private Vector3D _rotation;
private Vector3D _scale;
public Matrix4 getTransformation(){
Matrix4 translationMatrix = new Matrix4().initTranslation(
this._translation.getPoint().getX().getCoord(),
this._translation.getPoint().getY().getCoord(),
this._translation.getPoint().getZ().getCoord()
);
Matrix4 rotationMatrix = new Matrix4().initRotation(
_rotation.getPoint().getX().getCoord(),
_rotation.getPoint().getY().getCoord(),
_rotation.getPoint().getZ().getCoord()
);
Matrix4 scaleMatrix = new Matrix4().initScale(
_scale.getPoint().getX().getCoord(),
_scale.getPoint().getY().getCoord(),
_scale.getPoint().getZ().getCoord()
);
return translationMatrix.mult(rotationMatrix.mult(scaleMatrix));
}
public Matrix4 getProjectedTransformation(){
Matrix4 transformationMatrix = getTransformation();
Matrix4 projectionMatrix = new Matrix4().initProjection(_fov, _width,
_height, _zNear, _zFar);
return projectionMatrix.mult(transformationMatrix);
}
}
我的Matrix4类字段及其相关功能:
public class Matrix4 {
private double[][] _m;
public Matrix4 initProjection(double fov, double width, double height,
double zFar, double zNear){
double ar = width / height;
double tanHalfFov = Math.tan(Math.toRadians(fov / 2));
double zRange = zNear - zFar;
setRow(0,1 / (tanHalfFov * ar),0, 0, 0);
setRow(1,0, 1/tanHalfFov,0, 0);
setRow(2,0, 0, (-zNear - zFar) / zRange,2
* zFar * zNear / zRange);
setRow(3,0, 0, 1, 0);
return this;
}
public Matrix4 mult(Matrix4 matrix) {
Matrix lhs = new Matrix(_m);
Matrix rhs = new Matrix(matrix.getMatrix());
Matrix result = lhs.mult(rhs);//simple matrix multiplication
return new Matrix4(result.get_matrix());
}
}
我的Matrix类字段及其相关功能:
public class Matrix {
private double[][] _matrix;
private int _numOfRows;
private int _numOfCols;
public Matrix mult(Matrix matrix) {
if (_numOfCols != matrix.getRows())
return null;
Matrix result = new Matrix(_numOfRows, matrix.getColumns());
for (int i = 0; i < _numOfRows; i++)
{
for (int j = 0; j < matrix.getColumns(); j++)
{
BigDecimal sum = new BigDecimal(0, MathContext.UNLIMITED);
for (int k = 0; k < matrix.getRows(); k++)
{
BigDecimal temp = new BigDecimal(
_matrix[i][k]*matrix.get_element(k, j),
MathContext.UNLIMITED);
sum = sum.add(temp);
}
Coordinate temp = new Coordinate(sum.doubleValue());
result.set_element(i, j, temp.getCoord());
}
}
return result;
}
}
“我的相机”类别字段及其相关功能:
public class Camera {
private Point3D _origin;
private Vector3D _direction;
private Vector3D _up;
private Vector3D _right;
public Ray constructRayThroughPixel(int Nx, int Ny, int i, int j, double
screenDistance, double screenWidth, double screenHeight){
//Fix pixel locations
i = Nx - i - 1;
//j = Ny - j;
Point3D p0 = get_origin();
Vector3D direction = get_direction();
Vector3D up = get_up();
Vector3D right = get_right();
//Image center point
Point3D Pc = p0.add(direction.scale(screenDistance));
//Pixel ratios
double Rx = screenWidth / Nx; //Pixel width
double Ry = screenHeight / Ny; //Pixel height
//Center pixel
double Xi = (i - Nx / 2.0)*Rx + Rx / 2.0;
double Yj = (j - Ny / 2.0)*Ry + Ry / 2.0;
Point3D p_ij;
if (Xi == 0 && Yj == 0){
p_ij = new Point3D(Pc);
}
else if (Xi == 0){
p_ij = new Point3D(Pc.add(Vector3D.ZERO.subtract(up.scale(Yj))));
}
else if (Yj == 0){
p_ij = new Point3D(
Pc.add((right.scale(Xi)).subtract(Vector3D.ZERO)));
}
else{
p_ij = new Point3D
(Pc.add((right.scale(Xi)).subtract(up.scale(Yj))));
}
Vector3D v_ij = p_ij.subtract(p0);
return new Ray(p0, v_ij.normalized());
}
}
我希望任何对象在渲染后都能保持其原始形状,无论其位置如何。
我可以做的一件事是使相机真正远离物体,这样我就不会注意到那些伸展。但是我想从头解决这个问题。