สูตรแสง GLSL (ลดทอนสีและความเข้ม)


17

ฉันกำลังติดตั้งไฟจุดในเครื่องมือ Voxel ของฉันและฉันพยายามอย่างหนักเพื่อให้ได้แสงที่ดีจาก 100% ใกล้กับแหล่งกำเนิดแสงถึง 0% ที่รัศมีแสง

ฉันมี 5 ข้อโต้แย้งสำหรับฟังก์ชั่น:

  1. สีอ่อน (Vec3)
  2. ความเข้มของแสง (ระยะทางจากแสงจนถึงระยะทางที่จุดตกหล่น 100%)
  3. ระยะทางจากแสงถึงชิ้นส่วน
  4. มุมจากชิ้นส่วนปกติถึงแสง
  5. ตำแหน่งของแสง

ทุกคนสามารถผลักฉันไปในทิศทางที่ถูกต้องเพื่อสร้างฟังก์ชั่นสำหรับการคำนวณสีชิ้นส่วนได้หรือไม่?

ภาพหนึ่งในการทดลองของฉัน:

การทดสอบแสงสว่างต่อชิ้นส่วนของ Voxel Engine

แก้ไข (รหัสปัจจุบันที่ขอโดย 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
คุณยังคงบอกว่าสิ่งที่ชอบ "ดิ้นรนเพื่อให้ได้ดูดี , ไฟธรรมชาติ " และ "ผลงาน แต่ไกลจากที่สมบูรณ์ " คุณต้องรวมภาษาที่เจาะจงและแน่นอน เราไม่ทราบว่าคุณดูดีแค่ไหนหรือมีแสงธรรมชาติส่องเข้ามาหาคุณหรืออะไรที่สมบูรณ์แบบที่สุด
MichaelHouse

2
คุณลองนำออกif (dist < 9)หรือไม่ อีกทางหนึ่งคุณสามารถคำนวณattด้วยฟังก์ชันที่ส่งคืน 1 เมื่อระยะทางเป็น 0 และ 0 เมื่อระยะทางเท่ากับ 9 เช่น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))สำหรับพารามิเตอร์ tweakable บางและa bเพื่อทำความเข้าใจว่าเส้นโค้งนี้ทำงานมันเป็นประโยชน์ที่จะเล่นกับพารามิเตอร์โต้ตอบ เส้นโค้งนี้เป็นสิ่งที่ดีเพราะมันเข้าใกล้กฏตารางผกผันที่ถูกต้องทางร่างกายในระยะทางไกล แต่มันไม่ได้พุ่งขึ้นไปถึงระยะอนันต์ในระยะทางสั้น ๆ อันที่จริงแล้วa = 0มันเป็นแบบจำลองที่ดีของแสงพื้นที่ทรงกลม

อย่างไรก็ตามข้อเสียอย่างหนึ่งของมันคือแสงไม่เคยไปที่ศูนย์ในระยะทางอัน จำกัด สำหรับการใช้งานจริงใน CG แบบเรียลไทม์โดยทั่วไปเราจำเป็นต้องตัดไฟที่ระยะทางที่ จำกัด ในขณะที่คุณกำลังทำกับif (dist < 9)ประโยค อย่างไรก็ตามรัศมีของ 9 นั้นสั้นเกินไป - ด้วยการตั้งค่าของคุณในฟังก์ชั่นการลดทอนแสงจะไม่เข้าใกล้ศูนย์จนกว่า dist จะอยู่ที่ประมาณ 100

คุณสามารถคำนวณรัศมีของแสงจากbพารามิเตอร์ในฟังก์ชั่นการลดทอน (เนื่องจากสมการกำลังสองอยู่ในระยะทางไกล) สมมติว่าคุณต้องการตัดแสงเมื่อการลดทอนมาถึงค่าบางอย่างminLightเช่น 0.01 จากนั้นตั้งค่า

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

ที่ให้รัศมีของ 100 หาและb = 0.01 minLight = 0.01หรือคุณสามารถตั้งค่ารัศมีและคำนวณbให้ตรงกับ:

b = 1.0 / (radius*radius * minLight)

สำหรับradius = 9และที่ช่วยให้minLight = 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

เล่นกับพารามิเตอร์สำหรับคนเหล่านั้นด้วย เส้นโค้งเหล่านี้มีประโยชน์จากการไปว่าให้เป็นศูนย์ในรัศมีที่กำหนดในขณะที่ยังคงมองหาชนิดเช่นธรรมชาติกฎหมายตารางผกผัน


ที่ดี! แม้ว่าฉันต้องการใช้maxมากกว่าclampเพื่อเหตุผลด้านประสิทธิภาพเท่านั้น
Mike Weir

4
@ MikeWeir Clamping ถึง [0, 1] นั้นฟรีบน GPU หลายตัวจริง ๆ แล้ว มันเป็นการดำเนินการทั่วไปที่พวกเขามีเป็นตัวดัดแปลงคำสั่ง
นาธานรีด
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.