Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

WebGLで描画した3Dモデルに陰影をつけたい

解決したいこと

Three.jsのPlaneBufferGeometryとShaderMaterialを使って地形を表示するプログラムを作っています。地形は時間軸に沿って変形するようにしています。地形変化のための計算は、計算に必要なパラメータを頂点シェーダに渡して処理しています。頂点シェーダで計算しているため、元のPlainBufferGeometryの法線ベクトルは(0,0,1)が並んでいるだけです。適当な場所に並行光源を配置して陰影をつけてそれらしく見せたいのですが、陰影をつける方法がわからず現在はワイヤーフレームで適当に色付けして表示させています。
このような場合、どのようにして陰影をつけるのでしょうか。現状の記述の要約は下記です。

頂点シェーダの記述

void main () {
    //elevationを計算する

    //計算したelevationを点の位置のz座標にする
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position.xy, elevation, 1.0 );
}

フラグメントシェーダの記述

void main () {
    //色を計算する

    //計算した色を設定する
    gl_FragColor    = vec4( outColor.rgb, outAlpha );
}

調べたこと

PlaneBufferGeometryで生成したオブジェクトそのものに対してsetAttributeで頂点を変形させた場合はcomputeFaceNormalsやcomputeVertexNormalsにより、オブジェクトに対して法線ベクトルを再計算させることが出来ますが、全て頂点シェーダ内で計算させているためその方法が使えません。
@aa_debdebさんの【Unity】頂点シェーダーで頂点を変形した後に法線を再計算する
こちらの記事が近いのかと思ったのですが、Unityを使ったことがないのでよく理解できませんでした。

どのように実現したらよいか、初心者(GLSLの1年生)でも参考にできそうな情報がありましたら教えていただけると嬉しいです。

因みに、陰影を実現したいページは下記になります。
西之島海底火山噴火に伴う土地形状変化のアニメーション

0

1Answer

こういったときによく使われているのは「フラグメントシェーダでddx/ddy関数を使って、隣接したピクセルのワールド座標の差ベクトルから外積を計算してそれを法線とする」方法ですかね。

英語かつGLSLではないんですが、以下のページのコードで雰囲気はだいたいつかめるかなと
http://c0de517e.blogspot.com/2008/10/normals-without-normals.html?m=1

0Like

Comments

  1. @UsagiLabo

    Questioner

    ご回答下さり、ありがとうございました。リンク先のページの記述だけではよくわかりませんでしたので、追加でいろいろと検索してみたらこちらの記事を見つけました(さすがKLabさん・・・)。
    https://qiita.com/gam0022/items/1878150981494fd66abe
    わからないなりにテストしてみたのですが、こちらの関数はWebGL2.0から?でWebGL1.0では使えないのでしょうか。SafariがまだWebGL2.0未対応なので、もし別のやり方があるなら教えていただきたいです。
    法線ベクトルが求められたとしても、法線ベクトルとライトをどのように適用するかも調べないといけないのですが・・・。
  2. OES_standard_derivatives という拡張があって、それを使うとddx/ddy(GLSLではdFdx/dFdy)が使えるようになるみたいです。
    https://wgld.org/d/webgl/w087.html

    ただしMDNのサイトを見るとSafariだけ対応状況が「?」になっているので、Safariだけシェーディングを諦めるか他の方法を探すかしかないですかね……
    シェーダでできないとなるとJavaScript側で似たような計算するしかないですが
  3. @UsagiLabo

    Questioner

    早々にコメント下さりありがとうございます。
    元のコードにJavaScriptとGLSLの双方で有効化の記述を追加しました。結果main関数内でdFdx関数を使ってもエラーが出なくなりました!。
    これで引き続き開発を続けてみます。うまく出来ない場合は別に質問を立てたいと思います。
    ご親切に教えて下さり、どうもありがとうございました。

Your answer might help someone💌