Làm cách nào tôi có thể sao chép các giới hạn màu của NES bằng trình đổ bóng pixel HLSL?


13

Vì chế độ 256 màu không được dùng nữa và không còn được hỗ trợ trong chế độ Direct3D, tôi đã có ý tưởng sử dụng trình đổ bóng pixel để mô phỏng bảng màu NES của tất cả các màu có thể để các đối tượng mờ dần và không bị mờ dần với các kênh alpha . (Tôi biết các đối tượng không thể thực sự mờ dần trên NES, nhưng tôi có tất cả các đối tượng mờ dần trên và trên nền đen, điều này có thể xảy ra với hoán đổi bảng màu. Ngoài ra, màn hình mờ dần khi bạn tạm dừng Điều mà tôi biết cũng có thể xảy ra với việc hoán đổi bảng màu như đã được thực hiện trong một vài trò chơi Mega Man.) Vấn đề là, tôi không biết gì về các shader HLSL.

Tôi phải làm nó như thế nào?


Nhận xét bên dưới mô tả cách tiếp cận bằng cách sử dụng trình đổ bóng pixel, nhưng chỉ cần giới hạn màu như thế này bằng cách sử dụng một hướng dẫn phong cách phù hợp cho nhóm nghệ thuật của bạn.
Evan

bạn chỉ muốn giảm bảng màu hoặc cũng muốn thực hiện phối màu (có thể sử dụng các shader nữa). mặt khác, câu trả lời zezba9000 có vẻ là câu trả lời hay nhất đối với tôi
tigrou

Tôi muốn giảm các màu có thể vào bảng màu NES. Tôi cần nó chủ yếu để bắt các hiệu ứng kênh alpha và các hiệu ứng mực khác vì ở chế độ 256 màu, nó bắt được chúng nhưng Direct3D không còn hỗ trợ chế độ 256 màu nữa nên trong đó các hiệu ứng được làm mịn theo màu thật.
Michael Allen Crain

Câu trả lời:


4

Trong trình tạo bóng pixel, bạn có thể chuyển qua Texture2D 256x256 với các màu pallet được xếp theo hàng ngang trong một hàng. Sau đó, kết cấu NES của bạn sẽ được chuyển đổi thành direct3D Texture2Ds với từng pixel được chuyển đổi thành giá trị chỉ số 0-255. Có một định dạng kết cấu chỉ sử dụng giá trị màu đỏ trong D3D9. Vì vậy, kết cấu sẽ chỉ chiếm 8 bit cho mỗi pixel, nhưng dữ liệu đi vào trình đổ bóng sẽ từ 0-1.

// Pixel shader có thể trông như thế này:

float4 mainPS() : COLOR0
{
    float4 colorIndex = tex2D(MainTexture, uv);
    float4 palletColor = tex2D(PalletTexture, float2(colorIndex.x, 0);
    return palletColor;
}

EDIT: Một cách chính xác hơn sẽ là thêm vào tất cả các phiên bản pallet trộn mà bạn cần căn chỉnh theo chiều dọc trong kết cấu và tham chiếu chúng với giá trị 'alpha' của colorIndex:

float4 mainPS() : COLOR0
{
    float4 colorIndex = tex2D(MainTexture, uv);
    float4 palletColor = tex2D(PalletTexture, float2(colorIndex.x, colorIndex.a);
    return palletColor;
}

Cách thứ ba là chỉ giả mạo chất lượng mờ dần của NES bằng cách tô màu cho màu alpha:

float4 mainPS() : COLOR0
{
    float4 colorIndex = tex2D(MainTexture, uv);
    float4 palletColor = tex2D(PalletTexture, float2(colorIndex.x, 0);
    palletColor.a = floor(palletColor.a * fadeQuality) / fadeQuality;
    //NOTE: If fadeQuality where to equal say '3' there would be only 3 levels of fade.
    return palletColor;
}

1
Ý bạn là 256x1, không phải 256x256, tôi đoán vậy? Ngoài ra, hãy chắc chắn tắt chức năng lọc song tuyến trên cả hai kết cấu, nếu không, bạn sẽ có được sự pha trộn giữa các "mục" bảng màu.
Nathan Reed

Ngoài ra, bạn không thể thực hiện bất kỳ loại ánh sáng hoặc toán học nào về các giá trị kết cấu với sơ đồ này, vì bất cứ điều gì bạn làm có thể sẽ đưa bạn đến một phần hoàn toàn khác của bảng màu.
Nathan Reed

@Nathan Reed Bạn có thể làm ánh sáng. Bạn chỉ cần tính toán ánh sáng trên "palletColor" trước khi bạn trả về giá trị màu của nó. Ngoài ra, bạn có thể tạo kết cấu 256x1, nhưng phần cứng có thể ngay dưới mui xe sử dụng 256x256 và 256x256 là kích thước nhanh nhất để sử dụng trên hầu hết phần cứng. Trừ khi đó thay đổi idk.
zezba9000

Nếu bạn thực hiện chiếu sáng sau khi chỉnh màu thì có lẽ nó sẽ không còn là một trong những màu NES nữa. Nếu đó là những gì bạn muốn, điều đó tốt - nhưng điều đó không giống như những gì câu hỏi đang yêu cầu. Đối với điều 256, điều đó là có thể nếu bạn có GPU trên 10 tuổi ... nhưng bất cứ điều gì gần đây hơn chắc chắn sẽ hỗ trợ kết cấu hình chữ nhật có sức mạnh 2 hình chữ nhật, như 256x1.
Nathan Reed

Nếu anh ta không muốn làm mờ dần, anh ta có thể làm: "sàn palletColor.a = (float) (palletColor.a * fadeQuality) / fadeQuality;" Anh ta thậm chí có thể làm tương tự như phương pháp kết cấu 3D nhưng với kết cấu 2D bằng cách thay đổi dòng 4 thành: "float4 palletColor = tex2D (PalletTexture, float2 (colorIndex.x, colorIndex.a);" Kênh alpha chỉ lập chỉ mục các pallet khác nhau các lớp trên một kết cấu 2D duy nhất.
zezba9000

3

Nếu bạn không thực sự quan tâm đến việc sử dụng bộ nhớ kết cấu (và ý tưởng thổi một lượng bộ nhớ kết cấu điên rồ để đạt được giao diện retro có một loại hấp dẫn đồi trụy), bạn có thể tạo một kết cấu 3d 256x256x256 ánh xạ tất cả các kết hợp RGB vào bảng màu đã chọn của bạn . Sau đó, trong shader của bạn, nó chỉ trở thành một dòng mã ở cuối:

return tex3d (paletteMap, color.rgb);

Thậm chí có thể không cần thiết phải chuyển sang 256x256x256 - một cái gì đó như 64x64x64 là đủ - và bạn thậm chí có thể thay đổi ánh xạ bảng màu bằng cách sử dụng phương pháp này (nhưng với chi phí đáng kể nhờ cập nhật kết cấu động lớn).


Đây có thể là phương pháp tốt nhất nếu bạn muốn thực hiện ánh sáng, pha trộn alpha hoặc bất kỳ loại toán nào khác trên kết cấu của bạn, sau đó chụp kết quả cuối cùng với màu NES gần nhất. Bạn có thể tính toán trước kết cấu âm lượng của mình bằng hình ảnh tham chiếu như ảnh này ; với thiết lập để lọc hàng xóm gần nhất, bạn có thể thoát khỏi thứ gì đó nhỏ như 16x16x16, sẽ không có nhiều bộ nhớ.
Nathan Reed

1
Đây là một ý tưởng hay, nhưng sẽ chậm hơn nhiều và không tương thích với phần cứng cũ. Hoạ tiết 3D sẽ lấy mẫu chậm hơn nhiều so với kết cấu 2D và Hoạ tiết 3D cũng sẽ cần nhiều băng thông hơn, điều này sẽ làm chậm hơn nữa. Thẻ mới hơn này không quan trọng mặc dù, nhưng vẫn còn.
zezba9000

1
Phụ thuộc bao nhiêu tuổi bạn muốn đi. Tôi tin rằng hỗ trợ kết cấu 3d quay trở lại GeForce 1 ban đầu - đã đủ 14 tuổi?
Maximus Minimus

Vâng, vâng, có lẽ họ cũng vậy, chưa bao giờ sử dụng những thẻ đó, đoán tôi đã suy nghĩ nhiều hơn với GPU của Phone. Có rất nhiều mục tiêu ngày nay không có hỗ trợ kết cấu 3D. Nhưng bởi vì anh ta đang sử dụng D3D và không đoán được OpenGL, ngay cả WP8 cũng hỗ trợ điều này. Tuy nhiên, kết cấu 3D sẽ chiếm nhiều băng thông hơn 2D.
zezba9000

1

(cả hai giải pháp của tôi chỉ hoạt động nếu bạn không quan tâm đến việc thay đổi palletes khi đang sử dụng shader)

Bạn có thể sử dụng bất kỳ loại kết cấu nào và chỉ thực hiện một tính toán đơn giản trên một shader. Thủ thuật là bạn có nhiều thông tin màu hơn bạn cần, vì vậy những gì bạn sẽ loại bỏ thông tin mà bạn không muốn.

Màu 8 bit có dạng RRRGGGBB . Cung cấp cho bạn 8 màu đỏ và xanh lá cây và 4 màu xanh lam.

Giải pháp này sẽ hoạt động cho mọi kết cấu định dạng màu RGB (A).

float4 mainPS() : COLOR0
{
    const float oneOver7 = 1.0 / 8.0;
    const float oneOver3 = 1.0 / 3.0;

    float4 color = tex2D(YourTexture, uvCoord);
    float R = floor(color.r * 7.99) * oneOver7;
    float G = floor(color.g * 7.99) * oneOver7;
    float B = floor(color.b * 3.99) * oneOver3;

    return float4(R, G, B, 1);
}

lưu ý: tôi đã viết nó từ đỉnh đầu của tôi, nhưng tôi thực sự chắc chắn rằng nó sẽ biên dịch và làm việc cho bạn


Một khả năng khác , sẽ là sử dụng định dạng kết cấu D3DFMT_R3G3B2 thực sự giống như đồ họa 8 bit. Khi bạn đặt dữ liệu vào kết cấu này, bạn có thể sử dụng thao tác bit đơn giản trên mỗi byte.

tex[index] = (R & 8) << 5 + ((G & 8) << 2) + (B & 4);

Đó là một ví dụ tốt. Chỉ có tôi nghĩ rằng anh ta cần để có thể trao đổi pallet màu. Trong trường hợp đó anh ta sẽ phải sử dụng một cái gì đó giống như ví dụ của tôi.
zezba9000

Đây hoàn toàn không phải là bảng màu NES. NES không sử dụng RGB 8 bit, nó sử dụng bảng màu cố định khoảng 50 đến 60 màu trong không gian YPbPr.
sam hocevar
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.