マイクロファセットBRDFモデルを実装しようとしています。セバスチャンラガルドのスライドを読んでいます。コードに数式を実装しましたが、結果の画像が間違っていると思います。
黄色は素材のベースカラーです。鏡面色は正しく見えるように赤です。
私のコード:
// Fragment Shader
#version 330 core
in vec3 Position;
in vec2 TexCoord0;
in vec3 Normal;
in vec3 Tangent;
out vec4 FinalColor;
uniform vec3 uCameraPosition; // init value: vec3(0, 0, 5)
#define PI 3.1415926f
#define EPSILON 10e-5f
#define saturate(value) clamp(value, 0.0f, 1.0f);
float BRDF_Lambert(float NdotL)
{
return NdotL;
}
// Got these BRDF formulas Moving Frostbite to PBR slide by Sebastien Lagarde & Charles de Rousiers
// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr_v2.pdf
float BRDF_D_GGX(float NdotH, float Roughness)
{
float Roughness2 = Roughness * Roughness;
float f = (NdotH * Roughness2 - NdotH) * NdotH + 1.0f;
return Roughness2 / (f * f + EPSILON);
}
float BRDF_F_FresnelSchlick(float LdotH, float F0)
{
float f = F0 + (1.0f - F0) * pow((1.0f - LdotH), 5);
return f;
}
float BRDF_G_SmithGGXCorrelated(float NdotL, float NdotV, float Roughness)
{
float Roughness2 = Roughness * Roughness;
float GV = NdotL * sqrt((-NdotV * Roughness2 + NdotV) * NdotV + Roughness2);
float GL = NdotV * sqrt((-NdotL * Roughness2 + NdotL) * NdotL + Roughness2);
return 0.5f / (GV + GL + EPSILON);
}
float BRDF_Specular(float NdotV, float NdotL, float NdotH, float LdotH, float Roughness, float F0)
{
float D = BRDF_D_GGX(NdotH, Roughness);
float F = BRDF_F_FresnelSchlick(LdotH, F0);
float G = BRDF_G_SmithGGXCorrelated(NdotL, NdotV, Roughness);
return (D * F * G) / PI;
}
void main()
{
FinalColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
vec4 BaseColor = vec4(1.0f, 1.0f, 0.0f, 1.0f);
vec4 SpecularColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);
vec3 LightDirection = normalize(vec3(0, 4, 4));
vec3 ViewDirection = normalize(Position - uCameraPosition);
vec3 HalfVector = normalize(ViewDirection + LightDirection);
float Roughness = 0.9f; // [0.04 - 0.1f] -> Dielectric, [0.7, 1.0f] -> Metallic
float RefractiveIndex = 0.27049f; // RI for Gold materials. I got this from http://refractiveindex.info/
float F0 = pow(((1.0f - RefractiveIndex) / (1.0f + RefractiveIndex)), 2);
float NdotL = saturate(dot(LightDirection, Normal));
float NdotV = abs(dot(ViewDirection, Normal)) + EPSILON; // Avoid artifact - Ref: SIGGRAPH14 - Moving Frosbite to PBR
float LdotH = saturate(dot(LightDirection, HalfVector));
float NdotH = saturate(dot(Normal, HalfVector));
float DiffuseFactor = BRDF_Lambert(NdotL);
float SpecularFactor = BRDF_Specular(NdotV, NdotL, NdotH, LdotH, Roughness, F0);
FinalColor = BaseColor * DiffuseFactor + SpecularColor * SpecularFactor;
}
編集
1
私はコードをあまり詳しく調べていませんが、画像は問題ないようです。フレネル効果は赤いリングとして表示されます。粗さが非常に高い(0.9)ので、画像の残りの部分がほとんど黄色(つまり、ほとんど拡散している)であることは理にかなっています。粗さを下げると、赤い鏡面ハイライトが表示される場合があります
—
RichieSams
@RichieSamsさまざまな粗さの値の新しい画像を追加しましたが、まだ赤い光沢のある鏡面ハイライトを見ることができません。
—
hmkum
2番目と3番目の画像は、一般に(黄色の拡散領域で)元の画像よりも赤が少ないように見えます。黄色の領域に少し赤を加えると、同じような色(黄色ではなくオレンジ色から黄色)が残るため、これはそれほど明白ではありません。黄色を大幅に減らすと、赤い分布の詳細がわかりますか?黄色を完全に省略すると、問題の原因を特定するのに役立つ場合があります。
—
trichoplax
@trichoplax私は黄色を減らしましたが、ここでも赤い鏡面反射を見る方法はありません。赤いリング(フレネル)の効果だけが見えます。粗さの値を何に設定してもかまいませんが、ポイントに焦点を当てた鏡面反射効果がわかりません。
—
hmkum
最初に法線ベクトルを正規化してから使用し、次にviewDirectionは位置からカメラへの出力ベクトルです:uCameraPosition-位置。
—
xpicox 2015