OpenTK Oblique Frustum (сдвиг линзы) - PullRequest
2 голосов
/ 09 мая 2020

Я новичок в OpenGL и использую последнюю версию OpenTK с C#.

Мой класс камеры в настоящее время выполняет следующие функции:

public Matrix4 GetProjectionMatrix()
{
    return Matrix4.CreatePerspectiveFieldOfView(_fov, AspectRatio, 0.01f, 100f);
}

public Matrix4 GetViewMatrix()
{
    Vector3 lookAt = new Vector3(myObject.Pos.X, myObject.Pos.Y, myObject.Pos.Z);
    return Matrix4.LookAt(Position, lookAt, _up);
}

У меня немного странная вариант использования, когда мое игровое окно будет длинным, что-то вроде соотношения 4:12, и оно будет представлять собой длинный объект. Из моего чтения в Интернете, лучший способ представить это так, как я хочу, - это сделать сдвиг линзы (Oblique Frustum).

Я видел в Интернете статьи о том, как это сделать, а именно: http://www.terathon.com/code/oblique.html https://docs.unity3d.com/Manual/ObliqueFrustum.html

Но у меня возникли проблемы с переводом этого на OpenTk.

Интересно, делал ли кто-нибудь здесь что-то подобное в OpenTK .

РЕДАКТИРОВАТЬ: Это сработало, но не совсем то, что я искал: (

private float sgn(float a)
{
    if (a > 0.0F) return (1.0F);
    if (a < 0.0F) return (-1.0F);
    return (0.0F);
}

public Matrix4 CreatePerspectiveFieldOfView(Matrix4 projectionMatrix)
{
    Vector4 clipPlane = new Vector4(0.0f, 0.7f, 1.0f , 1.0f);
    Vector4 q = new Vector4
    {
        X = (sgn(clipPlane.X) + projectionMatrix.M13) / projectionMatrix.M11,
        Y = (sgn(clipPlane.Y) + projectionMatrix.M23) / projectionMatrix.M22,
        Z = -1.0f,
        W = (1.0F + projectionMatrix.M33) / projectionMatrix.M34
    };

    Vector4 c = clipPlane * (2.0F / Vector4.Dot(clipPlane, q));
    projectionMatrix.M31 = c.X;
    projectionMatrix.M32 = c.Y;
    projectionMatrix.M33 = c.Z + 1.0f;
    projectionMatrix.M34 = c.W;

    return projectionMatrix;
}

РЕДАКТИРОВАТЬ 2:

В основном то, что я хочу сделать, приближает точку взгляда к краю усеченной кости, например: enter image description here

1 Ответ

1 голос
/ 09 мая 2020

Есть очевидные проблемы. Матрицы OpenGL имеют порядок столбцов. Следовательно, i - это столбец, а j - это строка для Mij свойств Matrix4:

Следующие столбцы расположены сверху вниз, а строки расположены слева направо, потому что это представление полей матрицы в памяти и то, как матрица «выглядит» в отладчике:

         row1 row2 row3 row4             indices
column1 (M11, M12, M13, M14)             ( 0,  1,  2,  3) 
column2 (M21, M22, M23, M24)             ( 4,  5,  6,  7) 
column3 (M31, M32, M33, M34)             ( 8,  9, 10, 11) 
column4 (M41, M42, M43, M44)             (12, 13, 14, 15)  

Таким образом,

q.x = (sgn(clipPlane.x) + matrix[8]) / matrix[0];
q.y = (sgn(clipPlane.y) + matrix[9]) / matrix[5];
q.z = -1.0F;
q.w = (1.0F + matrix[10]) / matrix[14];

необходимо преобразовать в:

Vector4 q = new Vector4
{
    X = (sgn(clipPlane.X) + projectionMatrix.M31) / projectionMatrix.M11,
    Y = (sgn(clipPlane.Y) + projectionMatrix.M32) / projectionMatrix.M22,
    Z = -1.0f,
    W = (1.0f + projectionMatrix.M33) / projectionMatrix.M43
};

and 

```cpp
matrix[2] = c.x;
matrix[6] = c.y;
matrix[10] = c.z + 1.0F;
matrix[14] = c.w;

должно быть

projectionMatrix.M13 = c.X;
projectionMatrix.M23 = c.Y;
projectionMatrix.M33 = c.Z + 1.0f;
projectionMatrix.M43 = c.W;

Если вы хотите asymmetri c перспективная проекция, затем подумайте о том, чтобы создать матрицу perojection на Matrix4.CreatePerspectiveOffCenter.

public Matrix4 GetProjectionMatrix()
{
    var offset_x  = -0.0f; 
    var offset_y  = -0.005f; // just for instance
    var tan_fov_2 = Math.Tan(_fov / 2.0);

    var near   = 0.01f;
    var far    = 100.0f; 
    var left   = -near * AspectRatio * tan_fov_2 + offset_x;
    var right  =  near * AspectRatio * tan_fov_2 + offset_x;
    var bottom = -near * tan_fov_2 + offset_y;
    var top    =  near * tan_fov_2 + offset_y;

    return Matrix4.CreatePerspectiveOffCenter(left, right, bottom, top, near, far);
}
...