2016-04-08 6 views
2

私はプロジェクトで物理的なレンダリング(PBR)を実装しようとしています(アカデミックおよびラーニングの目的で小さなゲームエンジンを開始しました)、材料のメタリックに基づいて鏡面反射と拡散寄与を計算する正しい方法は何か分かりませんおよび粗さ。PBRのスペキュラ寄与を計算する方法は?

レンダリングにサードパーティライブラリ/エンジンを使用していません。すべてOpenGL 3.3で書かれています。

は、今私は(私は以下の完全なコードを入れます)、これを持っている:

// Calculate contribution based on metallicity 
vec3 diffuseColor = baseColor - baseColor * metallic; 
vec3 specularColor = mix(vec3(0.00), baseColor, metallic); 

しかし、私は鏡面用語は何とか粗さによって依存する必要がある印象の下です。私はこれを次のように変更しようと考えていました。

vec3 specularColor = mix(vec3(0.00), baseColor, roughness); 

もう一度、わかりません。それを行う正しい方法は何ですか?私は満足のいく結果を得るまで、正しい方法さえありますか、あるいは私はちょうど '試行錯誤'の方法を使うべきですか?ここで

は、完全なGLSLコードです:

// Calculates specular intensity according to the Cook - Torrance model 
float CalcCookTorSpec(vec3 normal, vec3 lightDir, vec3 viewDir, float roughness, float F0) 
{ 
    // Calculate intermediary values 
    vec3 halfVector = normalize(lightDir + viewDir); 
    float NdotL = max(dot(normal, lightDir), 0.0); 
    float NdotH = max(dot(normal, halfVector), 0.0); 
    float NdotV = max(dot(normal, viewDir), 0.0); // Note: this could also be NdotL, which is the same value 
    float VdotH = max(dot(viewDir, halfVector), 0.0); 

    float specular = 0.0; 
    if(NdotL > 0.0) 
    { 
     float G = GeometricalAttenuation(NdotH, NdotV, VdotH, NdotL); 
     float D = BeckmannDistribution(roughness, NdotH); 
     float F = Fresnel(F0, VdotH); 

     specular = (D * F * G)/(NdotV * NdotL * 4); 
    } 
    return specular; 
} 

vec3 CalcLight(vec3 lightColor, vec3 normal, vec3 lightDir, vec3 viewDir, Material material, float shadowFactor) 
{ 
    // Helper variables 
    vec3 baseColor = material.diffuse; 
    vec3 specColor = material.specular; 
    vec3 emissive = material.emissive; 
    float roughness = material.roughness; 
    float fresnel = material.fresnel; 
    float metallic = material.metallic; 

    // Calculate contribution based on metallicity 
    vec3 diffuseColor = baseColor - baseColor * metallic; 
    vec3 specularColor = mix(vec3(0.00), baseColor, metallic); 

    // Lambertian reflectance 
    float Kd = DiffuseLambert(normal, lightDir); 

    // Specular shading (Cook-Torrance model) 
    float Ks = CalcCookTorSpec(normal, lightDir, viewDir, roughness, fresnel); 

    // Combine results 
    vec3 diffuse = diffuseColor * Kd; 
    vec3 specular = specularColor * Ks; 
    vec3 result = lightColor * (emissive + diffuse + specular); 
    return result * (1.0 - shadowFactor); 
} 

答えて

1

あなたが探しているものを材料のための双方向反射率分布関数(BRDF)です。あなたのコードでは、一般的で効果的な(計算上高価な)BRDFである "Cook - Torranceモデル"を参照しています。 「金属/粗さ」モデルと「鏡面/光沢」モデルの両方からアイデアを得るかもしれないようです。これは大きな話題ですが、この2つを理解することが役立つかもしれません。

とにかく、物理的なシェーディングモデルでは、BRDFはエネルギーを節約する必要があります。したがって、拡散+鏡面反射の寄与は超えてはならない1か:

Kd = 1 - Ks 

あなたのシェーダの物理的な精度はあなたが材料特性に行う計算に依存しているが、あなたのケースであなたに金属製の用語を組み込むことができますこのようなBRDF:あなたが照明を扱うことができますここから

BRDF = (1-m)*diffuse + m*specular 

など

- Metalness /粗シェーダ起源

ディズニーはより現実的なシェーダメソッドを思いついた。 UnrealEngine4はこのモデルを実装しました。今では、用語とテクスチャのワークフローについて多くの混乱があります。

UE4 BRDF code - signup required

Disney's BRDF

Basic Background

+0

うん、まだ、どのように私は、材料の粗さと金属量に基づいてCookTorranceからの鏡面とランバートから拡散貢献をブレンドする必要がありますか? – TheCrafter

+0

私はうまくいけば良い情報を提供するために答えを編集しました。 – adon

+0

私はそれを取得し始めていると思う。 「メタリック/ラフネス」モデルと「スペキュラ/光沢」モデルの両方からアイデアを得るかもしれないようだと言っているときはどういう意味ですか? ? – TheCrafter

関連する問題