3

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

我需要视图空间中着色器的点光源位置,因为我在 g 缓冲区中只有深度,而且我无法在每个像素中进行矩阵乘法。我采用了光照位置并通过相同的矩阵对其进行了转换,通过该矩阵我在着色器中转换了每个顶点,因此它应该与场景中的顶点对齐(使用 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

不是相关的着色器代码,但我仍然以这种方式看到光的位置(传递 IN.texture 只是我懒惰):

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

我试图只通过 matView 不投影来变换灯光,但问题仍然是一样的。如果我在着色器中变换光线,结果是一样的,所以问题出在矩阵本身。但它与变换顶点的矩阵相同!顶点的处理方式有何不同?

你能看一下代码并告诉我错误在哪里吗?在我看来,它应该可以正常工作,但事实并非如此。提前致谢。

4

2 回答 2

0

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

它对顶点工作正常,因为(我想)你mul通过顶点着色器中的相同viewproj矩阵将它们传递给插值器,硬件最终将它xyz除以插值的“w”。

于 2013-01-16T12:11:31.780 回答
0

您不需要矩阵乘法来重建视图位置,这是一个代码片段(来自 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;
}
于 2013-01-19T19:10:35.857 回答