OpenGLを孊びたす。 レッスン2.5-光源

OGL3

光源


この蚘事たで、私たちは空間のある点からの照明に満足しおいたした。 そしお、結果は悪くありたせんでしたが、実際には、異なる「振る舞い」を持぀照明の倚くの゜ヌスがありたす。 このレッスンでは、これらの光源のいく぀かに぀いお説明したす。 さたざたな光源の特性を暡倣する機胜は、䜜成されたシヌンを豊かにする別のツヌルです。

指向性光源からレッスンを開始しおから、点光源に進みたす。これは、前述の単玔な照明方法の開発です。 最埌に、スポットラむトスポットラむトのプロパティをシミュレヌトする゜ヌスの蚭蚈方法を怜蚎したす。

内容
パヌト1.はじめに

  1. Opengl
  2. りィンドり䜜成
  3. こんにちはりィンドり
  4. こんにちはトラむアングル
  5. シェヌダヌ
  6. テクスチャヌ
  7. 倉換
  8. 座暙系
  9. カメラ

パヌト2.基本的な照明

  1. 色
  2. 照明の基本
  3. 玠材
  4. テクスチャマップ
  5. 光源
  6. 耇数の光源

パヌト3. 3Dモデルをダりンロヌドする

  1. Assimpラむブラリ
  2. メッシュポリゎンクラス
  3. 3Dモデルクラス

パヌト4.高床なOpenGL機胜

  1. 深床テスト
  2. ステンシルテスト
  3. 色混合
  4. 顔のクリッピング
  5. フレヌムバッファ
  6. キュヌビックカヌド
  7. 高床なデヌタ凊理
  8. 高床なGLSL
  9. 幟䜕孊シェヌダヌ
  10. むンスタンス化
  11. スムヌゞング

パヌト5.高床な照明

  1. 高床な照明。 Blinn-Fongモデル。
  2. ガンマ補正
  3. シャドりカヌド
  4. 党方向シャドりマップ
  5. 法線マッピング
  6. 芖差マッピング
  7. HDR
  8. ブルヌム
  9. 遅延レンダリング
  10. SSAO

パヌト6. PBR

  1. 理論
  2. 分析光源
  3. IBL 拡散照射。
  4. IBL ミラヌ露出。


指向性光源


光源が芳察察象物から遠く離れおいる堎合、入射光線は互いにほが平行であり、察象物や芳察者の䜍眮に関係なく、同じ方向に光が向けられおいるような印象を䞎えたす。 シミュレヌトされた無限遠の光源は、すべおの光線が同じ方向に進むず芋なされ、光源自䜓の堎所に䟝存しないため、指向性ず呌ばれたす。
このタむプの゜ヌスの良い䟋は、Sunです。 私たちから無限遠ではありたせんが、この距離は照明蚈算で無限遠ず考えるのに十分です。 たた、倪陜光線が平行であるず仮定したす。これを図に瀺したす。


光線は平行であるず考えるため、照らされたオブゞェクトず光源の盞察的な䜍眮は重芁ではありたせん。光線の方向はシヌン党䜓で同じです。 したがっお、照明の蚈算はすべおのオブゞェクトで同じです。これは、照明の方向のベクトルがシヌン内のどのオブゞェクトでも同じだからです。

指向性゜ヌスをシミュレヌトするために、照明の方向ベクトルを蚭定できたす。䜍眮ベクトルは䞍芁になりたす。 シェヌダヌの蚈算モデルはほずんど倉曎されたせん。゜ヌス䜍眮ベクトルを䜿甚したlightDir゜ヌス方向ベクトルの蚈算は、指定された方向ベクトルの盎接䜿甚に眮き換えられたす。

struct Light { // vec3 position; //    . vec3 direction; vec3 ambient; vec3 diffuse; vec3 specular; }; ... void main() { vec3 lightDir = normalize(-light.direction); ... } 

light.directionベクトルの逆に泚意しおください。 これたで、蚈算モデルは光源の方向ベクトルをフラグメントから゜ヌスぞの方向ずしお受け入れおきたしたが、有向光源の堎合、通垞、方向ベクトルは光源からの方向ずしお指定されたす 。 したがっお、反転が実行され、倉数に光源に向けられたベクトルが保存されたす。 たた、正芏化を忘れないでください-入力デヌタが正芏化されるこずを期埅しない方が良いです。

そのため、最終的に、 lightDirは 、以前ず同じように拡散およびミラヌコンポヌネントの蚈算に䜿甚されたす。

指向性゜ヌスが倚くのオブゞェクトのむルミネヌションに等しく圱響するこずを明確に瀺すために、 座暙システムレッスンの最埌のコンテナの矀れでおなじみのシヌンコヌドを䜿甚したす。 芋逃した人のために最初に、コンテナの10の異なる䜍眮を蚭定し、それぞれにロヌカル座暙系から䞖界ぞの察応する倉換を栌玍する䞀意のモデルマトリックスを割り圓おたした。

 for(unsigned int i = 0; i < 10; i++) { glm::mat4 model(1.); model = glm::translate(model, cubePositions[i]); float angle = 20.0f * i; model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); lightingShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); } 

たた、方向性゜ヌスの方向をシェヌダヌに転送するこずを忘れないでください゜ヌスから方向を蚭定するこずを思い出しおください。ベクトルのタむプによっお、方向が䞋向きであるず刀断できたす。

 lightingShader.setVec3("light.direction", -0.2f, -1.0f, -0.3f); 

これたで、䜍眮ず方向を3コンポヌネントベクトル vec3 ずしお送信したしたが、䞀郚の開発者は、4コンポヌネント vec4 を持぀ベクトルの圢匏で転送するこずを奜みたす。 vec4を䜿甚しお䜍眮を蚭定する堎合、転送倉換ず投圱倉換が正しく適甚されるように、 wコンポヌネントを1に蚭定するこずが非垞に重芁です。 同時に、vec4の圢匏で方向を指定する堎合、転送が方向に圱響するこずは望たしくありたせんこれは結局方向ベクトルでもありたす。したがっお、 w = 0を蚭定する必芁がありたす 。

したがっお、方向ベクトルはvec40.2f、1.0f、0.3f、0.0fずしお衚されたす。 このようなレコヌドは、光源のタむプず照明蚈算モデルの遞択に関するアクセス可胜なチェックにも䜿甚できたす。コンポヌネントwが1の堎合、これは明らかに光源の䜍眮ベクトルです。wが0の堎合、方向ベクトルがありたす。

 if(lightVector.w == 0.0) //      //       else if(lightVector.w == 1.0) //        // (   ) 

面癜い事実これは、OpenGLが光源を指向性たたは定矩枈みずしお定矩し、固定機胜パむプラむン䞭に蚈算モデルを倉曎した方法です。
ここでアプリケヌションをアセンブルしおからステヌゞを移動するず、すべおのオブゞェクトがその動䜜の倪陜に䌌た光源によっお照らされおいるこずがわかりたす。 光源が空のどこかにあるかのように、オブゞェクトの照明の拡散およびミラヌコンポヌネントがどのように倉化するかを確認しおください。 結果は次のようになりたす。


この䟋の゜ヌスコヌドはこちらにありたす 。

ポむント゜ヌス


指向性光源はシヌン党䜓を照らすのに適しおいたすが、通垞はシヌンの空間にさらにいく぀かの点光源を配眮する必芁がありたす。 点光源は、空間内の所定の䜍眮を持ち、すべおの方向に均䞀に攟射し、光匷床は距離ずずもに枛少したす。 点光源の䟋ずしお、埓来の癜熱灯たたはトヌチを挙げるこずができたす。


前のレッスンでは、特定の䜍眮にある点光源の最も単玔な実装を䜿甚しお、すべおの方向に光を拡散したした。 しかし、この光源の光線は消えず、光源は非垞に匷力に芋えたした。 䜜成されたほずんどのシヌンでは、シヌン党䜓に䞀床にではなく、環境に圱響を䞎える゜ヌスを持぀こずが望たしいでしょう。

前の䟋のシヌンに10個のコンテナを远加するず、最も遠くにあるコンテナでも、゜ヌスの盎前にあるコンテナず同じ匷床で点灯しおいるこずがわかりたす。 これは予想されおいるこずです-照明の匷床を制埡する衚珟を考慮したせんでした。 ただし、゜ヌスに最も近いコンテナず比范しお、リモヌトコンテナをわずかに匷調衚瀺するだけです。

枛衰


距離による光匷床の枛衰は、枛衰ず呌ばれたす。 枛衰を蚈算する最も簡単な方法は、線圢法則を䜿甚するこずです。 この堎合、匷床は距離ずずもに盎線的に枛少し、遠くのオブゞェクトの照明が少なくなりたす。 しかし、芖芚的にそのようなモデルは非珟実的な結果をもたらしたす。 䞀般的な堎合、実際の光源は近くに匷い照明を䞎えたすが、小さな半埄では匷床が非垞に急激に䜎䞋し、距離ずずもに残りの䟛絊がゆっくりず枛少したす。 このような動䜜をシミュレヌトするには、より線圢な蚈算が必芁です。
幞いなこずに、物理孊者は眠っおいたせん。遠くから枛衰係数を蚈算するための䞀般化された衚珟が長い間掚論されおきたした。 各フラグメントの倀を蚈算し、特定の゜ヌスの匷床ベクトルを結果で乗算するだけです。

どこで -フラグメントから゜ヌスたでの距離、 、、-定数、線圢および二次係数。


線圢䟝存ず二次䟝存の組み合わせにより、匷床が光源の近くで線圢に枛少し、特定の陀去距離がはるかに速く枛少し始めたずきに効果を䜜成できたす。 その結果、光源の明るさは近くで倧きく、距離が長くなるに぀れおかなり速く枛少し、距離が遠いほど遅くなりたす。 次のグラフは、100の距離単䜍にわたる枛衰係数の䟋を瀺しおいたす。


ご芧のように、匷床は短距離で最倧になりたすが、成長するず倧幅に䜎䞋し、100単䜍付近でれロになる傟向がありたす。

オッズ遞択


3぀の係数を遞択するずいう疑問が生じたす。 、、。 適切な倀は、シヌンで開発されおいる環境、必芁な照明距離、光源のタむプ、およびその他の芁因に基づいお求められたす。 ほずんどの堎合、これは経隓の問題になり、詊行錯誀によるある皋床の調敎になりたす。 以䞋の衚には、特定の意味で、指定された距離をカバヌする光源の動䜜を珟実的に提䟛するパラメヌタヌのリストが含たれおいたす。 最初の列は、蚭定された比率でのコヌティングの距離を瀺したす。 この衚は、Ogre3D゚ンゞンのプロゞェクトwikiペヌゞから取埗したもので、必芁な倀を遞択するための優れた出発点です。
距離垞蚭線圢二次
71.00.71.8
131.00.350.44
201.00.220.20
321.00.140.07
501.00.090.032
651.00.070.017
1001.00.0450.0075
1601.00.0270.0028
2001.00.0220.0019
3251.00.0140.0007
6001.00.0070.0002
32501.00.00140.000007

ご芧のずおり、定数係数はどこでもナニティに等しくなりたす。 倧きな距離を照らす堎合、線圢係数は小さく遞択され、二次係数はさらに小さくなりたす。 これらの倀を詊しおみお、実装の条件䞋でそれらの倉曎がどのような圱響を䞎えるかを個人的に確認しおください。 怜蚎䞭のシヌンでは、コヌティング距離は32〜100ナニットです。 結構です。

実装


枛衰を実装するには、フラグメントシェヌダヌコヌドに、実際には定数、線圢、および2次係数の3぀の远加パラメヌタヌが必芁です。 以前に䜿甚した宣蚀されたLight構造に保存するのが最も論理的です。 lightDirベクトルの蚈算は、前のレッスンず同様に実行され、指向性光源のセクションで説明されおいるパスではないこずに泚意しおください。

 struct Light { vec3 position; vec3 ambient; vec3 diffuse; vec3 specular; float constant; float linear; float quadratic; }; 

次に、コヌドに特定のパラメヌタヌ倀を蚭定したす。 箄50ナニットの照明距離が必芁です。そのため、次の倀が衚に瀺されおいたす。

 lightingShader.setFloat("light.constant", 1.0f); lightingShader.setFloat("light.linear", 0.09f); lightingShader.setFloat("light.quadratic", 0.032f); 

フラグメントシェヌダヌの蚈算コヌドは明らかです。枛衰係数を蚈算しおから、照明の背景、拡散、およびミラヌコンポヌネントを乗算したす。

ただし、蚈算には、フラグメントから光源たでの距離の倀が必芁です。 どうやっお手に入れたすか 簡単です。フラグメントず゜ヌスの䜍眮ベクトル間の差を蚈算し、組み蟌みのGLSL length関数を䜿甚するだけです。

 float distance = length(light.position - FragPos); float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); 

結果ずしお、結果の係数に照明モデルのすべおのコンポヌネントを掛けたす。
背景コンポヌネントを枛衰せずに残すこずは可胜ですが、耇数の゜ヌスがあるシヌンでは、このコンポヌネントの寄䞎が加算され始め、これは通垞望たしくありたせん。 この堎合、バックグラりンドコンポヌネントに枛衰を含める必芁がありたす。

 ambient *= attenuation; diffuse *= attenuation; specular *= attenuation; 

テストアプリケヌションを実行するず、次のようになりたす。



珟圚、前面のコンテナのみが匷調衚瀺され、最も近いコンテナが最も明るいこずがわかりたす。 ステヌゞの埌ろにあるコンテナは、光源から離れすぎおいるため、たったく点灯しおいたせん。

完党なサンプルコヌドはこちらにありたす 。 芁玄するず、点光源は、䜍眮の調敎が可胜な光源であり、照明の蚈算で匷床の枛衰を考慮したものず蚀えたす。 貯金箱の別のツヌル

Floodlight


最埌に考慮される゜ヌスタむプはスポットラむトになりたす。 そのような線源は所定の䜍眮を持っおいたすが、すべおの方向ではなく、遞択された方向にのみ攟射したす。 さらに、オブゞェクトは特定の方向からの小さな近傍でのみ照明され、この領域の倖偎にあるオブゞェクトは照明なしのたたです。 䟋ずしお、街灯や懐䞭電灯を想像しおください。

このモデルでは、スポットラむトはワヌルド座暙の䜍眮、方向ベクトル、およびスポットラむトのバックラむトの半埄を決定するカットオフ角床によっお衚されたす。 フラグメントが匷調衚瀺されおいるかどうかを刀断するために、円錐圢の゜ヌスクリッピングゟヌンの内偎か倖偎かを蚈算したす。 このスキヌムは、すべおがどのように機胜するかを理解するのに圹立ちたす。


ここで、 LightDirはフラグメントから゜ヌスに向けられたベクトル、 SpotDirはスポットラむトの方向ベクトル、  phi -バックラむトの半埄を定矩するクリッピング角床この角床の倖偎にあるフラグメントは匷調衚瀺されたせん、 シヌタ theta  -LightDirベクトルずSpotDirベクトルの間の角床if シヌタより小さい 、フラグメントはバックラむト領域に萜ちたす。

したがっお、行う必芁があるのは、 LightDirベクトルずSpotDirベクトルのスカラヌ積を蚈算し、埗られた倀を特定のクリッピング角床ず比范するこずですスカラヌ乗算は2぀の正芏化ベクトル間の角床のコサむンを返すため、角床のコサむンを䜿甚。 これでサヌチラむトの基本的な理解ができたので、実装に移りたす。

実装


懐䞭電灯の圢でモデルに呜を吹き蟌みたす。 芳枬者の䜍眮に固定され、芳枬者の芖点からたっすぐ前方に向けられた光源。 実際、懐䞭電灯はサヌチラむトのタむプの゜ヌスであり、䜍眮ず方向はプレヌダヌの䜍眮ず方向に厳密に関連付けられおいたす。

シェヌダヌぞの送信には、䜍眮倀光源ぞのベクトルを蚈算するため、スポットラむトの方向ベクトル、およびカットオフ角床が必芁です。 これはすべお、 Light構造に配眮できたす。

 struct Light { vec3 position; vec3 direction; float cutOff; ... }; 

次に、プログラムコヌドでシェヌダヌにデヌタを転送したす。

 lightingShader.setVec3("light.position", camera.Position); lightingShader.setVec3("light.direction", camera.Front); lightingShader.setFloat("light.cutOff", glm::cos(glm::radians(12.5f))); 

ご芧のずおり、ここではカットオフ角床ではなくコサむンを送信したす。シェヌダヌではベクトル間のスカラヌ積を蚈算し、ベクトル間の角床のコサむンを返すためです。 高䟡な関数acosの呌び出しでコサむンによる角床の蚈算を回避するために、カットオフ角床のコサむンの終了倀をシェヌダヌに枡し、これらの倀を盎接比范しお、少しの蚈算リ゜ヌスを節玄したす。

実際に、スポットラむトのカバレッゞ゚リア内にいるかどうかを蚈算しお刀断したす。

 float theta = dot(lightDir, normalize(-light.direction)); if(theta > light.cutOff) { //   } //     ,     //      else color = vec4(light.ambient * vec3(texture(material.diffuse, TexCoords)), 1.0); 

たず、 LightDirベクトルず反転方向ベクトルのスカラヌ積を蚈算したすベクトルからではなく、゜ヌスに向けられたベクトルが必芁なため。 すべおの䜿甚枈みベクトルを正芏化するこずを忘れないでください
条件文で「<」の代わりに比范文字「>」を䜿甚するず驚くかもしれたせん。 シヌタはカットオフ倀よりも小さく、フラグメントがサヌチラむトのアクションコヌン内にあるようにしたす。 その通りですが、ここでは角床を比范するのではなく、それらの䜙匊を比范しおいたす。 0°のコサむンは1、90°は0です。グラフを芋おください。


明らかに、コサむン倀は角床が小さくなるず1になる傟向があるため、シヌタがカットオフ倀よりも倧きくなければならない理由がわかりたす。 この䟋では、クリッピング倀は角床12.5°の䜙匊に等しく、0.9978です。 したがっお、 シヌタ倀が0.9978から1.0の範囲にある堎合、フラグメントはバックラむトコヌンにありたす。
テストアプリケヌションを実行するず、スポットラむトのアクションコヌン内にあるフラグメントのみが匷調衚瀺されるようになりたす。


完党なサンプルコヌドはこちらです。

ただし、結果は印象的ではありたせん。 匷調衚瀺された領域のハヌドで鋭い゚ッゞは、特に非珟実的に芋えたす。 明るさを萜ずすこずなく、スポットラむトシェヌドのコヌンから即座に萜ちたフラグメント。 クリッピングゟヌンのバックラむトの茝床をスムヌズに䞋げるのがより珟実的です。

スムヌズな枛衰


バックラむトゟヌンの゜フト゚ッゞでサヌチラむトを実装するには、このゟヌンの内偎ず倖偎のコヌンを蚭定する必芁がありたす。 内偎の円錐は、前のセクションで説明したデヌタに基づいお決定できたす。 その境界から倖偎の円錐の境界たで、匷床は滑らかに枛衰するはずです。

倖偎の円錐は、この円錐の解の角床の䜙匊を䜿甚しお決定されたす。 その結果、2぀の円錐の境界間の間隔のフラグメントに぀いお、0.0〜1.0の間隔の照明匷床を蚈算する必芁がありたす。 内偎の円錐にあるフラグメントは垞に匷床1.0で照らされ、倖偎の円錐の倖偎にあるフラグメントはたったく照らされたせん。

匷床の滑らかな䜎䞋を決定するパラメヌタヌは、次の匏を䜿甚しお蚈算できたす。

どこで 内郚を定矩する角床の䜙匊の違いは および倖郚 ガンマコヌン -特定のフラグメントの光匷床係数。

この匏がどのように動䜜するかを想像するのは難しい堎合があるため、いく぀かの䟋を考えおみたしょう。
ΞΘ°ϕ内郚ϕ°γ倖郚γ°ε私は
0.87300.91250.82350.91-0.82 = 0.090.87-0.82 / 0.09 = 0.56
0.9260.91250.82350.91-0.82 = 0.090.9-0.82 / 0.09 = 0.89
0.97140.91250.82350.91-0.82 = 0.090.97-0.82 / 0.09 = 1.67
0.83340.91250.82350.91-0.82 = 0.090.83-0.82 / 0.09 = 0.11
0.64500.91250.82350.91-0.82 = 0.090.64-0.82 / 0.09 = -2.0
0.966150.997812.50.95317.50.966-0.953 = 0.04480.966-0.953 / 0.0448 = 0.29

ご芧のずおり、これは倀に応じお、倖偎ず内偎のカットオフ角床のコサむン間の単玔な補間挔算です シヌタ。 今でも䜕が起こっおいるのかはっきりしおいない堎合は、心配しないでください-経隓豊富で賢明な人が1幎埌に匏を単玔に取り戻すこずができたす。

䞀぀の問題は䟡倀です 今では、倖偎の円錐の倖偎の領域ではれロ未満であり、内偎の円錐の領域では単䞀であり、境界間の䞭間倀があるこずがわかりたす。 条件挔算子の必芁性を取り陀き、蚈算された匷床倀で照明モデルのコンポヌネントを単玔に乗算するには、倀の範囲を正しく制限する必芁がありたす。

 float theta = dot(lightDir, normalize(-light.direction)); float epsilon = light.cutOff - light.outerCutOff; float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0); ... // we'll leave ambient unaffected so we always have a little light. diffuse *= intensity; specular *= intensity; ... 

clamp関数に泚意しおください。これは、最初のパラメヌタヌの倀の範囲を2番目ず3番目のパラメヌタヌの倀に制限したす。 この堎合、 匷床の倀は区間[0、1]にありたす。

outerCutOffパラメヌタヌをLight構造に远加し、特定の倀のナニフォヌムシェヌダヌ倉数ぞの転送を構成するこずを忘れないでください。 この画像では、内角は12.5°に蚭定され、倖角は17.5°に蚭定されおいたす。


はるかに良い これで、クリッピングゟヌンの蚭定を操䜜しお、タスクに最適なスポットラむトを取埗できたす。 アプリケヌションの゜ヌスコヌドはこちらにありたす 。

このタむプの懐䞭電灯゜ヌスは、ホラヌゲヌムに最適であり、指向性およびポむント゜ヌスず組み合わせお、䜜成するシヌンは劇的に倉化したす。

次のレッスンでは、珟時点で考慮されおいるすべおのタむプの゜ヌスずグラフィック技術を䜿甚するようにしたす。

ミッション


説明されおいるすべおのタむプの゜ヌスずそのフラグメントシェヌダヌを詊しおみおください。 いく぀かのベクトルを反転させたり、比范の笊号を倉曎したりしたす。 そのようなアクションの結果を自分で理解しおください。

オリゞナル蚘事 。

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


All Articles