Kết xuất hoàn hảo pixel thành một mục tiêu kết xuất với một màn hình toàn màn hình


9

Tôi gặp một số khó khăn khi hiển thị một loạt các giá trị cho mục tiêu kết xuất. Các giá trị không bao giờ kết thúc trong phạm vi chính xác mà tôi muốn. Về cơ bản, tôi sử dụng một quad toàn màn hình và một pixel shader để kết xuất với kết cấu renderertarget của tôi và sau đó có ý định sử dụng các tọa độ kết cấu làm cơ sở cho một số tính toán trong shader. Các tọa độ kết cấu của phạm vi quad từ (0,0) ở trên cùng bên trái đến (1,1) ở góc dưới bên phải ... vấn đề là, sau khi nội suy, các giá trị này không đến được bộ đổ bóng pixel như vậy .

Một ví dụ: Tôi kết xuất với kết cấu 4 x 4 và trình đổ bóng trong trường hợp này chỉ đơn giản là xuất ra tọa độ kết cấu (u, v) trong các kênh màu đỏ và màu xanh lá cây:

return float4(texCoord.rg, 0, 1);

Những gì tôi muốn nhận được từ nó là một kết cấu trong đó pixel ở phía trên bên trái là RGB (0,0,0) và do đó màu đen, pixel ở phía trên bên phải là RGB (255,0,0) và do đó sáng màu đỏ và pixel ở phía dưới bên trái là RGB (0,255,0) - màu xanh lá cây tươi sáng.

Tuy nhiên, thay vào đó tôi nhận được điều này ở bên phải:

(kết xuất quad thẳng, không hiệu chỉnh)
kết xuất thẳng của quad, không áp dụng hiệu chỉnh

Điểm ảnh trên cùng bên trái là màu đen, nhưng tôi chỉ nhận được màu đỏ và xanh đậm tương đối ở các góc khác. Giá trị RGB của chúng là (191,0,0) và (0,191,0). Tôi nghi ngờ rằng nó phải làm với các vị trí lấy mẫu của hình tứ giác: pixel trên cùng bên trái lấy mẫu chính xác góc trên cùng bên trái của hình tứ giác và lấy (0,0) làm tọa độ UV, nhưng các pixel góc khác không lấy mẫu từ các góc khác của tứ giác. Tôi đã minh họa điều này trong hình ảnh bên trái với hộp màu xanh tượng trưng cho hình tứ giác và các chấm trắng tọa độ lấy mẫu phía trên.

Bây giờ tôi đã biết về độ lệch nửa pixel mà bạn nên áp dụng cho tọa độ của mình khi hiển thị các góc được căn chỉnh theo màn hình trong Direct3D9. Chúng ta hãy xem loại kết quả tôi nhận được từ điều này:

(quad được hiển thị với độ lệch nửa pixel của DX9)
quad kết xuất với bù một nửa pixel

Màu đỏ và màu xanh lá cây đã sáng hơn nhưng vẫn không chính xác: 223 là mức tối đa tôi có được trên kênh màu đỏ hoặc xanh lục. Nhưng bây giờ, tôi thậm chí không còn màu đen thuần khiết nữa mà thay vào đó là màu xám đen, vàng nhạt với RGB (32,32,0)!

Những gì tôi thực sự cần sẽ là loại kết xuất này:

(kết xuất mục tiêu, giảm kích thước quad)
màu đen, xanh lá cây và đỏ thuần với nội suy chính xác

Có vẻ như tôi phải di chuyển bên phải và viền dưới của hình tứ giác của tôi chính xác một pixel lên và sang trái, so với hình đầu tiên. Sau đó, cột bên phải và hàng pixel dưới cùng sẽ nhận được chính xác tọa độ UV ngay từ đường viền của hình tứ giác:

VertexPositionTexture[] quad = new VertexPositionTexture[]
{
    new VertexPositionTexture(new Vector3(-1.0f,  1.0f, 1f), new Vector2(0,0)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X,  1.0f, 1f), new Vector2(1,0)),
    new VertexPositionTexture(new Vector3(-1.0f, -1.0f + pixelSize.Y, 1f), new Vector2(0,1)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X, -1.0f + pixelSize.Y, 1f), new Vector2(1,1)),
};

Tuy nhiên, điều này không thực sự hiệu quả và khiến các pixel phía dưới và bên phải hoàn toàn không hiển thị. Tôi cho rằng các trung tâm của các pixel này không còn được bao phủ bởi bộ tứ nữa và do đó sẽ không được xử lý bởi trình đổ bóng. Nếu tôi thay đổi phép tính pixelSize bằng một số lượng nhỏ để làm cho số lượng lớn hơn gấp bốn lần thì nó sẽ hoạt động ... ít nhất là trên kết cấu 4 x 4. Nó không hoạt động trên các kết cấu nhỏ hơn và tôi sợ nó làm biến dạng một cách tinh tế sự phân phối đồng đều các giá trị uv trên các kết cấu lớn hơn:

Vector2 pixelSize = new Vector2((2f / textureWidth) - 0.001f, (2f / textureHeight) - 0.001f);

(Tôi đã sửa đổi phép tính pixelSize bằng 0,001f - đối với các kết cấu nhỏ hơn, ví dụ: bảng tra cứu 1D, điều này không hoạt động và tôi phải tăng nó lên 0,01f hoặc một cái gì đó lớn hơn)

Tất nhiên đây là một ví dụ tầm thường và tôi có thể thực hiện phép tính này dễ dàng hơn nhiều trên CPU mà không phải lo lắng về việc ánh xạ tia cực tím đến các trung tâm pixel ... tuy nhiên, vẫn phải có một cách để thực sự hiển thị đầy đủ, hoàn chỉnh [0, 1] phạm vi đến pixel trên một mục tiêu kết xuất!?


Không phải là bất kỳ sự giúp đỡ nào, nhưng tôi đang có cùng một vấn đề.
IUsedToBeAPygmy

1
Đừng quên vô hiệu hóa lấy mẫu tuyến tính.
r2d2rigo

Nó không giống như hệ tọa độ mà bạn đang sử dụng khớp với các pixel của màn hình, nếu có, thì có vẻ như bạn chỉ đang vẽ 2 × 2 pixel ở đây. Vấn đề đầu tiên tôi giải quyết là làm cho ma trận dự án và mô hình được chia tỷ lệ sao cho +1 trong không gian tọa độ là sự dịch chuyển 1 pixel trên màn hình.
Slipp D. Thompson

Câu trả lời:


4

Vấn đề của bạn là UV được thiết kế để phối hợp kết cấu. Tọa độ 0,0 là góc trên cùng bên trái của pixel trên cùng bên trái trong kết cấu, đây không phải là nơi bạn thường muốn đọc kết cấu. Đối với 2D, bạn muốn đọc kết cấu ở giữa pixel đó.

Nếu toán học của tôi đúng, những gì bạn cần làm để làm việc đó là:

return float4((texCoord.rg - (0.5f/textureSize)) * (textureSize/(textureSize-1)), 0, 1);

Đó là bạn trừ đi phần bù thích hợp để lấy pixel trên cùng bên trái ở mức 0,0 và sau đó áp dụng tỷ lệ để lấy phần dưới cùng bên phải.

Điều tương tự cũng có thể đạt được bằng cách mở rộng tọa độ UV cho hình học bên ngoài phạm vi 0-1.


Để giải thích câu cuối cùng: bạn có thể áp dụng phép biến đổi này cho các tia cực tím trong bộ đệm đỉnh cho bốn góc của hình tứ giác, sau đó trong trình tạo bóng pixel chỉ cần làm return float4(texCoord.rg, 0, 1);.
Nathan Reed

Tôi đã thử công thức được đề xuất ở trên và nó không hoạt động: trong mục tiêu kết xuất mẫu 4 x 4 của tôi từ trên xuống, tôi nhận được 0, 42, 127 và 212 trong các kênh R và G, từ trái sang phải hoặc từ trên xuống dưới. Tuy nhiên, tôi muốn các giá trị từ 0 đến 255 trong các bước cách đều nhau (đối với kết cấu 4 x 4 là 0, 85, 170 và 255). Tôi cũng đã cố gắng thay đổi tọa độ UV, nhưng vẫn chưa tìm thấy độ lệch phù hợp.
Mario

0

Có vẻ như tôi phải di chuyển bên phải và viền dưới của hình tứ giác của tôi chính xác một pixel lên và sang trái, so với hình đầu tiên.

Hầu như, nhưng chỉ một nửa pixel. Chỉ cần trừ 0,5 từ các đỉnh của bạn. Ví dụ: bạn muốn 256x256 quad có cùng kết cấu, đây là điểm của bạn:

p1 = (-0.5, -0.5)
p2 = (-0.5, 255-0.5)
p3 = (255-0.5, 255-0.5)
p4 = (255-0.5, -0.5)

Hoặc, thay vào đó, bạn có thể thêm một nửa số texel trong trình đổ bóng pixel (texCoord.rg + 0,5 * (1.0 / texSize))

Độ lệch một nửa pixel là một thực tế đã biết trong DX9. Điều này và bài viết này có thể giúp bạn là tốt.


0

Điều này chắc chắn được gây ra bởi lấy mẫu tuyến tính. Nếu bạn nhìn vào các texels ở bên phải và bên dưới pixel phía trên bên trái toàn màu đen, bạn sẽ thấy rằng chúng có 63 trong các kênh R và / hoặc G, và 2 trong số chúng có 2 trong B. Bây giờ hãy nhìn vào bùn-vàng đậm bạn nhận được; đó là 31 ở R và G và 1 ở B. Đó chắc chắn là kết quả của việc tính trung bình các nhóm trên một nhóm 2x2, vì vậy giải pháp là đặt bộ lọc kết cấu của bạn thành điểm.


-2

Đó chỉ đơn giản là beacuse bạn đang sử dụng texCoords từ đầu ra đỉnh được nội suy bởi ổ cứng sau khi xử lý shader đỉnh.

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.