Category:Шейдер

From Multi Theft Auto: Wiki
Revision as of 09:26, 15 April 2021 by EOFIK (talk | contribs) (Перевод страницы на русский язык)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search


Класс shader представляет файл эффекта Microsoft HLSL Effect File (.fx), загруженный клиентом, который можно использовать вместо текстуры при вызове "dxDrawImage".

Тип элемента этого класса - "shader".

Как файлы HLSL Effect Files интегрируется в MTA:SA

[[{{{image}}}|link=|]] Примечание: На этой странице предполагается, что вы знаете, что такое файл эффектов и HLSL. Если нет, вам лучше сначала поискать информацию об этом.

Вы можете использовать этот шейдер тест-ресурс, чтобы попробовать приведённые ниже примеры. Скопируйте источник эффекта из полей кода в shadertest/clientshader.fx и (повторно) запустите "shadertest", чтобы увидеть результат.

После того, как вы всё это проделали (или, может быть, до, если взгляд ниже вызывает у вас панику), посетите ещё несколько примеров шейдерных ресурсов.

Методы

Файлы эффектов обычно содержат несколько методов, но для простоты MTA будет использовать только первый метод, который будет правильно работать на клиентском оборудовании. Итак, для любого данного файла эффектов на первое место ставьте передовые методы, а в последнюю очередь - самые простые. Таким образом, игроки с хорошим оборудованием получат лучшую технику, а игроки со старым оборудованием получат хоть что-то.

Простой пример

Вот содержимое файла эффекта с одной техникой, которая должна работать на всём оборудовании:

//-- Объявите текстуры. Они устанавливаются с помощью [[RU/dxSetShaderValue|dxSetShaderValue( shader, "Tex0", texture )]]
texture Tex0;
texture Tex1;

//-- Очень простой метод
technique simple
{
    pass P0
    {
        //-- Установить текстуры - индекс 0
        Texture[0] = Tex0;
        ColorOp[0] = SelectArg1;
        ColorArg1[0] = Texture;
        AlphaOp[0] = SelectArg1;
        AlphaArg1[0] = Texture;
            
        //-- Отключить текстуры - индекс 1
        ColorOp[1] = Disable;
        AlphaOp[1] = Disable;
    }
}

Он не использует вершинные или пиксельные шейдеры, только стандартные состояния рендеринга D3D. Все состояния, которые вы можете установить, находятся здесь.

Сложный пример

Вот файл эффекта, содержащий вершинный и пиксельный шейдер:

//-- Объявите текстуры. Они устанавливаются с помощью [[RU/dxSetShaderValue|dxSetShaderValue( shader, "Tex0", texture )]]
texture Tex0;
texture Tex1;

//-- Объявите пользовательскую переменную. Она устанавливается с помощью [[RU/dxSetShaderValue|dxSetShaderValue( shader, "PositionOfCheese", 1, 2, 3 )]]
float3 PositionOfCheese;

//-- Эти переменные устанавливаются автоматически MTA.
float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 WorldViewProjection;
float Time;


//---------------------------------------------------------------------
//-- Образец для основной текстуры (необходим для пиксельных шейдеров)
//---------------------------------------------------------------------
sampler Sampler0 = sampler_state
{
    Texture = (Tex0);
};


//---------------------------------------------------------------------
//-- Структура данных, отправляемых в вершинный шейдер
//---------------------------------------------------------------------
struct VSInput
{
    float3 Position : POSITION;
    float4 Diffuse  : COLOR0;
    float2 TexCoord : TEXCOORD0;
};

//---------------------------------------------------------------------
//-- Структура данных, отправляемых в пиксельный шейдер (из вершинного шейдера)
//---------------------------------------------------------------------
struct PSInput
{
  float4 Position : POSITION0;
  float4 Diffuse  : COLOR0;
  float2 TexCoord : TEXCOORD0;
};


//-----------------------------------------------------------------------------
//-- Пример вершинного шейдера
//--  1. Читает из структуры VS
//--  2. Процесс
//--  3. Пишет в структуру PS
//-----------------------------------------------------------------------------
PSInput VertexShaderExample(VSInput VS)
{
    PSInput PS = (PSInput)0;

    //-- Преобразование положения вершины (вам почти всегда нужно делать что-то подобное)
    PS.Position = mul(float4(VS.Position, 1), WorldViewProjection);

    //-- Скопируйте координаты цвета и текстуры, чтобы пиксельный шейдер мог их использовать.
    PS.Diffuse = VS.Diffuse;
    PS.TexCoord = VS.TexCoord;

    return PS;
}


//-----------------------------------------------------------------------------
//-- Пример пиксельного шейдера
//--  1. Читает из структуры PS
//--  2. Процесс
//--  3. Возвращает цвет пикселя
//-----------------------------------------------------------------------------
float4 PixelShaderExample(PSInput PS) : COLOR0
{
    //-- Измените координаты текстуры, чтобы изображение выглядело шатким
    PS.TexCoord.y += sin(PS.TexCoord.y * 100 + Time * 10) * 0.03;

    //-- Возьмите пиксель из текстуры
    float4 finalColor = tex2D(Sampler0, PS.TexCoord);

    //-- Примените цветовой оттенок
    finalColor = finalColor * PS.Diffuse;

    return finalColor;
}


//-----------------------------------------------------------------------------
//-- Методы
//-----------------------------------------------------------------------------

//--
//-- MTA сначала попробует ''complercated'' метод:
//--
technique complercated
{
    pass P0
    {
        VertexShader = compile vs_2_0 VertexShaderExample();
        PixelShader  = compile ps_2_0 PixelShaderExample();
    }
}

//--
//-- И если предыдущий метод не подтвердится на
//-- компьютере игрока, MTA попробует ''simple'' метод:
//--
technique simple
{
    pass P0
    {
        //-- Установить текстуры - индекс 0
        Texture[0] = Tex0;
        ColorOp[0] = SelectArg1;
        ColorArg1[0] = Texture;
        AlphaOp[0] = SelectArg1;
        AlphaArg1[0] = Texture;
            
        //-- Отключить текстуры - индекс 1
        ColorOp[1] = Disable;
        AlphaOp[1] = Disable;
    }
}

Метод complercated будет использоваться, если компьютер поддерживает Shader Model 2, в противном случае будет использован метод simple. Комментарии в источнике объясняют, что делает MTA и где.

Разное

Что следует помнить при переключении между редактированием файлов lua и .fx:

  • HLSL утверждения часто заканчиваются на ";" (точка с запятой)
  • HLSL индексы начинаются с 0 (где Lua обычно начинается с 1)
  • HLSL ошибки компиляции можно просмотреть, набрав "debugscript 3" в клиентской консоли.


Шейдеры для текстур мира

Вот несколько примеров шейдеров, которые можно использовать при замене текстур мира на engineApplyShaderToWorldTexture

Простой пример

Этот шейдер просто заменяет текстуру и позволяет GTA управлять всеми состояниями рендеринга.

//-- Объявите текстуру. Они устанавливаются с помощью [[RU/dxSetShaderValue|dxSetShaderValue( shader, "Tex0", texture )]]
texture Tex0;

technique simple
{
    pass P0
    {
        //-- Установить текстуру - индекс 0
        Texture[0] = Tex0;

        //-- Оставьте остальные состояния по умолчанию
    }
}


Сложный пример

Этот шейдер можно использовать как основу для замены текстуры мира, если вы собираетесь добавить какой-нибудь необычный эффект.

Он использует mta-helper.fx для согласованного именования предустановленных настроек шейдера (gWorld, gTexture0 и т.д.)

mta-helper.fx также содержит несколько полезных функций для расчета освещения GTA.

//-----------------------------------------------------------------------
//-- Настройки
//-----------------------------------------------------------------------
texture Tex0;   //-- Замена текстуры


//---------------------------------------------------------------------
// Включите некоторые общие вещи
//---------------------------------------------------------------------
#include "mta-helper.fx"


//-----------------------------------------------------------------------
//-- Образец для новой текстуры
//-----------------------------------------------------------------------
sampler Sampler0 = sampler_state
{
    Texture = (Tex0);
};


//-----------------------------------------------------------------------
//-- Структура данных, отправляемых в вершинный шейдер
//-----------------------------------------------------------------------
struct VSInput
{
    float3 Position : POSITION0;
    float3 Normal : NORMAL0;
    float4 Diffuse : COLOR0;
    float2 TexCoord : TEXCOORD0;
};

//-----------------------------------------------------------------------
//-- Структура данных, отправляемых в пиксельный шейдер (из вершинного шейдера)
//-----------------------------------------------------------------------
struct PSInput
{
    float4 Position : POSITION0;
    float4 Diffuse : COLOR0;
    float2 TexCoord : TEXCOORD0;
};


//--------------------------------------------------------------------------------------------
//-- Функция вершинного шейдера
//--  1. Читает из структуры VS
//--  2. Процесс
//--  3. Пишет в структуру PS
//--------------------------------------------------------------------------------------------
PSInput VertexShaderFunction(VSInput VS)
{
    PSInput PS = (PSInput)0;

    //-- Вычислить экранную позицию вершины
    PS.Position = mul(float4(VS.Position, 1), gWorldViewProjection);

    //-- Пройти через TexCoord
    PS.TexCoord = VS.TexCoord;

    //-- Рассчитать освещение GTA для зданий
    PS.Diffuse = MTACalcGTABuildingDiffuse( VS.Diffuse );
    //--
    //-- {{RU/Note|Вышеупомянутая строка относится к зданиям GTA.}}
    //-- Если вы заменяете текстуру транспортного средства, сделайте это:
    //--
    //--      // Рассчитать освещение GTA для автомобилей
    //--      float3 WorldNormal = MTACalcWorldNormal( VS.Normal );
    //--      PS.Diffuse = MTACalcGTAVehicleDiffuse( WorldNormal, VS.Diffuse );

    return PS;
}


//--------------------------------------------------------------------------------------------
//-- Функция пиксельного шейдера
//--  1. Читает из структуры PS
//--  2. Процесс
//--  3. Возвращает цвет пикселя
//--------------------------------------------------------------------------------------------
float4 PixelShaderFunction(PSInput PS) : COLOR0
{
    //-- Получить пиксель текстуры
    float4 texel = tex2D(Sampler0, PS.TexCoord);

    //-- Применить рассеянное освещение
    float4 finalColor = texel * PS.Diffuse;

    return finalColor;
}


//--------------------------------------------------------------------------------------------
//-- Методы
//--------------------------------------------------------------------------------------------
technique tec
{
    pass P0
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

//-- Отступление
technique fallback
{
    pass P0
    {
        //-- Заменить текстуру - индекс 0
        Texture[0] = Tex0;

        //-- Оставьте остальные состояния по умолчанию
    }
}


Приведенный выше код в его нынешнем виде рассчитает правильное освещение для зданий GTA. Если вы заменяете автомобиль, замените:

    //-- Рассчитать освещение GTA для зданий
    PS.Diffuse = MTACalcGTABuildingDiffuse( VS.Diffuse );

на:

    //-- Рассчитать освещение GTA для автомобилей
    float3 WorldNormal = MTACalcWorldNormal( VS.Normal );
    PS.Diffuse = MTACalcGTAVehicleDiffuse( WorldNormal, VS.Diffuse );


Многопроходные шейдеры

Чтобы выполнить более одного прохода, добавьте блоки pass следующим образом:

//-- Объявите текстуру. Они устанавливаются с помощью [[RU/dxSetShaderValue|dxSetShaderValue( shader, "Tex0", texture )]]
texture Tex0;

technique simple
{
    pass P0
    {
        // Первый проход
        Texture[0] = Tex0;
    }
    pass P1
    {
        // Второй проход
        SrcBlend = Add;
        DestBlend = One;
    }
    pass P2
    {
        // Третий проход
        SrcBlend = InvDestColor;
        DestBlend = InvSrcColor;
    }
}


This category currently contains no pages or media.