Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебник по GLScene.doc
Скачиваний:
253
Добавлен:
16.12.2018
Размер:
7.18 Mб
Скачать

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

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

Рассмотрим вышесказанное на примере. Допустим, у нас есть текстура размером 1024/512. И на этой текстуре есть точка с координатами (300, 120). Тогда её текстурные координаты по формуле будут равны: s = 300/1024 = 0.29296875 t = 120/512 = 0.234375 Соответственно если подставить сюда координаты левого угла, то получится 0/1024 = 0, если поставить координаты правого угла, то будет 1024/1024 = 1. То есть все координаты ложатся в диапазоне от 0 до 1. Эта процедура называется нормализацией.

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

Стоит отметить, что на самом деле расчёт координат производится на всех видеокартах по – разному. Но результат всё равно получается схожим с тем, что получается при использовании fract.

А теперь что – нибудь затекстурируем. Поместите на форму GLScene1 (инспектор объектов сцены), GLSceneViewer. В инспекторе объектов создайте камеру, свойству GLCamera.Position.Z присвойте значение 2; свойству GLSceneViewer.Camera присвойте GLCamera. Так же в инспекторе объектов создайте GLDirectOpenGL. Последний нужен, поскольку мы будем использовать прямой доступ к OpenGL. Для того чтобы увидеть результат действия шейдера, создадим сферу. Она будет называться GLSphere.

Теперь очень важная вещь. Необходимо зайти в окошко Editing GLSphere.TextureEx. Открывается это окошко при нажатии на многоточии свойства GLSphere.Material.TextureEx. Там (в окошке) нужно создать один материал. Свойству .Texture.Disabled этого матириала нужно присвоить значение False. И, как наверное вы уже догадались, в него нужно загрузить текстуру.

И подключите модуль GLContext, иначе компилятор не будет знать о TGLProgramHandle. Так же нужно подключить модуль OpenGL1x. Теперь объявите в программе две константы типа string для хранения вершинного (vp) и фрагментного (fp) шейдера.

const _vp:string=

'void main(void){'+

'gl_Position = ftransform();'+

'gl_TexCoord[0] = gl_MultiTexCoord0;'+

'}';

Первая строка - gl_Position = ftransform(); нам уже знакома. Она обозначает трансформацию вершин с учётом мировой матрицы.

А теперь разберёмся с gl_TexCoord[0] = gl_MultiTexCoord0. Поскольку мы должны передать во фрагментный шейдер текстурные координаты текущей вершины (а сам фрагментный шейдер не может получить эту информацию) мы используем команду gl_TexCoord[0] = gl_MultiTexCoord0;

_fp:string=

'uniform sampler2D DirtTex;'+

'void main (void){'+

'vec4 Dt = texture2D(DirtTex, gl_TexCoord[0].xy);'+

'gl_FragColor = Dt;'+

'}';

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

Так же мы использовали специальный тип sampler2D, для работы с текстурами.

…texture2D(DirtTex, gl_TexCoord[0].xy);…

тут мы получаем цвет точки из нашей текстуры.

Возвращаемя в Delphi. Объявите переменную glsl типа TGLProgramHandle. Она нужна для управления шейдером.

GLSLHandle:TGLProgramHandle;

И переменную для проверки успешности запуска. Значение задаётся в зависимости от результата инициализации шейдера и будет записано один раз, что избавит программу от лишних проверок и значительно повысит быстродействие.

InitDGL:boolean;

Теперь в событие OnRender объекта GLDirectOpenGL добавим сам код инициализации шейдера.

if not InitDGL=true then 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);

CheckOpenGLError;

InitDGL:=True;

end;

if InitDGL then

with GLSLHandle do begin

UseProgramObject;

Uniform1i['DirtTex']:=0;

GLSphere.Render(rci);

EndUseProgramObject;

end;

В строке Uniform1i['DirtTex']:=0; мы указываем, что в шейдер, в переменную 'DirtTex', передается текстура с индексом 0, заданная в свойстве .Material.TextureEx.

В шейдер мы можем передавать разные данные используя 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

Предаёт в шейдер дескриптор некой текстуры.