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ó:
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 đạ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ở.
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:
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;
}