2013-01-07 21 views
5

Tôi có một cảnh với một số kiểu máy có vị trí và phép quay riêng lẻ. Đưa ra các tiêu chuẩn, các shader áp dụng ánh sáng hai chiều đơn giản cho mỗi pixel.Xoay các chỉ số trong Shader

Đó là hình bóng đỉnh của tôi.

#version 150 

in vec3 position; 
in vec3 normal; 
in vec2 texcoord; 

out vec3 f_normal; 
out vec2 f_texcoord; 

uniform mat4 model; 
uniform mat4 view; 
uniform mat4 proj; 

void main() 
{ 
    mat4 mvp = proj * view * model; 

    f_normal = normal; 
    f_texcoord = texcoord; 

    gl_Position = mvp * vec4(position, 1.0); 
} 

Và đây là trình đổ bóng phân đoạn.

#version 150 

in vec3 f_normal; 
in vec2 f_texcoord; 

uniform sampler2D tex; 

vec3 sun = vec3(0.5, 1.0, 1.5); 

void main() 
{ 
    vec3 light = max(0.0, dot(normalize(f_normal), normalize(sun))); 

    gl_FragColor = texture(tex, f_texcoord) * vec4(light, 1.0); 
} 

Đối với các đối tượng không quay hoạt động tốt. Nhưng đối với các mô hình luân phiên, ánh sáng cũng được luân chuyển, điều này không phải là trường hợp.

Lý do cho điều đó là các chuẩn không được xoay. Tôi đã thử f_normal = model * normal; nhưng điều này áp dụng cả luân chuyển và chuyển đổi cho các chuẩn mực.

Vậy làm cách nào tôi có thể xoay các chỉ tiêu trong trình đổ bóng đỉnh trước khi tôi gửi chúng đến trình đổ bóng phân đoạn để chiếu sáng? Cách tiếp cận chung là gì?

Trả lời

4

Bạn cần phải chuyển đổi các chỉ tiêu, bằng 3 hàng/cột trên của ma trận mô hình-xem-chiếu. (Nếu bạn đang thực hiện bất kỳ tỷ lệ mặc dù, bạn cần phải sử dụng chuyển đảo ngược của ma trận này. See this article).

mat3 normalMatrix = mat3(mvp); 
normalMatrix = inverse(normalMatrix); 
normalMatrix = transpose(normalMatrix); 
f_normal = normalize(normal * normalMatrix); 
// You should also send your tranformed position to the fragment shader 
f_position = vec3(mvp * vec4(position, 1.0)); 

Trong trình đổ bóng phân đoạn, bạn cần tính toán khoảng cách từ nguồn sáng đến đoạn của bạn và chuẩn hóa. Tìm sản phẩm dấu chấm của vectơ thông thường và ánh sáng và nhân với màu sáng.

vec3 light = normalize(sun - f_position); 
light = max(dot(f_normal, light), 0.0) * vec3(1.0, 1.0, 1.0); 
gl_FragColor = texture(tex, f_texcoord) * vec4(light, 1.0); 

Chắc chắn có chỗ để tối ưu hóa trong mã của tôi.

Tôi khuyên bạn nên đọc sách này OpenGL 4.0 Shading Language Cookbook.

+0

Cảm ơn. Bạn có lời khuyên tôi để gửi một ma trận bình thường riêng biệt (bao gồm cả việc quay mô hình nhưng không chia tỷ lệ cũng không chuyển đổi) để đổ bóng không? Tôi thấy rằng thực hành một nơi nào đó và tự hỏi nếu đó là tốt hơn so với tái chiết xuất luân phiên từ ma trận mô hình trong bóng đổ. – danijar

+0

Xin lỗi về điều đó, thời gian của tôi đã hết khi chỉnh sửa nhận xét trước ... Tôi nghĩ rằng việc chia tỷ lệ là cần thiết, vì nó có thể thay đổi khoảng cách của bề mặt thành nguồn sáng. Và kể từ khi bạn cần quy mô, bạn cần phải sửa cho quy mô bằng cách sử dụng chuyển vị nghịch đảo của ma trận 3 x 3 trên. Tôi gửi ma trận bình thường của tôi để đổ bóng như một đồng phục mặc dù, do đó nó chỉ được tính một lần thay vì một lần cho mỗi đỉnh.Bạn có thể cần một thư viện toán học để làm điều này mặc dù, vì nền tảng của bạn có thể không cung cấp các chức năng để thực hiện các phép tính ma trận này. – bwroga

+0

Điều đó có ý nghĩa. Bằng cách này tôi sử dụng GLM. – danijar

0

Giải pháp sau đây phù hợp với mô hình của tôi, nhưng tôi không hiểu sâu về toán học đằng sau nó. Đây là nguồn của tôi: Adding Depth and Realism - Surface Normals

Các chuyển đổi bạn cần phải áp dụng đối với vectơ bình thường được ký hiệu là: N'= N * (M -1) T

Về cơ bản, điều này có nghĩa là bạn nhân các chỉ tiêu của bạn (N) bằng cách đảo ngược-transpose của ma trận ModelView (M) của bạn. Nếu ma trận M của bạn là 4x4, bạn chỉ nên sử dụng góc phần tư trên cùng bên trái 3x3 của (M -1) T cho phép nhân bình thường.

Một lần nữa, điều này làm việc cho tôi nhưng tôi không thể giải thích toán học quá tốt.

+0

Cảm ơn, tôi hiểu rồi. – danijar

Các vấn đề liên quan