vulkan坐标系转换

本文详细介绍了Vulkan中的坐标系转换过程,包括从3D到2D的转换,以及如何通过设置投影矩阵将坐标适应窗口大小。通过调整矩阵,实现了与DirectX相匹配的坐标范围,并利用orthoM函数扩展坐标系,确保了2D图形的精确绘制,解决了DirectX的精度问题。此外,文章还提到了Vulkan在QT中的应用,以及其跨平台的优势。
摘要由CSDN通过智能技术生成

前文我们谈论了DirectX的坐标系转换,把3D坐标转换为2D坐标系,这篇文章我们将谈论vulkan的坐标系转换,当然如果你有OpenGL的坐标系转换的基础,本文对于你会很简单,代码参考《vulkan应用详解》这边书的,我们先看一下坐标系变换关键函数:

void MyVulkanManager::initMatrix()
{
    MatrixState3D::setCamera(0, 0, 200, 0, 0, 0, 0, 1, 0);//初始化摄像机
    MatrixState3D::setInitStack();//初始化基本变换矩阵
    float ratio = (float)screenWidth / (float)screenHeight;//求屏幕长宽比
    //MatrixState3D::setProjectFrustum(-ratio, ratio, -1, 1, 1.5f, 1000);//设置投影参数
    MatrixState3D::setProjectFrustum(0, (float)screenWidth, (float)screenHeight, 0, 1.5f, 1000);//设置投影参数

}

注释是原作者的代码,后面的那行是我修改的

第一行初始化摄像机,这个只操作了Z轴

第二行,初始化基本变换


void MatrixState3D::setInitStack()
{
    Matrix::setIdentityM(currMatrix, 0);

    //初始化从OpenGL标准设备空间到Vulkan设备空间变换的矩阵
    //OpenGL标准设备空间XYZ三个轴范围都是从-1.0~+1.0
    //Vulkan设备空间XYZ三个轴范围分别是 -1.0~+1.0、+1.0~-1.0、0.0~+1.0
    //变换时本质上采用的是缩放加平移矩阵
    //X轴不变Y轴置反Z轴缩放0.5
    //缩放后Z轴正向平移0.5
    vulkanClipMatrix[0] = 1.0f;
    vulkanClipMatrix[1] = 0.0f;
    vulkanClipMatrix[2] = 0.0f;
    vulkanClipMatrix[3] = 0.0f;

    vulkanClipMatrix[4] = 0.0f;
    vulkanClipMatrix[5] = -1.0f;
    vulkanClipMatrix[6] = 0.0f;
    vulkanClipMatrix[7] = 0.0f;

    vulkanClipMatrix[8] = 0.0f;
    vulkanClipMatrix[9] = 0.0f;
    vulkanClipMatrix[10] = 0.5f;
    vulkanClipMatrix[11] = 0.0f;

    vulkanClipMatrix[12] = 0.0f;
    vulkanClipMatrix[13] = 0.0f;
    vulkanClipMatrix[14] = 0.5f;
    vulkanClipMatrix[15] = 1.0f;
}

关键的地方:

vulkanClipMatrix[5] = -1.0f;是把坐标系的Y轴本来是向上的,现在带负号就是变成向下

vulkanClipMatrix[10] = 0.5f;是变成原理的0.5,也就是缩小一半,这样Z轴范围就从0.0~+1.0变成0.0~+0.5了,

上面的Z轴还不是中心对称,我们现在要平移0.5f,于是:

vulkanClipMatrix[14] = 0.5f;就是正向平移0.5,现在Z轴就是-0.5f ~ 0.5f,x坐标轴没变,y轴反转了,z轴的范围变成对称的-0.5f ~ 0.5f

vulkanClipMatrix[15] = 1.0f;使得Z轴范围变成[-1.0f,1,0f],这就跟DirectX的范围一样了

如果不看Z轴,那么现在xy组成的坐标轴就是与2D坐标系一样了。不过我们还需让范围扩大到窗口的宽高:

MatrixState3D::setProjectFrustum(0, (float)screenWidth, (float)screenHeight, 0, 1.5f, 1000);

实际调用:

void MatrixState3D::setProjectFrustum
(
    float left,
    float right,
    float bottom,
    float top,
    float near,
    float far
)
{
    //Matrix::frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
    Matrix::orthoM(mProjMatrix,0,left,right,bottom,top,near,far);
}

注释的是原作者的代码,后面我要使用orthoM扩展坐标系,这个函数跟DirectX基本差不多,


    static void orthoM(float * m, int mOffset, float left, float right, float bottom, float top, float near1, float far1)
    {
        assert(left != right);
        assert(bottom != top);
        assert(near1 != far1);

        float r_width = 1.0f / (right - left);
        float r_height = 1.0f / (top - bottom);
        float r_depth = 1.0f / (far1 - near1);
        float x = 2.0f * (r_width);
        float y = 2.0f * (r_height);
        float z = -2.0f * (r_depth);
        float tx = -(right + left) * r_width;
        float ty = -(top + bottom) * r_height;
        float tz = -(far1 + near1) * r_depth;

        m[mOffset + 0] = x;
        m[mOffset + 5] = y;
        m[mOffset + 10] = z;
        m[mOffset + 12] = tx;
        m[mOffset + 13] = ty;
        m[mOffset + 14] = tz;
        m[mOffset + 15] = 1.0f;
        m[mOffset + 1] = 0.0f;
        m[mOffset + 2] = 0.0f;
        m[mOffset + 3] = 0.0f;
        m[mOffset + 4] = 0.0f;
        m[mOffset + 6] = 0.0f;
        m[mOffset + 7] = 0.0f;
        m[mOffset + 8] = 0.0f;
        m[mOffset + 9] = 0.0f;
        m[mOffset + 11] = 0.0f;
    }

关键函数orthoM,关键代码:

 float r_width = 1.0f / (right - left);
        float r_height = 1.0f / (top - bottom);
        float r_depth = 1.0f / (far1 - near1);

        float x = 2.0f * (r_width);
        float y = 2.0f * (r_height);
        float z = -2.0f * (r_depth);

这六句的意思就是把X轴[-1.0,1.0]总共长度2.0变成2.0f / (right - left)也就是扩展到窗口宽度,y轴同样的道理扩展到窗口高度,Z轴带个负数这个是右手坐标系变为左手坐标系,因为DirectX是左手坐标系,这样摄像机镜头就是对着里面而不是对着工程师了,习惯都是左手坐标系。

现在坐标系都变换完了,那么怎么使用坐标呢,哈哈,那跟在2D中使用坐标点一样了

float* TriangleData::vdata;//数据数组首地址指针
int TriangleData::dataByteCount;//数据所占总字节数量
int TriangleData::vCount;//顶点数量
void  TriangleData::genVertexData() {//顶点数据生成方法
    vCount = 5;
    dataByteCount = vCount * 6 * sizeof(float);
    vdata = new float[vCount * 6]
    {
        1,720,0,        1, 0, 0, /*颜色*/
        700, 720, 0,    1, 0, 0,

        1, 721, 0,        0,1, 0,
        700, 721, 0,    0, 1, 0,
            
        100, 200, 0,    1, 1, 0
    };

}

经过前面坐标系变换,现在2D坐标点,其原点在左上角,上面代码坐标点1,2,3,4行就是画两条平行线,相聚一个像素,看看效果:

两条相邻平行线,精度能精确到一个像素,完美解决DirectX取图不精的问题,vulkan是替代directx的不二之选,而且还支持跨平台,更重要的是你可以在QT里面调用QVulkanWindow类去使用它,QT很早就已经支持Vulkan了,这对应QT画图再合适不过了 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值