Làm thế nào để kết cấu ảo thực sự có hiệu quả?


27

Để tham khảo, cái mà tôi đang đề cập đến là "tên chung" cho kỹ thuật đầu tiên (tôi tin) được giới thiệu với công nghệ MegaTexture của idTech 5 . Xem video ở đây để xem nhanh về cách thức hoạt động.

Gần đây tôi đã đọc lướt qua một số bài báo và ấn phẩm liên quan đến nó và điều tôi không hiểu là làm thế nào nó có thể hiệu quả. Nó không yêu cầu tính toán lại tọa độ UV liên tục từ không gian "trang kết cấu toàn cầu" vào tọa độ kết cấu ảo? Và làm thế nào mà không hạn chế hầu hết các nỗ lực trong việc tạo khối hình học hoàn toàn? Làm thế nào nó có thể cho phép phóng to tùy ý? Tại một số điểm, có yêu cầu chia đa giác không?

Có quá nhiều điều tôi không hiểu, và tôi đã không thể tìm thấy bất kỳ tài nguyên thực sự dễ tiếp cận nào về chủ đề này.

Câu trả lời:


20

Tổng quan

Lý do chính cho Hoạ tiết ảo (VT), hoặc Hoạ tiết ảo thưa thớt , như đôi khi được gọi, là như một tối ưu hóa bộ nhớ. Ý chính của điều này là chỉ di chuyển vào bộ nhớ video các texels thực tế (được khái quát là các trang / ô) mà bạn có thể cần cho một khung hình được hiển thị. Vì vậy, nó sẽ cho phép bạn có nhiều dữ liệu kết cấu hơn trong lưu trữ ngoại tuyến hoặc chậm (HDD, Đĩa quang, Đám mây) so với cách khác phù hợp với bộ nhớ video hoặc thậm chí là bộ nhớ chính. Nếu bạn hiểu khái niệm về Bộ nhớ ảo được sử dụng bởi các Hệ điều hành hiện đại, thì đó là điều tương tự về bản chất của nó (tên không được đặt ngẫu nhiên).

VT không yêu cầu tính toán lại UV theo nghĩa là bạn sẽ thực hiện từng khung hình trước khi kết xuất lưới, sau đó gửi lại dữ liệu đỉnh, nhưng nó yêu cầu một số công việc đáng kể trong các trình tạo bóng Vertex và Fragment để thực hiện tra cứu gián tiếp từ các UV đến. Tuy nhiên, trong một triển khai tốt, nó phải hoàn toàn trong suốt cho ứng dụng nếu nó đang sử dụng một kết cấu ảo hoặc một kết cấu truyền thống. Trên thực tế, hầu hết thời gian một ứng dụng sẽ pha trộn cả hai loại kết cấu, ảo và truyền thống.

Batching trong lý thuyết có thể hoạt động rất tốt, mặc dù tôi chưa bao giờ xem xét chi tiết về điều này. Vì các tiêu chí thông thường để phân nhóm hình học là kết cấu và với VT, mọi đa giác trong cảnh có thể chia sẻ cùng một kết cấu "vô cùng lớn", theo lý thuyết, bạn có thể đạt được bản vẽ toàn cảnh với 1 cuộc gọi vẽ. Nhưng trong thực tế, các yếu tố khác đi vào làm cho điều này không thực tế.

Các vấn đề với VT

Phóng to / thu nhỏ và di chuyển camera đột ngột là những điều khó xử lý nhất trong thiết lập VT. Nó có thể trông rất hấp dẫn đối với một cảnh tĩnh, nhưng một khi mọi thứ bắt đầu di chuyển, nhiều trang / gạch kết cấu sẽ được yêu cầu hơn là bạn có thể phát trực tuyến cho bộ nhớ ngoài. Tập tin Async và phân luồng có thể giúp ích, nhưng nếu đó là một hệ thống thời gian thực, như trong trò chơi, bạn sẽ chỉ phải kết xuất một vài khung hình với các ô có độ phân giải thấp hơn cho đến khi các độ phân giải cao đến, mọi lúc mọi nơi , dẫn đến một kết cấu mờ. Không có viên đạn bạc nào ở đây và đó là vấn đề lớn nhất với kỹ thuật này, IMO.

Kết cấu ảo cũng không xử lý độ trong suốt một cách dễ dàng, vì vậy đa giác trong suốt cần một đường dẫn hiển thị truyền thống riêng cho chúng.

Nói chung, VT rất thú vị, nhưng tôi sẽ không giới thiệu nó cho mọi người. Nó có thể hoạt động tốt, nhưng rất khó để thực hiện và tối ưu hóa, cộng với chỉ có quá nhiều trường hợp góc và các điều chỉnh cụ thể theo từng trường hợp cần thiết cho sở thích của tôi. Nhưng đối với các trò chơi thế giới mở hoặc ứng dụng trực quan hóa dữ liệu, nó có thể là cách tiếp cận khả thi duy nhất để phù hợp với tất cả nội dung vào phần cứng có sẵn. Với rất nhiều công việc, nó có thể được thực hiện để chạy khá hiệu quả ngay cả trên phần cứng hạn chế, như chúng ta có thể nhìn thấy trong PS3 và XBOX360 phiên bản của id của Rage .

Thực hiện

Tôi đã quản lý để khiến VT hoạt động trên iOS với OpenGL-ES, ở một mức độ nhất định. Việc triển khai của tôi không phải là "có thể chuyển được", nhưng tôi có thể hình dung ra nó như vậy nếu tôi muốn và có tài nguyên. Bạn có thể xem mã nguồn ở đây , nó có thể giúp hiểu rõ hơn về cách các mảnh khớp với nhau. Đây là video giới thiệu chạy trên Sim iOS. Nó trông rất lag vì trình giả lập rất tệ trong việc mô phỏng các shader, nhưng nó chạy rất mượt trên thiết bị.

Sơ đồ sau đây phác thảo các thành phần chính của hệ thống trong quá trình thực hiện của tôi. Nó khác một chút so với bản demo SVT của Sean (liên kết xuống dưới), nhưng nó gần hơn với kiến ​​trúc được trình bày bởi bài báo Tăng tốc kết cấu ảo bằng CUDA , được tìm thấy trong cuốn sách GPU Pro đầu tiên (dưới đây liên kết).

hệ thống kết cấu ảo

  • Page Fileslà các kết cấu ảo, đã được cắt thành các ô (trang AKA) như một bước tiền xử lý, vì vậy chúng sẵn sàng được chuyển từ đĩa vào bộ nhớ video bất cứ khi nào cần. Một tệp trang cũng chứa toàn bộ tập hợp mipmap, còn được gọi là mipmap ảo .

  • Page Cache Managergiữ một đại diện phía ứng dụng của Page TablePage Indirectionkết cấu. Vì việc chuyển một trang từ bộ nhớ ngoại tuyến sang bộ nhớ rất tốn kém, chúng tôi cần một bộ đệm để tránh tải lại những gì đã có sẵn. Bộ đệm này là bộ đệm Least Recent used (LRU) rất đơn giản . Bộ đệm cũng là thành phần chịu trách nhiệm giữ cho các kết cấu vật lý được cập nhật với biểu diễn dữ liệu cục bộ của chính nó.

  • Các Page Providerlà một hàng đợi công việc async rằng sẽ tìm nạp các trang cần thiết cho một cái nhìn nhất định hiện trường và gửi chúng vào bộ nhớ cache.

  • Kết Page Indirectioncấu là một kết cấu với một pixel cho mỗi trang / ô trong kết cấu ảo, sẽ ánh xạ các Page Tabletia cực tím tới kết cấu bộ đệm có dữ liệu texel thực tế. Kết cấu này có thể khá lớn, do đó nó phải sử dụng một số định dạng nhỏ gọn, như RGBA 8: 8: 8: 8 hoặc RGB 5: 6: 5.

Nhưng chúng tôi vẫn còn thiếu một phần quan trọng ở đây và đó là cách xác định trang nào phải được tải từ bộ nhớ vào bộ đệm và do đó vào Page Table. Đó là nơi Phản hồi vượt quaPage Resolvernhập.

Feedback Pass là phần kết xuất trước của chế độ xem, với trình đổ bóng tùy chỉnh và ở độ phân giải thấp hơn nhiều, sẽ ghi id của các trang cần thiết vào bộ đệm khung màu. Sự chắp vá đầy màu sắc của khối lập phương và hình cầu ở trên là các chỉ mục trang thực tế được mã hóa dưới dạng màu RGBA. Kết xuất trước vượt qua này sau đó được đọc vào bộ nhớ chính và được xử lý bằng cách Page Resolvergiải mã các chỉ mục trang và thực hiện các yêu cầu mới với Page Provider.

Sau khi thông qua Phản hồi trước, cảnh có thể được hiển thị bình thường với các bóng đổ tra cứu VT. Nhưng lưu ý rằng chúng tôi không đợi yêu cầu trang mới kết thúc, điều đó thật tồi tệ, vì chúng tôi chỉ đơn giản chặn trên tệp đồng bộ IO. Các yêu cầu không đồng bộ và có thể hoặc có thể không sẵn sàng vào thời điểm chế độ xem cuối cùng được hiển thị. Nếu chúng đã sẵn sàng, ngọt ngào, nhưng nếu không, chúng ta luôn giữ một trang bị khóa của mipmap độ phân giải thấp trong bộ đệm như một dự phòng, vì vậy chúng ta có một số dữ liệu kết cấu trong đó để sử dụng, nhưng nó sẽ bị mờ.

Các tài nguyên khác đáng để kiểm tra

VT vẫn là một chủ đề hơi nóng trên Đồ họa máy tính, vì vậy có rất nhiều tài liệu tốt có sẵn, bạn sẽ có thể tìm thấy nhiều hơn nữa. Nếu có bất cứ điều gì khác tôi có thể thêm vào câu trả lời này, xin vui lòng hỏi. Tôi hơi khó hiểu về chủ đề này, đã không đọc nhiều về nó trong năm qua, nhưng nó rất tốt cho bộ nhớ để xem lại nội dung :)


Hey, cảm ơn bạn đã trả lời tuyệt vời. Tôi biết điều này thường gây khó chịu, nhưng tôi có nhiều vấn đề khác nhau, vì vậy tôi chủ yếu chỉ lướt qua mọi thứ - để có cái nhìn tổng quan trực quan về các chủ đề cho tương lai (Tôi sợ việc học và thực hiện đúng cách là ngoài tầm với ) - dù sao đi nữa, nếu có thể, bạn có thể đăng một ví dụ mã giả phác thảo chính quá trình, lý tưởng, nhưng không nhất thiết, được minh họa?
Llamageddon

1
@Llamageddon, thật sự xảy ra là tôi vẫn có một sơ đồ trong tay;) Tôi sợ mã giả sẽ hơi khó cung cấp, vì có khá nhiều mã thực cho nó. Nhưng tôi hy vọng câu trả lời mở rộng sẽ giúp đưa ra ý tưởng chung về kỹ thuật này.
glampert

3
Điều đáng chú ý là hầu hết các phần cứng hiện đại hiện nay đều phơi bày các bảng trang có thể lập trình, loại bỏ sự cần thiết phải có kết cấu chuyển hướng. Điều này được thể hiện thông qua ví dụ tài nguyên dành riêng directx12 , được xây dựng trên tài nguyên được lát gạch directx11 hoặc OpenGL thưa thớt textures .
MooseBoys

1
@Llamageddon, việc vượt qua phản hồi có thể được thực hiện ở độ phân giải thấp hơn để tiết kiệm càng nhiều máy tính và bộ nhớ càng tốt, vì các pixel cho một trang thường sẽ lặp lại (bạn có thể nhận thấy các ô vuông màu lớn trong bản demo của tôi). Bạn đã đúng rằng cuối cùng nó có thể bỏ lỡ một trang hiển thị như vậy, nhưng điều đó thường sẽ không có tác động trực quan lớn vì hệ thống phải luôn giữ ít nhất mipmap thấp nhất của toàn bộ VT có sẵn trong bộ đệm. Bài báo thứ hai mà tôi liên kết có tất cả các ví dụ về shader trong phần phụ lục, bạn cũng có thể tham khảo repo cho dự án của riêng tôi, chúng tương tự nhau.
glampert

1
@glampert Ahh, tôi hiểu rồi; Điều đó có ý nghĩa. Tuy nhiên, tôi nghĩ rằng có rất nhiều lựa chọn để xử lý trong suốt; trong thẻ ID trang, bạn có thể hòa sắc (vì vậy biểu đồ sẽ nhìn thấy tất cả các trang, trừ khi có một số lượng lớn các lớp trong suốt) hoặc sử dụng phương pháp đệm k , hoặc thậm chí chỉ là cư trú kết cấu trong suốt trên các đối tượng gần máy ảnh (trái ngược với hiển thị chúng trong một thông tin phản hồi).
Nathan Reed

11

Kết cấu ảo là cực kỳ logic của các kết cấu.


Một tập bản đồ kết cấu là một kết cấu khổng lồ duy nhất chứa kết cấu cho các mắt lưới riêng lẻ bên trong nó:

Ví dụ về kết cấu Atlas

Kết cấu nền đã trở nên phổ biến do thực tế là việc thay đổi kết cấu gây ra hiện tượng tràn đường ống trên GPU. Khi tạo các mắt lưới, các tia cực tím được nén / dịch chuyển sao cho chúng thể hiện đúng 'phần' của toàn bộ bản đồ kết cấu.

Như @ nathan-reed đã đề cập trong các bình luận, một trong những nhược điểm chính của các bản đồ họa tiết là mất các chế độ quấn như lặp lại, kẹp, viền, v.v. Ngoài ra, nếu họa tiết không có đủ viền xung quanh chúng, bạn có thể vô tình mẫu từ một kết cấu liền kề khi thực hiện lọc. Điều này có thể dẫn đến hiện vật chảy máu.

Kết cấu Atlaza có một hạn chế chính: kích thước. API đồ họa đặt giới hạn mềm cho mức độ lớn của kết cấu. Điều đó nói rằng, bộ nhớ đồ họa chỉ là rất lớn. Vì vậy, cũng có một giới hạn cứng về kích thước kết cấu, được đưa ra bởi kích thước của v-ram của bạn. Hoạ tiết ảo giải quyết vấn đề này, bằng cách mượn các khái niệm từ bộ nhớ ảo .

Hoạ tiết ảo khai thác thực tế là trong hầu hết các cảnh, bạn chỉ thấy một phần nhỏ của tất cả các kết cấu. Vì vậy, chỉ có tập hợp con của kết cấu cần phải có trong vram. Phần còn lại có thể là trong RAM chính, hoặc trên đĩa.

Có một vài cách để thực hiện nó, nhưng tôi sẽ giải thích việc thực hiện được mô tả bởi Sean Barrett trong bài nói chuyện về GDC của mình . (mà tôi rất khuyên bạn nên xem)

Chúng tôi có ba yếu tố chính: kết cấu ảo, kết cấu vật lý và bảng tra cứu.

Kết cấu ảo

Kết cấu ảo đại diện cho tập bản đồ lý thuyết lớn mà chúng ta sẽ có nếu chúng ta có đủ vram để phù hợp với mọi thứ. Nó không thực sự tồn tại trong bộ nhớ ở bất cứ đâu. Kết cấu vật lý đại diện cho dữ liệu pixel mà chúng ta thực sự có trong vram. Bảng tra cứu là ánh xạ giữa hai. Để thuận tiện, chúng tôi chia cả ba yếu tố thành các ô có kích thước bằng nhau hoặc các trang.

Bảng tra cứu lưu trữ vị trí của góc trên cùng bên trái của lát trong kết cấu vật lý. Vì vậy, với một tia cực tím cho toàn bộ kết cấu ảo, làm thế nào để chúng ta có được tia UV tương ứng cho kết cấu vật lý?

Đầu tiên, chúng ta cần tìm vị trí của trang trong kết cấu vật lý. Sau đó, chúng ta cần tính toán vị trí của tia cực tím trong trang. Cuối cùng, chúng ta có thể thêm hai độ lệch này lại với nhau để có được vị trí của tia cực tím trong kết cấu vật lý

float2 pageLocInPhysicalTex = ...
float2 inPageLocation = ...
float2 physicalTexUV = pageLocationInPhysicalTex + inPageLocation;


Tính toán trangLocInPhysicalTex

Nếu chúng ta tạo bảng tra cứu có cùng kích thước với số ô trong kết cấu ảo, chúng ta có thể lấy mẫu bảng tra cứu với mẫu hàng xóm gần nhất và chúng ta sẽ có được vị trí của góc trên cùng bên trái của trang trong kết cấu vật lý.

float2 pageLocInPhysicalTex = lookupTable.Sample(virtTexUV, nearestNeighborSampler);


Tính toán inPageLocation

inPageLocation là tọa độ UV tương đối ở phía trên bên trái của trang, thay vì ở phía trên bên trái của toàn bộ kết cấu.

Một cách để tính toán điều này là bằng cách trừ đi tia cực tím ở phía trên bên trái của trang, sau đó thu nhỏ theo kích thước của trang. Tuy nhiên, đây là một chút toán học. Thay vào đó, chúng ta có thể khai thác cách biểu diễn dấu phẩy động của IEEE. Điểm nổi của IEEE lưu trữ phần phân số của một số bằng một chuỗi 2 phân số cơ sở.

nhập mô tả hình ảnh ở đây

Trong ví dụ này, số là:

number = 0 + (1/2) + (1/8) + (1/16) = 0.6875

Bây giờ hãy xem xét một phiên bản đơn giản hóa của kết cấu ảo:

Kết cấu ảo đơn giản

1/2 bit cho chúng ta biết nếu chúng ta ở nửa bên trái của kết cấu hoặc bên phải. 1/4 bit cho chúng ta biết một phần tư của một nửa chúng ta đang ở đâu. Trong ví dụ này, do kết cấu được chia thành 16 hoặc 4 cho một bên, hai bit đầu tiên này cho chúng ta biết chúng ta đang ở trang nào. Phần còn lại bit cho chúng tôi biết vị trí bên trong trang.

Chúng ta có thể lấy các bit còn lại bằng cách dịch chuyển float với exp2 () và tước chúng ra bằng fract ()

float2 inPageLocation = virtTexUV * exp2(sqrt(numTiles));
inPageLocation = fract(inPageLocation);

Trong đó numTiles là một int2 cho số lượng gạch trên mỗi mặt của kết cấu. Trong ví dụ của chúng tôi, điều này sẽ là (4, 4)

Vì vậy, hãy tính inPageLocation cho điểm xanh, (x, y) = (0,6875, 0,375)

inPageLocation = float2(0.6875, 0.375) * exp2(sqrt(int2(4, 4));
               = float2(0.6875, 0.375) * int2(2, 2);
               = float2(1.375, 0.75);

inPageLocation = fract(float2(1.375, 0.75));
               = float2(0.375, 0.75);

Một điều cuối cùng phải làm trước khi chúng ta hoàn thành. Hiện tại, inPageLocation là tọa độ UV trong kết cấu ảo 'không gian'. Tuy nhiên, chúng tôi muốn tọa độ UV trong kết cấu vật lý 'không gian'. Để làm điều này, chúng ta chỉ cần chia tỷ lệ inPageLocation theo tỷ lệ kích thước kết cấu ảo so với kích thước kết cấu vật lý

inPageLocation *= physicalTextureSize / virtualTextureSize;



Vậy hàm hoàn thành là:

float2 CalculatePhysicalTexUV(float2 virtTexUV, Texture2D<float2> lookupTable, uint2 physicalTexSize, uint2 virtualTexSize, uint2 numTiles) {
    float2 pageLocInPhysicalTex = lookupTable.Sample(virtTexUV, nearestNeighborSampler);

    float2 inPageLocation = virtTexUV * exp2(sqrt(numTiles));
    inPageLocation = fract(inPageLocation);
    inPageLocation *= physicalTexSize / virtualTexSize;

    return pageLocInPhysicalTex + inPageLocation;
}

Tôi không, tôi đang đề cập đến kết cấu ảo, được biết đến nhiều nhất là công nghệ MegaTexture của idTech 5 . Cũng thấy cái nàycái này . Tôi đã thấy nó được đề cập trong tổng quan về các đường ống kết xuất của nhiều động cơ hiện đại, và trong một vài bài báo sử dụng cách tiếp cận tương tự cho bóng tối. Nó có rất nhiều điểm chung với các bản đồ kết cấu, vâng, nó sử dụng chúng, theo một cách nào đó, nhưng tôi không nhầm lẫn nó với các bản đồ kết cấu.
Llamageddon

À Cảm ơn các liên kết. Bạn có thể thêm chúng vào câu hỏi Tôi sẽ cập nhật câu trả lời của mình cho phù hợp
RichieSams 2/12/2015

3
IMO, nhược điểm chính của các nền tảng kết cấu đơn giản (không phải kết cấu ảo) là bạn mất các chế độ quấn như lặp lại và kẹp, và chảy máu xảy ra do lọc / mipmapping - không chính xác điểm nổi. Tôi sẽ ngạc nhiên khi thấy độ chính xác của float trở thành một vấn đề đối với các kết cấu thông thường (không ảo); ngay cả một kết cấu 16K (mức tối đa được cho phép bởi các API hiện tại) không đủ lớn để thực sự làm căng độ chính xác.
Nathan Reed

@RichieSams Btw, tôi nghĩ rằng câu trả lời của bạn là một câu hỏi hay, ngay cả khi một câu hỏi khác. Bạn nên làm một bài hỏi đáp.
Llamageddon

Hmm, điều này giải thích nó khá tốt, mặc dù tôi không thực sự hiểu nó hoạt động như thế nào với các cấp độ mip. Tôi ước tôi có thể viết ra vấn đề cụ thể của mình bằng cách hiểu nó, nhưng nó giúp tôi hiểu được ...
Llamageddon
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.