Ogre3d / Отложенный рендеринг / Точечный свет

Я пытаюсь настроить отложенный рендерер, используя фреймворк ogre compositor. Я попытался реализовать шейдер точечного света (как полноэкранный четырехъядерный эффект, без затухания или расчетов отражения) в приведенном ниже коде:

Материал, выводящий отложенные данные в GBuffer:

void ToGBufferVP
                (
                    float4 iPosition : POSITION,
                    float3 iNormal : NORMAL,
                    float2 iUV0 : TEXCOORD,

                    out float4 oPosition : POSITION,
                    out float3 oViewPos : TEXCOORD0,
                    out float3 oNormal : TEXCOORD1,
                    out float2 oUV0 : TEXCOORD2,

                    uniform float4x4 cWorldViewProj,
                    uniform float4x4 cWorldView
                )
{
    oPosition = mul(cWorldViewProj, iPosition);
    oNormal = mul(cWorldView, float4(iNormal,0)).xyz;
    oViewPos = mul(cWorldView, iPosition).xyz;
    oUV0 = iUV0;
}

void ToGBufferFP
                (
                    float3 iViewPos : TEXCOORD0,
                    float3 iNormal : TEXCOORD1,
                    float2 iUV0 : TEXCOORD2,

                    out float4 oColor0 : COLOR0,
                    out float4 oColor1 : COLOR1,

                    uniform sampler2D sTex : register(s0),
                    uniform sampler2D sSpec : register(s1),

                    uniform float cFarDistance
                )
{
    oColor0.rgb = tex2D(sTex, iUV0);
    oColor0.a = tex2D(sSpec, iUV0);
    oColor1.rgb = normalize(iNormal);
    oColor1.a = length(iViewPos) / cFarDistance;
}

Описание программы Vertex:

vertex_program ScreenQuadDebugLight_VS cg
{
    source MyDeferredPostShader.hlsl
    profiles vs_1_1 arbvp1
    entry_point ScreenQuadDebugLight_VS

    default_params
    {
        param_named_auto worldViewProj worldviewproj_matrix
    }
}

Фрагмент описания программы:

fragment_program ScreenQuadDebugLight_PS cg
{
    source MyDeferredPostShader.hlsl
    profiles ps_2_0 arbfp1
    entry_point ScreenQuadDebugLight_PS

    default_params
    {
        param_named_auto vpWidth viewport_width
        param_named_auto vpHeight viewport_height       

        param_named_auto flip render_target_flipping
        param_named_auto farClipDistance far_clip_distance

        param_named_auto lightPos light_position_view_space 0
    }
}

Сценарий светового материала:

material DeferredShadingPostQuadLight
{
    technique
    {
        pass
        {
            cull_hardware none
            cull_software none

            depth_func always_pass

            vertex_program_ref ScreenQuadDebugLight_VS
            {
            }

            fragment_program_ref ScreenQuadDebugLight_PS
            {
            }

            texture_unit
            {
                tex_coord_set 0
                tex_address_mode clamp
                filtering none
            }

            texture_unit
            {
                tex_coord_set 1
                tex_address_mode clamp
                filtering none
            }
        }
    }
}

Светлый шейдер:

void ScreenQuadDebugLight_VS
    (
        float4 Pos: POSITION,   
        out float4 oPos: POSITION,
        out float4 oTexCoord : TEXCOORD0,   
        uniform float4x4 worldViewProj
    )
{
    float4 projPos = mul(worldViewProj, Pos);
    oTexCoord = projPos;    
    oPos = projPos;
}

float4 ScreenQuadDebugLight_PS
    (
        float4 projPos : TEXCOORD0,
        uniform sampler Tex0: register(s0),
        uniform sampler Tex1: register(s1),

        uniform float vpWidth,
        uniform float vpHeight,

        uniform float flip,
        uniform float farClipDistance,

        uniform float3 lightPos
    ) : COLOR 
{
    // Get homogenous coordinates
    projPos.xy /= projPos.w;

    // Compensate texture coordinate half pixel jitter
    float2 texCoord = 0.5f * (float2(projPos.x, -projPos.y) + 1);
    float2 halfPixel = float2(0.5/vpWidth, 0.5/vpHeight);
    texCoord += halfPixel;

    float3 ray = float3(projPos.x, projPos.y * flip, 1);

    float4 a0 = tex2D(Tex0, texCoord); // Albedo and Specularity
    float4 a1 = tex2D(Tex1, texCoord); // Normal and Depth

    // Attributes
    float3 colour = a0.rgb;
    float specularity = a0.a;
    float distance = a1.w;
    float3 normal = a1.xyz;

    float3 viewPos = normalize(ray);
    viewPos.z = distance;

    float3 objToLightVec =  lightPos - viewPos;
    float len_sq = dot(objToLightVec, objToLightVec);
    float len = sqrt(len_sq);
    float3 objToLightDir = normalize(objToLightVec);

    float3 total_light_contrib;
    total_light_contrib = max(0.0, dot(objToLightDir, normal));

    return float4(total_light_contrib, 0.0);
}

Вот как я объявляю свет в своем файле .cpp:

lLightSceneNodeHolder = mSceneMgr->getRootSceneNode()->createChildSceneNode();

Ogre::Light *light;
light = mSceneMgr->createLight();
light->setType(Ogre::Light::LT_POINT);
light->setPosition(Ogre::Vector3(0, 0, -0.7f));
light->setVisible(true);
light->setDiffuseColour(Ogre::ColourValue::White);
light->setSpecularColour(Ogre::ColourValue::White);
lLightSceneNodeHolder->attachObject(light);

Я получаю вывод, и все работает нормально, за исключением того, что я не могу заставить освещение работать правильно. Буфер G содержит достоверные данные — нормали пространства обзора, линейную глубину по оси z, текстуры. Я также получаю положение света в пространстве обзора в качестве параметра — однако есть некоторые проблемы во время векторных вычислений — и результат совсем не похож на точечный свет. Что я здесь делаю неправильно?

Спасибо!

P.S. Я также пытался передать параметр lightPos вручную через прослушиватель композитора, но тогда свет больше походил на направленный свет...


person Vis Viva    schedule 25.12.2012    source источник


Ответы (1)


Проблема заключалась в уравнении:

float3 ray = float3(projPos.x, projPos.y * flip, 1);

Его нужно было умножить на значение farCorner, которое находится в дальнем углу пирамиды видимости камеры:

float3 ray = float3(projPos.x, projPos.y * flip, 1) * farCorner;

Вы можете получить его с помощью

mCamera->getWorldSpaceCorners()[1];

а затем подключите его к прослушивателю композитора следующим образом:

void LightListener::notifyMaterialSetup(Ogre::uint32 pass_id, Ogre::MaterialPtr &mat)
{
    vpParams = mat->getBestTechnique()->getPass(0)->getVertexProgramParameters();
    fpParams = mat->getBestTechnique()->getPass(0)->getFragmentProgramParameters();
}

void LightListener::notifyMaterialRender(Ogre::uint32 pass_id, Ogre::MaterialPtr &mat)
{
    vpParams->setNamedConstant("lightPos", lightPos);
    fpParams->setNamedConstant("farCorner", mCamera->getWorldSpaceCorners()[1]);
}
person Vis Viva    schedule 28.12.2012