GLSL Light(減衰、色、強度)の式


17

ボクセルエンジンにポイントライトを実装していますが、光源の近くで100%から光の半径で0%まで、適切な光の流れを得るのに苦労しています。

関数には5つの引数があります。

  1. 明るい色(Vec3)
  2. 光の強度(光から減衰が100%になる距離までの距離)
  3. ライトからフラグメントまでの距離
  4. ライトに垂直なフラグメントからの角度
  5. ライトの位置

フラグメントの色を計算するための関数を作成するために、誰かが私を正しい方向に押すことができますか?

私の実験の1つの画像:

ボクセルエンジンのフラグメントごとの照明テスト

編集(Byteによって要求された現在のコード)これは私の側からの単なる実験コードであることに注意してください。私はウェブサイトからフロート属性を取得しましたが、それは動作しますが、完璧からはほど遠いです。

void main()
{
// Light color
vec3 torchColor = vec3(1.0f, 1.0f, 1.0f);

float lightAdd = 0.0f;
for (int i=0; i<5; i++) {
    vec3 pos = lights[i];
    if (pos.x == 0.0f) continue;

    float dist = distance(vertex_pos, pos);
    if (dist < 9) {
        float att=1.0/(1.0+0.1*dist+0.01*dist*dist);
        vec3 surf2light = normalize(pos - vertex_pos);
        vec3 norm = normalize(normal);
        float dcont=max(0.0,dot(norm,surf2light));
        lightAdd += att*(dcont+0.4);
    }
}

vec3 textureColor = texture2D(texture, texture_coordinate).rgb;
vec3 torch_output = lightAdd * torchColor;

vec3 final_color = ((0.1+torch_output) * textureColor);

gl_FragColor = vec4(final_color, 1.0f); 
}

6
あなたはまだ「格好良い自然光を得るのに苦労している」と「作品、しかし完璧にはほど遠い」などのことを言っています。特定の正確な言語を含める必要があります。あなたにとって見栄えが良いか、自然光があなたにとってどのように見えるか、完璧かどうかはわかりません。
マイケルハウス

2
削除してみましたif (dist < 9)か?別の方法としては、計算できattリターン1の距離は9例:あるときの距離が0と0であることを機能でmix(1.0, 0.0, dist / 9.0)
msell

回答:


39

あなたが持っている減衰機能、

att = 1.0 / (1.0 + 0.1*dist + 0.01*dist*dist)

コンピュータグラフィックスではかなり一般的なものである-または、より一般的には、1.0 / (1.0 + a*dist + b*dist*dist))いくつかの微調整できるパラメータについてab。この曲線がどのように機能するかを理解するには、パラメーターをインタラクティブに操作すると便利です。この曲線は、遠距離では物理的に正しい逆二乗の法則に近づくので便利ですが、短距離では無限遠までは撮影されません。実際、a = 0それは球面エリアライトのかなり良いモデルです。

ただし、1つの欠点は、有限の距離で光がゼロにならないことです。リアルタイムCGの実用的な目的のために、一般に、このif (dist < 9)節で行っているように、有限の距離でライトを遮断する必要があります。ただし、半径9は短すぎます-減衰機能の設定では、distが100付近になるまでライトはゼロに近づきません。

b減衰関数のパラメーターから光の半径を計算できます(2次項は大きな距離で支配的であるため)。減衰がminLight0.01などの値に達したときに、ライトを遮断するとします。次に設定する

radius = sqrt(1.0 / (b * minLight))

との半径は100にb = 0.01なりminLight = 0.01ます。または、半径を設定し、b一致するように計算できます。

b = 1.0 / (radius*radius * minLight)

以下の場合radius = 9minLight = 0.01、それができますb = 1.23。どちらの方法でも設定できますが、重要なのは半径と減衰関数を一致させて、減衰関数がすでに非常に低くなるまでライトを遮断しないようにすることです。そのため、鋭いエッジは見えません。


とはいえ、使用できる代替の減衰関数があります。別のかなり一般的なものは次のとおりです。

att = clamp(1.0 - dist/radius, 0.0, 1.0); att *= att

または少し手の込んだ:

att = clamp(1.0 - dist*dist/(radius*radius), 0.0, 1.0); att *= att

それらのパラメーターも試してください。これらの曲線には、与えられた半径で正確にゼロになるという利点がありますが、自然な逆二乗の法則のように見えます。


すごい!ただし、パフォーマンス上の理由でのみ使用maxclampます。
マイクウィアー

4
@MikeWeir Clamping to [0、1]は、実際には多くのGPUで無料です。これは非常に一般的な操作であり、命令修飾子として使用されます。
ネイサンリード
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.