2

GLSL シェーダーを使用するプログラムに取り組んでいます。2 つの異なる方法で ADS (アンビエント + ディフューズ + スペキュラー) シェーディングを計算する 2 つの異なる方法をコーディングしました。この仕事を適切に行うために、サブルーチンを使用して、いずれかの方法を使用して ADS シェーディングを計算しました。

フラグメント シェーダー コードの一部を次に示します。

subroutine vec3 LightShadingEffectType(int idx, vec3 normal, vec3 lightDir);
subroutine uniform LightShadingEffectType LightShadingEffect;

subroutine (LightShadingEffectType)
vec3 Basic_ADS_Shading(int idx, vec3 normal, vec3 lightDir)
{
    vec3 reflectDir = reflect(-lightDir, normal);
    vec3 viewDir = normalize(-Position.xyz);

    vec3 Ambient = LightInfos[idx].La * MaterialInfos.Ka;
    vec3 Diffuse = LightInfos[idx].Ld * MaterialInfos.Kd * max(dot(lightDir, normal), 0.0f);
    vec3 Specular = LightInfos[idx].Ls * MaterialInfos.Ks * pow(max(dot(reflectDir, viewDir), 0.0f), MaterialInfos.Shininess);
    vec3 Emissive = MaterialInfos.Ke;

    return (Ambient + Diffuse + Specular + Emissive);
}

subroutine (LightShadingEffectType)
vec3 Phong_ADS_Shading(int idx, vec3 normal, vec3 lightDir)
{
    vec3 v = normalize(vec3(-Position));
    vec3 h = normalize(v + lightDir);

    vec3 Ambient = LightInfos[idx].La * MaterialInfos.Ka;
    vec3 Diffuse = LightInfos[idx].Ld * MaterialInfos.Kd * max(dot(lightDir, normal), 0.0f);
    vec3 Specular = LightInfos[idx].Ls * MaterialInfos.Ks * pow(max(dot(h, normal), 0.0f), MaterialInfos.Shininess);
    vec3 Emissive = MaterialInfos.Ke;

    return (Ambient + Diffuse + Specular + Emissive);
}

そしてC++コード:

type::uint32 basic_ads_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Basic_ADS_Shading");
type::uint32 phong_ads_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Phong_ADS_Shading");

glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &phong_ads_idx);

ここまで表示は正しいです。この場合、2 番目のサブルーチン定義 (Phong_ADS_Shading 呼び出し) を実行することにしました。

しかし、テクスチャを管理するためにプログラムで別のサブルーチン型を宣言したいと考えています (シグネチャは同じではありません)。(同じシェーダー内の) フラグメント シェーダー コードの別の部分を次に示します。

subroutine vec4 TexturedShadingType();
subroutine uniform TexturedShadingType TexturedShading;

subroutine (TexturedShadingType)
vec4 Textured_Shading(void)
{
    vec4 TexColor = texture(Tex1, TexCoords);
    return (vec4(getLightIntensity(), 1.0f) * TexColor);
}

subroutine (TexturedShadingType)
vec4 Untextured_Shading(void)
{
    return (vec4(getLightIntensity(), 1.0f));
}

最後に、私の C++ コードは次のとおりです。

type::uint32 basic_ads_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Basic_ADS_Shading");
type::uint32 phong_ads_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Phong_ADS_Shading");

glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &phong_ads_idx);

type::uint32 textured_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Textured_Shading");
type::uint32 untextured_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Untextured_Shading");

glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &untextured_idx);

各サブルーチン index の値は次のとおりです。

std::cout << phong_idx << ", " << blinn_phong_idx << ", " << textured_idx << ", " << untextured_idx << std::endl;

-> 1, 0, 4294967295, 4294967295

最初の 2 つの値は正しいようですが、他の 2 つの値は正しいようです。

私の問題をよりよく理解するために、フラグメントシェーダーコード全体を次に示します。

#version 400

in vec3 Position;
in vec3 Normal;
in vec2 TexCoords;

layout (location = 0) out vec4 FragColor;

uniform sampler2D Tex1;
uniform int lightCount;

struct PointLight
{
    vec4 Position;
    vec3 La, Ld, Ls;
    float Kc, Kl, Kq;
    vec3 direction;
    float exponent;
    float cutoff;
    int type;
};

struct Material
{
    vec3 Ka, Kd, Ks, Ke;
    float Shininess;
};

uniform PointLight LightInfos[10];
uniform Material MaterialInfos;

subroutine vec3 LightShadingEffectType(int idx, vec3 normal, vec3 lightDir);
subroutine uniform LightShadingEffectType LightShadingEffect;

subroutine (LightShadingEffectType)
vec3 Phong_Shading(int idx, vec3 normal, vec3 lightDir)
{
    vec3 reflectDir = reflect(-lightDir, normal);
    vec3 viewDir = normalize(-Position.xyz);

    vec3 Ambient = LightInfos[idx].La * MaterialInfos.Ka;
    vec3 Diffuse = LightInfos[idx].Ld * MaterialInfos.Kd * max(dot(lightDir, normal), 0.0f);
    vec3 Specular = LightInfos[idx].Ls * MaterialInfos.Ks * pow(max(dot(reflectDir, viewDir), 0.0f), MaterialInfos.Shininess);
    vec3 Emissive = MaterialInfos.Ke;

    return (Ambient + Diffuse + Specular + Emissive);
}

subroutine (LightShadingEffectType)
vec3 Blinn_Phong_Shading(int idx, vec3 normal, vec3 lightDir)
{
    vec3 v = normalize(vec3(-Position));
    vec3 h = normalize(v + lightDir);

    vec3 Ambient = LightInfos[idx].La * MaterialInfos.Ka;
    vec3 Diffuse = LightInfos[idx].Ld * MaterialInfos.Kd * max(dot(lightDir, normal), 0.0f);
    vec3 Specular = LightInfos[idx].Ls * MaterialInfos.Ks * pow(max(dot(h, normal), 0.0f), MaterialInfos.Shininess);
    vec3 Emissive = MaterialInfos.Ke;

    return (Ambient + Diffuse + Specular + Emissive);
}

float getLightAttenuation(vec3 lightDir, PointLight light)
{
    float lightAtt = 0.0f;
    float dist = 0.0f;

    dist = length(lightDir);
    lightAtt = 1.0f / (light.Kc + (light.Kl * dist) + (light.Kq * pow(dist, 2)));
    return (lightAtt);
}

float getSpotFactor(vec3 lightDir, vec3 spotDir, PointLight light)
{
    return (pow(dot(-lightDir, spotDir), light.exponent));
}

vec3 Spot_ADS_Shading(float lightAtt, vec3 tnorm, vec3 lightDirNorm, int idx)
{
    vec3 LightIntensity = vec3(0.0f);
    vec3 spotDirNorm = normalize(LightInfos[idx].direction);
    float angle = acos(dot(-lightDirNorm, spotDirNorm));
    float cutoff = radians(clamp(LightInfos[idx].cutoff, 0.0f, 90.0f));

    if (angle < cutoff)
    {
        float spotFactor = getSpotFactor(lightDirNorm, spotDirNorm, LightInfos[idx]);
        LightIntensity = lightAtt * spotFactor * LightShadingEffect(idx, -tnorm, lightDirNorm);
    }
    else
    {
        LightIntensity = LightShadingEffect(idx, -tnorm, lightDirNorm) * MaterialInfos.Ka;
    }
    return (LightIntensity);
}

vec3 Point_ADS_Shading(float lightAtt, vec3 tnorm, vec3 lightDirNorm, int idx)
{
    return (lightAtt * LightShadingEffect(idx, tnorm, lightDirNorm));
}

vec3 getLightIntensity(void)
{
    vec3 LightIntensity = vec3(0.0f);

    for (int idx = 0; idx < lightCount; idx++)
    {
        vec3 tnorm = (gl_FrontFacing ? -normalize(Normal) : normalize(Normal));
        vec3 lightDir = vec3(LightInfos[idx].Position) - Position;
        vec3 lightDirNorm = normalize(lightDir);
        float lightAtt = getLightAttenuation(lightDir, LightInfos[idx]);

        if (LightInfos[idx].type == 1)
        {
            LightIntensity += Spot_ADS_Shading(lightAtt, tnorm, lightDirNorm, idx);
        }
        else
        {
            LightIntensity += Point_ADS_Shading(lightAtt, -tnorm, lightDirNorm, idx);
        }
    }
    return (LightIntensity);
}

subroutine vec4 TexturedShadingType();
subroutine uniform TexturedShadingType TexturedShading;

subroutine (TexturedShadingType)
vec4 Textured_Shading(void)
{
    vec4 TexColor = texture(Tex1, TexCoords);
    return (vec4(getLightIntensity(), 1.0f) * TexColor);
}

subroutine (TexturedShadingType)
vec4 Untextured_Shading(void)
{
    return (vec4(getLightIntensity(), 1.0f));
}

void main(void)
{
    FragColor = TexturedShading();
}

問題は、ジオメトリが黒でレンダリングされることです。2 つの均一なサブルーチンの間に矛盾があると思います。道に迷いました。誰でも私を助けることができますか?

4

1 に答える 1

6

glUniformSubroutines1 つのシェーダー ステージだけでなく、すべてのサブルーチンを設定します。

OpenGL がプログラムをリンクすると、すべてのサブルーチン ユニフォームが取得され、それらから配列が作成されます。各ユニフォームには、この配列へのインデックスがあります。配列内の特定のサブルーチンuniformのインデックスが何であるかを知りたい場合は、 を呼び出す必要がありますglGetSubroutineIndex。あるいは、4.3/ARB_explicit_uniform_locations (確かに AMD はかなり遅い) があると仮定すると、これを直接layout(location = #)layout qualifierで設定できます。そうすれば、クエリを実行する必要はありません。

各サブルーチン ユニフォームが参照するインデックスがわかれば、 を1 回呼び出すだけで、ステージのすべてのサブルーチン ユニフォームを設定できますglUniformSubroutines。短い配列を作成します。配列内の各インデックスには、使用するサブルーチン関数のインデックスが含まれます。


しかし、4 つのサブルーチンから毎回 2 つのサブルーチンだけを選択したいと考えています。

サブルーチンは 4 つあるかもしれませんが、サブルーチン一様変数は2 つしかありません。これらのユニフォームは、呼び出されるシェーダーの特定の関数を設定するユーザーを表します。

さらに、どちらのユニフォームも使用するタイプが異なるため、4 つのサブルーチンから選択することはできません。各サブルーチン ユニフォームは、その特定のタイプで使用される特定のサブルーチンの中からのみ選択できます。これは、サブルーチン関数を で宣言するときに定義されますsubroutine(SubroutineType)。各タイプには、一緒に使用できる独自の関数セットがあります。したがって、各ユニフォームは、そのユニフォーム用に宣言されたサブルーチン型に設定された特定の関数の中からのみ選択できます。

したがって、4 つのサブルーチンから選択することはできません。各ユニフォームは、サブルーチン タイプごとに設定した機能の中からのみ選択できます。各ユニフォームは、サブルーチン型を宣言した 2 つの関数からのみ選択できます。

glUniformSubroutinesuiv の呼び出しが 1 つしかない場合、どうすればそれらを選択できますか?

配列を渡すことによって。3 番目のパラメーターがpointerであり、2 番目のパラメーターが配列内のエントリ数であるのには理由があります

フラグメント シェーダーには、2 つのサブルーチンの均一な値があります。したがって、配列には 2 つの要素があり、それぞれが特定のサブルーチン ユニフォームのサブルーチン インデックスを表します。配列を作成し、両方のサブルーチン インデックスをその配列に設定し、その配列を関数に渡すことで、両方を選択します。

2 つの均一なサブルーチンの間に矛盾があると思います。

いいえ、(前述の配列の問題以外に) 問題は、他のサブルーチンを使用していないことです。サブルーチンのユニフォームは、通常のユニフォームとはほとんどの点で異なりますが、この点では通常のユニフォームに似ています。それらを使用しない場合、ドライバーはそれら (およびそれらが依存するもの) を最適化できます。

TexturedShadingフラグメント シェーダーはおそらくどこにも使用されていません。また、uniform を宣言するサブルーチン uniform は他にないためTexturedShadingType、コンパイラは、これら 2 つの関数がサブルーチンとして使用されないことを認識します。したがって、それらを最適化します。したがって、それらに対して得られるインデックスは ですGL_INVALID_INDEX

于 2013-08-29T00:20:45.860 に答える