我的 MVP 矩阵运算有什么问题?

问题描述 投票:0回答:1

我正在尝试使用 Vulkan 编写 3D 图形引擎(几乎是游戏引擎),遵循 https://vulkan-tutorial.com/。 我已经到达了Uniform Buffer部分的末尾,但是我的方块不是旋转角度很好的正方形,而是在空隙中旋转。

我正在像这样更新统一缓冲区:

void updateUniformBuffer(ref Application app, uint currentImage)
{
    MonoTime currentTime = MonoTime.currTime;
    float time = 0.0f;

    time = (currentTime - app.startTime).total!"msecs"() / 50.0f;
    // writeln("time: ", time);
    vec3 rotation_data = [time, 0.0f , 1.0f];
    mat4 modelMatrix;
    modelMatrix = mat4.identity().rotate_new(90.0f, rotation_data); 

    UniformBufferObject ubo = {
        model: modelMatrix,
        view: lookAt(vec3([2.0f, 02.0f, 2.0f])
            , vec3([0.0f, 0.0f, 0.0])
            , vec3([0.0f, -1.0f, -1.0f])
        ),
        proj: perspective(45.0f, app.width/cast(float)app.height, 0.1f, 10.0f),
    };

//  For debugging
//    ubo.model = mat4.identity();
//    ubo.view = mat4.identity();
//    ubo.proj = mat4.identity();

    //ubo.proj[2] = 1;
    writeln("Uniform buffer Model: \n", ubo.model);
    // writeln("Uniform buffer View: \n", ubo.view);

    ubo.proj[5] = -1 * ubo.proj[5];
    ubo.proj[15] = 1;
    // writeln("Uniform buffer Projection: \n", ubo.proj);

    void* data;
    vkMapMemory(app.device, app.uniformBuffersMemory[currentImage], 0, ubo.sizeof, 0, &data);
    memcpy(data, &ubo, ubo.sizeof);
    vkUnmapMemory(app.device, app.uniformBuffersMemory[currentImage]);
}

我的矩阵运算代码如下所示:

module matrix;

import std.math;

import dlib;

vec3 normalise(ref vec3 v)
{
    float len = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
    if (len == 0.0f) 
        return v;
    v[0] /= len;
    v[1] /= len;
    v[2] /= len;
    return v;
}

vec3 crossProduct(vec3 v1, vec3 v2)
{
    vec3 res = [ 0.0f, 0.0f, 0.0f ];
    res[0] = v1[1]*v2[2] - v1[2]*v2[1];
    res[1] = v1[2]*v2[0] - v1[0]*v2[2];
    res[2] = v1[0]*v2[1] - v1[1]*v2[0];
    return res;
}

// https://www.3dgep.com/understanding-the-view-matrix/
/***
    * 
    * @param camera 
    * @param target 
    * @param up 
    * @returns 
    *
    * 1. Calculate the camera's forward vector.
    * 2. Calculate the camera's right vector.
    * 3. Calculate the camera's up vector.
    * 4. Calculate the orientation matrix.
    * 5. Calculate the translation matrix.
    * 6. Return the view matrix.
*/
mat4 lookAt(vec3 camera, vec3 target, vec3 up) 
{
    mat4 res;

    auto a = target - camera;
    normalise(a);

    auto b = crossProduct(a, up);
    normalise(b);

    auto c = crossProduct(b, a);

    res[0] = b[0]; 
    res[1] = c[0]; 
    res[2] = -a[0]; 
    res[3] = 0.0f; 
    res[4] = b[1]; 
    res[5] = c[1]; 
    res[6] = -a[1]; 
    res[7] = 0.0f; 
    res[8] = b[2]; 
    res[9] = c[2]; 
    res[10] = -a[2]; 
    res[11] = 0.0f; 
    res[12] = 0.0f;
    res[13] = 0.0f;
    res[14] = 0.0f;
    res[15] = 1.0f;    
    mat4 orientation = [
        b[0] , c[0] , a[0] , 0.0f,
        b[1] , c[1] , a[1] , 0.0f,
        b[2] , c[2] , a[2] , 0.0f,
        0.0f , 0.0f , 0.0f , 1.0f
    ];

    mat4 translation = [
        1.0f      , 0.0f      , 0.0f      , 0.0f, 
        0.0f      , 1.0f      , 0.0f      , 0.0f,  
        0.0f      , 0.0f      , 1.0f      , 0.0f, 
        -camera[0], -camera[1], -camera[2], 1.0f
    ];
    return res;
//    return orientation.multiply(translation);
}

mat4 perspective(float degrees, float ratio, float near, float far)
{
    // https://vincent-p.github.io/posts/vulkan_perspective_matrix/
    mat4 returnme = mat4.zero();
    float y = (1.0f / cos(degrees * PI / 180.0f));
    // float y = 1.0f / tan(degrees * (PI / 180.0f) * 0.5f);                        // cos(radians * PI / 180.0f);
    float x = y / ratio;
    float visible_length = far - near;

    returnme[0] = x;
    returnme[5] = -y;
    returnme[10] = -((far + near) / visible_length);  // -((far + near) / visible_length);
    returnme[11] = -1.0f; // (near * far) / (visible_length) ;
    returnme[14] = -((2.0f * near * far) / visible_length); // 1.0f;

    return returnme;
}

mat4 multiply(const mat4 m1, const mat4 m2)
{
    mat4 res;
    res[0] = m1[0]*m2[0] + m1[1]*m2[4] + m1[2]*m2[8]  + m1[3]*m2[12];
    res[1] = m1[0]*m2[1] + m1[1]*m2[5] + m1[2]*m2[9]  + m1[3]*m2[13];
    res[2] = m1[0]*m2[2] + m1[1]*m2[6] + m1[2]*m2[10] + m1[3]*m2[14];
    res[3] = m1[0]*m2[3] + m1[1]*m2[7] + m1[2]*m2[11] + m1[3]*m2[15];
    res[4] = m1[4]*m2[0] + m1[5]*m2[4] + m1[6]*m2[8]  + m1[7]*m2[12];
    res[5] = m1[4]*m2[1] + m1[5]*m2[5] + m1[6]*m2[9]  + m1[7]*m2[13];
    res[6] = m1[4]*m2[2] + m1[5]*m2[6] + m1[6]*m2[10] + m1[7]*m2[14];
    res[7] = m1[4]*m2[3] + m1[5]*m2[7] + m1[6]*m2[11] + m1[7]*m2[15];
    res[8] = m1[8]*m2[0] + m1[9]*m2[4] + m1[10]*m2[8]  + m1[11]*m2[12];
    res[9] = m1[8]*m2[1] + m1[9]*m2[5] + m1[10]*m2[9]  + m1[11]*m2[13];
    res[10] = m1[8]*m2[2] + m1[9]*m2[6] + m1[10]*m2[10] + m1[11]*m2[14];
    res[11] = m1[8]*m2[3] + m1[9]*m2[7] + m1[10]*m2[11] + m1[11]*m2[15];
    res[12] = m1[12]*m2[0] + m1[13]*m2[4] + m1[14]*m2[8]  + m1[15]*m2[12];
    res[13] = m1[12]*m2[1] + m1[13]*m2[5] + m1[14]*m2[9]  + m1[15]*m2[13];
    res[14] = m1[12]*m2[2] + m1[13]*m2[6] + m1[14]*m2[10] + m1[15]*m2[14];
    res[15] = m1[12]*m2[3] + m1[13]*m2[7] + m1[14]*m2[11] + m1[15]*m2[15];

    return res;
}

vec4 multiply(const mat4 m1, const vec3 v)
{
    vec4 res;
    res[0] = m1[0]*v[0] + m1[1]*v[1] + m1[2]*v[2];
    res[1] = m1[4]*v[1] + m1[5]*v[1] + m1[6]*v[2];
    res[2] = m1[8]*v[2] + m1[9]*v[1] + m1[10]*v[2];
    res[3] = 1.0f;

    return res;
}

mat4 multiply(const vec3 v, const mat4 m2)
{
    mat4 m1 = [ v[0], v[1], v[2], 1.0f , 
        0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f,
    ];

    return multiply(m1, m2);
}

/**
Rotate a matrix by an angle around a vector
Parameters
    m       Input matrix multiplied by this rotation matrix.
    angle   Rotation angle expressed in radians.
    v       Rotation axis, recommended to be normalized. 
*/
mat4 rotate_new(const mat4 m, float angle, const vec3 v) 
{
  float α = (v[0] * PI) / 180.0f;
  float β = (v[1] * PI) / 180.0f; //radian(v[1]); 
  float γ = (v[2] * PI) / 180.0f; //radian(v[2]);
  // rotate around x, then y, then z
  // http://web.archive.org/web/20140515121518/http://inside.mines.edu:80/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.html
  mat4 mt = [
        cos(α)*cos(β), (cos(α)*sin(β)*sin(γ)) - (sin(α)*cos(γ)), (cos(α)*sin(β)*cos(γ)) + (sin(β)*sin(γ)), 0.0f,
        sin(α)*cos(β), (sin(α)*sin(β)*sin(γ)) + (cos(α)*cos(γ)), (sin(α)*sin(β)*cos(γ)) - (cos(β)*sin(γ)), 0.0f,
        -sin(β)      ,  cos(β)*sin(γ)                          ,  cos(β)*cos(γ)                          , 0.0f,
        0.0f        ,  0.0f                                   ,  0.0f,                                    1.0f 
    ]
  ;
  auto r = mt.multiply(m);
  return(r);
}

unittest {
    mat4 m = [  1, 2, 3, 4 ,
                5, 6, 7, 8 ,
                9, 10, 11, 12 ,
                13, 14, 15, 16 ];
    assert(m.multiply(m) == [ 90.0f, 100.0f, 110.0f, 120.0f, 
        202.0f, 228.0f, 254.0f, 280.0f, 
        314.0f, 356.0f, 398.0f, 440.0f, 
        426.0f, 484.0f, 542.0f, 600.0f]);

    // vec3 v = [0, 0, 0];
    // writeln(m.rotate_new(0, v));
    // assert
}

game-engine d vulkan
1个回答
0
投票

我还不能发表评论,所以我把它放在这里......

什么是rotation_data?据我所知,它是旋转轴吗?如果是这种情况,那么奇怪的旋转是由于您改变了旋转轴而不是每帧的角度。

© www.soinside.com 2019 - 2024. All rights reserved.