OpenGLを学びます。 パート2.4。 -テクスチャマップ

画像


前に、光に対して異なる応答をするために、各オブジェクトが固有のマテリアルを持つ可能性について説明しました。 これは、各オブジェクトをシーン内の他のオブジェクトと比較してユニークな外観にするのに最適です。 しかし、これでもオブジェクトの外観をカスタマイズする際の柔軟性はあまりありません。





テクスチャマップ


前のレッスンでは、オブジェクト全体のマテリアルを定義しましたが、現実の世界では、オブジェクトは通常1つではなく複数のマテリアルで構成されています。 車を想像してみてください。その外側のケーシングは素晴らしいです。 ウィンドウは環境を部分的に反映しています。 車にはつや消しのタイヤも付いていて、リムもきらきらしています(車をよく洗えばスパークリングします)。 そのため、各オブジェクトには、パーツごとに異なるマテリアルプロパティがあります。


そのため、前のレッスンのマテリアルシステムは、多少複雑なオブジェクトには適していません。そのため、 拡散マップとグレアマップを導入して拡張する必要があります。 これにより、拡散(およびほぼ常に同じであるため間接的に背景)とオブジェクトのフレア成分に、より高い精度で影響を与えることができます。


拡散カード


必要なのは、オブジェクトの各フラグメントに拡散色を設定する方法だけです。 フラグメントの位置に基づいて色の値に影響を与えるものは何ですか?


覚えてる? これらは、以前のレッスンの1つで集中的に議論したテクスチャです。 照明マップは、同じ原理の単なる別の名前です。オブジェクトの表面に印刷された画像を使用して、各フラグメントのカラーサンプルを作成できます。 テクスチャイメージはオブジェクトのすべての拡散色を表すため、照明のあるシーンでは、これは通常拡散マップと呼ばれます (通常は3Dアーティストによって呼び出されます)。


拡散マップを示すために、鉄のフレームが付い木製のコンテナの画像を使用します



シェーダーで拡散マップを使用することは、前のレッスンのいずれかでテクスチャを使用することに非常に似ています。 ただし、以前に定義し拡散色のvec3 ベクトルを拡散sampler2D カードに sampler2D ます


sampler2Dは、いわゆる不透明データ型であることにsampler2Dください。 つまり、このタイプのインスタンスを作成することはできず、 均一としてのみ定義できます。 この型を均一で はなく (たとえば、関数パラメーターとして)使用しようとすると、GLSLは奇妙なエラーを出力します。 この規則は、 不透明(OPAQUE)型を含む構造にも適用されます。



ほとんどの場合、拡散色と一致するため、 ambientベクトルも削除しました。そのため、個別に保存する必要はありません。


 struct Material { sampler2D diffuse; vec3 specular; float shininess; }; ... in vec2 TexCoords; 

頑固で、背景色を拡散に設定したい場合は、 ambientベクトルをそのままにしておくことができます。 ただし、背景色はオブジェクト全体で 同じです。 オブジェクトのフラグメントごとに異なる背景色の値を取得するには、背景色の値に個別のテクスチャを使用する必要があります。



フラグメントシェーダーにはテクスチャ座標が再び必要なので、追加の入力変数を宣言することに注意してください。 次に、テクスチャから選択を行い、フラグメントの拡散カラー値を抽出します。


 vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); 

また、マテリアルの背景色を拡散と同じに設定することを忘れないでください:


 vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); 

拡散マップを使用するために必要なのはこれだけです。 お気づきかもしれませんが、これは目新しいことではありませんが、視覚的な品質の印象的な向上をもたらします。 これを機能させるには、頂点データにテクスチャ座標を追加し、それらをフラグメントシェーダーに頂点属性として転送し、テクスチャをロードして、対応するテクスチャブロックに関連付ける必要があります。


更新された頂点データはこちらにあります 。 頂点の位置、法線ベクトル、キューブの各頂点のテクスチャ座標が含まれるようになりました。 頂点シェーダーを更新して、テクスチャー座標を頂点属性として取得し、フラグメントシェーダーに渡すことができるようにします。


 #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; layout (location = 2) in vec2 aTexCoords; ... out vec2 TexCoords; void main() { ... TexCoords = aTexCoords; } 

両方のVAOの頂点属性を更新してください( 翻訳者注:テクスチャキューブのVAOとランプキューブのVAOを意味します )。新しい頂点データと一致し、コンテナイメージをテクスチャにロードします。 コンテナを描画する前に、優先テクスチャブロックを変数material.diffuseに割り当て、コンテナテクスチャをそれに関連付ける必要があります。


 lightingShader.setInt("material.diffuse", 0); ... glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, diffuseMap); 

拡散マップを使用して、再び詳細が大幅に増加しました。今、照明を追加すると、コンテナが本当に輝いたようになりました(文字通り)。 おそらく次のようになります。



アプリケーションの完全なソースコードはこちらで見つけることができます。


フレアカード


オブジェクトはコンテナであり、ほとんどの部分が木材で構成されているため、ハイライトが少し奇妙に見えることに気づいたでしょう。 そして、私たちが知っているように、木はそのような鏡の輝きを与えません。 Material構造のspecularベクトルをvec3(0.0)に設定することでこれを修正できますが、これはコンテナーの鉄フレームもグレアを停止することを意味し、金属少なくとも少し輝きます。 繰り返しますが、オブジェクトのどの部分をどの力で照らすかを制御したいと思います。 この問題は、拡散マップの説明と非常によく似ています。 偶然? そうは思いません


テクスチャマップを再び使用できるようになりましたが、今は鏡面反射ハイライトのみです。 これは、オブジェクトの各部分の輝きを決定する白黒(または必要に応じて色)のテクスチャを作成する必要があることを意味します。 グレアカードの例を次に示します



光沢の強さは、画像内の各ピクセルの明るさによって決まります。 このようなマップの各ピクセルは、たとえば、黒がvec3(0.0) 、灰色がvec3(0.5)カラーベクトルとして表すことができます。 次に、フラグメントシェーダーで、対応するカラー値を選択し、フレアカラーの強度で乗算します。 したがって、ピクセルが白くなるほど、乗算の結果が得られ、その結果、オブジェクトの断片上のフレアの明るさが得られます。


コンテナは主に木材で構成されており、木材はまぶしさを与えない素材であるため、テクスチャの「木製」部分全体が黒く塗りつぶされています。 黒い部分まったく光りません。 コンテナの鉄骨フレームの表面には、鏡面光沢のさまざまな力があります。鉄骨自体は非常に強いグレアを与えますが、亀裂や擦り傷は与えません。


技術的には、ツリーには鏡面反射もありますが、明るさははるかに低くなりますが(光はより強く散乱します)、教育目的のために、ツリーは鏡面反射光に反応しないふりをします。



PhotoshopGimpなどのツールを使用すると、拡散テクスチャをグレアに変えるのは非常に簡単です。 いくつかの部分を切り取り、画像を白黒にし、輝度/コントラストを上げるだけで十分です。


グレアサンプリング


鏡像マップは最も一般的なテクスチャであるため、そのロードコードは拡散マップのロードに非常に似ています。 画像を正しくロードし、テクスチャオブジェクトを生成したことを確認してください。 同じフラグメントシェーダーで新しいテクスチャを使用しているため、グレアマップに異なるテクスチャブロックを使用する必要があります。 レンダリングする前に、このテクスチャを対応するテクスチャブロックにバインドしましょう。


 lightingShader.setInt("material.specular", 1); ... glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, specularMap); 

次に、フラグメントシェーダーのマテリアルプロパティを更新して、反射コンポーネントがsampler2Dではなくvec3として受け入れられるようにしvec3


 struct Material { sampler2D diffuse; sampler2D specular; float shininess; }; 

最後に、フレアマップをサンプリングして、オブジェクトの各フラグメントに対応するフレア強度を取得する必要があります。


 vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); FragColor = vec4(ambient + diffuse + specular, 1.0); 

グレアマップを使用して、オブジェクトのどの部分が鏡面反射グレアを生成するかを非常に正確に判断し、対応する強度を確立できます。 したがって、グレアマップにより、拡散マップをさらに制御できます。


まぶしさマップで色を使用して、まぶしさの強度だけでなく色も決定できます。 ただし、実際には、グレアの色は大部分(およびほとんどの場合完全に)光源に依存するため、カラーグレアマップを使用しても現実的な結果は得られません(そのため、これらの画像は通常白黒です-グレアの強度にのみ関心があります)。



アプリケーションを実行すると、コンテナの素材が鉄のフレームを備えた木製のコンテナに非常に似ていることがわかります。



アプリケーションの完全なソースコードはこちらで見つけることができます。


拡散マップとフレアマップを使用して、比較的単純なオブジェクトに膨大な量の詳細を追加できます。 法線/標高マップや反射マップなど、他のテクスチャマップを使用してさらに詳細を追加できますが、次のチュートリアルのために保存します。 コンテナを友人や家族に見せ、いつか私たちのコンテナが今よりもさらに魅力的になることを忘れないでください!


演習


Source: https://habr.com/ru/post/J337550/


All Articles