Як я можу повторити обмеження кольорів NES за допомогою піксельного шейдера HLSL?


13

Оскільки 256 кольоровий режим знецінюється і більше не підтримується в режимі Direct3D, у мене з’явилася ідея використовувати піксельний шейдер замість того, щоб імітувати палітру NES усіх можливих кольорів, щоб зникаючі об'єкти та щось не мали плавних вицвітання з альфа-каналами . (Я знаю, що об'єкти не можуть зникати на NES, але у мене є всі об'єкти, які вицвітають і виходять на суцільному чорному тлі, що було б можливо при зміні палітри. Також екран вимикає і вимикається, коли ви призупиняєте що, як я знаю, було можливим і з заміною палітри, як це було зроблено в кількох іграх Mega Man.) Проблема в тому, що я майже нічого не знаю про шейдери HLSL.

Як це зробити?


У коментарі нижче описаний підхід із використанням піксельного шейдера, але просто обмеження кольорів, як це, можна досягти, використовуючи відповідний посібник зі стилю для вашої художньої команди.
Еван

ви просто хочете зменшити палітру, а також хочете виконувати забарвлення (можливо, використовуючи і шейдери). інакше відповідь zezba9000 мені здається найкращою
tigrou

Я хочу просто зменшити можливі кольори до палітри NES. Мені це було потрібно в основному для того, щоб вловлювати ефекти альфа-каналів та інші ефекти чорнила, оскільки в кольоровому режимі 256 він ловить їх, але Direct3D більше не підтримує 256 кольоровий режим, тому в ньому ефекти вирівнюються в справжні кольори.
Майкл Аллен Креййн

Відповіді:


4

У піксельному шейдері ви могли пройти в форматі 256x256 Texture2D з кольорами піддону, усі вишикувалися горизонтально підряд. Тоді ваші текстури NES будуть перетворені на direct3D Texture2Ds з будь-коли пікселем, перетвореним на значення індексу 0-255. Існує формат текстури, який використовує лише червоне значення в D3D9. Таким чином, текстура займе лише 8 біт на піксель, але дані, які надходять у шейдер, становитимуть від 0-1.

// Піксельний шейдер може виглядати приблизно так:

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

РЕДАКТУВАННЯ: Більш правильним способом було б додати до всієї версії піддону, що потрібно змішувати, по вертикалі вирівняти текстуру і посилати їх на значення "альфа" вашого colorIndex:

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

Третім способом було б просто підробити NES з низькою якістю в’янення, відтіняючи альфа-колір тоном:

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
Ви маєте на увазі 256x1, а не 256x256, я здогадуюсь? Також не забудьте відключити білінеарну фільтрацію на обох текстурах, інакше ви отримаєте суміш між "записами" палітри.
Натан Рід

Крім того, за цією схемою ви не можете займатися будь-яким освітленням або математикою на значеннях текстур, оскільки все, що ви робите, швидше за все, направить вас до зовсім іншої частини палітри.
Натан Рід

@Nathan Reed Ви можете зробити освітлення. Ви просто обчислюєте світло на "palletColor", перш ніж повернути його значення кольору. Крім того, ви можете зробити текстуру 256x1, але апаратне обладнання, що знаходиться під кришкою, все одно може використовувати 256x256, а 256x256 - це найшвидший розмір для використання на більшості апаратних засобів. Якщо тільки це не змінило idk.
zezba9000

Якщо ви займаєтеся освітленням після палетизації, то, ймовірно, вже не буде одного з кольорів NES. Якщо це те, що ти хочеш, це добре - але це не схоже на те, про що задавали питання. Що стосується 256- річного , то це можливо, якщо у вас є графічний процесор старше 10 років ... але все, що більше, ніж останній, безумовно, підтримуватиме прямокутні текстури потужності-2, як-от 256x1.
Натан Рід

Якщо він просто не хоче плавного вицвітання, він міг би зробити: "palletColor.a = (float) підлога (palletColor.a * fadeQuality) / fadeQuality;" Він навіть міг би зробити те саме, що і методом 3D текстури, але з 2D текстурою, змінивши лінію 4 на: "float4 palletColor = tex2D (PalletTexture, float2 (colorIndex.x, colorIndex.a);" Альфа-канал просто індексує різні піддони шари на одній двовимірній фактурі
zezba9000

3

Якщо вас не дуже цікавить використання текстурної пам'яті (а ідея видумати шалений об'єм текстурної пам'яті для досягнення ретро-вигляду має певну викривлену привабливість), ви можете створити 3d-текстуру 256x256x256, що відображає всі комбінації RGB у вибраній палітрі. . Тоді у вашому шейдері він просто стає одним рядком коду в кінці:

return tex3d (paletteMap, color.rgb);

Можливо, навіть не доведеться пройти весь шлях до 256x256x256 - чогось типу 64x64x64 може бути достатньо - і ви навіть можете змінити відображення палітри на ходу за допомогою цього методу (але за значних витрат через велике динамічне оновлення текстури).


Це може бути найкращим методом, якщо ви хочете зробити освітлення, альфа-змішування або будь-який інший тип математики на ваших текстурах, а потім підключити кінцевий результат до найближчого кольору NES. Ви можете попередньо обчислити об'ємну текстуру за допомогою еталонного зображення, подібного до цього ; якщо він встановлений для фільтрації найближчого сусіда, ви, можливо, уникнете чогось такого розміру, як 16x16x16, що б зовсім не мало пам'яті.
Натан Рід

1
Це крута ідея, але буде набагато повільніше і не настільки сумісна зі старим обладнанням. 3D-текстури будуть вибирати набагато повільніше, ніж 2D, а 3D-текстури також потребуватимуть значно більшої пропускної здатності, що сповільнить її ще більше. Новіші картки це звичайно не мають значення, але все ж.
zezba9000

1
Залежить, скільки років ти хочеш їхати. Я вважаю, що підтримка 3d текстури повертається до оригінальної GeForce 1 - достатньо 14 років?
Максим Мінімус

Lol Ну так, можливо, вони так і не використовували, але я ніколи не використовував ці картки, напевно, я думав, що більше в Інтернеті з телефоном GPU. Сьогодні існує безліч цілей, які не мають тривимірної підтримки текстури. Але оскільки він використовує D3D, а не OpenGL здогадується, навіть WP8 підтримує це. Проте 3D-текстура займе більше пропускної здатності, ніж 2D.
zezba9000

1

(моє рішення працює лише в тому випадку, якщо ви не турбуєтесь про зміну піддонів під час руху за допомогою шейдерів)

Ви можете використовувати будь-який тип текстури і робити просто прорахунок на шейдері. Хитрість полягає в тому, що у вас більше інформації про колір, ніж вам потрібно, тож ви просто позбудетесь інформації, якої не хочете.

8-бітний колір є у форматі RRRGGGBB . Що дає 8 відтінків червоного та зеленого та 4 відтінки синього.

Це рішення працюватиме для будь-яких текстур кольорового формату 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);
}

зауважте: я написав, що зверху голови, але я дійсно впевнений, що він буде збиратись і працювати для вас


Іншою можливістю буде використання текстурного формату D3DFMT_R3G3B2 , який насправді такий же, як 8-бітна графіка. Коли ви додаєте дані до цієї текстури, ви можете використовувати прості операції по бітам на один байт.

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

Це гарний приклад. Тільки я думаю, що йому потрібно було замінити кольорову палітру. У такому випадку йому доведеться використовувати щось на зразок мого прикладу.
zezba9000

Це зовсім не колірна палітра NES. NES не використовував 8-бітний RGB, він використовував фіксовану палітру приблизно від 50 до 60 кольорів у просторі YPbPr.
sam hocevar
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.