Direct3D9计算视图空间点光位置



我正在开发自己的差分渲染引擎。我正在渲染场景到包含漫射颜色,视图空间法线和深度的g-buffer(目前)。我已经在第二个渲染阶段实现了定向光,效果很好。现在我想渲染一个点光,这有点难。

我需要着色器在视图空间中的点光位置,因为我在g缓冲区中只有深度,而且我无法负担每个像素的矩阵乘法。我用同样的矩阵变换光的位置,我用同样的矩阵变换shader中的每个顶点,所以它应该与场景中的顶点对齐(使用D3DXVec3Transform)。但事实并非如此:转换后的位置几乎根本不代表视图空间位置。它的x,y坐标不在图表上,它们经常超出(-1,1)的范围。变换后的位置在一定程度上尊重了相机的方向,但光线移动太快,y轴倒了。只有当相机位于(0,0,0)时,光线才会位于屏幕中央的(0,0)处。以下是每帧执行的相关渲染代码:

D3DXMATRIX matView;    // the view transform matrix
D3DXMATRIX matProjection;    // the projection transform matrix
D3DXMatrixLookAtLH(&matView,
                   &D3DXVECTOR3 (x,y,z),    // the camera position
                   &D3DXVECTOR3 (xt,yt,zt),    // the look-at position
                   &D3DXVECTOR3 (0.0f, 0.0f, 1.0f));    // the up direction
D3DXMatrixPerspectiveFovLH(&matProjection,
                           fov,    // the horizontal field of view
                           asp,    // aspect ratio
                           znear,    // the near view-plane
                           zfar);    // the far view-plane
D3DXMATRIX vysl=matView*matProjection;
eff->SetMatrix("worldViewProj",&vysl); //vertices are transformed ok ín shader
//render g-buffer
D3DXVECTOR4 lpos; D3DXVECTOR3 lpos2(0,0,0);
D3DXVec3Transform(&lpos,&lpos2,&vysl); //transforming lpos into lpos2 using vysl, still the same matrix
eff->SetVector("poslight",&lpos); //but there is already a mess in lpos at this time
//render the fullscreen quad with wrong lighting

不相关的着色器代码,但仍然,我看到这样的光位置(传入)。纹理只是我偷懒):

float dist=length(float2(IN.texture0*2-1)-float2(poslight.xy));
OUT.col=tex2D(Sdiff,IN.texture0)/dist;

我已经尝试转换光仅通过matView没有投影,但问题仍然是一样的。如果我在着色器中变换光线,结果是一样的,所以问题是矩阵本身。但它和变换顶点的矩阵是一样的!对顶点的处理有何不同?

你能看一下代码并告诉我错误在哪里吗?在我看来,它应该可以工作,但它没有。

您不需要矩阵乘法来重建视图位置,这里是一个代码片段(来自andrew lauritzen的差分光示例)

tP是投影变换,位置屏幕是-1/1像素坐标,viewspaceZ是从纹理中采样的线性深度。

float3 ViewPosFromDepth(float2 positionScreen,
                            float viewSpaceZ)
{
    float2 screenSpaceRay = float2(positionScreen.x / tP._11,
                               positionScreen.y / tP._22);
    float3 positionView;
    positionView.z = viewSpaceZ;
    positionView.xy = screenSpaceRay.xy * positionView.z;
    return positionView;
}

这个变换的结果D3DXVec3Transform(&lpos,&lpos2,&vysl);是齐次空间中的向量(即投影向量,但不除以w)。但是在你的着色器中,你使用它的xy组件而不尊重这个(w)。这很可能就是问题所在。你可以自己用w除以向量,或者用D3DXVec3Project代替D3DXVec3Transform

对于顶点来说,它的工作很好,因为(我想)你在顶点着色器中通过相同的viewproj矩阵mul它们,并将转换后的值传递给插值器,硬件最终将xyz除以插值的'w'。

相关内容

最新更新