数日前、この一連のレッスンの最初の記事に出会いました。 残念ながら、最初のレッスンのみが翻訳されており、最も興味深いもの(SSAO、PBR、シャドウ)はすべて先に進んでいます。 このコースは3人(現在4人)によって翻訳されました。読者の一人が残りの部分の翻訳を手伝ってくれることを願っています。 残念ながら、私はプロの翻訳者ではありませんので、テキストに異なる性質のエラーがあるかもしれません。 報告していただければ嬉しいです。 素敵な読書を!
パート2.基本的な照明
パート3. 3Dモデルをダウンロードする
パート4.高度なOpenGL機能
パート5.高度な照明
パート6. PBR
素材
現実の世界では、すべてのオブジェクトは光に対して異なる反応を示します。 鉄のオブジェクトは、通常、たとえば粘土の花瓶よりも強く輝きます。 木製の容器は、スチール製の容器と同じように光に反応しません。 各オブジェクトには異なる反射率があります。 強い散乱なしで光を反射するオブジェクトもあれば、かなり大きな反射半径を持つオブジェクトもあります。 OpenGLでさまざまなタイプのオブジェクトをシミュレートする場合は、各オブジェクトに固有のマテリアルプロパティを決定する必要があります。
前のレッスンでは、光の色を設定して、オブジェクトの外観を決定し、背景と反射コンポーネントを組み合わせました。 オブジェクトを記述して、3つの照明コンポーネントすべてのマテリアルの色を設定できます: ambient 、 diffuse 、 specular 。 その後、オブジェクトの結果の色を詳細に制御します。 次に、3つの色に光沢を追加し、必要なすべてのマテリアルプロパティを取得します。
#version 330 core struct Material { vec3 ambient; vec3 diffuse; vec3 specular; float shininess; }; uniform Material material;
フラグメントシェーダーでは、オブジェクトのマテリアルのプロパティを格納する構造を作成します。 もちろん、から独立した均一変数として保存できますが、これはあまり整理されていません。 まず、構造を定義してから、作成した構造の型を使用してunifrom変数を宣言するだけです。
ご覧のとおり、Phongによってライティングの各コンポーネントの色ベクトルを定義しています。 ambient
ベクトルは、オブジェクトが背景照明の下で反射する色を決定します。 これは通常、オブジェクト自体の色です。 diffuse
ベクトルは、拡散照明下のオブジェクトの色を定義します。 背景と同様に、オブジェクトの目的の色を決定します。 specular
ベクトルはオブジェクトのフレアカラーをshininess
変数はフレアの半径をshininess
ます。
これら4つのコンポーネントを使用して、多くの実際のマテリアルをシミュレートできます。 devernay.free.frの表には、実際に見ることができるいくつかの材料の特性が含まれています。 次の画像は、さまざまな材料を使用したキューブを示しています。
お気づきかもしれませんが、マテリアルのプロパティを正しく選択すると、キューブが完全に変換されます。 もちろん、これは肉眼で見ることができますが、よりリアルにするには、もっと面白い数字が必要です。 チュートリアルの次のセクションでは、複雑な3Dモデルの読み込みについて説明します。
オブジェクトに適した素材の選択は複雑な芸術であり、多くの経験と実験が必要です。 このため、不適切な素材が選択された場合、オブジェクトの視覚的品質が完全に失われることは珍しくありません。
シェーダーにマテリアルシステムを実装してみましょう。
素材のカスタマイズ
シェーダーフラグメントにマテリアル構造を作成したので、これをさらに照明計算で考慮する必要があります。 すべての材料変数は構造に格納されているため、 均一な material
変数を介してそれらにアクセスできます。
void main() { // ambient vec3 ambient = lightColor * material.ambient; // diffuse vec3 norm = normalize(Normal); vec3 lightDir = normalize(lightPos - FragPos); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = lightColor * (diff * material.diffuse); // specular vec3 viewDir = normalize(viewPos - FragPos); vec3 reflectDir = reflect(-lightDir, norm); float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); vec3 specular = lightColor * (spec * material.specular); vec3 result = ambient + diffuse + specular; FragColor = vec4(result, 1.0); }
お気づきかもしれませんが、照明の計算ではmaterial
構造のプロパティを使用します。したがって、今回は結果の色が決定したマテリアルに依存します。 オブジェクトのマテリアルの各コンポーネントには、対応する光のコンポーネントが乗算されます。
適切な均一変数の値を設定することにより、アプリケーション内のオブジェクトのマテリアルをカスタマイズできます 。 ただし、GLSLには値を構造に割り当てる特別な方法はありません。 構造は、単に均一な変数をカプセル化します 。 したがって、それを埋めたい場合は、以前と同じ方法で各均一変数の値を設定する必要がありますが、今回は構造名のプレフィックスを使用します。
lightingShader.setVec3("material.ambient", 1.0f, 0.5f, 0.31f); lightingShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f); lightingShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f); lightingShader.setFloat("material.shininess", 32.0f);
背景と散乱成分をオブジェクト自体の色に設定し、 ハイライトを適度に明るく設定します 。 彼が目立つ必要はありません。 また、 光沢力を32のままにしました 。アプリケーションからオブジェクトのマテリアルに簡単に影響を与えることができます。
プログラムを実行すると、次の結果が生成されます。
今のところあまりリアルに見えませんよね?
光特性
オブジェクトが明るすぎます。 この理由は、背景、拡散、グレアの色があらゆる光源から完全な力で反射されるという事実にあります。 ただし、光源の強度も異なる場合があります。 前のレッスンでは、背景と散乱成分を定数値に置き換えることでこの問題を解決しました。 次に、同様のことを行う必要がありますが、ライトの各コンポーネントに対して行う必要があります。 lightColor
をvec3(1.0)
としてvec3(1.0)
すると、コードは次のようになります。
vec3 ambient = vec3(1.0) * material.ambient; vec3 diffuse = vec3(1.0) * (diff * material.diffuse); vec3 specular = vec3(1.0) * (spec * material.specular);
これらの値( vec3(1.0)
)は光源ごとに個別に変更できます。これはまさに必要なものです。 これで、背景コンポーネントの色はキューブの色に完全に影響しますが、背景コンポーネントは結果の色にそれほど影響しないはずなので、少し小さくします。
vec3 ambient = vec3(0.1) * material.ambient;
同様に、光の拡散およびフレア成分に影響を与えることができます。 これは、前のレッスンで行ったことと密接に関連しています。 ここで、マテリアルの構造に似たものを作成する必要がありますが、今は軽量です。
struct Light { vec3 position; vec3 ambient; vec3 diffuse; vec3 specular; }; uniform Light light;
光源には、 背景光、 拡散光、 フレア光の強度が異なります。 通常、背景の光の強度は非常に低いので、それを過度に支配したくありませんか? 拡散コンポーネントの色は、光源自体の色です。 多くの場合、明るい白です。 ミラーコンポーネントは、通常vec3(1.0)
等しくなります。 軽い位置ベクトルも構造に追加したことに注意してください。
フラグメントシェーダーのライティング計算を更新します。
vec3 ambient = light.ambient * material.ambient; vec3 diffuse = light.diffuse * (diff * material.diffuse); vec3 specular = light.specular * (spec * material.specular);
また、アプリケーション自体で光の強度を設定する必要があります。
lightingShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f); lightingShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f); // darken the light a bit to fit the scene lightingShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
これで、オブジェクトのマテリアルに対する光の影響をモデル化し、前のレッスンの結果と同様の結果を得ました。 ただし、オブジェクトの照明とマテリアルを完全に制御できるようになりました。
オブジェクトの外観を変更するのは比較的簡単です。
異なる色の光
これまで、光源の色は白から黒に変化していたため、オブジェクト自体の色を変更できませんでした(強度のみ)。 ただし、これからはライトのプロパティに簡単にアクセスできるようになるので、このようなクールな結果を得るために時間の経過とともに変更することができます。
お気づきかもしれませんが、光の変化はオブジェクトが反射できる色に影響し(色のレッスンで覚えているでしょう)、これが結果に大きな影響を与えます。
背景を変更し、 sin
とglfwGetTime
介して色を拡散させることにより、時々光を簡単に変えることができます。
glm::vec3 lightColor; lightColor.x = sin(glfwGetTime() * 2.0f); lightColor.y = sin(glfwGetTime() * 0.7f); lightColor.z = sin(glfwGetTime() * 1.3f); glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f); // decrease the influence glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); // low influence lightingShader.setVec3("light.ambient", ambientColor); lightingShader.setVec3("light.diffuse", diffuseColor);
照明とマテリアルを試してみてください。結果にどのように影響するかがわかります。 アプリケーションのソースコードはこちらで確認できます。