Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/377.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java OpenGL 3+;具有平行光的正交投影_Java_Opengl_Shadow Mapping - Fatal编程技术网

Java OpenGL 3+;具有平行光的正交投影

Java OpenGL 3+;具有平行光的正交投影,java,opengl,shadow-mapping,Java,Opengl,Shadow Mapping,我目前在移动(类似太阳)光源的平行光阴影贴图方面遇到问题 当我最初实现时,灯光投影矩阵被计算为3D,阴影贴图看起来很漂亮。然后我了解到,对于我正在尝试做的事情,正交投影效果会更好,但我很难替换正确的投影矩阵 正如人们所预料的那样,每一次滴答声,太阳都会沿着一个圆圈移动一定量。我使用一种自制的“注视”方法来确定合适的观察矩阵。例如,日光从早上6点到下午6点。当太阳位于上午9点位置(45度)时,它应该查看原点并将阴影贴图渲染到帧缓冲区。正交投影似乎发生的是,它不会“向下倾斜”到原点。它只是一直沿着Z

我目前在移动(类似太阳)光源的平行光阴影贴图方面遇到问题

当我最初实现时,灯光投影矩阵被计算为3D,阴影贴图看起来很漂亮。然后我了解到,对于我正在尝试做的事情,正交投影效果会更好,但我很难替换正确的投影矩阵

正如人们所预料的那样,每一次滴答声,太阳都会沿着一个圆圈移动一定量。我使用一种自制的“注视”方法来确定合适的观察矩阵。例如,日光从早上6点到下午6点。当太阳位于上午9点位置(45度)时,它应该查看原点并将阴影贴图渲染到帧缓冲区。正交投影似乎发生的是,它不会“向下倾斜”到原点。它只是一直沿着Z轴向下看。早上6点和下午6点的情况看起来很好,但比如说中午12点,情况就完全没有变化

以下是我的设置方式:

原始三维投影矩阵:

Matrix4f projectionMatrix = new Matrix4f();
float aspectRatio = (float) width / (float) height;

float y_scale = (float) (1 / cos(toRadians(fov / 2f)));
float x_scale = y_scale / aspectRatio;
float frustum_length = far_z - near_z;

projectionMatrix.m00 = x_scale;
projectionMatrix.m11 = y_scale;
projectionMatrix.m22 = (far_z + near_z) / (near_z - far_z);
projectionMatrix.m23 = -1;
projectionMatrix.m32 = -((2 * near_z * far_z) / frustum_length);
观察方法:

public Matrix4f lookAt( float x, float y, float z,
                      float center_x, float center_y, float center_z ) {
  Vector3f forward = new Vector3f( center_x - x, center_y - y, center_z - z );
  Vector3f up      = new Vector3f( 0, 1, 0 );

  if ( center_x == x && center_z == z && center_y != y ) {
    up.y = 0;
    up.z = 1;
  }

  Vector3f side = new Vector3f();

  forward.normalise();

  Vector3f.cross(forward, up, side );
  side.normalise();

  Vector3f.cross(side, forward, up);
  up.normalise();

  Matrix4f multMatrix = new Matrix4f();
  multMatrix.m00 = side.x;
  multMatrix.m10 = side.y;
  multMatrix.m20 = side.z;
  multMatrix.m01 = up.x;
  multMatrix.m11 = up.y;
  multMatrix.m21 = up.z;
  multMatrix.m02 = -forward.x;
  multMatrix.m12 = -forward.y;
  multMatrix.m22 = -forward.z;

  Matrix4f translation = new Matrix4f();
  translation.m30 = -x;
  translation.m31 = -y;
  translation.m32 = -z;

  Matrix4f result = new Matrix4f();

  Matrix4f.mul( multMatrix, translation, result );
  return result;
}
正交投影(使用宽度100,高度75,近1.0,远100)我用许多不同的值尝试过:

Matrix4f projectionMatrix = new Matrix4f();

float r = width * 1.0f;
float l = -width;
float t = height * 1.0f;
float b = -height;

projectionMatrix.m00 = 2.0f / ( r - l );
projectionMatrix.m11 = 2.0f / ( t - b );
projectionMatrix.m22 = 2.0f / (far_z - near_z);
projectionMatrix.m30 = - ( r + l ) / ( r - l );
projectionMatrix.m31 = - ( t + b ) / ( t - b );
projectionMatrix.m32 = -(far_z + near_z) / (far_z - near_z);
projectionMatrix.m33 = 1;
阴影贴图顶点着色器:

#version 150 core

uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;

in vec4 in_Position;

out float pass_Position;

void main(void) {
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * in_Position;
  pass_Position = gl_Position.z;
}
阴影贴图片段着色器:

#version 150 core

in vec4 pass_Color;
in float pass_Position;

layout(location=0) out float fragmentdepth;

out vec4 out_Color;

void main(void) {
  fragmentdepth = gl_FragCoord.z;
}

我觉得我错过了一些非常简单的东西。正如我所说,这对3D投影矩阵很好,但我希望用户在世界各地旅行时阴影保持不变,这对定向照明和正交投影都有意义。

实际上,谁告诉过你使用正交投影矩阵制作阴影贴图是个好主意?这可能适用于像太阳这样的物体,它们实际上是无限远的,但对于局部光来说,透视是非常相关的。但是,在使用透视投影和阴影贴图时必须小心,因为采样频率随距离而变化,在某些距离上会获得很多精度,而在其他距离上则不够,除非通常使用层叠或透视扭曲之类的方法;不过,这可能超出了您目前应该考虑的范围:)

此外,正交投影矩阵的3D效果并不比透视图差,因为它们通过将3D“图像”投影到2D观察平面上来工作。。。它们和透视图之间的唯一区别是平行线保持平行。换句话说,(x,y,near)和(x,y,far)理想地以正交投影方式投影到屏幕上的相同位置。


在片段着色器中使用
gl_FragCoord.z
是不寻常的。因为这是写入深度缓冲区的值,所以最好在片段着色器中不写入任何内容,然后重新使用深度缓冲区。除非您的实现不支持浮点深度缓冲区,否则将深度写入两个位置是在浪费内存带宽。使用
glColorMask(GL\u-FALSE,GL\u-FALSE,GL\u-FALSE,GL\u-FALSE)
的仅深度通道通常会在构建阴影贴图时获得更高的吞吐量

如果您实际使用了
pass_Position
(剪辑空间中未经透视校正的Z坐标)的值,我可以看到使用了单独的颜色附件来编写此内容,但您当前正在编写透视校正深度范围调整深度(
gl_FragDepth




在任何情况下,当太阳在正上方且使用正交投影时,预计不会投射阴影。这可以追溯到我前面解释的属性,其中平行线保持平行。由于对象与太阳的距离对对象的投影位置(正交)没有影响,因此如果对象直接位于头顶,则不会看到任何阴影。尝试沿着球体而不是圆形跟踪太阳的位置,以尽量减少这种情况。

从我所看到的情况来看(由于这是一种类似太阳的光线),正交透视图更符合我的要求。我确实明白三维透视对定位灯光会更好。@Chris:当然,我并不是说正交投影不合适。只是,您将来可能需要实现这两种类型的阴影贴图。点光源和位置聚光灯应使用透视。另外,为了解决中午的问题,我建议你的太阳以球形运动在天空中移动(例如,x、y和z位置都是时间的函数,而不是你在问题中描述的三个位置中的两个)。glFragCoord.z与pass_位置是我一直在切换的位置,因为我缺乏对差异的理解,但你已经为我澄清了这一点。最后,对开销的解释是正确的,至少是我一直缺少的一部分。不过,这个问题其实开始得更早。这就像阴影贴图从缓冲区“脱落”一样。我将发布一些图片,看看我是否可以用这种方式更好地解释。我想我真的需要更多地重新审视这一点。阴影坐标不像在投影中那样工作。我在错误的地方看到奇怪的阴影,直到它到达原点。负x完全点亮。我要说的是,在进行“注视”时,将灯光移近原点似乎有很大帮助。虽然我不确定我能说为什么。。。要开始理解这些阴影,我还有很长的路要走,但我非常感谢你的帮助。