2

有名な前面カリング手法を使用して、ハードおよび PCF シャドウ マッピング アルゴリズムを実装する単純な 3D アプリケーションを作成しました。残念ながら、この手法の問題は、密閉されたメッシュのみがキャスト シャドウを生成できることです。たとえば、平面はそれ自体が前面であるため、このような効果を生み出すことはできません。

したがって、解決策は関数「glPolygonOffset」を使用することです。この目的は、「ライト ビュー」から見える各頂点の深度レンダリング パス中に深度値をわずかに変更することです。言い換えれば、この関数は、今回はすべてのメッシュの前面を維持する「シャドウ アクネ」アーティファクトを回避するために必要です。

ハード シャドウ マッピング アルゴリズムを使用したこのようなレンダリングの表示を次に示します。

ここに画像の説明を入力

ご覧のとおり、影のレンダリングはアーティファクトなしで完璧です!

以下は、深度テクスチャ レンダリング パスを定義する C++ クライアント コードです。

/*glEnable(GL_CULL_FACE);   //OLD TECHNIQUE
    glCullFace(GL_FRONT);*/

for (uint32_t idy = 0; idy < lightSceneNodeList.size(); idy++)
{   
    if (lightSceneNodeList[idy]->IsShadowEnabled())
    {
        type::ShadowCasterPtr pShadowCaster = ShadowManager::GetSingleton()
            .FindShadowCasterByName(lightSceneNodeList[idy]->GetName());
        {
            pShadowCaster->Bind(TARGET_FBO);
            {
                glEnable(GL_POLYGON_OFFSET_FILL);   //NEW TECHNIQUE
                glPolygonOffset(1.1f, 4.0f);

                glClear(GL_DEPTH_BUFFER_BIT);
                glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
                {
                    pShadowCaster->UpdateFrustrumPosition(
                        lightSceneNodeList[idy]->GetParentModelMatrix());
                    pShadowCaster->SetViewport();
                    {
                        for (uint32_t idx = 0; idx < pBatchList.size(); idx++)
                            pBatchList[idx]->Render(pShadowCaster);
                    }
                }
                glDisable(GL_POLYGON_OFFSET_FILL);
            }
            pShadowCaster->Unbind(TARGET_FBO);
        }
    }
}
//glDisable(GL_CULL_FACE);

次に、2 番目のレンダリング パスでシャドウ ファクターを計算するためにフラグメント シェーダー コードで使用されるコード:

/*
** \brief Recover the depth value from shadow map by projection
*/
float Tex2D_Proj(sampler2DShadow shadowSampler, vec4 LightToVertexDir_LS)
{
    float ShadowFactor = 1.0f;
    {
        vec3 LightToVertexDir_CS = LightToVertexDir_LS.xyz/LightToVertexDir_LS.w;

        ShadowFactor = texture(shadowSampler, LightToVertexDir_CS);
    }
    return (ShadowFactor);
}
/*
** \brief Returns biased hard shadow factor.
*/
float Get_2D_Hard_ShadowFactor(sampler2DShadow shadowSampler, int index)
{
    float shadowFactor = 1.0f;
    {
        if (ShadowCoords[index].z <= MaxShadowDist[index])
        {
            if (ShadowCoords[index].w > 0.0f);
            {
                shadowFactor = Tex2D_Proj(shadowSampler, ShadowCoords[index]);
            }
        }
    }
    return (shadowFactor);
}

「ShadowCoords」一様変数はライト空間の頂点位置で、「index」はライト インデックスです。

しかし、最初のパスで「glPolygonOffset」関数も使用して、PCF シャドウ マッピング アルゴリズム (4 つのサンプルの例) を使用すると問題が発生します。

ここに画像の説明を入力

ご覧のとおり、「シャドウ アクネ」のアーティファクトがはっきりとわかります。

私のフラグメントシェーダーのコードは次のとおりです。

float Get_2D_PCF_ShadowFactor(sampler2DShadow shadowSampler, int index)
{
    float shadowFactor = 0.0f;
    {
        int kernel_base = int(PCFKernelType[index])/2;
        float kernel_count = pow(int(PCFKernelType[index]), 2.0f);

        if (ShadowCoords[index].z <= MaxShadowDist[index])
        {
            if (ShadowCoords[index].w > 0.0f)
            {
                shadowFactor += textureProjOffset(shadowSampler, ShadowCoords[index], ivec2(-1, 1));
                shadowFactor += textureProjOffset(shadowSampler, ShadowCoords[index], ivec2(1, 1));
                shadowFactor += textureProjOffset(shadowSampler, ShadowCoords[index], ivec2(1, -1));
                shadowFactor += textureProjOffset(shadowSampler, ShadowCoords[index], ivec2(-1, -1));

                shadowFactor *= 0.25f;
            }
        }
    }
    return (shadowFactor);
}

「textureProjOffset」コードは次のコードと同じです。

float Tex2D_Proj_Offset(sampler2DShadow shadowSampler, vec4 LightToVertexDir_LS, vec2 offsetCoords, vec2 shadowMapSize)
{
    float offset_x = 1.0f/shadowMapSize.x;
    float offset_y = 1.0f/shadowMapSize.y;

    float ShadowFactor = 1.0f;
    {
        vec3 LightToVertexDir_CS = LightToVertexDir_LS.xyz/LightToVertexDir_LS.w;
        vec2 ShadowTexCoords = vec2(LightToVertexDir_CS.x, LightToVertexDir_CS.y);

        vec2 DerivedShadowTexCoords = vec2(
            ShadowTexCoords.x + offsetCoords.x * offset_x,
                ShadowTexCoords.y + offsetCoords.y * offset_y);

        ShadowFactor = texture(shadowSampler, vec3(
            DerivedShadowTexCoords, LightToVertexDir_CS.z));
    }
    return (ShadowFactor);
}

「textureProjOffset(shadowSampler, ShadowCoords[index], ivec2(0, 0))」の呼び出しのみが正しく機能します (もちろん、最初のハード シャドウ マッピング手法を参照しています)。

次の呼び出しのみを使用する場合 (つまり、単純なハード シャドウ マッピングですが、オフセットを使用します):

shadowFactor = textureProjOffset(shadowSampler, ShadowCoords[index], ivec2(-1, 0));

次のレンダリングがあります。

ここに画像の説明を入力

ご覧のとおり、立方体の右側面のみに「影ニキビ」のアーティファクトがあります。

私の問題を解決するために、いくつかのバイアス値を追加してライト空間の頂点深度値を処理するコードの組み合わせをいくつか試しましたが、成功しませんでした。

4

1 に答える 1

0

これが役立つかどうかはわかりません。たぶん私はあなたの質問を複雑にしすぎています。このコードは Objective C アプリケーションからのものですが、関連するコードはほとんどが C です。実行して動作します。シーン フラグメント シェーダーにステートメント if (depthInShadow > 0.006) が表示されます。この影の数の深さは、にきびを取り除くために「微調整」しなければならなかったものです.

これは編集です。あなたの投稿を読み直した後、次のステートメントが表示されます: if (ShadowCoords[index].w > 0.0f)。これは、シーン フラグメント シェーダーの depthInShadow ステートメントと非常によく似ており、にきびを取り除くために 0.0 よりも少し大きい値に「微調整」する必要がありました。試してみてください。

シャドウ マッピングに慣れていない他の人が興味を持っている場合に備えて、コードを以下に投稿したままにします。

変数の多くは .h ファイルで宣言されていますが、おわかりいただけると思います。これは非常に標準的なシャドウ マッピング コードなので、これまでにすべて見たことがある場合は、ここでやめて、長い時間を節約できます。

シャドウ バッファーとシェーダーをセットアップします。

// ************************************* Save the Current Frame Buffer

glGetIntegerv(GL_FRAMEBUFFER_BINDING, renderBuffer);

// ************************************ Create the Shadow Map Texture

glGenTextures(1, shadowTexture);
glBindTexture(GL_TEXTURE_2D, shadowTexture[0]);

glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST );
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST );

glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, SHADOWMAPRATIO * VIEWWIDTH, SHADOWMAPRATIO * VIEWHEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D, shadowTexture[0]);

// ************************************ Create the Shadow Map Frame Buffer

glGenFramebuffersEXT(1, shadowBuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadowBuffer[0]);

// **************************************** No Color Attachment

glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);

// ************************************* Attach the Shadow Texture to It

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, shadowTexture[0], 0);

// ******************************* Check to see if Frame Buffer is Complete

GLenum frameBufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
if(frameBufferStatus != GL_FRAMEBUFFER_COMPLETE)
{
    NSLog(@"There is a problem with the shadow frame buffer, %d", frameBufferStatus);
    if(frameBufferStatus == GL_INVALID_ENUM) NSLog(@"Invalid Enum.");
    if(frameBufferStatus == GL_INVALID_VALUE) NSLog(@"Invalid Value.");
    if(frameBufferStatus == GL_INVALID_OPERATION) NSLog(@"Invalid Operation");
    if(frameBufferStatus == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) NSLog(@"Incomplete Attachment");
    if(frameBufferStatus == GL_FRAMEBUFFER_UNSUPPORTED) NSLog(@"Unsupported");
}

// *********************************** Reset the original Frame Buffer

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, renderBuffer[0]);

// ************************************** Compile and Link the Shadow Shaders

ShaderInfo shadowShaderInfo[] = {
        { GL_VERTEX_SHADER, "path/shadow120.vsh" },
        { GL_FRAGMENT_SHADER, "path/shadow120.fsh" },
        { GL_NONE, NULL }
    };

shadowShaders = LoadShaders(shadowShaderInfo);

glUseProgram(shadowShaders);

shadowPositionLoc = glGetAttribLocation(shadowShaders, "ShadowPosition");

shadowViewMatrixLoc= glGetUniformLocation(shadowShaders, "ShadowViewMatrix");
if(shadowViewMatrixLoc == -1) NSLog(@"View Matrix not found in shadow shader");

shadowModelMatrixLoc= glGetUniformLocation(shadowShaders, "ShadowModelMatrix");
if(shadowModelMatrixLoc == -1) NSLog(@"Model Matrix not found in shadow shader");

shadowProjectionMatrixLoc= glGetUniformLocation(shadowShaders, "ShadowProjectionMatrix");
if(shadowProjectionMatrixLoc == -1) NSLog(@"Projection Matrix not found in shadow shader");

shadowColorLoc= glGetUniformLocation(shadowShaders, "FrontColor");
if(shadowColorLoc == -1) NSLog(@"Front Color not found in shadow shader");

均一なシャドウ マトリックスは、もちろん、カメラ位置からのものです。

シャドウ バッファーにレンダリングするために使用されるシャドウ シェーダーは簡単です。

シャドウ頂点シェーダー:

#version 120

attribute vec4 ShadowPosition;

uniform mat4 ShadowModelMatrix;
uniform mat4 ShadowViewMatrix;
uniform mat4 ShadowProjectionMatrix;

void main()
{
    gl_Position = ShadowProjectionMatrix * ShadowViewMatrix * ShadowModelMatrix * ShadowPosition;
}

シャドウ フラグメント シェーダー:

#version 120

uniform vec4 FrontColor;

void main()
{

    gl_FragColor = FrontColor;
}

まず、シーンを次のようにシャドウ バッファーにレンダリングします。

glUseProgram(shadowShaders);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadowBuffer[0]);

glColorMask ( GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE );

glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D, shadowTexture[0]);

glClearDepth(1.0);
glClear(GL_DEPTH_BUFFER_BIT);

glUniformMatrix4fv(shadowModelMatrixLoc, 1, GL_FALSE, lightGLKModelMatrix.m);
glUniformMatrix4fv(shadowViewMatrixLoc, 1, GL_FALSE, lightGLKViewMatrix.m);
glUniformMatrix4fv(shadowProjectionMatrixLoc, 1, GL_FALSE, lightGLKProjectionMatrix.m);
glUniform4fv(shadowColorLoc, 1, worldAmbient);

.... rendering code ....

glDisable(GL_POLYGON_OFFSET_FILL);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, renderBuffer[0]);
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE );

次に、これらのシェーダーを使用してシーンを通常どおりにレンダリングします。

シーン頂点シェーダー:

#version 120

attribute vec4 RingPosition;
attribute vec3 RingNormal;

uniform vec4 LightPosition;

uniform mat4 RingModelMatrix;
uniform mat4 RingViewMatrix;
uniform mat4 RingProjectionMatrix;
uniform mat3 RingNormalMatrix;

uniform mat4 ShadowBiasMatrix;
uniform mat4 ShadowModelMatrix;
uniform mat4 ShadowViewMatrix;
uniform mat4 ShadowProjectionMatrix;

varying float DiffuseIntensity;
varying float SpecularIntensity;
varying vec4 ShadowCoordinate;

const float specularContribution = 1.0;
const float diffuseContribution = 1.0;

void main()
{
    mat4 ShadowMatrix =  ShadowBiasMatrix * ShadowProjectionMatrix * ShadowViewMatrix * ShadowModelMatrix;

    ShadowCoordinate = ShadowMatrix * RingPosition;

    vec3 lightPosition= vec3(LightPosition);
    float shininess = gl_FrontMaterial.shininess;

    vec3 ecPosition = vec3(RingViewMatrix * RingModelMatrix  * RingPosition);
    vec3 tnorm = normalize(RingNormalMatrix * RingNormal);
    vec3 lightVec = normalize(lightPosition - ecPosition);
    vec3 reflectVec = reflect(-lightVec, tnorm);
    vec3 viewVec = normalize(-ecPosition);

    float spec = clamp(dot(reflectVec, viewVec), 0.0, 1.0);
    SpecularIntensity = specularContribution * pow(spec, shininess / 5.0);

    DiffuseIntensity = diffuseContribution * max(dot(lightVec, tnorm), 0.0);

    gl_Position = RingProjectionMatrix * RingViewMatrix * RingModelMatrix * RingPosition;
}

シーン フラグメント シェーダ:

#version 120

uniform sampler2D ShadowMap;

varying float DiffuseIntensity;
varying float SpecularIntensity;
varying vec4 ShadowCoordinate;

void main()
{

    vec3 emission = vec3(gl_FrontMaterial.emission);
    vec3 ambient = vec3(gl_FrontMaterial.ambient);
    vec3 diffuse = vec3(gl_FrontMaterial.diffuse);
    vec3 specular = vec3(gl_FrontMaterial.specular);

    // Normalize the Shadow Map coordinates
    // shadowCoordinateWdivide.z = current fragment depth from light

    vec3 shadowCoordinateWdivide = ShadowCoordinate.xyz / ShadowCoordinate.w ;

    float distanceFromLight = texture2D(ShadowMap, shadowCoordinateWdivide.xy).r;

    float depthInShadow = shadowCoordinateWdivide.z - distanceFromLight;

    float specularIntensity = SpecularIntensity;
    float diffuseIntensity = DiffuseIntensity;

    if (depthInShadow > 0.006)
    {
        specularIntensity = SpecularIntensity * 0.0;
        diffuseIntensity = DiffuseIntensity * 0.0;
    }

    vec3 lightColor = emission;
    lightColor = lightColor + ambient;
    lightColor = lightColor + (specularIntensity * specular);
    lightColor = lightColor + (diffuseIntensity * diffuse);

    lightColor = clamp(lightColor, 0.0, 1.0);

    gl_FragColor = vec4(lightColor, 1.0);

}

シャドウ バイアス マトリックスは次のとおりです。

GLfloat shadowBiasMatrix[16] = {
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0};
于 2014-12-17T18:14:55.363 に答える