- •Учебник
- •Оглавление
- •Введение
- •Глава 1
- •I. Установка
- •II. Удаление
- •Глава 2. Первый проект
- •Глава 3. Создание сцены в режиме design time
- •Создание объектов:
- •Глава 4. Примитивные объекты. Вкладка Basic geometry.
- •Глава 5. Ориентация, координаты.
- •Глава 6. Движение.
- •Глава 7. Как узнать, сколько сейчас fps?
- •Глава 8. Полноэкранный режим.
- •Глава 9. Работа с материалами.
- •I. Прямое обращение к .Material
- •Глава 10. Использование 3d моделей.
- •I. Форматы моделей
- •Глава 11. Прокси объекты.
- •Глава 12. Создание земной поверхности с glTerrainRenderer.
- •Глава 13. Создание земной поверхности с glFreeForm.
- •Глава 14. Итоги работы с glTerainrender и glFreeForm.
- •Глава 15. Создание земной поверхности с glHeightField.
- •Глава 15. Создание неба.
- •Глава 16. GlAtmosphere.
- •Глава 17. Спецэффекты.
- •I. Огонь
- •II. Молния
- •III. Дождь
- •IV. Снег
- •VI. Блики от источников света
- •Глава 18. Растительность.
- •I. Деревья и кустарники
- •II. Трава
- •Глава 19. Работа со шрифтами и вывод надписей.
- •I. Вывод текста через компонент glWindowsBitmapFont
- •II. Проблема с glWindowsBitmapFont в Windows Vista
- •Глава 20. Выделение объекта мышкой.
- •Глава 21. Создание сцены в режиме runtime.
- •Глава 22. Тени.
- •Глава 23. Туман.
- •Глава 24. Vbo или расширение arb_vertex_buffer_object в OpenGl.
- •Глава 25. Fbo или расширение ext_framebuffer_object в OpenGl.
- •Глава 26. Рисование на канве.
- •Глава 27. Использование чистого OpenGl.
- •Глава 28. Звуки.
- •I. Проигрывание звуков с помощью bass
- •II. Проигрывание звуков с помощью fmod
- •III. Проигрывание звуков с помощью OpenAl
- •Глава 29. Игровое меню.
- •Глава 30. Примитивная физика dce.
- •Глава 31. Физика ode.
- •II. Основы библиотеки ode(: tglodeManager и tglodeJointList) на примере создания подобия боулинга.
- •Глава 32. Физика Newton.
- •Глава 33. Ручная проверка коллизий.
- •V. Ручная проверка коллизии
- •Глава 34. Шейдеры. Терменология.
- •Глава 35. Шейдеры. История и компоненты.
- •Глава 36. Шейдеры glsl. Введение.
- •Глава 37. Шейдеры glsl. Использование без компонентов. Самый примитивный шейдер.
- •Глава 38. Шейдеры glsl. Немного о спецификации. Типы данных и переменные
- •Стандартные функции
- •Поддерживаемые компоненты векторов
- •Глава 40. Шейдеры glsl. Текстурирование.
- •Глава 41. Шейдеры glsl. Использование без компонентов. Мультитекстурирование. Смешение трёх цветов по базовой карте.
- •Глава 42. Шейдеры glsl. Использование через компонент glslShader. Часть первая – Первые шаги.
- •Глава 43. Шейдеры glsl. Использование через компонент glslShader. Часть вторая – знакомимся со светом. Передача параметров в шейдер.
- •Глава 44. Шейдеры glsl. Использование через компонент glslShader. Часть третья – текстуры.
- •Глава 45. RenderMonkey.
- •Глава 46. Оптимизация программы.
- •Глава 47. Практика. Создание мира
- •Приложение
- •I. Типы векторов и матриц
- •II. Работа с векторами
- •III. Работа с матрицами
- •IV. Методы объектов glScene
- •Предметный указатель по компонентам glScene
Глава 36. Шейдеры glsl. Введение.
GLSL (The OpenGL Shading Language) - шейдерный язык OpenGL. GLSL основан на языке ANSI C. Большинство возможностей языка ANSI C сохранено, к ним добавлены векторные и матричные типы данных, часто применяющиеся при работе с трехмерной графикой. В отличие от HLSL/Cg язык создавался в расчете на будущее железо, поэтому теоретически он намного мощнее. В частности, GLSL много взял от RenderMan Shading Language.
Для программ на GLSL требуется поддержка следующих расширений:
-
GL_ARB_shader_objects;
-
GL_ARB_shading_language_100;
-
GL_ARB_vertex_shader;
-
GL_ARB_fragment_shader.
Следует отметить, что в OpenGL и, следовательно, в GLSL нет геометрических шейдеров.
Нижеследующие статьи посвящены использованию GLSL без каких-либо компонентов и с использованием компонента GLSLShader. Сейчас я попробую рассказать о плюсах обоих способов.
С GLSLShader.
1. Лёгкость в настройке параметров.
2. Лёгкость при работе с весьма малым количеством шейдеров.
Без GLSLShader.
1. Контролировать работу шейдера гораздо проще.
2. Вам не понадобится при каждом новом шейдере заводить на форме очередной компонент GLSLShader, что уменьшает рутину и экономит память.
3. Если вы используете много шейдеров, не придётся перебирать множество окон и искать, какой компонент за какой шейдер отвечает.
4. При использовании Turbo Delphi код модифицировать не придётся.
Частично материал последующих глав позаимствован отсюда: http://wingman.org.ru/glsl
Глава 37. Шейдеры glsl. Использование без компонентов. Самый примитивный шейдер.
Сейчас мы сделаем, пожалуй, самый примитивный шейдер. Мы покрасим сферу в красный цвет. Итак, приступим. Поместите на форму GLScene1 (инспектор объектов сцены), GLSceneViewer. В инспекторе объектов создайте камеру, свойству GLCamera.Position.Z присвойте значение 2; свойству GLSceneViewer.Camera присвойте GLCamera. Так же в инспекторе объектов создайте GLDirectOpenGL. Последний нужен, поскольку мы будем использовать прямой доступ к OpenGL. Для того чтобы увидеть результат действия шейдера, создадим сферу.
И подключите модуль GLContext, иначе компилятор не будет знать о TGLProgramHandle. Так же нужно подключить модуль OpenGL1x. Теперь объявите в программе две константы типа string для хранения вершинного (vp) и фрагментного (fp) шейдера. Учтите, что текст любого шейдера это всегда константа т.к. шейдер нельзя изменять в runtime. Сейчас оба текста мы поместим в код программы для облегчения редактирования. Но учтите, часто их помещают в виде отдельных файлов.
const _vp:string=
'void main(void){'+
'gl_Position = ftransform();'+
'}';
Прежде, чем мы сможем работать с вершинами нам необходимо их трансформировать с учётом глобальной (мировой) матрицы. Вот это и выполняется командой gl_Position = ftransform(). По сути, эта команда должна присутствовать во всех вершинных шейдерах, хотя вместо неё можно использовать более очевидную функцию: gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;. То есть перемножение матрицы вида на координаты текущей вершины.
_fp:string=
'void main(void){'+
'gl_FragColor = vec4(4,0,0.1,0);'+
'}';
vec4 - это вектор, состоящий из 4-х компонентов - x,y,z,w.
Тут требуется пояснение касательно кода шейдеров вообще.
В коде шейдера обязательно должна быть функция main(). Это касается всех типов шейдеров. Так же пользователь может объявлять свои функции. Ещё всегда помните, что GLSL различает маленькие и большие буквы.
В GLSL существует возможность рендинга сразу в несколько цветовых буферов – это называется Multiple Render Targets. Тогда в шейдерной программе вместо GL_FragColor пишется GL_FragData[]. Обратите внимание, что не допускается одновременная работа с gl_FragColor и glFragData. Подробнее о MRT можете прочитать здесь: http://steps3d.narod.ru/tutorials/mrt-tutorial.html.
Возвращаемся в 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;
GLSphere.Render(rci);
EndUseProgramObject;
end;
Небольшое замечание – вы можете иметь столько программ-шейдеров, прилинкованных и готовых к употреблению, сколько хотите, но не больше чем это позволяет GPU.
Разберём использованные свойства класса TGLProgramHandle и его потомка – класса GLSLHandle.
Свойство |
Описание |
CreateAndAllocate |
Каждая программа хранится как дескриптор. А это свойство создаёт и распределяет дескриптор. |
AddShader |
Добавление шейдера. Первый параметр – тип шейдера. Может быть TGLVertexShaderHandle (вершинный шейдер) либо TGLFragmentShaderHandle (фрагментный шейдер), но никак иначе. Второй параметр – константа, содержащая текст шейдера.
|
LinkProgram |
Линкует шейдер. Перед вызовом этого оператора шейдер уже должен быть откомпилирован.
|
ValidateProgram |
Проверяет правильность программы шейдера. |
InfoLog |
Хранит информацию о последней произведённой операции. И по требованию выводит её. К сожалению, для сообщений InfoLog нет никакой спецификации, так что разные драйвера и видеокарты могут выдавать разный текст.
|
UseProgramObject |
Функция для загрузки и использования шейдера. |
EndUseProgramObject |
Функция, обозначающая конец использования программы шейдера. Если вовремя не применить эту функцию, шейдер будет применяться ко всем объектам сцены. |
Ну, собственно и всё. Запускайте проект и смотрите на работу самого примитивного GLSL шейдера. Внизу на картинке результат выполнения программы. Думаю, вас удивило то, что шар превратился в круг. Всё дело в том, что чтобы вернуть “шару” шарообразный вид, нужно учитывать освещение, что у нас не делается. Но в этой главе делать мы этого и не будем. Этому посвящена глава 33.