Расширяем шейдер 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: дрожание вершин и аффинная интерполяция текстур. Эти особенности, присущие старым играм, помогут придать вашей игре винтажный вид и уникальный стиль