Расширяем шейдер PlayStation 1 — Аффинная текстурная интерполяция в Unity
В прошлой статье мы реализовали эффект дрожания вершин, характерный для PlayStation 1, воссоздав ограниченную точность вычислений, свойственную старым консолям. Теперь добавим еще одну ключевую особенность рендеринга PS1 — аффинную интерполяцию текстур.
На оригинальной PlayStation не использовалась перспективная коррекция текстур, что приводило к заметным искажениям при изменении угла наклона полигонов. Этот эффект был побочным результатом работы GPU консоли и активно использовался в таких играх, как Metal Gear Solid и Tomb Raider. Давайте воссоздадим этот визуальный артефакт в Unity!
Как работала аффинная интерполяция текстур на PS1?
Современные графические движки интерполируют текстурные координаты с учетом перспективы, корректируя масштаб текстуры на дальних полигонах. В PlayStation 1 этого не было, и текстурные координаты просто линейно интерполировались между вершинами, без учета глубины.
Пример эффекта:
Современная перспективная интерполяция:

Аффинная интерполяция (PS1-стиль):

На PS1 это приводило к «плавающим» текстурам, особенно заметным на больших плоскостях.
Реализация эффекта в Unity
Воссоздать этот эффект в Unity можно путем отключения перспективной коррекции текстур. Для этого нам нужно изменить способ вычисления UV-координат в пиксельном шейдере.
Шаг 1: Создание шейдера
Создадим шейдер, в котором будем передавать текстурные координаты напрямую из вершинного шейдера без перспективной коррекции.
Shader "Custom/PS1AffineTexture"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
struct appdata_t
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv; // Передаем UV без деления на w
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return tex2D(_MainTex, i.uv);
}
ENDCG
}
}
}В отличие от стандартных шейдеров, мы не делим UV на w, что создает эффект аффинной интерполяции.
Шаг 1: Дополним наш основной шейдер новой техникой
Так же введем возможность отключать аффинные преобразования в настройках материала
Shader "Custom/PS1Shader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_JitterStrength ("Jitter Strength", Range(0, 1)) = 0.02
_UseAffine ("Use Affine Mapping", Float) = 1
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
float _JitterStrength;
float _UseAffine;
struct appdata_t
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float2 Quantize(float2 pos, float step)
{
return floor(pos / step + 0.5) * step;
}
v2f vert (appdata_t v)
{
v2f o;
// Дрожание вершин
float jitter = _JitterStrength * (sin(v.vertex.x * 10.0) + cos(v.vertex.y * 10.0));
v.vertex.xy += jitter;
// Преобразование в Clip Space с квантованием координат
o.vertex = UnityObjectToClipPos(v.vertex);
o.vertex.xy = Quantize(o.vertex.xy, _JitterStrength);
// Включение/выключение аффинной интерполяции
if (_UseAffine > 0.5)
o.uv = v.uv; // Без перспективной коррекции (аффинная интерполяция)
else
o.uv = v.uv / o.vertex.w; // Перспективная коррекция
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return tex2D(_MainTex, i.uv);
}
ENDCG
}
}
}
Добавлен параметр _UseAffine, который работает как чекбокс в Unity:
1(по умолчанию) — аффинная интерполяция ВКЛЮЧЕНА.0— аффинная интерполяция ВЫКЛЮЧЕНА, используется стандартная перспективная коррекция.
Теперь можно легко включать и выключать эффект PS1 без необходимости менять шейдер!
Результаты и визуальные особенности
После применения этого шейдера текстуры начнут «плыть» при изменении угла наклона поверхности, создавая узнаваемый эффект PS1.
Плюсы:
- Полное погружение в атмосферу ретро-графики.
- Идеально для стилизации под старые консоли.
Минусы:
- Эффект может выглядеть странно на высокополигональных моделях.
- Не подходит для реалистичных сцен.
Заключение
Теперь у нас есть два эффекта, воссоздающих стиль PlayStation 1 в Unity: дрожание вершин и аффинная интерполяция текстур. Эти особенности, присущие старым играм, помогут придать вашей игре винтажный вид и уникальный стиль
