2012-04-22 11 views
17

Vì vậy, tôi đã có một kẻ mạo danh (hình học thực sự là một khối lập phương, có thể cắt bớt, và hình dạng imposter là một miếng bọt biển Menger) và tôi cần phải tính toán chiều sâu của nó.GLSL gl_FragCoord.z ​​Tính toán và thiết lập gl_FragDepth

Tôi có thể tính toán số tiền để bù đắp trong không gian thế giới khá dễ dàng. Thật không may, tôi đã dành nhiều giờ không làm xáo trộn chiều sâu với nó.

duy nhất kết quả chính xác tôi có thể nhận được khi tôi đi:

gl_FragDepth = gl_FragCoord.z 

Về cơ bản, tôi cần phải biết làm thế nào gl_FragCoord.z ​​được tính toán sao mà tôi có thể:

  • Hãy việc chuyển đổi ngược từ gl_FragCoord.z ​​đến không gian mắt
  • Thêm độ nhiễu ở độ sâu
  • Biến đổi độ sâu bị xáo trộn này trở lại cùng không gian với gl_FragCoord.z ​​ban đầu.

Tôi xin lỗi nếu điều này có vẻ như một câu hỏi trùng lặp; có một số bài đăng khác ở đây đề cập đến những điều tương tự. Tuy nhiên, sau khi thực hiện tất cả chúng, không có gì hoạt động chính xác. Thay vì cố gắng chọn một để được giúp đỡ, tại thời điểm này, tôi yêu cầu mã hoàn chỉnh thực hiện điều đó. Nó chỉ là một vài dòng.

+0

Bạn đã viết một trình đổ bóng đỉnh chưa? hoặc chỉ là một shader fragment? –

+2

Tôi sẽ không cung cấp cho bạn mã theo nguyên tắc chung, nhưng tôi có thể cung cấp cho bạn [liên kết này tới Wiki OpenGL] (http://www.opengl.org/wiki/Compute_eye_space_from_window_space). Cũng như liên kết này đến hướng dẫn của tôi về [kẻ mạo danh và chiều sâu cũng cho thấy cách thực hiện điều này] (http://www.arcsynthesis.org/gltut/Illumination/Tut13%20Deceit%20in%20Depth.html). Chuyển đổi chiều sâu trở lại là tầm thường. –

+0

Michael: vâng, nhưng nó chỉ là thông qua shader.Khi nó xảy ra, các tính toán được thực hiện trong không gian thế giới, vì vậy tôi có thể tính toán không gian mắt trong chương trình phân đoạn. Nicol, tôi đã xem trang đó. Tôi triển khai nó như sau: vec4 clip_pos = gl_ProjectionMatrix * vec4 (eye_pos, 1.0); float ndc_depth = clip_pos.z/clip_pos.w; gl_FragDepth = (((clip_far-clip_near) * ndc_depth) + clip_near + clip_far)/2.0; Thật không may, độ sâu dường như nằm ngoài phạm vi độ sâu, mặc dù không có bù đắp. Cảm ơn, – imallett

Trả lời

28

Để tham khảo trong tương lai, các mã chủ chốt là:

float far=gl_DepthRange.far; float near=gl_DepthRange.near; 

vec4 eye_space_pos = gl_ModelViewMatrix * /*something*/ 
vec4 clip_space_pos = gl_ProjectionMatrix * eye_space_pos; 

float ndc_depth = clip_space_pos.z/clip_space_pos.w; 

float depth = (((far-near) * ndc_depth) + near + far)/2.0; 
gl_FragDepth = depth; 
+0

Không nên "gl_DepthRange.far" và "gl_DepthRange.near;" được thay thế bằng phạm vi gần và xa của ma trận chiếu thay vì giá trị mặt phẳng kẹp? – Tara

+0

Không hề. gl_DepthRange không giống như giá trị mặt phẳng gần và xa được sử dụng để tính toán ma trận chiếu. Tôi có thể hiểu lầm điểm của bạn mặc dù. – Tara

+0

@ Dudeson Các mặt phẳng clip đơn giản xác định, thông qua ma trận chiếu, các giá trị sẽ ánh xạ bên ngoài NDC (và do đó bị cắt bớt bởi phần cứng). Chúng tôi hoàn toàn được thực hiện với chúng sau khi ma trận chiếu được chỉ định. Trong khi đó, 'gl_DepthRange. (Ne | f) ar' là phạm vi của bộ đệm độ sâu, và cần thiết để chuyển đổi từ NDC sang bộ đệm độ sâu. HTH – imallett

4

Đối với một tài liệu tham khảo trong tương lai, đây là cùng một công thức như được đưa ra bởi imallett, được làm việc cho tôi trong một ứng dụng OpenGL 4.0:

vec4 v_clip_coord = modelview_projection * vec4(v_position, 1.0); 
float f_ndc_depth = v_clip_coord.z/v_clip_coord.w; 
gl_FragDepth = (1.0 - 0.0) * 0.5 * f_ndc_depth + (1.0 + 0.0) * 0.5; 

Ở đây, modelview_projection là ma trận chiếu mô hình 4x4 và v_position là vị trí không gian đối tượng của pixel được hiển thị (trong trường hợp của tôi được tính bằng raymarcher).

Phương trình đến từ phần window coordinates của this manual. Lưu ý rằng trong mã của tôi, gần là 0.0 và xa là 1.0, là các giá trị mặc định là gl_DepthRange. Lưu ý rằng gl_DepthRangekhông phải điều tương tự như khoảng cách gần/xa trong công thức cho perspective projection matrix! Bí quyết duy nhất là sử dụng 0.01.0 (hoặc gl_DepthRange trong trường hợp bạn thực sự cần thay đổi), tôi đã đấu tranh trong một giờ với phạm vi độ sâu khác - nhưng điều đó đã "được nướng" trong ma trận chiếu (quan điểm) của tôi . Lưu ý rằng theo cách này, phương trình thực sự chỉ chứa một phép nhân với một hằng số ((far - near)/2) và thêm một hằng số khác ((far + near)/2). So sánh đó để nhân, thêm và chia (có thể được chuyển đổi thành một nhân với một trình biên dịch tối ưu hóa) được yêu cầu trong mã của imallett.