Пример, рассматриваемый в данной главе, будет немного более сложным, но при этом динамичным и более интересным.
Сейчас же мы попробуем нарисовать двухмерный треугольник. Его особенность будет заключаться в том, что при установке каждой его вершины, мы будем задавать отдельный цвет, умножаемый на некоторую переменную. Таким образом, цвет на протяжении плоскости треугольника будет интерполироваться между цветов вершин, и так мы получим разложенный спектр цветов на треугольнике.
Также мы внесем в код управляемые переменные, которые смогут влиять на установку цвета в определенной вершине, и тем самым в реальном времени посмотреть, как может быть разложен различный цветовой спектр.
Итак, приступим. В первую очередь создайте новый проект и реализуйте на нем систему визуализации, основанную на объекте SimpleOpenGLControl и подключении ссылок к библиотекам Tao, как это было рассказано в главе 4.4. Настройки инициализации OpenGL (код функции Form1_Load будет соответствовать коду, представленному в главе 4.4).
На всякий случай код функции-обработчика события Form1_Load:
/*http://esate.ru, Anvi*/
private void Form1_Load(object sender, EventArgs e)
{
// инициализация библиотеки GLUT
Glut.glutInit();
// инициализация режима окна
Glut.glutInitDisplayMode(Glut.GLUT_RGB | Glut.GLUT_DOUBLE);
// устанавливаем цвет очистки окна
Gl.glClearColor(255, 255, 255, 1);
// устанавливаем порт вывода, основываясь на размерах элемента управления AnT
Gl.glViewport(0, 0, AnT.Width, AnT.Height);
// устанавливаем проекционную матрицу
Gl.glMatrixMode(Gl.GL_PROJECTION);
// очищаем ее
Gl.glLoadIdentity();
// теперь необходимо корректно настроить 2D ортогональную проекцию
// в зависимости от того, какая сторона больше
// мы немного варьируем то, как будут сконфигурированы настройки проекции
if (AnT.Width <= AnT.Height)
Glu.gluOrtho2D (0.0, 30.0, 0.0, 30.0 * (float)AnT.Height / (float)AnT.Width);
else
Glu.gluOrtho2D(0.0, 30.0 * (float)AnT.Width / (float)AnT.Height, 0.0, 30.0);
// переходим к объектно-видовой матрице
Gl.glMatrixMode(Gl.GL_MODELVIEW);
}
Помимо этого, нам понадобится добавить на окно программы дополнительные элементы управления: 3 элемента TrackBar (вы можете найти их в Панели элементов (ToolBox) в конце самого первого свитка («Все формы Windows Forms»), три элемента Label, которые будут находиться над элементами TrackBar и содержать названия коэффициентов, которыми будут управлять данные TrackBar’.
Также под каждым элементом TrackBar будут находиться по одному дополнительному элементу label для вывода текущего значения параметра, которым управляет данный ползунок.
Сверху будут находиться элементы label1, label2, label3, а снизу label4, label5, label6.
Разместите все элементы, как показано на рисунке 1. Для того чтобы элемент TrackBar стал вертикальным, необходимо в его свойствах указать параметр Orientation равным Vertical.
Рисунок 1. Пример расположения элементов на форме.
В свойствах TackBar'ов необходимо указать диапазон значений:
Minimum - 0
Maximum - 1000
TickFrequensy - 10 (количество позиций между отметками)
Для первого TackBar'а установите значение (Value) равное 1000. Для остальных – 0.
Выполните двойной щелчок левой клавишей мыши по каждому TrackBar'у, чтобы создать функции обработчики события перемещения ползунка пользователем.
В начале класса, отвечающего за нашу форму, добавьте следующую строку (для порядка и исключения путаницы в коде разместите эту строку перед функцией Form1_Load).
/*http://esate.ru, Anvi*/
double a = 1, b = 0, c = 0;
Теперь реализуем функцию, отвечающую за рисование. Назовем ее Draw. Эта функция будет вызываться при нажатии на кнопку «Визуализировать» и при перемещении управляющих ползунков на TrackBar'ах, так как при этом будут изменяться коэффициенты a, b, c и наша сцена будет нуждаться в повторной визуализации.
Код функции с подробными комментариями:
/*http://esate.ru, Anvi*/
// функция Draw
private void Draw()
{
// очищаем буфер цвета
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);
// активируем рисование в режиме GL_TRIANGLES, при котором задание
// трех вершин с помощью функции glVertex2d или glVertex3d
// будет объединяться в трехгранный полигон (треугольник)
Gl.glBegin(Gl.GL_TRIANGLES);
// устанавливаем параметр цвета, основанный на параметрах a b c
Gl.glColor3d(a, b, c);
// рисуем вершину в координатах 5,5
Gl.glVertex2d(5.0, 5.0);
// устанавливаем параметр цвета, основанный на параметрах с a b
Gl.glColor3d(c, a, b);
// рисуем вершину в координатах 25,5
Gl.glVertex2d(25.0, 5.0);
// устанавливаем параметр цвета, основанный на параметрах b c a
Gl.glColor3d(b, c, a);
// рисуем вершину в координатах 25,5
Gl.glVertex2d(5.0, 25.0);
// завершаем режим рисования примитивов
Gl.glEnd();
// дожидаемся завершения визуализации кадра
Gl.glFlush();
// обновляем изображение в элементе AnT
AnT.Invalidate();
}
Функции обработчики перемещения ползунка в TrackBar'ах будут выглядеть следующим образом:
/*http://esate.ru, Anvi*/
private void trackBar1_Scroll(object sender, EventArgs e)
{
// генерация коэффициента
a = (double)trackBar1.Value / 1000.0;
// вывод значения коэффициента, управляемого данным ползунком.
// (под TrackBa'ом)
label4.Text = a.ToString();
}
private void trackBar2_Scroll(object sender, EventArgs e)
{
// генерация коэффициента
b = (double)trackBar2.Value / 1000.0;
// вывод значения коэффициента, управляемого данным ползунком.
// (под TrackBa'ом)
label5.Text = b.ToString();
}
private void trackBar3_Scroll(object sender, EventArgs e)
{
// генерация коэффициента
c = (double)trackBar3.Value / 1000.0;
// вывод значения коэффициента, управляемого данным ползунком.
// (под TrackBa'ом)
label6.Text = c.ToString();
}
Для корректной визуализации в том случае, если, например, наше окно перекроет какое-либо другое, мы добавим в нашу форму объект Таймер. Он будет отсчитывать промежутки времени таким образом, чтобы примерно 40 раз в секунду перерисовывать содержимое нашего окна.
Для того чтобы добавить объект, перейдите к окну ToolBox, выберите свитке «Компоненты» элемент Timer (рис. 2) и перетащите на форму.
Рисунок 2. Добавление элемента Timer для визуализации.
Место, куда вы перетащите этот элемент не важно, он не занимает его на форме и отобразится в полоске таких «не занимающих место» объектов под формой.
Щелкните по нему и перейдите в его свойства.
Смените параметр name на значение RenderTimer, а параметр Interval на значение 25 (раз в 25 миллисекунд будет вызываться событие OnTimer).
Теперь щелкните по нему двойным щелчком левой клавиши мыши. Создатся функция обработчик события OnTimer. Отсюда мы будем вызывать функцию Draw:
/*http://esate.ru, Anvi*/
private void RenderTimer_Tick(object sender, EventArgs e)
{
// функция визуализации
Draw();
}
Кнопка «Визуализировать» будет отвечать за активацию этого таймера. Для этого будет использоваться функция Start:
/*http://esate.ru, Anvi*/
// обработчики кнопки "Визуализировать"
private void button1_Click(object sender, EventArgs e)
{
// страт таймера, отвечающего за вызов функции
// визуализирующей кадр
RenderTimer.Start();
}
И в заключении, назначьте обработчик кнопке «Выйти»:
/*http://esate.ru, Anvi*/
// обработчики кнопки "Выйти"
private void button2_Click(object sender, EventArgs e)
{
// выход из приложения
Application.Exit();
}
Вот и все, если вы правильно выполнили все инструкции, то теперь после компиляции и запуска программы вы сможете управлять разложением спектра на треугольнике (рис. 3 и 4).
Рисунок 3. Пример визуализации треугольника с разложенным спектром в OpenGL C#.
Рисунок 4. Еще один пример визуализации треугольника с измененными коэффициентами, влияющими на цвета в вершинах.