ปัญหาการแมปเงาครั้งแรก


9

ฉันใช้การทำแผนที่เงาพื้นฐานเป็นครั้งแรกใน OpenGL โดยใช้ shaders และฉันประสบปัญหาบางอย่าง ด้านล่างคุณสามารถดูตัวอย่างของฉากที่แสดงผลของฉัน:

ป้อนคำอธิบายรูปภาพที่นี่

กระบวนการของการแมปเงาที่ฉันกำลังติดตามคือฉันแสดงฉากให้กับ framebuffer โดยใช้ View Matrix จากมุมมองแสงและเมทริกซ์การฉายและแบบจำลองที่ใช้สำหรับการเรนเดอร์ปกติ

ในรอบที่สองฉันส่งเมทริกซ์ MVP ด้านบนจากมุมมองแสงไปยังตัวแบ่งจุดยอดซึ่งเปลี่ยนตำแหน่งเป็นพื้นที่แสง ส่วนของ shader จะแบ่งมุมมองและเปลี่ยนตำแหน่งเป็นพิกัดพื้นผิว

นี่คือจุดสุดยอดของฉัน


#version 150 core

uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 MVPMatrix;
uniform mat4 lightMVP;

uniform float scale;

in vec3 in_Position;
in vec3 in_Normal;
in vec2 in_TexCoord;

smooth out vec3 pass_Normal;
smooth out vec3 pass_Position;
smooth out vec2 TexCoord;
smooth out vec4 lightspace_Position;

void main(void){
    pass_Normal = NormalMatrix * in_Normal; 
    pass_Position = (ModelViewMatrix * vec4(scale * in_Position, 1.0)).xyz;
    lightspace_Position = lightMVP * vec4(scale * in_Position, 1.0);
    TexCoord = in_TexCoord;

    gl_Position = MVPMatrix * vec4(scale * in_Position, 1.0);
}

และส่วนที่แตกของฉัน


#version 150 core

struct Light{
    vec3 direction;
};

uniform Light light;
uniform sampler2D inSampler;
uniform sampler2D inShadowMap;

smooth in vec3 pass_Normal;
smooth in vec3 pass_Position;
smooth in vec2 TexCoord;
smooth in vec4 lightspace_Position;

out vec4 out_Color;


float CalcShadowFactor(vec4 lightspace_Position){

    vec3 ProjectionCoords = lightspace_Position.xyz / lightspace_Position.w;

    vec2 UVCoords;
    UVCoords.x = 0.5 * ProjectionCoords.x + 0.5;
    UVCoords.y = 0.5 * ProjectionCoords.y + 0.5;

    float Depth = texture(inShadowMap, UVCoords).x;
    if(Depth < (ProjectionCoords.z + 0.001)) return 0.5;
    else return 1.0;
}

void main(void){

    vec3 Normal = normalize(pass_Normal);
    vec3 light_Direction = -normalize(light.direction);
    vec3 camera_Direction = normalize(-pass_Position);
    vec3 half_vector = normalize(camera_Direction + light_Direction);

    float diffuse = max(0.2, dot(Normal, light_Direction));
    vec3 temp_Color = diffuse * vec3(1.0);

    float specular = max( 0.0, dot( Normal, half_vector) );

    float shadowFactor = CalcShadowFactor(lightspace_Position);

    if(diffuse != 0 && shadowFactor > 0.5){
        float fspecular = pow(specular, 128.0);
        temp_Color += fspecular;
    }

    out_Color = vec4(shadowFactor * texture(inSampler, TexCoord).xyz * temp_Color, 1.0);
}

หนึ่งในปัญหาคือเงาตัวเองอย่างที่คุณเห็นในภาพลังมีเงาของตัวเอง สิ่งที่ฉันได้ลองคือการเปิดใช้งานรูปหลายเหลี่ยมชดเชย (เช่น glEnable (POLYGON_OFFSET_FILL), glPolygonOffset (GLfloat, GLfloat) แต่มันไม่ได้เปลี่ยนแปลงอะไรมาก อย่างที่คุณเห็นในตัวแบ่งส่วนฉันใส่ค่าออฟเซ็ตคงที่ 0.001 แต่ฉันต้องเปลี่ยนค่าขึ้นอยู่กับระยะทางของแสงเพื่อให้ได้เอฟเฟ็กต์ที่ต้องการมากขึ้นซึ่งไม่ค่อยมีประโยชน์ ฉันยังลองใช้การเผชิญหน้าด้านหน้าเมื่อฉันแสดงผลกับ framebuffer นั่นก็ไม่ได้เปลี่ยนไปเหมือนกัน

ปัญหาอื่นคือพิกเซลที่อยู่นอกมุมมองของแสงจะได้รับการแรเงา วัตถุเดียวที่ควรจะสามารถหล่อเงาได้คือลัง ฉันเดาว่าฉันควรเลือกการฉายภาพที่เหมาะสมกว่าและดูเมทริกซ์ แต่ฉันไม่แน่ใจว่าจะทำอย่างไร ฉันควรเลือกวิธีการฉายภาพแบบออโทกราฟ

ฉันเข้าใจว่าปัญหาเหล่านี้ไม่ใช่เรื่องเล็กน้อย ไม่มีใครมีวิธีแก้ไขปัญหาเหล่านี้ได้ง่ายบ้างไหม คุณให้คำแนะนำเพิ่มเติมกับฉันได้ไหม

โปรดถามฉันหากคุณต้องการข้อมูลเพิ่มเติมเกี่ยวกับรหัสของฉัน

นี่คือการเปรียบเทียบที่มีและไม่มีการแมปเงาของระยะใกล้ของลังไม้ เงาตัวเองสามารถมองเห็นได้มากขึ้น


ดูเหมือนว่าคุณควรอธิบายปัญหาของคุณโดยละเอียด คุณมีหนึ่งประโยคเกี่ยวกับปัญหาของคุณและประโยคถัดไปจะแนะนำวิธีแก้ไขปัญหาหนึ่งข้อ บอกเราอย่างชัดเจนว่าปัญหาคืออะไรและสิ่งที่คุณทำไปแล้วเพื่อลองแก้ไข
MichaelHouse

ฉันแก้ไขโพสต์ของฉันฉันหวังว่าตอนนี้ดีขึ้นแล้ว
Grieverheart

คำตอบ:


6

คุณไม่ควรเงารูปหลายเหลี่ยมที่ด้านหลังหันจากแสง

ฉันเปลี่ยนส่วนของคุณเป็นรหัสด้านล่าง

float CalcShadowFactor(vec4 lightspace_Position)
{

    vec3 ProjectionCoords = lightspace_Position.xyz / lightspace_Position.w;

    vec2 UVCoords;
    UVCoords.x = 0.5 * ProjectionCoords.x + 0.5;
    UVCoords.y = 0.5 * ProjectionCoords.y + 0.5;

    float Depth = texture(inShadowMap, UVCoords).x;
    if(Depth < (ProjectionCoords.z + 0.001)) return 0.5;
    else return 1.0;
}

void main(void)
{

    vec3 Normal = normalize(pass_Normal);
    vec3 light_Direction = -normalize(light.direction);
    vec3 camera_Direction = normalize(-pass_Position);
    vec3 half_vector = normalize(camera_Direction + light_Direction);

    float fndotl = dot(Normal, light_Direction);
    float shadowFactor = CalcShadowFactor(lightspace_Position);
    float diffuse = max(0.0, fndotl) * shadowFactor + 0.2;
    vec3 temp_Color = vec3(diffuse);

    float specular = max( 0.0, dot( Normal, half_vector) );

    if(shadowFactor > 0.9){
        float fspecular = pow(specular, 128.0);
        temp_Color += fspecular;
    }

    out_Color = vec4(shadowFactor * texture(inSampler, TexCoord).xyz * temp_Color, 1.0);
}

8

เกี่ยวกับการแชโดว์ด้วยตนเองฉันไม่แน่ใจว่าสิ่งที่คุณพูดถึงคืออะไรฉันไม่เห็น "เงาสิว" บนลังในหน้าจอของคุณ หากคุณหมายความว่าใบหน้าที่หันหน้าไปทางแสงนั้นมืดแน่นอนว่าพวกเขาเป็น - พวกเขาควรจะเป็น! :) ใบหน้าด้านข้างดูแปลก ๆ เล็กน้อยแบ่งเส้นทแยงมุมออกเป็นครึ่งแสงและครึ่งเงา หากคุณใช้ N dot L สำหรับให้แสงสว่างและคุณมีบรรทัดฐานที่ดี (เช่นมาตรฐานที่ยากสำหรับลูกบาศก์นี้ไม่ใช่บรรทัดฐานที่ทำให้ราบเรียบ) ซึ่งไม่ควรเกิดขึ้น

การใช้รูปหลายเหลี่ยมชดเชยและ / หรือวาดใบหน้าด้านหลังลงในแผนที่เงาเป็นวิธีแก้ไขปัญหามาตรฐาน

สำหรับเมทริกซ์การฉายภาพคุณควรนึกถึงแสงในฐานะกล้อง ถ้ามันเป็นแสงพอยต์มันจะเป็นกล้องมุมมองและถ้ามันเป็นแสงทิศทางมันจะเหมือนกับกล้องออร์โธกราฟ สร้างเมทริกซ์การฉายเช่นเดียวกับที่คุณทำกับกล้องโดยใช้มุมมองของแสงอัตราส่วนภาพ ฯลฯ

ในการ จำกัด การพิกเซลของภาพวาดเพียงแค่พิกเซลในมุมมองของแสงเมื่อคุณคำนวณเงาแผนที่ UV เพียงตรวจสอบว่าพวกเขาอยู่ระหว่าง 0 และ 1 และdiscardถ้าไม่ (หรือตั้งค่าสีของแสงเป็นศูนย์) อีกวิธีหนึ่งคือการตั้งค่าพื้นผิวแผนที่เงาเป็น "ยึดไปยังขอบ" และตั้งค่าสีเส้นขอบเป็นศูนย์ซึ่งจะทำให้ทุกอย่างที่อยู่นอกแผนที่เงาได้รับเงาอย่างเต็มที่


นี่คือโคลสอัพของกล่องและการเปรียบเทียบสินค้าที่มีและไม่มีการทำแผนที่เงาลิงค์ เงาตัวเองปรากฏให้เห็นที่นี่มากขึ้น คุณช่วยอธิบายได้ไหมว่าทำไมคุณถึงใช้กล้องเปอร์สเปคทีฟสำหรับไฟส่องทางและจุดภาพสำหรับทิศทาง?
Grieverheart

โอเคในภาพนั้นมันดูเหมือนสิวเงา การดึงกลับใบหน้าลงในแผนที่เงา (และไม่ใช่ใบหน้าด้านหน้า) ควรแก้ไขปัญหานั้น ฉันรู้ว่าคุณพูดว่าคุณลองแล้ว แต่อาจมีบางอย่างผิดปกติ? glCullFace(GL_FRONT)มันเป็นเพียงแค่ สำหรับจุดเทียบกับทิศทางมันเกี่ยวกับรังสี รังสีจากกล้องมาบรรจบกัน ณ จุดหนึ่งในมุมมองของกล้องและรังสีของแสงมาบรรจบกันที่จุดหนึ่งในแสงพอยน์ รังสีของกล้องนั้นขนานกันสำหรับกล้อง orthographic และรังสีของแสงนั้นขนานกับแสงในทิศทางนั้น
นาธานรีด

ฉันเห็นว่าเหมาะสมแล้ว นี่คือการเปรียบเทียบทั้งที่มีและไม่มีการเลือกสรรใบหน้า ส่วนที่อยู่ด้านล่างเปิดใช้งานการเลือกใบหน้า ฉันจะพยายามใช้การฉายภาพแบบออร์โธกราฟสำหรับเมทริกซ์แสงของฉันซึ่งไม่ควรส่งผลกระทบต่อปัญหาการเกิดเงาด้วยตัวเองใช่ไหม? บางทีช่วงคลิปของฉันใหญ่เกินไป (เช่นฉันมี 0.1 ถึง 100)
Grieverheart

พวกนั้นดูเหมือนกันหมด คุณกำลังใช้การคัดกลับด้านหลังสำหรับฉากที่เหลือใช่มั้ย คุณทำglEnable(GL_CULL_FACE)อะไร
นาธานรีด

พวกเขาจะไม่เหมือนกันดูอย่างใกล้ชิดที่กล่อง ในภาพด้านบนเส้นเงาจะนูนขณะที่ด้านล่างเว้า
Grieverheart

3

พิกเซลที่อยู่ด้านนอกของแสงไฟนั้นดูมืดเพราะพวกมันถูกสุ่มตัวอย่างจากพื้นผิวที่มีความลึกของแสง

เมื่อคุณแปลงจุดสุดยอดด้วยเมทริกซ์การฉายคุณจะได้รับพิกัดคลิป [lightspace_Position] ของแฟรกเมนต์ จากนั้นคุณจะแปลงเป็นพิกัดพื้นผิว [UVCoords] อย่างไรก็ตามพิกัดพื้นที่คลิปของแฟรกเมนต์ยังคงสามารถอยู่นอกช่วง -1.0 ถึง 1.0 (ปิดหน้าจอและถูกตัดออก) และดังนั้นพิกัดพื้นผิวที่แปลงจะอยู่นอกช่วง 0.0 ถึง 1.0 ของพื้นผิวของคุณ

ลองสิ่งนี้:

if(UVCoords.x >= 0.0 && UVCoords.x <= 1.0 && UVCoords.y >= 0.0 && UVCoords.y <= 1.0 && (Depth < (ProjectionCoords.z + 0.001)))
    return 0.5;

คุณสามารถคูณเมทริกซ์ไบอัสลงใน [lightMVP] ของคุณและหลีกเลี่ยงการแปลงพิกัดในส่วนย่อยของคุณ


อคติเมทริกซ์มักเป็นวิธีที่ผู้คนไป มันเร็วกว่าการแยกรหัสในส่วนย่อย ๆ
Ian Young
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.