SSAOeffect.fx из примера Screen Space Ambient Occlusion XNA 3.1 не работает в XNA 4.0

Я пытаюсь преобразовать пример Screen Space Ambient Occlusion из XNA 3.1 в XNA 4.0. Я исправил все проблемы в исходном коде, кроме этой странной проблемы в файле шейдера. Я рассмотрел и исправил все очевидные проблемы с шейдером, как указано в блоге Шона Харгривза, но при компиляции он использует 620 слотов инструкций, что намного превышает ограничение в 512 слотов инструкций. Как это могло работать в XNA 3.1, но не в XNA 4.0?

Изменения по сравнению с копией файла 3.1 очень минимальны и заключаются только в переименовании нескольких функций. ниже представлен полный исходный код шейдера в его текущем виде. Я буду очень благодарен за любую помощь в сокращении количества слотов инструкций, в которые он компилируется.


float sampleRadius;
float distanceScale;
float4x4 Projection;

float3 cornerFustrum;

struct VS_OUTPUT
{
    float4 pos              : POSITION;
    float2 TexCoord         : TEXCOORD0;
    float3 viewDirection    : TEXCOORD1;
}; 

VS_OUTPUT VertexShaderFunction(
    float4 Position : POSITION, float2 TexCoord : TEXCOORD0)
{
    VS_OUTPUT Out = (VS_OUTPUT)0;

    Out.pos = Position;
    Position.xy = sign(Position.xy);
    Out.TexCoord = (float2(Position.x, -Position.y) + float2( 1.0f, 1.0f ) ) * 0.5f;
    float3 corner = float3(-cornerFustrum.x * Position.x,
            cornerFustrum.y * Position.y, cornerFustrum.z);
    Out.viewDirection =  corner;

    return Out;
}


texture depthTexture;
texture randomTexture;

sampler2D depthSampler = sampler_state
{
    Texture = <depthTexture>;
    ADDRESSU = CLAMP;
    ADDRESSV = CLAMP;
    MAGFILTER = LINEAR;
    MINFILTER = LINEAR;
};

sampler2D RandNormal = sampler_state
{
    Texture = <randomTexture>;
    ADDRESSU = WRAP;
    ADDRESSV = WRAP;
    MAGFILTER = LINEAR;
    MINFILTER = LINEAR;
};

float4 PixelShaderFunction(VS_OUTPUT IN) : COLOR0
{
    float4 samples[16] =
    {
        float4(0.355512,    -0.709318,  -0.102371,  0.0 ),
        float4(0.534186,    0.71511,    -0.115167,  0.0 ),
        float4(-0.87866,    0.157139,   -0.115167,  0.0 ),
        float4(0.140679,    -0.475516,  -0.0639818, 0.0 ),
        float4(-0.0796121,  0.158842,   -0.677075,  0.0 ),
        float4(-0.0759516,  -0.101676,  -0.483625,  0.0 ),
        float4(0.12493,     -0.0223423, -0.483625,  0.0 ),
        float4(-0.0720074,  0.243395,   -0.967251,  0.0 ),
        float4(-0.207641,   0.414286,   0.187755,   0.0 ),
        float4(-0.277332,   -0.371262,  0.187755,   0.0 ),
        float4(0.63864,     -0.114214,  0.262857,   0.0 ),
        float4(-0.184051,   0.622119,   0.262857,   0.0 ),
            float4(0.110007,    -0.219486,  0.435574,   0.0 ),
        float4(0.235085,    0.314707,   0.696918,   0.0 ),
        float4(-0.290012,   0.0518654,  0.522688,   0.0 ),
        float4(0.0975089,   -0.329594,  0.609803,   0.0 )
    };

    IN.TexCoord.x += 1.0/1600.0;
    IN.TexCoord.y += 1.0/1200.0;

    normalize (IN.viewDirection);
    float depth = tex2D(depthSampler, IN.TexCoord).a;
    float3 se = depth * IN.viewDirection;

    float3 randNormal = tex2D( RandNormal, IN.TexCoord * 200.0 ).rgb;

    float3 normal = tex2D(depthSampler, IN.TexCoord).rgb;
    float finalColor = 0.0f;

    for (int i = 0; i < 16; i++)
    {
        float3 ray = reflect(samples[i].xyz,randNormal) * sampleRadius;

        //if (dot(ray, normal) < 0)
        //  ray += normal * sampleRadius;

        float4 sample = float4(se + ray, 1.0f);
        float4 ss = mul(sample, Projection);

        float2 sampleTexCoord = 0.5f * ss.xy/ss.w + float2(0.5f, 0.5f);

        sampleTexCoord.x += 1.0/1600.0;
        sampleTexCoord.y += 1.0/1200.0;
        float sampleDepth = tex2D(depthSampler, sampleTexCoord).a;

        if (sampleDepth == 1.0)
        {
            finalColor ++;
        }
        else
        {       
            float occlusion = distanceScale* max(sampleDepth - depth, 0.0f);
            finalColor += 1.0f / (1.0f + occlusion * occlusion * 0.1);
        }
    }

    return float4(finalColor/16, finalColor/16, finalColor/16, 1.0f);
}


technique SSAO
{
    pass P0
    {          
        VertexShader = compile vs_3_0 VertexShaderFunction();
        PixelShader  = compile ps_3_0 PixelShaderFunction();
    }
}

person acp10bda    schedule 30.03.2011    source источник


Ответы (3)


XNA 4.0 применяет ограничение на 512 инструкций (которое есть у xbox360 и профиля HiDef как минимум), тогда как в XNA3.1 этого не было.

С другой стороны, любая видеокарта, которая может запускать профиль XNA HiDef, не должна упасть, где, как и в случае с XNA, допускающей любое количество инструкций, она могла бы упасть.

Поскольку в вашем коде есть цикл, вы можете попробовать заставить компилятор использовать инструкции цикла, если он в настоящее время его разворачивает (сам с этим не знаком).

person George Duckett    schedule 30.03.2011
comment
Я понимаю, что есть этот предел, я не знал, что XNA 3.1 его не применяет. Так что велика вероятность, что все время лимит был превышен. Я знаю, что в XNA 4.0 есть реализации SSAO, но, насколько я обнаружил, они имеют закрытый исходный код. Итак, я знаю, что это возможно, но, возможно, они использовали какой-то другой набор операций, который имеет такой же эффект, но использует меньше инструкций. - person acp10bda; 30.03.2011
comment
После удаления оператора for из цикла (разумеется, выполняемого только один раз), инструкции упали до точки, в которой компилятор принимает их. Но теперь я получаю ошибки во время выполнения ... Я не думаю, что это имеет отношение к этому, поэтому я буду порождать новый вопрос. Я просто отмечу это как ответ, так как он имеет какое-то отношение к развертыванию цикла, однако я не мог понять, как заставить компилятор использовать циклы for, а не развертывать его ...: / - person acp10bda; 30.03.2011

Если вы ищете SSAO XNA 4 с открытым исходным кодом, проверьте эту ссылку: Отложенный рендеринг с нормами SSAO

person Neil Knight    schedule 30.03.2011
comment
О боже, я бы хотел найти это некоторое время назад, я только что прошел через процесс перевода примера отложенного рендеринга, данного Каталином Зимой, еще в XNA 2.0. Ух, какая боль. Я просто собираюсь это схватить. Большое спасибо. - person acp10bda; 30.03.2011
comment
Пожалуйста. Если вы хотите расширить это, я бы порекомендовал изменить функции get/set в пользу properties. Я сделал это с большим успехом (project-vanquish.co.cc). Я также изменил вызовы методов, чтобы Я не прохожу List<Model> и не имею public static List<Model>, который я могу вызвать из моего Engine класса. - person Neil Knight; 30.03.2011
comment
Ну, мне просто нужен полный и рабочий пример или учебник для него, чтобы я мог легко реализовать его в моем движке (это дает мне и то, и другое!), Однако я немного не в восторге от эффекта SSAO, но я думаю, что это из-за случайного нормалей, если я сделаю несколько хороших полигонов с жесткими краями в сцене, я смогу лучше судить о них на основе других SSAO, которые я видел. Конечно, я не ожидаю, что это будет супер потрясающе, учитывая ограничения шейдера SSAO по сравнению, очевидно, со всеми другими реализациями. Думаю, это ограничение, наложенное XNA, с которым мне просто придется поработать. - person acp10bda; 30.03.2011
comment
Что ж, куда бы вы ни пошли - наслаждайтесь: o) - person Neil Knight; 30.03.2011

уменьшить количество сэмплов в шейдере с 16 до 8

person angrywasp    schedule 08.04.2011