3

現在、移動する (太陽のような) 光源からのディレクショナル ライト シャドウ マップに問題があります。

最初に実装したとき、ライト プロジェクション マトリックスは 3D として計算され、シャドウ マップが美しく表示されました。次に、私がやろうとしていることについては、正投影の方がうまくいくことを学びましたが、適切な投影行列を代用するのに苦労しています。

1 ティックごとに、予想どおり、太陽は円に沿って一定量移動します。自家製の「lookAt」メソッドを使用して、適切な表示マトリックスを決定します。たとえば、日光は午前 6 時から午後 6 時まで発生します。太陽が午前 9 時の位置 (45 度) にあるとき、太陽は原点を見て、シャドウ マップをフレーム バッファにレンダリングする必要があります。正投影で起こっているように見えるのは、原点に向かって「下に傾いていない」ということです。代わりに、Z 軸をまっすぐ見続けるだけです。午前 6 時と午後 6 時は問題ないように見えますが、たとえば正午にはまったく何も表示されません。

設定方法は次のとおりです。

元の 3D 射影行列:

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);

LookAt メソッド:

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 プロジェクション マトリックスで問題なく動作しますが、ユーザーが世界中を移動する際に一定の影が必要です。これは、指向性照明、つまり正射投影に適しています。

4

1 に答える 1