2

Deferred レンダラーも実装した後、修士論文プロジェクト用に OpenGL で Pre-Pass Lighting アルゴリズムを実装しています。Deferred レンダラーは完全に機能し、PPL の実装はこれに基づいています。アルゴリズムのライティング パスの後、非常に奇妙なアーティファクトが発生しました。シーン内のライトの影響を蓄積する L バッファに含まれるデータは正しいのですが、結果はジオメトリに関してわずかにずれているため、マテリアルパスのシーンに適用すると、結果がはっきりと見えます! (ここに画像を投稿することはできませんが、ここにそれを見るためのリンクがありますhttp://postimage.org/image/kxhlbnl9v/

ライト マップ キューブは、ジオメトリからのオフセット (軸ごとに異なる) を使用して何らかの方法で計算されているようです。シェーダーと 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;
}

助言がありますか?

4

1 に答える 1

0

画面の位置を計算する代わりに、WPOS レジスタ (HLSL の VPOS) を使用することもできます。

于 2012-12-05T00:16:25.840 に答える