Cách tốt nhất để xử lý ID3D11InputLayout trong kết xuất mã?


7

Tôi đang tìm kiếm một cách thanh lịch để xử lý các bố cục đầu vào trong mã directx11 của mình.

Vấn đề tôi có là tôi có một lớp Hiệu ứng và một lớp Element. Lớp hiệu ứng đóng gói các shader và các cài đặt tương tự, và lớp Element chứa thứ gì đó có thể được vẽ (mô hình 3d, lanscape, v.v.)

Mã bản vẽ của tôi thiết lập các shader thiết bị, v.v ... bằng cách sử dụng hiệu ứng được chỉ định và sau đó gọi hàm vẽ của Element để vẽ hình học thực tế có trong nó.

Vấn đề là ở đây - tôi cần tạo D3D11InputLayout ở đâu đó. Điều này thực sự thuộc về lớp Element vì nó không phải là phần còn lại của hệ thống, làm thế nào phần tử đó chọn để thể hiện bố cục đỉnh của nó. Nhưng để tạo đối tượng, API yêu cầu mã byte của trình tạo bóng đỉnh cho trình tạo bóng đỉnh sẽ được sử dụng để vẽ đối tượng. Trong directx9 thật dễ dàng, không có sự phụ thuộc nên phần tử của tôi có thể chứa các cấu trúc bố cục đầu vào của riêng nó và đặt chúng mà không có hiệu ứng liên quan.

Nhưng Element không thực sự phải biết bất cứ điều gì về hiệu ứng mà nó được tạo ra, đó chỉ là cài đặt kết xuất và Element ở đó để cung cấp hình học.

Vì vậy, tôi thực sự không biết nơi lưu trữ và cách chọn InputLayout cho mỗi cuộc gọi rút thăm. Ý tôi là, tôi đã làm một cái gì đó hoạt động nhưng nó có vẻ rất xấu.

Điều này làm cho tôi biết rằng tôi đã bỏ lỡ điều gì đó rõ ràng hoặc nếu không thì thiết kế của tôi có tất cả các cài đặt kết xuất trong Hiệu ứng, Hình học trong một Thành phần và bên thứ 3 rút ra tất cả chỉ là thiếu sót.

Chỉ tự hỏi làm thế nào bất cứ ai khác xử lý bố trí đầu vào của họ trong directx11 một cách thanh lịch?

Câu trả lời:


3

Cách tôi xử lý điều này là tôi có một tệp VertexFormat.h trong đó tôi có một loạt các bố cục đầu vào thuộc các loại khác nhau (VertexPocationN normal, VertexN normalUV ...) được gói trong các cấu trúc để dễ dàng tạo / hủy. Nó hoạt động khá tốt mặc dù IMO xấu xí. Thật dễ dàng để thêm một định dạng đỉnh mới vào tệp nếu bạn có một shader sử dụng bố cục hiện không được hỗ trợ. Sau đó, tôi có một VertexFormatManager tạo / hủy các bố cục đó khi tôi cần chúng. Vì vậy, khi tôi cần tạo một cái, tôi cung cấp mã byte shader và ID vertexformat cho người quản lý và nó tạo nó cho tôi và lưu trữ nó trong một nhóm để bạn chỉ có một trong mỗi bố cục. Sau đó, bạn cần phải tạo hình học của bạn. Để làm điều này, tôi có một phương thức Tạo trên lớp hình học của mình, lấy ID cho định dạng đỉnh. Trong hàm tạo, nó truy vấn trình quản lý định dạng đỉnh với ID đã cho. Trình quản lý trả về một số nguyên đóng vai trò là bitfield với một cờ được đặt cho mọi loại phần tử mà bố cục đầu vào chứa. Vì vậy, tôi có thể có một cái gì đó như thế này:

int bitfield = VertexFormatManager::QueryFormat( formatID );
if (bitfield & VertexFormat::NORMAL)
{
    // do somethings
}
if (bitfield & VertexFormat::UV)
{
    // do somethings
}
...

Mỗi thành phần bố trí đầu vào được tạo thành một ID3D11Buffer riêng. Điều đó cho phép tôi xây dựng một lưới cho bất kỳ loại định dạng đỉnh. Giả sử bạn muốn kết xuất một khối lập phương có kết cấu, nó cần các vị trí đỉnh và hợp âm uv. Bạn cung cấp cho nó định dạng ID định dạng VertexPocationUV (làm ví dụ) và truy vấn trả về một bitfield chứa các bit được đặt cho các cờ POSATION và UV. Điều đó tạo ra hai ID3D11Buffers: một cho các vị trí, một cho các hợp âm uv. Sau đó, bạn gắn cả hai thứ này vào đường ống trước khi vẽ. Ưu điểm của việc này là nếu bạn muốn làm một cái gì đó như bản đồ bóng, bạn có thể kết xuất một lưới chỉ với bộ đệm vị trí đỉnh của nó.

Tôi không chắc chắn nhiều về điều này rất rõ ràng, tôi đang làm việc và tôi sẽ cố gắng viết một bài đúng vào tối nay. Trong lúc này, tôi đã hỏi câu hỏi này một lúc trước và nhận được câu trả lời này . Điều đó tốt, nhưng tôi thấy rằng cách tôi đang làm bây giờ có ý nghĩa hơn, đặc biệt là trong trường hợp của DX11.


Điều này rất có ý nghĩa, cảm ơn bạn đã trả lời toàn diện ... Vì vậy, bạn sử dụng nhiều bộ đệm đỉnh cho mỗi lệnh vẽ?
JohnB

Có, tôi sử dụng trên bộ đệm cho từng thành phần (vị trí, quy tắc, uv ...), nó hữu ích tùy thuộc vào loại kết xuất và có thể khá linh hoạt. Đây chắc chắn không phải là cách duy nhất để làm điều đó, nhưng nó hoạt động tốt cho hầu hết các thói quen kết xuất IMHO. Tôi đã thêm một chút chi tiết và mã giả ở đây: pastebin.com/XfqS6N7g Hy vọng nó sẽ giúp.
dotminic

6

Cảm ơn câu trả lời về điều này, chúng rất hữu ích. Tôi sẽ thêm một câu trả lời cho câu hỏi của riêng mình vì tôi đã chuyển một chút từ đó.

Cuối cùng, tôi nhận ra rằng có lẽ muốn tách hoàn toàn các shader khỏi các vật phẩm có thể rút được là một sai lầm. Chúng được kết hợp một cách cơ bản trong "đời thực" nên có lẽ không có vấn đề gì trong thiết kế.

Ví dụ, một shader nước sẽ chỉ hoạt động với một yếu tố muốn hút nước. Chỉ có điều đó mới có thể cung cấp dữ liệu cần thiết. Một shader vẽ mô hình hoạt hình sẽ chỉ hoạt động với một yếu tố mô hình hoạt hình. Tôi không thể đột nhiên quyết định sử dụng một shader nước với một mô hình hoạt hình. Nó chỉ đơn giản là không thể làm việc.

Cố gắng tạo một lớp shader trừu tượng có thể tải bất kỳ shader nào và làm việc với bất kỳ phần tử có thể vẽ nào là một sai lầm. Nó không phản ánh làm thế nào chúng có thể được sử dụng trong thực tế.

Vì vậy, thay vào đó tôi đã tạo các lớp shader AnimatedModelShader, WaterShader, ScenShader. Mỗi trong số này có thể có các tùy chọn khiến nó tải các tệp shader vật lý khác nhau nhưng chúng sẽ luôn có cùng một giao diện cơ bản bởi vì một shader phong cảnh sẽ luôn cần cùng một kiểu nhập dữ liệu.

Vì vậy, trình đổ bóng hiện chịu trách nhiệm tạo bố cục đầu vào của chính nó và nó cho phần tử sử dụng nó cách bố trí các đỉnh của nó bằng cách sử dụng một typedef công khai gọi là vertexType mà phần tử sử dụng nếu nó muốn sử dụng trình đổ bóng đó.

Hoàn toàn không phải là thiết kế ban đầu của tôi, nhưng hóa ra, mong muốn tách hai khái niệm này dù sao cũng không hữu ích lắm.


3

Tôi làm một cái gì đó tương tự như dotminic - Tôi có một thói quen là tôi truyền một mảng D3D11_INPUT_ELEMENT_DESC, sau đó xây dựng một shader đỉnh giả với một chữ ký đầu vào phù hợp, biên dịch nó, tạo ra một bố cục từ nó, cuối cùng phát hành shader giả.

Vâng, nó xấu, và vâng, điều đó có nghĩa là cần phải cẩn thận hơn tôi nếu tôi làm theo cách đúng đắn, nhưng chúng là sự đánh đổi mà tôi hiện đang chuẩn bị để chấp nhận đổi lấy một sự tách biệt sạch hơn.


Chỉ cần lưu ý rằng bây giờ tôi đã chuyển khỏi cách tiếp cận này và hướng tới việc kết hợp chặt chẽ hơn các Bố cục đầu vào và Trình tạo bóng Vertex, để mở rộng luôn tạo chúng cùng nhau. Cách tiếp cận tôi đưa ra ở đây có lẽ vẫn ổn nếu bạn thực sự muốn tách chúng ra.
Maximus Minimus

2

Có vẻ như tôi thực sự không cần phải lo lắng. Sau khi liếc qua tài liệu MSDN cho CreatInputLayout, tôi đã xem qua:

Khi một đối tượng bố trí đầu vào được tạo từ chữ ký shader, đối tượng bố trí đầu vào có thể được sử dụng lại với bất kỳ shader nào khác có chữ ký đầu vào giống hệt nhau (bao gồm ngữ nghĩa). Điều này có thể đơn giản hóa việc tạo các đối tượng bố trí đầu vào khi bạn đang làm việc với nhiều shader có đầu vào giống hệt nhau. (Bingo) Nếu một kiểu dữ liệu trong khai báo bố cục đầu vào không khớp với kiểu dữ liệu trong chữ ký đầu vào shader, thì CreatInputLayout sẽ tạo cảnh báo trong quá trình biên dịch. Cảnh báo chỉ đơn giản là gọi sự chú ý đến thực tế là dữ liệu có thể được giải thích lại khi đọc từ một thanh ghi. Bạn có thể bỏ qua cảnh báo này (nếu diễn giải lại là cố ý) hoặc làm cho các kiểu dữ liệu khớp với cả hai khai báo để loại bỏ cảnh báo.

http://msdn.microsoft.com/en-gb/l Library / windows / desktop / ff476512 (v = vs85) .aspx

Điều này cho thấy khá rõ rằng bạn sẽ có thể xử lý các bố cục đầu vào của mình theo cách gần như chính xác như các khai báo đỉnh DX9 cũ của bạn. Việc cung cấp mã byte shader trong lần đầu tiên bạn tạo từng cái trong số chúng chỉ cho phép DX11 xác thực chúng. Và rõ ràng điều tồi tệ nhất sẽ xảy ra nếu bạn tránh hoặc thất bại bước này là một cảnh báo thời gian chạy có vẻ an toàn để bỏ qua.

Vì vậy, DX11 không "tạo ra sự phụ thuộc" giữa bố cục đầu vào và trình đổ bóng của bạn ... nó cung cấp xác nhận miễn phí! : D


CreateInputLayoutcũng có thể được sử dụng để xác thực trình đổ bóng theo bố cục đầu vào hiện có, vì vậy bạn có thể kiểm tra tất cả các trình tạo bóng sẽ sử dụng nó - mà tôi khuyên bạn nên làm, ít nhất là trong các bản dựng gỡ lỗi, để đảm bảo an toàn.
Nathan Reed

Hmm, khi tôi thử điều này, tôi thấy rằng việc cung cấp bố cục đầu vào hiện tại làm tham số sẽ chỉ khiến con trỏ cũ bị ghi đè, dẫn đến rò rỉ bộ nhớ. Xấu hổ vì không có chức năng 'Xác thực' riêng biệt.
Richard Copperwaite

Xin lỗi, bởi "một bố cục đầu vào hiện có" Tôi thực sự có nghĩa là mảng D3D11_INPUT_ELEMENT_DESCs được sử dụng để tạo ra nó. Điều đó có thể được xác nhận đối với mã byte của shader khác mà không tạo đối tượng bố cục đầu vào mới.
Nathan Reed
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.