Vấn đề ánh xạ bóng lần đầu tiên


9

Tôi đã triển khai ánh xạ bóng cơ bản lần đầu tiên trong OpenGL bằng cách sử dụng trình đổ bóng và tôi đang gặp một số vấn đề. Dưới đây bạn có thể thấy một ví dụ về cảnh hiển thị của tôi:

nhập mô tả hình ảnh ở đây

Quá trình ánh xạ bóng tôi đang theo dõi là tôi kết xuất cảnh cho bộ đệm khung bằng cách sử dụng Ma trận xem từ điểm nhìn sáng và ma trận chiếu và mô hình được sử dụng để hiển thị bình thường.

Trong lần chuyển thứ hai, tôi gửi ma trận MVP ở trên từ điểm nhìn ánh sáng đến bộ đổ bóng đỉnh để biến đổi vị trí thành không gian ánh sáng. Trình tạo bóng mảnh phân chia phối cảnh và thay đổi vị trí thành tọa độ kết cấu.

Đây là shader đỉnh của tôi,


#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);
}

Và mảnh vỡ của tôi,


#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);
}

Một trong những vấn đề là tự đổ bóng như bạn có thể thấy trong hình, thùng có bóng của chính nó. Những gì tôi đã thử là cho phép bù đa giác (tức là glEnable (POLYGON_OFFSET_FILL), glPolygon Offerset (GLfloat, GLfloat)) nhưng nó không thay đổi nhiều. Như bạn thấy trong shader mảnh, tôi đã đặt giá trị offset tĩnh là 0,001 nhưng tôi phải thay đổi giá trị tùy thuộc vào khoảng cách của ánh sáng để có được hiệu ứng mong muốn hơn, không tiện dụng lắm. Tôi cũng đã thử sử dụng loại bỏ mặt trước khi kết xuất với bộ đệm khung, điều đó cũng không thay đổi nhiều.

Vấn đề khác là các pixel bên ngoài chế độ xem của Light bị mờ. Đối tượng duy nhất được cho là có thể tạo bóng là cái thùng. Tôi đoán tôi nên chọn phép chiếu và xem ma trận phù hợp hơn, nhưng tôi không chắc làm thế nào để làm điều đó. Một số thực tiễn phổ biến, tôi nên chọn một hình chiếu chính tả là gì?

Từ việc loay hoay một chút, tôi hiểu rằng những vấn đề này không phải là chuyện nhỏ. Có ai có bất kỳ dễ dàng để thực hiện các giải pháp cho những vấn đề này. Bạn có thể cho tôi một số lời khuyên bổ sung?

Xin hỏi tôi nếu bạn cần thêm thông tin về mã của tôi.

Dưới đây là một so sánh có và không có bản đồ bóng của cận cảnh thùng. Các bóng tự nhìn thấy rõ hơn.


Có vẻ như bạn nên mô tả (các) vấn đề của bạn chi tiết hơn. Bạn có một câu về vấn đề của bạn và câu tiếp theo gợi ý cách khắc phục. Hãy cho chúng tôi biết chính xác vấn đề là gì và bạn đã làm gì để thử và khắc phục nó.
MichaelHouse

Tôi đã chỉnh sửa bài viết của mình, tôi hy vọng nó tốt hơn bây giờ.
Grieverlove

Câu trả lời:


6

Bạn không nên phủ bóng lên các đa giác quay mặt ra khỏi ánh sáng.

Tôi đã thay đổi shader mảnh của bạn thành mã bên dưới.

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

Về việc tự tạo bóng, tôi không chắc chắn những gì bạn đang đề cập - Tôi không thấy bất kỳ "mụn bóng" nào trên thùng trong ảnh chụp màn hình của bạn. Nếu bạn muốn nói rằng những khuôn mặt tránh xa ánh sáng thì tối, dĩ nhiên là vậy - họ nên như vậy! :) Mặt bên trông hơi kỳ lạ, chia đôi đường chéo thành nửa sáng và nửa bóng. Nếu bạn đang sử dụng N chấm L để chiếu sáng và bạn có các quy tắc tốt (nghĩa là các quy tắc cứng trên khối này, không phải là các quy tắc được làm mịn) thì điều đó không nên xảy ra.

Sử dụng bù đa giác và / hoặc vẽ mặt sau vào bản đồ bóng là các giải pháp tiêu chuẩn (cũng ... giải pháp thực sự) cho mụn trứng cá.

Đối với ma trận chiếu, bạn nên nghĩ về ánh sáng như một máy ảnh. Nếu đó là đèn điểm, nó sẽ là máy ảnh phối cảnh và nếu là đèn định hướng thì nó sẽ giống như máy ảnh chính tả. Xây dựng ma trận chiếu giống như cách bạn làm cho máy ảnh, sử dụng trường nhìn của ánh sáng, tỷ lệ khung hình, v.v.

Để hạn chế trình đổ bóng pixel chỉ vẽ các pixel trong chế độ xem của ánh sáng, một khi bạn tính toán các tia UV của bản đồ bóng, chỉ cần kiểm tra xem chúng có nằm trong khoảng từ 0 đến 1 hay discardkhông (hoặc đặt màu của ánh sáng thành 0). Một cách khác là đặt kết cấu bản đồ bóng ở chế độ "kẹp thành viền" và đặt màu đường viền bằng 0, điều này sẽ đảm bảo mọi thứ bên ngoài bản đồ bóng sẽ bị che khuất hoàn toàn.


Dưới đây là một cái nhìn cận cảnh của hộp và so sánh với và không có liên kết ánh xạ bóng . Các bóng tự nhìn thấy rõ hơn ở đây. Bạn có thể giải thích lý do tại sao bạn sẽ sử dụng một camera phối cảnh cho đèn điểm và chỉnh hình cho định hướng?
Grieverlove

Được rồi, trong bức ảnh đó trông giống như mụn trứng cá. Vẽ mặt sau vào bản đồ bóng (và không phải mặt trước) sẽ khắc phục điều đó. Tôi biết bạn nói rằng bạn đã thử điều đó, nhưng có lẽ đã xảy ra sự cố? Chỉ là vậy thôi glCullFace(GL_FRONT). Đối với điểm so với hướng, đó là tất cả về các tia. Các tia camera hội tụ đến một điểm trong camera phối cảnh và các tia sáng hội tụ đến một điểm trong ánh sáng điểm; các tia camera song song với một camera chỉnh hình và các tia sáng song song với ánh sáng định hướng.
Nathan Reed

Tôi thấy, điều đó có ý nghĩa. Đây là một so sánh khác với và không có mặt loại bỏ. Cái ở phía dưới có mặt được kích hoạt. Tôi sẽ cố gắng sử dụng phép chiếu chính tả cho ma trận View ánh sáng của mình, điều đó không ảnh hưởng đến vấn đề tự đổ bóng, phải không? Có lẽ phạm vi clip của tôi quá lớn (tức là tôi có 0,1 đến 100)?
Grieverlove

Chúng trông giống hệt nhau. Bạn đang sử dụng loại bỏ mặt sau cho phần còn lại của cảnh, phải không? Bạn đã làm glEnable(GL_CULL_FACE)chưa
Nathan Reed

Chúng không hoàn toàn giống nhau, nhìn kỹ vào hộp. Trong hình trên, đường bóng là lồi trong khi đường dưới ở dưới lõm.
Grieverlove

3

Các pixel bên ngoài chế độ xem đèn bị tối vì chúng được lấy mẫu từ bên ngoài kết cấu độ sâu của đèn.

Khi bạn chuyển đổi đỉnh theo ma trận chiếu, bạn sẽ nhận được tọa độ clip [lightpace_P vị trí] của đoạn. Sau đó, bạn đang chuyển đổi nó thành tọa độ kết cấu [UVCoords]. Tuy nhiên, tọa độ không gian clip của một đoạn vẫn có thể nằm ngoài phạm vi -1.0 đến 1.0 (tắt màn hình và do đó bị cắt) và do đó tọa độ kết cấu được chuyển đổi có thể nằm ngoài phạm vi 0,0 đến 1,0 của kết cấu của bạn.

Thử đi:

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;

Bạn cũng có thể nhân ma trận thiên vị vào [lightMVP] của mình và tránh thực hiện chuyển đổi tọa độ trong trình đổ bóng mảnh.


Ma trận thiên vị thường là cách mọi người đi. Nó nhanh hơn rất nhiều so với mã phân nhánh trong một shader mảnh.
Ian Young
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.