Глава 37. Шейдеры GLSL. Текстурирование 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Глава 37. Шейдеры GLSL. Текстурирование



Все шейдеры в этой главе соответствуют стандартам GLSL 1.00 — 1.20.

 

Сначала немного поговорим о спецификации GLSL. Она такова, что работает только с текстурными координатами в пределах от 0 до 1.

Рассмотрим вышесказанное на примере. Допустим, у нас есть текстура размером 1024/512. И на этой текстуре есть точка с координатами (300, 120). Тогда её текстурные координаты по формуле будут равны:

x = 300/1024 = 0.29296875

y = 120/512 = 0.234375

Соответственно, если подставить сюда координаты левого угла, то получится 0/1024 = 0, если поставить координаты правого угла, то будет 1024/1024 = 1. То есть все координаты ложатся в диапазон от 0 до 1. Эта процедура называется нормализацией.

Если мы запишем 0.16 или 1123.16, то это будет указывать на одну и ту же точку. Почему? Как было только что написано, текстурные координаты могут находиться только в интервале от 0 до 1, а число 1213234.16 выходит из этого интервала. Поэтому GPU (видеокарта) при расчете координат выполняет операцию x = fract(x), т.е. отсекает целую часть числа. Стоит отметить, что на самом деле расчёт координат производится на всех видеокартах по-разному. Но результат всё равно получается схожим с тем, что получается при использовании fract.

А теперь что-нибудь затекстурируем. Подключите модуль GLContext, иначе компилятор не будет знать о TGLProgramHandle. Поскольку наш шейдер опять будет применяться к сфере, подключите к проекту GLObjects; так же нужно подключить OpenGL1x. Поместите на форму GLScene1 (инспектор объектов сцены), GLSceneViewer. В инспекторе объектов создайте камеру, ее Position.Z присвойте значение 2; свойству GLSceneViewer. Camera присвойте GLCamera. Также в инспекторе объектов создайте GLDirectOpenGL. Для того, чтобы увидеть результат действия шейдера, объявим MySphere:TGLSphere;

Теперь самое главное для шейдерного текстурирования. Почти у всех визуальных объектов есть свойство Material.TextureEx. Мы уже рассказывали вам про него, вот что говорилось: «Это контейнер для дополнительных текстур, текстур, которые можно использовать как альфу, как текстуру деталей и т.п.» Вот и пришло время использовать этот контейнер. Создайте в нём один материал, в который мы будем загружать текстуру. Делать это будем в FormCreate, вот и код:

procedure TForm1.FormCreate(Sender: TObject);

begin

MySphere:=TGLSphere.Create(nil); //Сначала нужно создать объект.

MySphere.Material.TextureEx.Add;

MySphere.Material.TextureEx.Items[0].Texture.Image.LoadFromFile(‘Texture.jpg’);

MySphere.Material.TextureEx.Items[0].Texture.Disabled:=False;

end;

 

Теперь объявите в программе две константы для хранения вершинного (_vp) и фрагментного (_fp) шейдеров.

const _vp =

‘varying vec2 TexCoord;’+

‘void main(void)’+

‘{‘+

‘gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;’+

‘TexCoord = gl_MultiTexCoord0.xy;’+

‘}’;

Первая строка — gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex — нам уже знакома. Она производит трансформацию вершин с учётом мировой матрицы.

А теперь разберёмся с TexCoord = gl_MultiTexCoord0.xy. Поскольку мы должны передать во фрагментный шейдер текстурные координаты текущей вершины (а сам фрагментный шейдер не может получить эту информацию), мы используем присваивание TexCoord = gl_MultiTexCoord0.xy. Индекс 0 отвечает за текстурную грань. Всего граней может быть 8.

В начале вершинного шейдера мы объявили varying величину TexCoord. Тип varying означает, что к переменной будут иметь доступ и другие шейдеры (если там тоже объявлен TexCoord). Посмотрите на вторую строку фрагментного шейдера; поскольку мы также объявили там varying vec2 TexCoord, и этот шейдер сможет читать и перезаписывать переменную. После слова varying идёт задание типа переменной; у нас это вектор, который хранит x и y координаты. Третьим словом идёт имя переменной.

texture2D(Tex, gl_TexCoord[0].xy): тут мы получаем из текстуры с именем «Tex» цвет точки с позицией gl_TexCoord[0].xy. x и y в конце вставлены так как в вершинном шейдере записывались только они. Теоретически, в вершинном шейдере мы можем записывать значение ещё и в z и w координат, но для двухмерных текстур это нам не нужно.

сonst _fp =

‘uniform sampler2D Tex;’+

‘varying vec2 TexCoord;’+

‘void main (void)’+

‘{‘+

‘gl_FragColor = texture2D(Tex, TexCoord);’+

‘}’;

Здесь мы также использовали uniform переменную. Задание этой переменной начинается, как вы поняли, с зарезервированного слова uniform; второе слово задаёт тип; третье имя. Приложение через unifom передаёт шейдеру любые величины: текстуры, матрицы, структуры, вектора, int и float числа и т.д. Uniform-переменные могут быть прочитаны (но не перезаписаны) всеми шейдерами — вершинным, пиксельным и геометрическим. Также мы использовали специальный тип sampler2D для работы с текстурами.

Возвращаемя в Delphi. Объявите переменную GLSLHandle типа TGLProgramHandle. Она нужна для управления шейдером. Как и в предыдущий раз, мы будем использовать два события OnRender у GLDirectOpenGL. Вот первое:

procedure TForm1.GLDirectOpenGLInit(Sender: TObject;

var rci: TRenderContextInfo);

begin

if not (GL.ARB_shader_objects and GL.ARB_vertex_program and

GL.ARB_vertex_shader and GL.ARB_fragment_shader) then

begin

ShowMessage(‘Ваша видеокарта не поддерживает GLSL шейдеры!’);

Halt;

end;

GLSLHandle:= TGLProgramHandle.CreateAndAllocate;

// Добавляем вершинный шейдер.

GLSLHandle.AddShader(TGLVertexShaderHandle, _vp);

// Добавляем фрагментный шейдер.

GLSLHandle.AddShader(TGLFragmentShaderHandle, _fp);

// Если у драйвера возникли какие-то нарекания,

// два оператора ниже оповестят о них пользователя.

if not GLSLHandle.LinkProgram then

raise Exception.Create(GLSLHandle.InfoLog);

if not GLSLHandle.ValidateProgram then

raise Exception.Create(GLSLHandle.InfoLog);

GL.CheckError;

 

with GLSLHandle do

begin

UseProgramObject;

Uniform1i[‘Tex’]:= 0;

EndUseProgramObject;

end;

GLDirectOpenGL.OnRender:= GLDirectOpenGLRender;

GLDirectOpenGL.BuildList(rci);

end;

Комментирую новое для вас. В строке Uniform1i[‘DirtTex’]:=0 мы указываем, что в шейдер, в переменную Tex, передается текстура с индексом 0, заданная в свойстве Material.TextureEx. Но перед тем как передать что-то в шейдерный объект, его нужно активировать (UseProgramObject), иначе OpenGL не будет знать куда передавать этот юниформ; после же передачи, шейдерный объект нужно деактивировать (EndUseProgramObject), чтобы не вызвать ошибок.

А теперь моя любимая часть — использование шейдеров на объекте. Событие OnRender у GLDirectOpenGL и приведите к такому виду:

procedure TForm1.GLDirectOpenGLRender(Sender: TObject;

var rci: TRenderContextInfo);

begin

with GLSLHandle do

begin

UseProgramObject;

MySphere.Render(rci);

EndUseProgramObject;

end;

end;

 

Последний штрих — напишите в OnCreate формы GLDirectOpenGL.OnRender:=GLDirectOpenGLInit или сделайте то же самое в design time.

В шейдер мы можем передавать разные данные, используя Uniform…. Ниже приведена таблица всех возможных свойств Uniform… и их значений.

Свойство Описание
Uniform1i Передаёт в шейдер одно значение типа int.
Uniform2i Передаёт в шейдер два значения типа int.
Uniform3i Передаёт в шейдер три значения типа int.
Uniform4i Передаёт в шейдер четыре значения типа int.
Uniform1f Передаёт в шейдер одно значение типа float.
Uniform2f Передаёт в шейдер два значения типа float.
Uniform3f Передаёт в шейдер три значения типа float.
Uniform4f Передаёт в шейдер четыре значения типа float.
UniformMatrix2fv Передаёт в шейдер матрицу 2x2
UniformMatrix3fv Передаёт в шейдер матрицу 3x3
UniformMatrix4fv Передаёт в шейдер матрицу 4x4
UniformTextureHandle Передаёт в шейдер дескриптор некой текстуры.
UniformBuffer Передаёт так называемый юниформ буфер. Юниформ буфер позволяет передавать блоки из uniform. Всё это очень муторно, ведь перед непосредственно передачей блока нужно ещё и сгенерировать и заполнить Uniform Buffer Object. Но как компенсацию нам обещают некоторое повышение производительности. Поддерживается только при наличии расширения ARB_uniform_buffer_object.

Вот такой шарик получился с моей текстурой:

Готовый пример берите здесь: http://narod.ru/...

 



Поделиться:


Последнее изменение этой страницы: 2016-04-19; просмотров: 387; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.222.117.109 (0.013 с.)