NES'in renk sınırlamalarını bir HLSL piksel gölgelendiricisi ile nasıl çoğaltabilirim?


13

256 renk modu amortismana tabi tutulduğundan ve artık Direct3D modunda desteklenmediğinden, olası tüm renklerin NES paletini simüle etmek için bir piksel gölgelendirici kullanma fikrimi aldım, böylece solma nesneleri ve alfa kanallarıyla pürüzsüz solma çıkışları yok . (Nesnelerin NES'de gerçekten solmadığını biliyorum, ancak palet değiştirmeyle mümkün olacak düz siyah bir arka plan üzerinde içeri ve dışarı kaybolan tüm nesneler var. Ayrıca, duraklattığınızda ekran içeri ve dışarı kayboluyor ki birkaç Mega Man oyununda yapıldığı gibi palet değiştirme ile de mümkün olduğunu biliyorum.) Sorun şu ki, HLSL gölgelendiricileri hakkında hiçbir şey bilmiyorum.

Nasıl yaparım?


Aşağıdaki yorum, piksel gölgelendiriciyi kullanan yaklaşımı açıklar, ancak sanat ekibiniz için uygun bir stil kılavuzu kullanılarak bunun gibi bir renk sınırlaması elde edilebilir.
Evan

sadece paleti azaltmak mı yoksa titreme yapmak mı istiyorsunuz (gölgelendiriciler de kullanmak mümkündür). aksi halde zezba9000 yanıtı benim için en iyisi gibi görünüyor
tigrou

Olası renkleri NES paletine düşürmek istiyorum. Esas olarak alfa kanalı efektlerini ve diğer mürekkep efektlerini yakalamak için ihtiyacım vardı çünkü 256 renk modunda onları yakalar, ancak Direct3D artık 256 renk modunu desteklemez, bu nedenle efektler gerçek renklerde yumuşatılır.
Michael Allen Crain

Yanıtlar:


4

Piksel gölgelendiricisinde, palet renklerinin tümü arka arkaya yatay olarak dizilmiş bir 256x256 Texture2D geçirebilirsiniz. Daha sonra NES dokularınız, hiç piksel 0-255 dizin değerine dönüştürülürken direct3D Texture2D'lere dönüştürülür. D3D9'da yalnızca kırmızı değeri kullanan bir doku biçimi vardır. Yani doku piksel başına sadece 8 bit alacaktı, ancak gölgelendiriciye gelen veriler 0-1 arasında olacaktı.

// Piksel gölgelendirici şöyle görünebilir:

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

DÜZENLEME: İhtiyacınız olan tüm harmanlama paleti versiyonuna dokuya dikey olarak hizalanmak ve bunları colorIndex'in 'alfa' değeri ile referans vermek daha doğru bir yol olacaktır:

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

Üçüncü yol, alfa rengini gölgeleyerek NES düşük solma kalitesini taklit etmek olacaktır:

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
256x1256 değil, 256x1 demek istiyorsun, tahmin ediyorum? Ayrıca, her iki dokuda bilinear filtrelemeyi devre dışı bıraktığınızdan emin olun, aksi takdirde palet "girişleri" arasında karışım elde edersiniz.
Nathan Reed

Ayrıca, bu şema ile doku değerleri üzerinde herhangi bir aydınlatma veya matematik yapamazsınız, çünkü yaptığınız her şeyin sizi paletin tamamen farklı bir bölümüne göndermesi muhtemeldir.
Nathan Reed

@Nathan Reed Aydınlatma yapabilirsiniz. Renk değerini döndürmeden önce "palletColor" üzerindeki ışığı hesaplarsınız. Ayrıca 256x1 doku yapabilirsiniz, ancak donanım kaputun hemen altında 256x256 kullanabilir ve 256x256 çoğu donanımda kullanmak için en hızlı boyuttur. Bu idk değişmediği sürece.
zezba9000

Palettizasyondan sonra aydınlatma yaparsanız, muhtemelen artık NES renklerinden biri olmayacaktır. Eğer istediğin buysa, sorun değil - ama bu sorunun istediği gibi görünmüyor. 256 şeye gelince, 10 yaşın üzerinde bir GPU'nuz varsa bu mümkündür ... ancak bundan daha yeni bir şey kesinlikle 256x1 gibi 2'li dikdörtgen gücü destekleyecektir.
Nathan Reed

Sadece pürüzsüz fadeouts istemiyorsa yapabilirdi: "palletColor.a = (float) floor (palletColor.a * fadeQuality) / fadeQuality;" Hatta 3D doku yöntemiyle aynı şeyi yapabilir, ancak satır 4'ü şu şekilde değiştirerek 2D bir doku ile: "float4 palletColor = tex2D (PalletTexture, float2 (colorIndex.x, colorIndex.a);" Alfa kanalı sadece farklı paleti endeksler katmanları tek bir 2B doku üzerinde
zezba9000

3

Doku belleği kullanımını gerçekten umursamıyorsanız (ve retro bir görünüm elde etmek için çılgınca bir doku belleği üfleme fikri bir tür sapkın çekiciliğe sahipse), tüm RGB kombinasyonlarını seçtiğiniz paletle eşleyen 256x256x256 3B doku oluşturabilirsiniz. . Sonra gölgelendiricinizde sonunda sadece bir kod satırı olur:

return tex3d (paletteMap, color.rgb);

256x256x256'ya kadar gitmek bile gerekli olmayabilir - 64x64x64 gibi bir şey yeterli olabilir - ve bu yöntemi kullanarak palet eşlemelerini anında değiştirebilirsiniz (ancak büyük bir dinamik doku güncellemesi nedeniyle önemli bir maliyetle).


Dokular üzerinde aydınlatma, alfa karıştırma veya başka bir matematik türü yapmak ve sonuçta en yakın NES rengine yapışmak istiyorsanız, bu en iyi yöntem olabilir. Sen böyle bir referans resmi kullanarak hacim dokusunu precompute olabilir bu bir ; en yakın komşu filtrelemeye ayarlandığında, 16x16x16 kadar küçük bir şeyle kaçabilirsiniz, ki bu hiç de fazla bellek olmaz.
Nathan Reed

1
Bu harika bir fikir, ancak çok daha yavaş olacak ve eski donanımlarla uyumlu olmayacak. 3D Dokular, 2D olanlardan çok daha yavaş örnekleme yapar ve 3D Dokular da daha fazla bant genişliği gerektirir ve bu da onu daha da yavaşlatır. Yeni kartlar bu önemli değil, ama yine de.
zezba9000

1
Kaç yaşında gitmek istediğinize bağlı. 3D doku desteğinin orijinal GeForce 1'e geri döndüğüne inanıyorum - 14 yaşında mı?
Maximus Minimus

Lol Evet evet, belki de bu kartları kullanmamışlardı, sanırım Telefon GPU'larıyla daha fazla satır içi düşünüyordum. Bugün 3D doku desteği olmayan çok sayıda hedef var. Ancak OpenGL değil D3D kullandığından, WP8 bile bunu destekliyor. Yine de bir 3B doku 2B'den daha fazla bant genişliği alacaktır.
zezba9000

1

(her iki çözümüm de sadece paletlerin gölgelendiricileri kullanarak değiştirmeyi umursamıyorsanız çalışır)

Herhangi bir doku türünü kullanabilir ve gölgelendirici üzerinde basit bir hesaplama yapabilirsiniz. Hile, ihtiyacınız olandan daha fazla renk bilgisine sahip olmanız, bu yüzden istemediğiniz bilgilerden kurtulacaksınız.

8 bit renk former RRRGGGBB'dir . Bu size 8 kırmızı ve yeşil tonu ve 4 mavi tonu verir.

Bu çözüm tüm RGB (A) renk formatı dokular için işe yarayacaktır.

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);
}

not: başımın üstünden yazdım, ama gerçekten derleyeceğim ve sizin için çalışacağından eminim


Başka bir olasılık , aslında 8 bit grafiklerle aynı olan D3DFMT_R3G3B2 doku formatını kullanmak olacaktır . Bu dokuya veri koyduğunuzda, bayt başına basit bit işlemini kullanabilirsiniz.

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

Bu iyi bir örnek. Sadece bence renk paletini değiştirebilmesi gerekiyordu. Bu durumda benim örneğim gibi bir şey kullanması gerekecekti.
zezba9000

Bu hiç NES renk paleti değil. NES 8 bit RGB kullanmadı, YPbPr alanında yaklaşık 50 ila 60 renk sabit bir palet kullandı.
sam hocevar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.