Цвет и точки
Содержание
Введение
Шаблон кода
Цвет
Точки
Заключение

Введение
Доброе время суток. И мы приступаем ко второму уроку, в котором я расскажу вам о цвете и о точках. Также в этом уроке мы создадим шаблон кода, который будем использовать в последующих уроках.  
Шаблон кода
Этот урок я хотел начать с шаблона кода, так как в последующих уроках мы будем использовать этот шаблон кода и заодно вспомним, как подключать OpenGL к нашим проектам. Создайте новый проект и сразу сохраните его, например, модуль под названием Unit.pas, проект как  OpenGL, а форму как frmGL.
В первую очередь, надо в разделе uses прописать наш заголовочный файл dglOpenGL. Если у вас нет этого заголовочного файла, то скачайте его с этого сайта или сайта разработчиков www.delphiGL.com
Теперь необходимо объявить две глобальные переменные формы в разделе public:
dc : HDC  - это контекст устройства и rc : HGLRC – это контекст рендеринга. Надеюсь, с прошлых уроков вы помните, что это такое.
Теперь необходимо создать  сперва контекст устройства, а затем контекст рендеринга, лучше всего это сделать  в событии формы OnCreate. Код представлен ниже:

procedure TfrmGL.FormCreate(Sender: TObject);
begin
DC := GetDC(Handle); //Определяем, что контекстом устройства будет  наше окно
if not InitOpenGL then //если OpenGL не доступна, то приложение закрываем
Application.Terminate;
RC := CreateRenderingContext(DC,[opDoubleBuffered],32,24,0,0,0,0); //здесь создаем контекст рендеринга, //необходимыми параметрами, в предыдущем уроке мы их изучали
ActivateRenderingContext(DC,RC); //теперь активируем и связываем контекст рендеринга и контекст //устройства
end;

Так как мы создавали контексты, то соответственно их надо, и удалить, лучше всего это сделать в событии формы OnDestroy, код представлен ниже:

procedure TfrmGL.FormDestroy(Sender: TObject);
begin
DeactivateRenderingContext; //деактивируем контекст рендеринга (разрываем связь между контекстами)
DestroyRenderingContext(RC); //разрушаем контекст рендеринга
ReleaseDC(Handle,DC); //разрушаем контекст устройства
end;

Теперь нам необходимо создать маленькую процедуру, в которой будут изначально, включаться необходимые состояния OpenGL. Назовем ее SetupGL и пропишем её в разделе private нашей формы. Теперь нажмем сочетание клавиш Ctrl+Shift+C и сразу создаться наша процедура в ней напишем следующее:

procedure TfrmGL.SetupGL;
begin
glClearColor(0.0,0.0,0.0,0.0); //цвет фона
glEnable(GL_DEPTH_TEST); //включить тест глубины
glEnable(GL_CULL_FACE); //показывать только передние грани
end;

После создания этой процедуры ее надо добавить в событие OnCreate нашей формы, после активации контекстов. Так же нам необходимо объявить две константы
const
NearClipping = 1; //ближняя плоскость отсечения
farClipping = 100; //дальняя плоскость отсечения

Теперь нам необходимо создать саму процедуру рисования. Назовем её Render и пропишем в разделе private нашей формы. Опять нажимаем сочетание клавиш Ctrl+Shift+C и в созданной процедуре пишем следующее:

procedure TfrmGL.Render;
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); //очищаем буфер цвета и буфер глубины

//эти команды мы изучим позже 
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluPerspective(45.0,ClientWidth/ClientHeight,NearClipping,FarClipping);   glMatrixMode(GL_MODELVIEW);
glLoadIdentity;   glTranslatef(0.0,0.0,-5.0);   SwapBuffers(DC); // эта команда выводит содержимого буфера на экран, если вы забудете написать эту //команду, то у вас ничего выводится, не будет.
end;
так же нам надо создать процедуру, которая реагировала бы на изменения размеров окна, для этого хорошо подходит событие формы OnResize.

procedure TfrmGL.FormResize(Sender: TObject);
var
tmpBool : Boolean;
begin
glViewport(0,0,ClientWidth,ClientHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluPerspective(45.0,ClientWidth/ClientHeight,NearClipping,FarClipping);   glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
IdleHandler(Sender,tmpBool);
end;

Теперь нам необходимо создать процедуру, которая вызывала бы нашу процедуру рисования render. Лучше всего это сделать в событие OnIdle нашего окна, эта событие вызывается, когда наше приложение находится в простое. Назовем её IdleHandler, и пропишем ее там же, где прописались наши основные события:

type
TfrmGL = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure IdleHandler(Sender : TObject;var Done : Boolean);
procedure FormDestroy(Sender: TObject);

Ставим курсор на нашу процедуру IdleHandler, нажимаем знакомое сочетание Ctrl+Shift+C и в созданной процедуре пишем следующее:

procedure TfrmGL.IdleHandler(Sender: TObject; var Done: Boolean);
begin
Render;
ErrorHandler;
sleep(1);
Done := FALSE;
end;

Теперь нам необходимо добавить одну строчку в конце события создания формы:

Application.OnIdle := IdleHandler;

И еще, запомните, что из под Delphi никогда не следует отлаживать ваши программы, в которых используется OpenGL. Поэтому мы напишем небольшую процедуру ErrorHandler, которая будет выводить ошибки (если они возникнуть) в заголовке нашего окна. Можно было бы сделать, конечно, и красивее, например все записывать в log-файл. Но мы сделаем, чтоб ошибки отображались в заголовке окна. И так в разделе Private напишем нашу процедуру ErrorHandler, нажмем тоже сочетание клавиш, надеюсь, вы его помните. И в созданной процедуре напишем следующее:

procedure TfrmGL.ErrorHandler;
begin
frmGL.Caption := gluErrorString(glGetError);
end;

Вот и все наш шаблон готов, если вы сейчас откомпилируете проект, то вы увидите только черный экран. Ну, это же шаблон, рисовать мы будем с каждым новым уроком, начиная с этого шаблона. Постойте, это еще не шаблон мы же его еще не сохранили как шаблон. Сохраните проект. Чтобы наш проект был  как шаблон, и не приходилось каждый раз писать код создания и удаления контекстов,  необходимо в меню Project выбрать пункт Add to Repository.. Перед вами должно открыться окно Add to Repository.

Слева выбираем Delphi Projects. В поле Title пишем OGL, в поле Description можете написать какое-нибудь описание к шаблону, также можете написать автора в поле Author и поменять иконку, нажав кнопку Browse.. Но, я ничего этого не делал написал только загловок OGL. Теперь чтобы открыть наш шаблон необходимо просто в меню File> New выбрать пункт Others. Перед вами должно появится окно New Items и в нем выбрать наш шаблон который мы сохраняли под именем OGL. После того как мы его выбрали, Delphi нам сразу предложит в какую папку сохранить новый проект, выбираем папку и сохраняем. Советую для каждого проекта создавать свою собственную папку. Закройте delphi и попробуйте создать проект из нашего шаблона, сейчас мы будем программировать используя OpenGL.
Цвет
Чтобы задать цвет фона необходимо ввести команду glClearColore у которой 4 параметра, первый указывает на долю красного цвета, второй на долю зеленого цвета, третий на долю синего цвета, четвертый на долю альфа (прозрачности). Все эти параметры от нуля до единицы – тип GLclampf. Ну чтобы очистить фон заданным цветом необходимо вызвать команду glClear с константой GL_COLOR_BUFFER_BIT. Вы можете не вызывать команду glClearColor, если хотите чтоб цвет фона был черный, потому что по умолчанию цвет фона черный. Но если мы хотим задать цвет фона красным, то необходимо вводить команду c параметрами glClearColor(1.0,0.0,0.0,0.0)  и при следующем вызове glClear(GL_COLOR_BUFFER_BIT) фон окрасится в красный цвет. При использовании этой функции может произойти ошибка, если команду glClearColor вызвать между командными скобками OpenGL (glBegin/glEnd). Тут может возникнуть вопрос. А что сделать если мы хотим закрасить фон определенным цветом, а значение параметров не знаем. Тут вам поможет моя маленькая программа ColorGL, в которой вы выбираете цвет, а она выводит значение параметров R,G,B для OpenGL. Её вы можете скачать с этого сайта. В OpenGL правильнее сначала определять цвет примитивов и объектов а потом их рисовать. И если однажды мы опредлим цвет перед рисованием, то все примитивы будут рисоваться этим цветом, до тех пор, пока мы снова не зададим новый цвет. Это можно показать с помощью псевдокода:
Задать цвет (красным)
Нарисовать объект (А)
Нарисовать объект (Б)
Задать цвет (синий)
Задать цвет (зеленный)
Нарисовать объект(В)
Здесь объекты А и Б нарисуются красным цветом, а объект В нарисуется зеленным, так как он был определен последним. Если мы будет рисовать другие объекты после объекта В, то они тоже будут рисоваться зеленым цветом, до тех пор пока мы не определим новый цвет.
Для установки цвета примитивов используется команда glColor3f(), у неё три аргумента типа GLclampf (вещественного типа с плавающей точкой от 0 до 1). Эти аргументы задают интенсивность цвета красного, зеленого и синего по порядку. Если будет стоять ноль, то данный компонент в этом цвете отсутвует, а еденица означает максимальную интенсивность данного цвета.
В этом уроке представлено простое закрашивание, на самом деле в OpenGL можно, разукрасить объект сложнее, задать цвет объекта синим, местами сделать чтоб на него падал желтый свет, и еще где-то на него доходил красный цвет, сделать затетение. Но это тема будет в следующих уроках.
Точки
            Наверняка, вы все помните из уроков алгебры или геометрии, что такое точка. В OpenGL это практически тоже самое. Но есть некоторые отличия, первое отличие это в том что все вычисления в  OpenGL с плавающей точкой, имеют погрешности огругления. Другое различие заключается в том, что в дисплеях минимальный отображаемый элемент является пиксель, а пиксель на экране может быть размером менее 1/100 дюйм, но все равно больше точки в математике. Поэтому, когда OpenGL выполняет вычисления, предполагается, что точка представлена вектором чисел с плавающей точкой и точка рисуется в виде пикселя (но всегда точка может рисоваться в виде одного пикселя), а множество различных точек с немного различающими координатами может быть нарисовано OpenGL в одном и том же пикселе.  Поэтому стоит запомнить, что мы работаем не с физическими экранными координатами и пикселями, а с позиционными координатами в выбраном объеме отсечения. Мы поручаем OpenGL забоиться о том, как спроектировать точки, линии и объекты трехмерного пространства на двухмерное изображение экрана.
И так, мы уже знаем, точка представлена набором вещественных чисел, называемых вершиной. Как мы знаем, положение точки в пространстве опредляется тремя координатами x,y,z так же и в OpenGL. Чтобы нарисовать точку с помощью  OpenGL необходимо сначала открыть командные скобки OpenGL. Командой glBegin открывается командная скобка OpenGL, а командой glEnd закрывается командная скобка OpenGL. После того как мы открываем командную скобку, командой glBegin(), необходимо укзаать пареметр, который указывал бы какой примитив мы будем рисовать.  Чтобы нарисовать точку (точки), необходимо в скобках указать константу GL_POINTS, которая указывает, что мы будет рисовать точки. После чего мы вызываем команду glVertex3f в которой указываем координаты (x, y, z), после чего закрывает командную скобку OpenGL командой glEnd. Вот так будет выглядить примерный код:
glBegin(GL_POINTS);
glVertex3f(2.0,-2.0,0.5);
glEnd;
Если мы хотим изобразить несколкьо точек, команду glVertex3f необходимо вызывать столько раз сколько мы хотим нарисовать точек. Например здесь уже нарисуется уже три точки:
glBegin(GL_POINTS);
glVertex3f(2.0,-2.0,0.5);
glVertex3f(-2.0,2.0,-0.5);
glVertex3f(2.0,2.0,0.5);
glEnd;

Также мы  в командных скобках OpenGL может создавать циклы, например:

glBegin(GL_POINTS);
for i:= 1 to 10 do
glVertex3f(random,random,random);
glEnd;

нарисует 10 точек в слцчайном порядке.

Так а давайте теперь изобразим что-нибудь более красивее. Например, сферу из точек. Откроем наш шаблон выбираем папку куда сохраняем наш проект и в процедуре render нашего шаблона объявим две переменные i и j типа Integer. Так же нам понадобится одна глобальная переменная spin типа GLfloat и еще три глобальных переменных r,g,b типа GLfloat, их надо объявить в разделе var нашего модуля. Теперь в процедуре SetupGL. Помните? мы договорились, в ней задавать начальные значения. Вот она теперь нам и понадобиться. И так в процедуре SetupGL после уже написаного кода необходимо дописать:

glPointSize(2);
glEnable(GL_POINT_SMOOTH);
spin := 1.0;
r := 0.5;
g := 0.5;
b := 0.5;
end;

В первой строчке мы задаем размер точки. Размер точки в OpenGL можно задать командой glPointSize() – у нее единственный параметр, который устанавливает ширину рисуемой точки (в пикселях). По умолчанию размер точки равен единицы, и этот парметр не должен быть равен нулю.
Во второй строчки мы видим еще одну новую команду glEnable, эта команда включает определенные режимы, для этой процедуры есть великое множество констант, одну из которых вы сейчас видите это GL_POINT_SMOOTH. Если эту строчку закомментировать, то наши точки будут квадратными, при включеном этом режиме наши точки округляются, превращаясь в окружность на экране.Чтобы отключить этот режим, необходимо вызвать команду glDisable с этой же константой GL_POINT_SMOOTH. И после этого все рисуемые точки вновь будут квадратными. По умолчанию сглаживание точек отключено, поэтому нам и пришлось включать режим сглаживания точек.
Переменная spin будет влият на угол поворота, а переменные r,g,b будут определять какой цвет текущий.
Теперь снова перейдем к фунции рисования, она у нас называется Render. В ней после строчки glTranslatef(0.0,0.0,-5.0); напишем следующий код:

glRotatef(spin,1.0,1.0,1.0);
glBegin(GL_POINTS);
for i := -90 to 90 do
for j := 0 to 360 do
begin
glColor3f(r,g,b);
glvertex3f(1.5*sin(j)*cos(i), //координата X
1.5*sin(j)*sin(i),        //координата Y
1.5*cos(j));                //координата Z
end;
glEnd;
SwapBuffers(DC); //выводим содержание буфера на экран
end;
glRotatef эту команду мы еще не изучали, но забегая вперед скажу, что она поворачивает координатную сетку на угол указанный в переменной spin, другие три параметра указывают, относительно какой оси поворачивать. Потом мы открываем командную скобку OpenGL в которой рисуем сферу из точек, цветом r,g,b.
Далее рисуем точки сферы, так как их много, то рисование точек происходит в цикле.
Если вы хорошо изучали геометрию, то сферу можно представить параметрическим уравнением: Где, (x0,y0,z0) – Центр сферы, R – радиус сферы, ? Є [-?/2,?/2), а ? Є [0,2?],
Как вы видите, центр сферы у нас совпадает с центром координатной сетки,  а радиус сферы равен 1,5.
Теперь для большей наглядности добавим на форму компонент TTimer, установим свойство interval равным 25 и в событии Timer1Timer, напишем следующий код:

spin := spin + 1.0; //здесь увеличиваем угол поворота
if spin > 360 then //если угол поворота больше 360, то его уменьшаем на 360
spin := spin - 360;
r := r + 0.001; //увеличиваем интенсивность красного цвета для точек
if r>=1.0 then
r := 0.0;
b := b - 0.001; //уменьшаем интенсивность синего цвета для точек
if b <= 0.0 then
b := 1.0;
g := g + 0.001; //увеличиваем интенсивность зеленого цвета для точек
if g >= 1.0 then
g := 0.25;
Теперь попробуйте откомпилировать проект, у вас должен получится, вращающийся шар из точек, который меняет свой цвет. Если что-то не получилось, прочтите внимательно, или скачайте готовый пример с этого сайта. И не стесняйтесь, можете отправить мне письмо oryth84@gmail.com или написать в ICQ 590138.
У вас может возникнуть вопрос, зачем мы используем таймер, когда все можно использовать в процедуре IdleHandler или в таймере. Вопрос очень прост, чтобы эта программа работала на всех компьютерах одинаково. Потому что на более мощных компьютерах процедура IdleHandler будет вызываться быстрее, настолько быстро, что вы можете ничего не увидеть. Поэтому изменение координат происходит в таймере, а вот процедура рисования уже вызывается в IdleHandler.
Заключение
Надеюсь, вам понравился этот урок, и вы будете читать дальнейшие мои уроки. Вы, возможно, еще скажите, зачем нам эти точки или что-то подобное. Но вспомните уроки химии, любое вещество состоит из молекул, а молекулы из более мелких частиц. Вы с помощью точек можете уже рисовать графики функций, смоделировать броуновское движение частиц, или сделать игру. Скажите, невозможно сделать игру из одних точек, ошибаетесь. С этого сайта вы можете скачать игру, Points, которая сделана из одних точек OpenGL. Эта игра не претендует на лавры шедевра, она просто как пример, что можно сделать игру из одних точек, была бы только фантазия.


Скачать игра "Точки"


Скачать шаблон кода


Скачать программу ColorGL для определения значений параметров цвета для OpenGL


Скачать примеры с точками для OpenGL * одним архивом


© Олин Р.И. aka Oryth email: oryth84@gmail.com ICQ #590138



OpenGL и Delphi. Урок 1. || Оглавление || OpenGL и Delphi. Урок 3.