矩阵地狱-将3D纹理中的点转换为世界空间

山姆·巴雷特

最近,我决定将体积雾添加到DirectX中的3D游戏中。我使用的技术来自于GPU Pro 6,但您不必为了帮助我而拥有一本书的副本:)。基本上,体积雾信息存储在3D纹理中。现在,我需要将3D纹理的每个纹理像素转换为世界空间。纹理是按视图对齐的,即我的意思是该纹理的X和Y映射到屏幕的X和Y,而该纹理的Z在相机前面向前延伸。所以本质上我需要一个函数:

float3 CalculateWorldPosition(uint3 Texel)
{
    //Do math
}

我知道视图矩阵,3D纹理的尺寸(190x90x64或190x90x128),屏幕的投影矩阵等。

但是,不幸的是,这还不是全部。

如您所知,DirectX中的深度缓冲区不是线性的。需要对我的3D纹理应用相同的效果-需要扭曲纹理像素,以使相机附近比远处更多,因为靠近相机的细节必须比距离更远更好。但是,我认为我有一个函数可以执行此操作,如果我错了,请纠正我:

//Where depth = 0, the texel is closest to the camera.
//Where depth = 1, the texel is the furthest from the camera.
//This function returns a new Z value between 0 and 1, skewing it
// so more Z values are near the camera.
float GetExponentialDepth(float depth /*0 to 1*/)
{
    depth = 1.0f - depth;

    //Near and far planes
    float near = 1.0f;
    //g_WorldDepth is the depth of the 3D texture in world/view space
    float far = g_WorldDepth;

    float linearZ = -(near + depth * (far - near));
    float a = (2.0f * near * far) / (near - far);
    float b = (far + near) / (near - far);
    float result = (a / -linearZ) - b;
    return -result * 0.5f + 0.5f;
}

这是我当前的函数,试图从texel查找世界位置(请注意,这是错误的):

float3 CalculateWorldPos(uint3 texel)
{
    //Divide the texel by the dimensions, to get a value between 0 and 1 for
    // each of the components
    float3 pos = (float3)texel * float3(1.0f / 190.0f, 1.0f / 90.0f, 1.0f / (float)(g_Depth-1));
    pos.xy = 2.0f * pos.xy - float2(1.0f, 1.0f);
    //Skew the depth
    pos.z = GetExponentialDepth(pos.z);
    //Multiply this point, which should be in NDC coordinates,
    // by the inverse of (View * Proj)
    return mul(float4(pos, 1.0f), g_InverseViewProj).xyz;
}

但是,投影矩阵也让我有些困惑,因此这是获取3D纹理的投影矩阵的线,因此如果不正确,可以对其进行校正:

//Note that the X and Y of the texture is 190 and 90 respectively.
//m_WorldDepth is the depth of the cuboid in world space.
XMMatrixPerspectiveFovLH(pCamera->GetFovY(), 190.0f / 90.0f, 1.0f, m_WorldDepth)

另外,我已经读到投影矩阵是不可逆的(它们的逆不存在)。如果是这样,那么可能不确定(View * Proj)的逆函数是否正确,我不确定。

因此,仅重申一个问题,给定与视图对齐的长方体的3D纹理坐标,我如何找到该点的世界位置?

在此先多谢,这个问题已经把我的时间吃光了!

尼科·谢特勒

首先让我解释一下透视投影矩阵的作用。

透视投影矩阵将矢量从视图空间转换为剪辑空间,以使x / y坐标对应于屏幕上的水平/垂直位置,而z坐标对应于深度。znear距离相机远的位置的顶点映射到深度0。zfar距离相机远的位置的顶点映射到深度1。紧随其后的深度值znear非常快地增加,而zfar紧靠在正前方的深度值就增加了慢慢改变。

具体来说,给定z坐标,结果深度为:

depth = zfar / (zfar - znear) * (z - znear) / z

如果在深度相等的位置(例如,每隔0.1之后用直线绘制平截头体,则会得到单元格。而且前面的单元格比后面的单元格薄。如果您绘制足够的单元格,这些单元格将映射到您的纹理像素。在此配置中,这正是您所希望的。前面的单元(导致更高的分辨率)比后面的单元更多。因此,您可以仅使用纹理像素坐标作为深度值(归一化为[0,1]范围)。这是给定深度值进入视图空间的标准背投影(假设znear=1, zfar=10

剪辑空间以查看空间

由于以下原因,您的代码无法正常工作:

return mul(float4(pos, 1.0f), g_InverseViewProj).xyz;

我们使用4D向量和矩阵是有原因的。如果只是丢掉第四维,您将得到错误的结果。而是使用w-clip:

float4 transformed = mul(float4(pos, 1.0f), g_InverseViewProj);
return (transformed / transformed.w).xyz;

顺便说一句,4D透视投影矩阵是完全可逆的。仅当移除一个维度时,您才能获得非二次矩阵,这是不可逆的。但这不是我们通常在计算机图形学中所做的。但是,这些矩阵也称为投影(但在不同的上下文中)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

将3D世界向量转换为模型视图矩阵

来自分类Dev

如何使用已知的正交(相机)投影矩阵将 2d 中的返回点转换为 3d?

来自分类Dev

Matlab矩阵地址

来自分类Dev

将矩阵转换为3D矩阵

来自分类Dev

将3D矩阵列表转换为4D矩阵

来自分类Dev

将2d矩阵转换为3d一个热矩阵numpy

来自分类Dev

将2D稀疏矩阵转换为3D矩阵

来自分类Dev

将4d矩阵转换为3d矩阵R

来自分类Dev

Matlab将2D矩阵转换为3D矩阵

来自分类Dev

将 2d 矩阵转换为 3D 矩阵

来自分类Dev

C - 作为函数参数的矩阵地址

来自分类Dev

将3D矩阵转换为垂直级联的1D数组

来自分类Dev

如何将Matlab向量转换为3D矩阵

来自分类Dev

将3D数组转换为矩阵并保留暗淡的名称

来自分类Dev

如何将2D数据帧转换为3D矩阵,并保留行和列顺序

来自分类Dev

计算 3D 空间中 4 个点之间的变换矩阵

来自分类Dev

3D矩阵:绝对转换为相对转换,反之亦然

来自分类Dev

将矩阵(CSV)转换为python中的3列列表

来自分类Dev

将3D矩阵转换/重塑为2D矩阵

来自分类Dev

响应矩阵3D转换

来自分类Dev

矩阵3d()转换属性?

来自分类Dev

在Matlab中,如何将点列表转换为二进制矩阵

来自分类Dev

maven 中的依赖地狱

来自分类Dev

使用opencv在c ++中将3d点从相机空间转换为对象空间

来自分类Dev

在R中将RGB十六进制转换为3d矩阵

来自分类Dev

在R中将RGB十六进制转换为3d矩阵

来自分类Dev

将列表转换为python中的矩阵

来自分类Dev

如何在z = 0平面中将2D转换矩阵(用于齐次坐标)转换为3D?

来自分类Dev

将屏幕2D转换为世界3D坐标