Làm cách nào tôi có thể triển khai trình kết xuất có thể vẽ nhiều loại nguyên thủy?


8

Điều này phần nào được liên kết với một câu hỏi mà tôi đã hỏi trước đây liên quan đến bản vẽ của các nguyên thủy được lập chỉ mục .

Vấn đề của tôi là tôi chỉ vẽ một khối khi tôi muốn vẽ nhiều hình. Tôi được cho biết rằng vấn đề là tôi đã ghi đè lên bộ đệm đỉnh và chỉ mục với mỗi lần khởi tạo mới Cubevà thay vào đó tôi nên tạo một cái ở gốc và sau đó vẽ nhiều, chuyển qua ma trận biến đổi sang shader khiến nó xuất hiện khác nhau nơi. Điều này làm việc rất đẹp.

Bây giờ tôi có một vấn đề mới: làm thế nào tôi có thể vẽ nhiều loại nguyên thủy khác nhau?

Đây là mã của tôi từ câu hỏi trước:

Cube::Cube(D3DXCOLOR colour, D3DXVECTOR3 min, D3DXVECTOR3 max)
{
// create eight vertices to represent the corners of the cube
VERTEX OurVertices[] =
{
    {D3DXVECTOR3(min.x, max.y, max.z), colour},
    {D3DXVECTOR3(min.x, max.y, min.z), colour},
    {D3DXVECTOR3(min.x, min.y, max.z), colour},
    {min, colour},
    {max, colour},
    {D3DXVECTOR3(max.x, max.y, min.z), colour},
    {D3DXVECTOR3(max.x, min.y, max.z), colour},
    {D3DXVECTOR3(max.x, min.y, min.z), colour},
};

// create the vertex buffer
D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(VERTEX) * 8;
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;

device->CreateBuffer(&bd, NULL, &pBuffer);

void* pVoid;    // the void pointer

pBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid);    // map the vertex buffer
memcpy(pVoid, OurVertices, sizeof(OurVertices));    // copy the vertices to the buffer
pBuffer->Unmap();

// create the index buffer out of DWORDs
DWORD OurIndices[] = 
{
    0, 1, 2,    // side 1
    2, 1, 3,
    4, 0, 6,    // side 2
    6, 0, 2,
    7, 5, 6,    // side 3
    6, 5, 4,
    3, 1, 7,    // side 4
    7, 1, 5,
    4, 5, 0,    // side 5
    0, 5, 1,
    3, 7, 2,    // side 6
    2, 7, 6,
};

// create the index buffer
// D3D10_BUFFER_DESC bd;    // redefinition
bd.Usage = D3D10_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(DWORD) * 36;
bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;

device->CreateBuffer(&bd, NULL, &iBuffer);

iBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid);    // map the index buffer
memcpy(pVoid, OurIndices, sizeof(OurIndices));    // copy the indices to the buffer
iBuffer->Unmap();

//this is simply a single call to the update method that sets up the scale, rotation
//and translation matrices, in case the cubes are static and you don't want to have to 
//call update every frame
Update(D3DXVECTOR3(1, 1, 1), D3DXVECTOR3(0, 0, 0), D3DXVECTOR3(0, 0, 0));
}

Rõ ràng nếu tôi sao chép và sửa đổi mã thành một đối tượng hoặc hình dạng khác, hình dạng cuối cùng được khởi tạo sẽ ghi đè lên bộ đệm đỉnh, phải không?

Tôi có sử dụng nhiều bộ đệm đỉnh không? Tôi có nối thêm bộ đệm đỉnh mới vào cái cũ và sử dụng các chỉ số thích hợp để vẽ chúng không? Tôi có thể làm được không? Cả hai?

Câu trả lời:


12

Có lẽ là một ý tưởng tồi để tạo các lớp mới cho từng loại hình học mà bạn sẽ hỗ trợ. Nó không phải là rất có thể mở rộng hoặc duy trì. Ngoài ra, thiết kế lớp mà bạn dường như muốn bây giờ dường như kết hợp các nhiệm vụ quản lý chính hình học và dữ liệu cá thể cho hình dạng đó.

Đây là một cách tiếp cận bạn có thể thực hiện:

Tạo hai lớp MeshMeshInstance. A Meshchứa tất cả các thuộc tính của hình học được chia sẻ - về cơ bản là bộ đệm đỉnh và bộ đệm chỉ mục. Nếu bạn muốn, bạn có thể tạo các hàm trợ giúp tạo các lưới chứa dữ liệu đỉnh khối (hoặc dữ liệu đỉnh hình cầu hoặc bất cứ thứ gì bạn thích). Bạn nên điều chỉnh giao diện chung của Meshlớp để cho phép các hàm trợ giúp như vậy được triển khai dưới dạng các hàm không phải là thành viên, không phải là bạn bè.

MeshInstancemặt khác, phải được xây dựng với tham chiếu đến a Mesh. Nó MeshInstancechứa các thuộc tính của một đối tượng riêng lẻ - đó là biến đổi thế giới và shader ghi đè được sử dụng để kết xuất nó, v.v.

Theo cách này, khi bạn muốn tạo một khối mới, trước tiên bạn phải lấy Meshđối tượng đại diện cho một khối từ một thư viện chia sẻ các đối tượng lưới nguyên thủy mà bạn đã tạo khi khởi động. Sau đó, bạn tạo một cái mới MeshInstance, gán nó khối đó Mesh.

Khi bạn kết xuất, bạn xây dựng một danh sách tất cả những MeshInstancegì bạn muốn vẽ và gửi chúng. Nếu bạn nhóm chúng theo Meshhoặc kết cấu, bạn có thể tối ưu hóa chi phí thay đổi trạng thái (nghĩa là bạn vẽ tất cả các trường hợp lưới tương ứng với lưới khối lập phương, và sau đó tất cả các trường hợp lưới tương ứng với lưới hình cầu, do đó bạn có ít SetVertexBuffercuộc gọi hơn thiết bị D3D). Bạn cũng có thể nhóm theo trạng thái khác, như kết cấu và đổ bóng.

Theo cách này, bạn tránh lãng phí bộ nhớ sao chép dữ liệu đỉnh và bạn đảm bảo rằng hệ thống kết xuất của bạn có thể mở rộng thành bất kỳ tập hợp nguyên thủy tùy ý nào bằng cách thực hiện các hàm (a) mới để tạo các mắt lưới theo chương trình hoặc (b) để tải lưới từ các tệp của một định dạng cụ thể.

Khi đường ống kết xuất của bạn hoạt động theo các Meshđối tượng tổng quát , việc điều chỉnh nó theo kiểu toàn cầu theo các kỹ thuật mới hoặc tối ưu hóa sẽ dễ dàng hơn nhiều.

Nhận xét cụ thể:

Rõ ràng nếu tôi sao chép và sửa đổi mã thành một đối tượng hoặc hình dạng khác, hình dạng cuối cùng được khởi tạo sẽ ghi đè lên bộ đệm đỉnh. phải không

Không. Trong mã bạn đã đăng, cách duy nhất pBuffervà tương tự sẽ được ghi đè là nếu đó là biến thành viên tĩnh. Nếu bạn đã sao chép lớp bán buôn để tạo (ví dụ) một Spherelớp, đó sẽ là một biến tĩnh mới. Đây vẫn là một ý tưởng tồi.

Tôi có sử dụng nhiều bộ đệm đỉnh không? Tôi có nối thêm bộ đệm đỉnh mới vào cái cũ và sử dụng các chỉ số thích hợp để vẽ chúng không? Tôi có thể làm được không? Cả hai?

Việc triển khai ngây thơ của kỹ thuật tôi mô tả ở trên bao gồm nhiều bộ đệm (một cho mỗi bộ hình học được chia sẻ). Nếu hình học đó là tĩnh, có thể lưu trữ tất cả thành một (hoặc nhiều, vì có giới hạn tối ưu thực tế đối với kích thước bộ đệm) để giảm thiểu thay đổi trạng thái bộ đệm hơn nữa. Điều đó nên được coi là một tối ưu hóa và được để lại như một bài tập cho người đọc; đầu tiên làm cho nó hoạt động, sau đó lo lắng về việc làm cho nó nhanh chóng.


Tôi biết chúng tôi không nên đăng bình luận 'cảm ơn', nhưng điều này rất hữu ích! Cảm ơn bạn!
SirYakalot

tại thời điểm pBuffer và iBuffer đang ở bên ngoài. Tôi có nên tạo các thành viên thể hiện của từng đối tượng Lưới không?
SirYakalot

1
Vâng, đó là một nơi tốt để bắt đầu.

Bây giờ tôi đến để thực hiện điều này, tôi gặp một chút khó khăn khi nghĩ về cách thực hiện, chỉ là phần bạn nói "Nếu bạn muốn, bạn có thể tạo các hàm trợ giúp tạo lưới chứa dữ liệu đỉnh khối (hoặc dữ liệu đỉnh hình cầu, hoặc bất cứ điều gì khác mà bạn thích). Bạn nên điều chỉnh giao diện chung của lớp Lưới để cho phép các hàm trợ giúp đó được triển khai như các hàm không phải là thành viên, không phải là bạn bè. " chính xác ý bạn là gì bởi các chức năng không phải là người trợ giúp, không phải là bạn bè?
SirYakalot

Một hàm không phải là thành viên của lớp (vì vậy là hàm toàn cục) cũng không được khai báo là bạn của lớp. Nói cách khác, một hàm "thông thường" - thao tác đối tượng lưới chỉ thông qua API công khai của nó.
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.