Документация/Уроки по программированию/Создание нового постэффекта

From NeoAxis Engine Wiki

Jump to: navigation, search
Перейти на уровень выше
Постэффект Glass

Contents

Введение

Постэффект - это обработка отрендеренного кадра сцены с помощью шейдера. Примером постэффекта может служить размытие картинки при быстром движении камеры (Motion Blur) или имитация тепловизора (Heat Vision).

В этом уроке мы создадим собственный постэффект и научимся его использовать.

Стандартные постэффекты NeoAxis Engine вы можете найти в директории "Game\Bin\Data\Materials\PostEffects". А чтобы посмотреть постэффект в действии нужно зайти в меню, нажав клавишу Escape, и выбрать пункт Post effects.

Posteffect2.jpg

Меню постэффектов позволяет включать и выключать тот или иной постэффект, а также настраивать их параметры.

Настройка постэффекта HDR

Создание постэффекта

Файлы относящиеся к постэффекту, можно поделить на 4 группы:

  • Файлы постэффектов (.compositor),
  • Файлы материалов (.material),
  • Шейдеры (.hlsl),
  • Текстуры (.dds).

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

В качестве примера мы сделаем постэффект, реализующий цветокоррекцию отрисованной сцены, т.е. умножающий цвет каждого пикселя кадра на некий коэффициент.

Для начала создадим папку в директории "Game\Bin\Data\Materials\PostEffects" под названием ColorCorrection.

Совет. Можно не создавать постэффект с нуля. Можно взять похожий эффект из доступных, скопировать его файлы и отредактировать их.

Написание эффекта

В созданную папку добавим файл ColorCorrection.compositor. Это будет главный файл нашего постэффекта. В этот файл запишем следующий код:

compositor ColorCorrection
{
	technique
	{
		// Temporary textures
		texture rt0 target_width target_height PF_A8R8G8B8
 
		target rt0
		{
			// Render output from previous compositor (or original scene)
			input previous
		}
 
		target_output
		{
			// Start with clear output
			input none
 
			// Draw a fullscreen quad with the colorscale image
			pass render_quad
			{
				// Renders a fullscreen quad with a material
				material Compositor/ColorCorrection
				input 0 rt0
			}
		}
	}
}

Главное, на что нужно обратить внимание в этом скрипте, это блок render_quad - отрисовка квада (закрашенного прямоугольника). На выходе мы получаем текстуру, обработанную материалом ColorCorrection. Этот скрипт использует одну дополнительную текстуру rt0.

Полное описание .compositor файлов можно найти в официальной документации OGRE.

Создание материала

Создадим в нашей директории файл материала ColorCorrection.material. Поместим в него следующий скрипт:

fragment_program Compositor/ColorCorrection_fp_hlsl hlsl
{
	source Materials\PostEffects\ColorCorrection\ColorCorrection.cg_hlsl
	entry_point main_fp
	target ps_2_0	
}
 
fragment_program Compositor/ColorCorrection_fp_cg cg
{
	source Materials\PostEffects\ColorCorrection\ColorCorrection.cg_hlsl
	entry_point main_fp
	profiles arbfp1
}
 
fragment_program Compositor/ColorCorrection_fp unified
{
	delegate Compositor/ColorCorrection_fp_hlsl
	delegate Compositor/ColorCorrection_fp_cg
}
 
material Compositor/ColorCorrection
{
	technique
	{
 
		pass
		{
			depth_check off
 
			vertex_program_ref Compositor/StdQuad_vp
			{
			}
 
			fragment_program_ref Compositor/ColorCorrection_fp
			{
			}
 
			texture_unit
			{
				tex_address_mode clamp
				filtering none
			}
		}
	}
}

Скрипт материала занимается обработкой текстуры (в нашем случае - отрендеренной сцены), с помощью шейдера.

Написание шейдера

Наконец, последний файл, который относится к нашему постэффекту, это шейдер ColorCorrection.cg_hlsl. Он будет иметь следующий код:

sampler RT : register(s0);
 
float4 main_fp(
	uniform float4 multiplier,
	float2 texCoord : TEXCOORD0
) : COLOR
{
	multiplier = float4(1.5, 1, 1, 1);
 
	return tex2D(RT, texCoord) * multiplier;
}

В этом шейдере цвет каждого пикселя текстуры умножается на значение параметра multiplier. Вообще говоря, этот параметр должен передаваться из приложения, но для простоты, пока, мы зададим его прямо в шейдере. Таким образом, коэффициент постоянен и влияет только на компоненту красного цвета, увеличивая ее в полтора раза.

Добавление постэффекта в меню

После того как файлы постэффекта созданы, нужно добавить в приложение возможность использовать его. Зайдем в проект Game и откроем файл PostEffectWindow.cs. Найдем метод OnAttach и присоединим к списку listBox еще один элемент:

protected override void OnAttach()
{
	base.OnAttach();
 
	...
 
	listBox = (EListBox)window.Controls[ "List" ];
	listBox.Items.Add( "HDR" );
	listBox.Items.Add( "LDRBloom" );
	listBox.Items.Add( "Glass" );
	listBox.Items.Add( "OldTV" );
	listBox.Items.Add( "HeatVision" );
	listBox.Items.Add( "MotionBlur" );
	listBox.Items.Add( "RadialBlur" );
	listBox.Items.Add( "Blur" );
	listBox.Items.Add( "Grayscale" );
	listBox.Items.Add( "Invert" );
	listBox.Items.Add( "Tiling" );
 
	//Add your posteffect here...
	listBox.Items.Add("ColorCorrection");
 
	...
}

Скомпилируем и запустим проект. Теперь нажмем кнопку Run Demo. Для того, чтобы включить созданный нами эффект, перейдем в меню, нажав клавишу Escape. В меню нажмем кнопку Post Effects. В появившемся окне поставим галочку рядом с пунктом меню Color Correction.

Меню постэффекта

Выйдем из меню и убедимся, что изображение сцены приняло красный оттенок.

Постэффект, осуществляющий цветокоррекцию

Передача параметров

Модернизируем наш постэффект: реализуем передачу параметра в шейдер из приложения. Прежде мы умножали каждый пиксел отрендеренной сцены на постоянное значение, теперь же будем регулировать цветокоррекцию из меню.

Изменяем скрипт постэффекта

Следующие изменения несущественны для нашего примера, но могут пригодиться при создании более сложных постэффектов. При отрисовке квада (render_quad) в постэффекте, мы можем сгенерировать для него идентификатор. Это нужно, чтобы различать квады в методе класса постэффекта, вызываемом при отрисовке. В этом методе вам может понадобится передать параметры в шейдер, как в нашем случае. Но если постэффект использует несколько квадов их необходимо различать, для этого им и присваиваются идентификатор. У нас квад всего лишь один, но мы все же присвоим ему идентификатор. Это делается с помощью следующей строчки: identifier 500.

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

Полный листинг скрипта постэффекта приведен ниже:

compositor ColorCorrection
{
	technique
	{
		// Temporary textures
		texture rt0 target_width target_height PF_A8R8G8B8
 
		target rt0
		{
			// Render output from previous compositor (or original scene)
			input previous
		}
 
		target_output
		{
			// Start with clear output
			input none
 
			// Draw a fullscreen quad with the grayscale image
			pass render_quad
			{
				// Renders a fullscreen quad with a material
				material Compositor/ColorCorrection
				input 0 rt0
				identifier 500
			}
		}
	}
}

Изменяем код шейдера

Откроем файл шейдера ColorCorrection.cg_hlsl. Удалим из него строчку, присваивающую значение параметру multiplier:

sampler RT : register(s0);
 
float4 main_fp(
	uniform float4 multiplier,
	float2 texCoord : TEXCOORD0
) : COLOR
{
	return tex2D(RT, texCoord) * multiplier;
}

Класс постэффекта

Теперь нам нужно заставить приложение передавать параметр multiplier в шейдер. Для этого нам понадобится класс постэффекта. Откроем проект GameCommon и добавим в папку Post Processing проекта файл ColorCorrectionCompositorInstance.cs.

Вы можете найти другие классы постэффектов в папке Post Processing проекта GameCommon и использовать их в качестве примеров.

Пусть теперь в цветокоррекции участвуют все три компоненты цвета: Red (красный), Green (зеленый), Blue (синий). Таким образом, наш класс должен:

  • хранить значения коэффициентов умножения трех цветовых компонент,
  • передавать параметр в шейдер.

Ниже приведен код класса:

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Engine.MathEx;
using Engine.Renderer;
 
namespace GameCommon
{
    /// <summary>
    /// Color correction scene post processing compositor instance.
    /// </summary>
    [CompositorName("ColorCorrection")]
    public class ColorCorrectionCompositorInstance : CompositorInstance
    {
        static float red = 1;
        static float green = 1;
        static float blue = 1;
 
        public static float Red
        {
            get { return red; }
            set { red = value; }
        }
 
        public static float Green
        {
            get { return green; }
            set { green = value; }
        }
 
        public static float Blue
        {
            get { return blue; }
            set { blue = value; }
        }
 
        //
 
        protected override void OnMaterialRender(uint passId, Material material, ref bool skipPass)
        {
            if (passId == 500)
            {
                Vec4 multiplier = new Vec4(Red, Green, Blue, 1);
 
                GpuProgramParameters parameters = material.GetBestTechnique().
                    Passes[0].FragmentProgramParameters;
                parameters.SetNamedConstant("multiplier", multiplier);
            }
        }
    }
}

Как видим из кода, у класса есть три свойства, соответствующих трем цветовым компонентам, а также метод OnMaterialRender, вызываемый при отрисовке постэффекта.

Здесь мы проверяем идентификатор отрисовываемого квада, а затем из трех компонент формируем один параметр типа вектор. Мы используем тип параметра Vec4 (четырехмерный вектор), но четвертая компонента, на которую в шейдере умножается альфа-канал, у нас всегда равна единице.

Параметр мы передаем с помощью метода SetNamedConstant класса GpuProgramParameters, указывая имя параметра из шейдера и его значение.

Добавление настроек постэффекта в меню

Наконец, нам осталось добавить в меню постэффектов функциональность, касающуюся цветокоррекции. Прежде мы могли лишь включать и выключать наш постэффект. Теперь мы добавим возможность управления постэффектом из приложения.

Зайдем в проект Game и откроем файл PostEffectsWindow.cs. Найдем там метод UpdateCurrentPostEffectControls. В нем формируется внешний вид меню всех постэффектов. В конце метода, перед последней строчкой, добавим код для нашего постэффекта.

void UpdateCurrentPostEffectControls()
{
    noPostEffectUpdate = true;
 
    ...
 
    //ColorCorrection specific
    if (name == "ColorCorrection")
    {
        window.Controls["FloatParameter0Text"].Visible = true;
        window.Controls["FloatParameter0Text"].Text = "Red";
        window.Controls["FloatParameter0Value"].Visible = true;
        scrollBarFloatParameters[0].Visible = true;
        scrollBarFloatParameters[0].ValueRange = new Range(0, 5);
        scrollBarFloatParameters[0].Value = ColorCorrectionCompositorInstance.Red;
 
        window.Controls["FloatParameter1Text"].Visible = true;
        window.Controls["FloatParameter1Text"].Text = "Green";
        window.Controls["FloatParameter1Value"].Visible = true;
        scrollBarFloatParameters[1].Visible = true;
        scrollBarFloatParameters[1].ValueRange = new Range(0, 5);
        scrollBarFloatParameters[1].Value = ColorCorrectionCompositorInstance.Green;
 
        window.Controls["FloatParameter2Text"].Visible = true;
        window.Controls["FloatParameter2Text"].Text = "Blue";
        window.Controls["FloatParameter2Value"].Visible = true;
        scrollBarFloatParameters[2].Visible = true;
        scrollBarFloatParameters[2].ValueRange = new Range(0, 5);
        scrollBarFloatParameters[2].Value = ColorCorrectionCompositorInstance.Blue;
    }
 
    noPostEffectUpdate = false;
}

С помощью написанного выше кода, мы добавляем пользовательский интерфейс для изменения трех параметров, связанных с соответствующими свойствами нашего класса постэффекта. Мы используем по три элемента интерфейса на каждое свойство:

  • надпись с названием свойства,
  • ползунок для изменения значения,
  • надпись с текущим значением.

С визуальной частью мы закончили. Осталось лишь связать изменение положения ползунков в меню и изменение значений свойств нашего класса. В том же PostEffectsWindow.cs найдем метод UpdateCurrentPostEffect. В нем мы присвоим значения трех ползунков к соответствующим свойствам нашего класса.

Добавим следующий код в конец метода:

void UpdateCurrentPostEffect()
{
    ...
 
    if( enabled )
    {
        ...
 
        //ColorScale specific
        if (name == "ColorCorrection")
        {
            //Update post effect parameters
            ColorCorrectionCompositorInstance.Red = scrollBarFloatParameters[0].Value;
            ColorCorrectionCompositorInstance.Green = scrollBarFloatParameters[1].Value;
            ColorCorrectionCompositorInstance.Blue = scrollBarFloatParameters[2].Value;
        }
    }
}

На этом редактирование кода, работающего с постэффектом, завершено. Скомпилируем и запустим проект.

Меню постэффекта

Теперь настройках постэффекта можно изменять коэффициенты для трех цветовых компонент.

ColorCorrection в действии