Saya menerapkan lampu titik di mesin Voxel saya, dan saya benar-benar berjuang untuk mendapatkan aliran cahaya yang baik, dari 100% di dekat sumber cahaya hingga 0% di radius cahaya.
Saya punya 5 argumen untuk fungsi ini:
- Warna terang (Vec3)
- Intensitas cahaya (jarak dari cahaya sampai jarak di mana falloff adalah 100%)
- Jarak dari cahaya ke fragmen
- Sudut dari fragmen normal ke cahaya
- Posisi cahaya
Adakah yang bisa mendorong saya ke arah yang benar untuk membuat fungsi untuk menghitung warna fragmen?
Gambar salah satu eksperimen saya:
Edit (kode saat ini diminta oleh Byte) Perhatikan bahwa ini hanya beberapa kode eksperimen dari pihak saya. Saya mendapat att float dari sebuah situs web, dan itu berfungsi, tetapi jauh dari sempurna. :
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);
}
if (dist < 9)
? Atau Anda dapat menghitungatt
dengan fungsi yang mengembalikan 1 ketika jarak adalah 0 dan 0 ketika jarak adalah 9. Misalnyamix(1.0, 0.0, dist / 9.0)
Jawaban:
Fungsi atenuasi yang Anda miliki,
adalah salah satu yang cukup umum dalam grafik komputer - atau, lebih umum,
1.0 / (1.0 + a*dist + b*dist*dist))
untuk beberapa parametera
dan tweakableb
. Untuk memahami cara kerja kurva ini, sebaiknya Anda memainkan parameter secara interaktif . Kurva ini bagus karena mendekati hukum kuadrat terbalik yang benar secara fisik pada jarak yang jauh, tetapi tidak melesat hingga tak terbatas pada jarak pendek. Bahkan, dengana = 0
model cahaya area bola yang cukup bagus.Namun, satu kelemahannya adalah bahwa cahaya tidak pernah benar-benar pergi ke nol pada jarak berapapun. Untuk tujuan praktis dalam CG waktu nyata, kami biasanya harus mematikan lampu pada jarak yang terbatas, seperti yang Anda lakukan dengan
if (dist < 9)
klausa. Namun, jari-jari 9 terlalu pendek - dengan pengaturan Anda pada fungsi atenuasi, cahayanya tidak mendekati nol sampai dist berada di sekitar 100.Anda dapat menghitung jari-jari cahaya dari
b
parameter dalam fungsi atenuasi (karena istilah kuadrat mendominasi pada jarak yang jauh). Katakanlah Anda ingin memotong lampu ketika redaman mencapai beberapa nilaiminLight
, seperti 0,01. Kemudian aturItu memberi radius 100 untuk
b = 0.01
danminLight = 0.01
. Atau, Anda dapat mengatur radius dan menghitungb
untuk mencocokkan:Untuk
radius = 9
danminLight = 0.01
, itu memberib = 1.23
. Anda dapat mengaturnya dengan baik, tetapi kuncinya adalah untuk membuat jari-jari dan fungsi atenuasi cocok sehingga Anda tidak memotong lampu sampai fungsi atenuasi sudah sangat rendah, sehingga Anda tidak akan melihat ujung yang tajam.Semua yang dikatakan, ada fungsi atenuasi alternatif yang dapat Anda gunakan. Satu lagi yang cukup umum adalah:
atau yang sedikit lebih keren:
Mainkan dengan parameter untuk parameter itu juga. Kurva-kurva ini memiliki keuntungan untuk pergi tepat ke nol pada radius yang diberikan, sambil tetap terlihat seperti hukum kuadrat terbalik alami.
sumber
max
lebihclamp
karena alasan kinerja saja.