DX 11计算着色器\ SharpDX Deferrerd平铺照明,点光源问题

时间:2015-10-07 10:07:20

标签: sharpdx compute-shader

我刚刚将我的引擎从XNA移植到SharpDX(DX11)。

一切都进展顺利,我已经征服了大部分问题,直到现在我都没有求助,而且我真的卡住了,也许我只需要另外一套眼睛来查看我的代码idk但是在这里是

我实现了基于图块的照明(目前仅点光源),我的代码基于英特尔样本,因为它不像ATI那样凌乱。

所以我的问题是灯光随着相机一起移动,我已经到处寻找修复,我已经尝试了一切(我疯了吗?)。

我确保我的所有法线和光线矢量都在视图空间中并且标准化(仍然相同)。

我尝试过使用反向视图,反向投影,网络上的两者和其他一些内容的混合,但我无法修复它。

所以这是我的CPU代码:

           Dim viewSpaceLPos As Vector3 = Vector3.Transform(New Vector3(pointlight.PosRad.X, pointlight.PosRad.Y, pointlight.PosRad.Z), Engine.Camera.EyeTransform)

            Dim lightMatrix As Matrix = Matrix.Scaling(pointlight.PosRad.W) * Matrix.Translation(New Vector3(pointlight.PosRad.X, pointlight.PosRad.Y, pointlight.PosRad.Z))

这是我的CS着色器代码:

[numthreads(GROUP_WIDTH, GROUP_HEIGHT, GROUP_DEPTH)]
void TileLightingCS(uint3 dispatchThreadID : SV_DispatchThreadID,     uint3 GroupID : SV_GroupID, uint3 GroupThreadID : SV_GroupThreadID)
{
int2 globalCoords = dispatchThreadID.xy;

uint groupIndex = GroupThreadID.y * GROUP_WIDTH + GroupThreadID.x;

float minZSample = FrameBufferCamNearFar.x;
float maxZSample = FrameBufferCamNearFar.y;

float2 gbufferDim;

DepthBuffer.GetDimensions(gbufferDim.x, gbufferDim.y);

float2 screenPixelOffset = float2(2.0f, -2.0f) / gbufferDim;
float2 positionScreen = (float2(globalCoords)+0.5f) * screenPixelOffset.xy + float2(-1.0f, 1.0f);

float depthValue = DepthBuffer[globalCoords].r;

float3 positionView = ComputePositionViewFromZ(positionScreen, Projection._43 / (depthValue - Projection._33));

// Avoid shading skybox/background or otherwise invalid pixels
float viewSpaceZ = positionView.z;
bool validPixel = viewSpaceZ >= FrameBufferCamNearFar.x &&  viewSpaceZ <  FrameBufferCamNearFar.y;

[flatten] if (validPixel)
{
    minZSample = min(minZSample, viewSpaceZ);
    maxZSample = max(maxZSample, viewSpaceZ);
}

// How many total lights?
uint totalLights, dummy;
InputBuffer.GetDimensions(totalLights, dummy);

// Initialize shared memory light list and Z bounds
if (groupIndex == 0)
{
    sTileNumLights = 0;
    sMinZ = 0x7F7FFFFF;      // Max float
    sMaxZ = 0;
}

GroupMemoryBarrierWithGroupSync();


if (maxZSample >= minZSample) {
    InterlockedMin(sMinZ, asuint(minZSample));
    InterlockedMax(sMaxZ, asuint(maxZSample));
}

GroupMemoryBarrierWithGroupSync();

float minTileZ = asfloat(sMinZ);
float maxTileZ = asfloat(sMaxZ);

// Work out scale/bias from [0, 1]
float2 tileScale = float2(FrameBufferCamNearFar.zw) * rcp(float(2 * GROUP_WIDTH));
float2 tileBias = tileScale - float2(GroupID.xy);

// Now work out composite projection matrix
// Relevant matrix columns for this tile frusta
float4 c1 = float4(Projection._11 * tileScale.x, 0.0f, tileBias.x, 0.0f);
float4 c2 = float4(0.0f, -Projection._22 * tileScale.y, tileBias.y, 0.0f);
float4 c4 = float4(0.0f, 0.0f, 1.0f, 0.0f);

// Derive frustum planes
float4 frustumPlanes[6];
// Sides
frustumPlanes[0] = c4 - c1;
frustumPlanes[1] = c4 + c1;
frustumPlanes[2] = c4 - c2;
frustumPlanes[3] = c4 + c2;
// Near/far
frustumPlanes[4] = float4(0.0f, 0.0f, 1.0f, -minTileZ);
frustumPlanes[5] = float4(0.0f, 0.0f, -1.0f, maxTileZ);

// Normalize frustum planes (near/far already normalized)
[unroll] for (uint i = 0; i < 4; ++i)
{
    frustumPlanes[i] *= rcp(length(frustumPlanes[i].xyz));
}

// Cull lights for this tile
for (uint lightIndex = groupIndex; lightIndex < totalLights; lightIndex += (GROUP_WIDTH * GROUP_HEIGHT))
{
    PointLight light = InputBuffer[lightIndex];
    float3 lightVS = light.PosRad.xyz;// mul(float4(light.Pos.xyz, 1), View);
                                      // Cull: point light sphere vs tile frustum
    bool inFrustum = true;
    [unroll]
    for (uint i = 0; i < 6; ++i)
    {
        float d = dot(frustumPlanes[i], float4(lightVS, 1.0f));
        inFrustum = inFrustum && (d >= -light.PosRad.w);
    }

    [branch]
    if (inFrustum)
    {
        uint listIndex;
        InterlockedAdd(sTileNumLights, 1, listIndex);
        sTileLightIndices[listIndex] = lightIndex;
    }
}

GroupMemoryBarrierWithGroupSync();

uint numLights = sTileNumLights;

if (all(globalCoords < FrameBufferCamNearFar.zw))
{

    float4 NormalMap = NormalBuffer[globalCoords];
    float3 normal = DecodeNormal(NormalMap);


    if (numLights > 0)
    {
        float3 lit = float3(0.0f, 0.0f, 0.0f);
        for (uint tileLightIndex = 0; tileLightIndex < numLights; ++tileLightIndex)
        {

            PointLight light = InputBuffer[sTileLightIndices[tileLightIndex]];

            float3 lDir = light.PosRad.xyz - positionView;
            lDir = normalize(lDir);
            float3 nl = saturate(dot(lDir, normal));

            lit += ((light.Color.xyz * light.Color.a) * nl) *  0.1f;
        }

        PointLightColor[globalCoords] = float4(lit, 1);
    }
    else
    {

        PointLightColor[globalCoords] = 0;
    }
}

GroupMemoryBarrierWithGroupSync();
}

所以我知道剔除是有效的,因为有灯光,他们只是随着相机移动。

这可能是一个用手问题吗?

我是否正确设置了CPU灯代码?

我把空间搞砸了吗?

我错过了什么?

我是否从深度错误重建我的位置? (不要认为这是因为剔除工作)

PS。我这样写深度:

                VS shader
    float4 viewSpacePos = mul(float4(input.Position,1), WV);
output.Depth=viewSpacePos.z ;

             PS Shader

     -input.Depth.x / FarClip

0 个答案:

没有答案