2012-11-22 11 views
2

Deferred 렌더러를 구현 한 후에도 OpenGL에서 마스터 논문 프로젝트 용으로 프리 패스 조명 알고리즘을 구현 중입니다. Deferred 렌더러는 완벽하게 작동하며 PPL 구현을 기반으로합니다. 알고리즘의 조명이 통과 된 후에 나는 이상한 유물을 얻었습니다 : 장면에서 빛의 기여를 축적하는 L 버퍼에 포함 된 데이터는 정확하지만 형상과 관련하여 약간의 차이가 있습니다. 재료 통과 장면에 적용하면 명확하게 볼 수 있습니다. (여기에 이미지를 게시 할 수는 없지만 그것을 볼 수있는 링크는 http://postimage.org/image/kxhlbnl9v/입니다.프리 패스 조명 OpenGL 구현 아티팩트

라이트 맵 큐브가 어떻게 든 지오메트리에서 오프셋 (모든 축이 다른)으로 계산 된 것처럼 보입니다. 셰이더와 C++ 코드를 여러 번 확인했는데이 문제의 원인을 이해할 수 없습니다. 나는 아이디어가 부족하다. 아래에는 순서대로 호출되는 알고리즘의 3 번 통과에 대한 코드가 있습니다. 이 코드는 현재 실험 중이므로이 단계에서 제대로 설계되지 않았다는 것을 알고 있습니다. 또한 모든 단계에서 사용하는 셰이더를 G 버퍼, L 버퍼 및 프레임 버퍼에 순서대로 추가합니다.

C++ 코드 :

// Draw geometry to g buffer 
void GLPrePassLightingRendererV2::GeometryStage() 
{ 
    // Set GL states 
    glFrontFace(GL_CCW); 
    glCullFace(GL_BACK); 
    glEnable(GL_CULL_FACE); 
    glDepthFunc(GL_LEQUAL); 
    glDisable(GL_BLEND); 
    glEnable(GL_DEPTH_TEST); 
    glDepthMask(GL_TRUE); 

    // Bind G-Buffer for geometry pass 
    mGBuffer->BindForWriting(); 

    // Bind geometry stage shaders 
    mTargetRenderSystem->BindShader(mGeometryStageVS); 
    mTargetRenderSystem->BindShader(mGeometryStageFS); 

    // Clear the framebuffer 
    mTargetRenderSystem->ClearFrameBuffer(FBT_COLOUR | FBT_DEPTH); 

    // Iterate over all the Renderables in the previously built RenderQueue 
    RenderableList* visibles = mSceneManager->GetRenderQueue()->GetRenderables(); 

    // Set shader params here 
    //[...] 

    // Get the transformation info from the node the renderable is attached to 
    for (RenderableList::iterator it = visibles->begin(); it != visibles->end(); ++it) 
    { 
    Renderable* renderable = *it; 
    Material* mat = renderable->GetMaterial(); 

    mGeometryStageVS->Update(); 
    mGeometryStageFS->Update(); 

    // Render the object 
    RenderOperation rop; 
    renderable->GetRenderOperation(rop); 
    mTargetRenderSystem->Render(rop); 
    } 

    // Only the geometry pass will write to the depth buffer 
    glDepthMask(GL_FALSE); 
    glDisable(GL_DEPTH_TEST); 
} 

// Accumulate lights contribs in L-buffer using G-buffer 
void GLPrePassLightingRendererV2::LightingStage() 
{ 
    // Enable additive blending for lights 
    glEnable(GL_BLEND); 
    glBlendEquation(GL_FUNC_ADD); 
    glBlendFunc(GL_ONE, GL_ONE); 
    //glCullFace(GL_FRONT); 

    // Bind shader for light stage 
    mTargetRenderSystem->BindShader(mLightStageVS); 
    mTargetRenderSystem->BindShader(mLightStageFS); 

    // Bind G-Buffer for reading and L-Buffer for writing for lighting pass 
    mGBuffer->BindForReading(); 
    mLBuffer->BindForWriting(); 

    mTargetRenderSystem->ClearFrameBuffer(FBT_COLOUR); 

    // Set shader params 
    // [...] 

    // Get all the lights in frustum, not by renderable 
    const LightList& lights = mSceneManager->GetLightsInFrustum(); 

    // For each light in the frustum 
    LightList::const_iterator front_light_it; 
    for (LightList::const_iterator lit = lights.begin(); lit != lights.end(); ++lit) 
    { 
    // Send per light parameters to the shader 
    Light* l = (*lit); 
    SetLight(*l); 

    // Calculate bounding sphere for light and scale accordingly to instensity 
    float lightSphereScale = GetPointLightSphereScale(l->GetColor(), l->GetDiffuseIntensity()); 

    // TODO: Render a sphere for each point light, a full screen quad for each directional 
    worldMtx.Identity(); 
    worldMtx.SetScale(lightSphereScale, lightSphereScale, lightSphereScale); 
    worldMtx.SetTranslation(l->GetPosition()); 

    mLightStageVS->SetParameterValue("gWorldMtx", (float*)&worldMtx); 

    mLightStageVS->Update(); 
    mLightStageFS->Update(); 
    static MeshInstance* sphere = mSceneManager->CreateMeshInstance("LightSphere", MBT_LIGHT_SPHERE); 

    RenderOperation rop; 
    sphere->GetSubMeshInstance(0)->GetRenderOperation(rop); 
    mTargetRenderSystem->Render(rop); 
    } 

    // Disable additive blending 
    glDisable(GL_BLEND); 
} 

// Combine L-buffer and material information per object 
void GLPrePassLightingRendererV2::MaterialStage() 
{ 
    // Set some GL states 
    glDepthMask(GL_TRUE); 
    glEnable(GL_DEPTH_TEST); 
    //glCullFace(GL_BACK); 

    // Bind material stage shaders (TODO: actually every object will bind its own matarial, if not a default one is used) 
    mTargetRenderSystem->BindShader(mMaterialStageVS); 
    mTargetRenderSystem->BindShader(mMaterialStageFS); 

    // Bind L-Buffer for reading 
    mLBuffer->BindForReading(); 

    mTargetRenderSystem->ClearFrameBuffer(FBT_COLOUR | FBT_DEPTH, Math::ColourValue::WHITE); 

    // Iterate over all the Renderables in the previously built RenderQueue 
    RenderableList* visibles = mSceneManager->GetRenderQueue()->GetRenderables(); 

    // Set shader params here 
    // [...] 

    // Get the transformation info from the node the renderable is attached to 
    for (RenderableList::iterator it = visibles->begin(); it != visibles->end(); ++it) 
    { 
    Renderable* renderable = *it; 
    Material* mat = renderable->GetMaterial(); 


    // Set texture units 
    if (mat) 
    { 
     for (unsigned short i = 0; i < mat->GetTextureUnitCount(); ++i) 
     { 
     const TextureUnit* unit = mat->GetTextureUnit(i); 
     GLTexture* t = static_cast<GLTexture*>(unit->GetTexture()); 
     glActiveTexture(GL_TEXTURE1); // This is needed because the first texture map slot is hold by the LBuffer! 
     glBindTexture(GL_TEXTURE_2D, t->GetGLId()); 
     } 
    } 

    mMaterialStageVS->Update(); 
    mMaterialStageFS->Update(); 

    // Render the object 
    RenderOperation rop; 
    renderable->GetRenderOperation(rop); 
    mTargetRenderSystem->Render(rop); 
    } 
} 

NVIDIA CG 쉐이더 :

// Vertex shader for Deferred Rendering geometry stage. 

float4x4 gWorldMtx; 
float4x4 gViewMtx; 
float4x4 gProjectionMtx; 

struct a2v 
{ 
    float3 position : POSITION; 
    float3 normal : NORMAL; 
    float2 texCoord : TEXCOORD0; 
}; 

struct v2f 
{ 
    float4 position  : POSITION; 
    float3 normal  : TEXCOORD0; 
    float3 wPosition : TEXCOORD1; 
    float2 texCoord  : TEXCOORD2; 
}; 


v2f PPL_geometry_stage_vs(a2v IN) 
{ 
    v2f OUT; 

    // Transform to world space 
    OUT.wPosition = mul(gWorldMtx, float4(IN.position, 1.0f)).xyz; 
    OUT.normal = mul(gWorldMtx, float4(IN.normal, 0.0f)).xyz; 

    // Transform to homogeneous clip space 
    OUT.position = mul(gViewMtx, float4(OUT.wPosition, 1.0f)); 
    OUT.position = mul(gProjectionMtx, OUT.position); 

    OUT.texCoord = IN.texCoord; 

    return OUT; 
} 

// Fragment shader for Pre-pass Lighing geometry stage. 

struct f2a 
{ 
    float4 position : COLOR0; 
    float4 normal : COLOR1; 
}; 

f2a PPL_geometry_stage_fs(v2f IN) 
{ 
    f2a OUT; 

    OUT.position = float4(IN.wPosition, 1.0f); 
    OUT.normal = float4(normalize(IN.normal), 1.0f); 

    return OUT; 
} 

// Vertex shader for Pre-pass lighing light stage. 

float4x4 gWorldMtx; 
float4x4 gViewMtx; 
float4x4 gProjectionMtx; 

struct a2v 
{ 
    float3 position : POSITION; 
}; 

struct v2f 
{ 
    float4 position : POSITION; 
    float4 lightPos : TEXCOORD0; 
}; 

v2f PPL_light_stage_vs(a2v IN) 
{ 
    v2f OUT; 

    float4x4 wv = mul(gWorldMtx, gViewMtx); 
    float4x4 wvp = mul(gViewMtx, gProjectionMtx); 
    wvp   = mul(wvp, gWorldMtx); 

    // Only transforms position to world space 
    OUT.position = mul(wvp, float4(IN.position, 1.0f)); 

    // Copy light position to calculate fragment coordinate 
    OUT.lightPos = OUT.position; 

    return OUT; 
} 

// Fragment shader for Pre-pass lighing light stage. 

// Light structures 
struct BaseLight 
{ 
    float3 color; 
    float ambientIntensity; 
    float diffuseIntensity; 
}; 

struct DirectionalLight 
{ 
    struct BaseLight base; 
    float3 direction; 
}; 

struct Attenuation 
{ 
    float constant; 
    float linearr; 
    float quadratic; 
}; 

struct PointLight 
{ 
    struct BaseLight base; 
    float3 position; 
    Attenuation atten; 
}; 

struct SpotLight 
{ 
    struct PointLight base; 
    float3 direction; 
    float cutoff; 
}; 

// G-Buffer textures 
sampler2D gPositionMap : TEXUNIT0; 
sampler2D gNormalMap : TEXUNIT1; 

// Light variables 
float3 gEyePosition; 
DirectionalLight gDirectionalLight; 
PointLight gPointLight; 
SpotLight gSpotLight; 
int gLightType; 
float gSpecularPower; 

float4 PPL_light_stage_point_light_fs(v2f IN) : COLOR0 
{ 
    // Get fragment coordinate, from NDC space [-1, 1] to [0, 1]. 
    float2 fragcoord = ((IN.lightPos.xy/IN.lightPos.w) + 1.0f)/2.0f; 

    // Calculate lighting with G-Buffer textures 
    float3 position = tex2D(gPositionMap, fragcoord).xyz; 
    float3 normal = tex2D(gNormalMap, fragcoord).xyz; 
    normal = normalize(normal); 

    // Attenuation 
    float3 lightDirection = position - gPointLight.position; 
    float dist = length(lightDirection); 
    float att = gPointLight.atten.constant + gPointLight.atten.linearr * dist + gPointLight.atten.quadratic * dist * dist; 

    // NL 
    lightDirection = normalize(lightDirection); 
    float NL = dot(normal, -lightDirection); 

    // Specular (Blinn-Phong) 
    float specular = 0.0f; 
    //if (NL > 0) 
    //{ 
    // float3 vertexToEye = normalize(gEyePosition - position); 
    // float3 lightReflect = normalize(reflect(lightDirection, normal)); 
    // specular = pow(saturate(dot(vertexToEye, lightReflect)), gSpecularPower); 
    //} 

    // Apply attenuation to NL 
    NL = NL/min(1.0, att); 

    float3 lightColor = gPointLight.base.color * gPointLight.base.diffuseIntensity; 
    return float4(lightColor.r, lightColor.g, lightColor.b, 1.0f) * NL; 
} 

// Vertex shader for Pre-pass lighing material stage. 

float4x4 gWorldMtx; 
float4x4 gViewMtx; 
float4x4 gProjectionMtx; 

struct a2v 
{ 
    float3 position : POSITION; 
    float3 normal : NORMAL; 
    float2 texcoord : TEXCOORD0; 
}; 

struct v2f 
{ 
    float4 position : POSITION; 
    float2 texcoord : TEXCOORD0; 
    float3 normal : TEXCOORD1; 
    float4 projPos : TEXCOORD2; 
}; 

v2f PPL_material_stage_vs(a2v IN) 
{ 
    v2f OUT; 

    float4x4 wv = mul(gWorldMtx, gViewMtx); 
    float4x4 wvp = mul(gViewMtx, gProjectionMtx); 
    wvp   = mul(wvp, gWorldMtx); 

    // Only transforms position to world space 
    OUT.position = mul(wvp, float4(IN.position, 1.0f)); 

    // Normal (It's not necessary, but i have to see if it influences the execution) 
    OUT.normal = mul(gWorldMtx, float4(IN.normal, 0.0f)).xyz; 

    // Copy texture coordinates 
    OUT.texcoord = IN.texcoord; 

    // Copy projected position to get the fragment coordinate 
    OUT.projPos = OUT.position; 

    return OUT; 
} 

// Fragment shader for Pre-pass lighing material stage. 

// L-buffer texture 
sampler2D gLightMap : TEXUNIT0; 
// Object's material specific textures 
sampler2D gColorMap : TEXUNIT1; 

float4 PPL_material_stage_fs(v2f IN) : COLOR0 
{ 
    float2 fragcoord = ((IN.projPos.xy/IN.projPos.w) + 1.0f)/2.0f; 

    // Get all light contributions for this pixel 
    float4 light = tex2D(gLightMap, fragcoord); 
    float3 combined = saturate(light.rgb);// + light.aaa); 

    // Get material albedo from texture map 
    float4 diffuse = tex2D(gColorMap, IN.texcoord); 

    return float4(combined, 1.0f) * diffuse; 
} 

어떤 제안?

+0

안녕하세요! 코드 예제가 너무 길다. 누군가가이 모든 것을 읽을 것 같지는 않습니다. 문제를 조금 좁히십시오. –

+0

감사! 나는 그것을 조금 줄였다. – user1844578

답변

0

화면 위치를 계산하는 대신 WPOS 레지스터 (HLSL의 VPOS)를 사용할 수 있습니다.