Java 完全封装对象的透视矩阵

Java 完全封装对象的透视矩阵,java,opengl,3d,lwjgl,fieldofview,Java,Opengl,3d,Lwjgl,Fieldofview,我想生成一个投影矩阵,它将从任意摄影机渲染对象。我已经成功地设置了一个viewMatrix,它可以从任意眼睛位置查看对象,但是设置投影矩阵有困难 假设一个以(x,y,z)为中心的物体,其距离中心的最远点是r,那么任意方向的物体都可以完全封闭在半径为r且原点为(x,y,z)的球体内,我计算透视矩阵如下: float dist2Object = (float) Math.sqrt(vec.lengthSquared()); float objectRadius = (float) Math.sqr

我想生成一个投影矩阵,它将从任意摄影机渲染对象。我已经成功地设置了一个viewMatrix,它可以从任意眼睛位置查看对象,但是设置投影矩阵有困难

假设一个以(x,y,z)为中心的物体,其距离中心的最远点是r,那么任意方向的物体都可以完全封闭在半径为r且原点为(x,y,z)的球体内,我计算透视矩阵如下:

float dist2Object = (float) Math.sqrt(vec.lengthSquared());

float objectRadius = (float) Math.sqrt(3 * Math.pow(0.5, 2));
float far = dist2Object + objectRadius;
float near = dist2Object - objectRadius;

// fov_2 = FOV / 2
float fov_2 = (float) (Math.asin(objectRadius / dist2Object));

float r = (float) (Math.tan(fov_2));
float frustum_length = far - near;

depthProjectionMatrix.m00 = 1 / r;
depthProjectionMatrix.m11 = depthProjectionMatrix.m00;
depthProjectionMatrix.m22 = -((far + near) / frustum_length);
depthProjectionMatrix.m23 = -1;
depthProjectionMatrix.m32 = -((2 * near * far) / frustum_length);
depthProjectionMatrix.m33 = 0;
在我的例子中:

  • vec是从摄影机到对象的向量
  • 该对象是一个立方体,其最远顶点为(0.5,0.5,0.5),表示sqrt的r(0.75)
据我所知,几何体和三角学应该是正确的,但使用以下片段着色器渲染坐标:

#version 150 core

in vec3 pCoord;

out vec4 out_Color;

void main(void) {
    out_Color = vec4(0,1,0,1);
    if(pCoord.x <= -1){
        out_Color = vec4(1,0,0,1);
    }
    if(pCoord.x >= 1){
        out_Color = vec4(0,0,1,1);
    }
    if(pCoord.z <= -1){
        out_Color = vec4(1,0,1,1);
    }
    if(pCoord.z >= 1){
        out_Color = vec4(1,0,1,1);
    }
}
#版本150核心
在vec3pcoord中;
out vec4 out_颜色;
真空总管(真空){
out_Color=vec4(0,1,0,1);
如果(pCoord.x=1){
out_Color=vec4(0,0,1,1);
}
如果(pCoord.z=1){
out_Color=vec4(1,0,1,1);
}
}
如图所示,视野太窄,近平面和远平面也太窄


如何解决此问题?

有一段时间没有这样做了,但您的计算中似乎缺少视口大小。这是我在一个项目中使用的。请注意,此处的矩阵以_11开始,其中使用m00:

double aspectRatio = (double)this.viewPort.Width /(double)this.viewPort.Height;
double fov = Math.toRadians(fieldOfView/2.0);
double size = nearClip * Math.tan(fov);

double left = -size* aspectRatio, right = size* aspectRatio, bottom = -size , top = size ;

projectionMatrix.resetToZero();

// the values in comments are for non symetrical frustrum 

// First Column
projectionMatrix._11 = (float) (nearClip/right);//(float) ((2 * nearClip )/ (double)(right - left));

// Second Column
projectionMatrix._22 = (float)(nearClip/top);//(float) (2 * nearClip / (double)(top - bottom));

// Third Column
projectionMatrix._31 = 0;//(float) ((right + left) / (right - left));
projectionMatrix._32 = 0;//(float) ((top + bottom) / (top - bottom));
projectionMatrix._33 = -1*(farClip + nearClip) / (float)(farClip - nearClip);
projectionMatrix._34 = -1;

// Fourth Column
projectionMatrix._43 = -(2 * farClip * nearClip) / (float)(farClip - nearClip);

如果希望“近”和“远”仅接触对象,则相机到对象的距离必须输入公式。我在代码中没有看到这一点。@DAWNKEPER从相机到对象的矢量存储在vec中,相机和对象之间的距离存储在DIST2对象中。谢谢您的回复。如果纵横比为1(平方),则top==right==size。由于尺寸=近*tan(FOV/2),m.11和m.22的赋值为:近/(近*尺寸)。这与1/size相同,这将使我们的两个投影矩阵相等。唯一的区别在于FOV的计算方式(代码示例中未显示)。我将检查我的FOV是否正确。我的示例中的FOV是手动/代码设置的,没有计算。你的视野似乎是。。。等等,这不应该是
Math.sin(objectRadius/dist2Object)
?我正在使用反正弦(java中的逆sin,Math.asin)来计算斜边(距离)和对边(半径)之间的角度。然而,这并不完全正确。。我应该使用arcsecant。我现在来检查一下。因为你有一个直角三角形正弦应该是可以的。因此,将FOV计算修正为asin(objectRadius/dist2Object)[arcsec(dist2Object/objectRadius)的三角等价物]解决了FOV太小的问题。然而,我的近平面和远平面计算仍然存在一个问题,从实验中可以看出,这似乎是某种非线性尺度。。。但我想不出比这更多的了。