Làm thế nào để nhiều shader shader hoạt động trong OpenGL?


12

Trong Direct3D, nhiều shader shader rất đơn giản để sử dụng vì bạn có thể định nghĩa các đường chuyền trong một chương trình. Trong OpenGL, có vẻ phức tạp hơn một chút vì có thể đưa ra một chương trình đổ bóng như nhiều đỉnh, hình học và các mảnh vỡ như bạn muốn.

Một ví dụ phổ biến của shader nhiều lần là shader toon. Một vượt qua thực hiện hiệu ứng cel-shading thực tế và cái còn lại tạo ra phác thảo. Nếu tôi có hai shader đỉnh, "cel.vert" và "line.vert", và hai shader mảnh, "cel.frag" và "line.frag" (tương tự như cách bạn làm trong HLSL), làm sao tôi có thể kết hợp chúng để tạo ra shon toon đầy đủ?

Tôi không muốn bạn nói rằng một shader hình học có thể được sử dụng cho điều này bởi vì tôi chỉ muốn biết lý thuyết đằng sau các shader GLSL nhiều lần;)


"Trong Direct3D, nhiều shader shader rất đơn giản để sử dụng vì bạn có thể định nghĩa các đường chuyền trong một chương trình." Không, bạn không thể. Bạn có thể xác định các đường chuyền trong tệp FX, nhưng nó không giống như trình đổ bóng HLSL.
Nicol Bolas

Câu trả lời:


11

Không có "lý thuyết" đằng sau bội số. Không có "nhiều shader". Multipass rất đơn giản: bạn vẽ đối tượng bằng một chương trình. Sau đó, bạn vẽ đối tượng với một chương trình khác .

Bạn có thể sử dụng công cụ D3DX như các tệp FX để ẩn các thẻ bổ sung này. Nhưng họ vẫn làm việc theo cách đó. OpenGL đơn giản là không có nơi ẩn náu cho nó.


1

Kết xuất đối tượng với trình đổ bóng di động, và sau đó kết xuất lại với trình tạo bóng phác thảo.


1
Vì vậy, tôi nên làm cho hai chương trình shader khác nhau? Tại sao sau đó tôi có thể cung cấp một chương trình đổ bóng như nhiều shader đỉnh / hình học / mảnh như tôi muốn? Phải có một cách để làm điều đó với một chương trình.
jmegaffin

1
Bạn không cung cấp cho nó nhiều shader đỉnh (v.v.). Chỉ có một chức năng chính, vì vậy bạn không có nhiều điểm vào. Nó rất giống với chương trình C ở chỗ bạn có thể có nhiều tệp được liên kết với nhau để tạo chương trình. Bạn có thể chia sẻ các tệp này giữa các chương trình khác nhau để bạn không cần sao chép mã, nhưng mỗi tệp không nhất thiết phải là một chương trình.
Chewy Gumball

1
Đó là cách để đi, Kết xuất một lần với một cặp shader (đỉnh + đoạn) sau đó kết xuất lại với một cặp khác (hoặc sử dụng cùng một shader đỉnh + một shader mảnh khác). Đôi khi bạn kết xuất vào bộ đệm và sử dụng (chưa) một shader khác để 'trộn' nó vào kết quả cuối cùng.
Valmond

1

Trong OpenGL 4.0 có các chương trình con thống nhất . Điều này cho phép bạn xác định các chức năng có thể được hoán đổi trong thời gian chạy với rất ít chi phí. Vì vậy, bạn có thể thực hiện 1 chức năng cho mỗi lần vượt qua. Ngoài ra 1 chức năng cho mỗi loại shader.

một hướng dẫn ở đây .

Đối với các phiên bản OpenGL cũ hơn, cách tốt nhất của bạn là có một loạt các shader khác nhau và trao đổi giữa chúng. Nếu không, bạn có thể thêm các giá trị mà bạn nhân với một đồng phục là 0,0 hoặc 1,0 để bật hoặc tắt. Mặt khác có điều kiện nếu các câu lệnh có thể được sử dụng nhưng OpenGL sẽ thực thi tất cả các kết quả có thể xảy ra cho mỗi lần thực hiện / vượt qua để đảm bảo chúng không quá nặng.


0

Có một số người biết rất nhiều về GLSL, vì vậy tôi hy vọng họ sẽ lập kỷ lục, nhưng dựa trên những gì tôi đã thấy, bạn có thể, trong shader mảnh của bạn, làm điều gì đó như thế này (mã giả, tôi 'sẽ để GLSL thực tế cho những người hiểu rõ hơn về nó):

out vec4 fragment_color
vec4 final_color
final_color = flat_color
If this fragment is in shadow
    final_color = shadow_color
If this fragment is an edge
    final_color = edge_color
If this fragment is a highlight
    final_color = highlight_color
fragment_color = final_color

Bằng cách sử dụng ifs theo cách này, bạn sẽ có được thứ gì đó giống như nhiều đường chuyền. Điều đó có ý nghĩa?

Chỉnh sửa: Ngoài ra, hy vọng câu hỏi này về SO giúp xua tan một số hiểu lầm.


2
Điều quan trọng cần lưu ý là GLSL sẽ thực thi tất cả các câu lệnh trong các nhánh nếu mọi lượt đều vượt qua ngay cả khi chúng không bật. Rõ ràng chỉ cần tính toán mọi thứ và cộng tất cả các màu lại với nhau nhưng nhân các giá trị với 1.0 hoặc 0.0 để bật hoặc tắt chúng thì nhanh hơn.
David C. Giám mục

1
@ DavidC.Bishop: Điều đó không đúng. Ít nhất, không được đảm bảo là đúng. Trình biên dịch sẽ quyết định xem một nhánh thực tế nhanh hơn hay cách tiếp cận "tính toán mọi thứ và sắp xếp nó sau" nhanh hơn.
Nicol Bolas

1
Bên cạnh đó, hành vi được đề cập bởi @ DavidC.Bishop hầu như không cụ thể đối với các shader và GPU. Các CPU hiện đại thực thi các chương trình bình thường sẽ thực hiện theo cách suy đoán ít nhất một trong các nhánh nếu giá trị được kiểm tra chưa khả dụng. Nếu họ trở thành sai, họ quay lại và làm lại. Điều này kết thúc với năng suất trung bình lớn.
ipeet
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.