В данной программе будет представлен пример, как работать с объёмными фигурами в
OpenGL на языке C#, где в итоге мы изобразим простой дом в 3-ёх мерном виде.
При построении фигур с подключением OpenGL важно помнить, что система координат отличается от декартовой системы координат и базисные вектора имеют следующие направления (по умолчанию)
При этом задание координат для точек имеет привычный нам вид
(X, Y, Z)
1. Начало работы:
В данной программе мы используем плагин SharpGL, который помимо поддержки OpenGL включает в себя создание шаблона с основными функциями при создании нового проекта, такие как:
public SharpGLForm(){} private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e){} private void openGLControl_OpenGLInitialized(object sender, EventArgs e){} private void openGLControl_Resized(object sender, EventArgs e){}
Как подключить SharpGL, смотрите здесь: http://grafika.me/node/365
2. Преобразование картинки к трёхмерному виду:
Для этого используется функция openGLControl_Resized(). В ней происходят наши преобразования координат для создания объёмного изображения:
private void openGLControl_Resized(object sender, EventArgs e) { // Возьмём OpenGL объект OpenGL gl = openGLControl.OpenGL; // Зададим матрицу проекции gl.MatrixMode(OpenGL.GL_PROJECTION); // Единичная матрица для последующих преобразований gl.LoadIdentity(); // Преобразование gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 100.0); // Данная функция позволяет установить камеру и её положение gl.LookAt( -5, 3, -6, // Позиция самой камеры (x, y, z) 0, 1, 0, // Направление, куда мы смотрим 0, 2, 0); // Верх камеры // Зададим модель отображения gl.MatrixMode(OpenGL.GL_MODELVIEW); }
3. Установка цвета фоновой заливки:
Для этого используется функция openGLControl_OpenGLInitialized(), в которой помимо фоновой заливки можно задать ряд других значения по умолчанию:
private void openGLControl_OpenGLInitialized(object sender, EventArgs e) { // Возьмём OpenGL объект OpenGL gl = openGLControl.OpenGL; // Устанавливаем цвет заливки по умолчанию (в данном случае цвет голубой) gl.ClearColor(0.1f, 0.5f, 1.0f, 0); }
4. Нарисуем крышу дома
Для начала нарисуем треугольник и посмотрим на него.
private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e) { // Возьмём OpenGL объект OpenGL gl = openGLControl.OpenGL; // Очищаем буфер цвета и глубины gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); gl.Begin(OpenGL.GL_TRIANGLES); // задаём какую фигуру будем рисовать gl.Color(1f, 0.2f, 0.0f); // здесь задаём цвет (для всех последующих элементов); // при повторном вызове Color() мы зададим цвет для последующих фигур; // иначе цвет будет одинаковым для всех фигур, до вызова следующей функции Color() gl.Vertex(0.0f, 2.5f, 0.0f); // здесь задаём координаты точек gl.Vertex(2.0f, 1.5f, -2.0f); gl.Vertex(2.0f, 1.5f, 2.0f); gl.End(); }
Получим следующую картинку (параметры для gl.LookAt(5, 4, 0, 0, 1, 0, 0, 1, 0)):
*Далее координаты фигур и изменение градуса поворота будут указываться в функции openGLControl_OpenGLDraw(), изменения gl.LookAt() производятся в функции openGLControl_Resized()*
Теперь дорисуем остальные стороны нашей "крыши" и посмотрим с другого ракурса. Получился следующий код:
gl.Begin(OpenGL.GL_TRIANGLES); gl.Color(1f, 0.2f, 0.0f); gl.Vertex(0.0f, 2.5f, 0.0f); gl.Vertex(2.0f, 1.5f, -2.0f); gl.Vertex(2.0f, 1.5f, 2.0f); gl.Color(1f, 0.3f, 0.0f); gl.Vertex(-2.0f, 1.5f, -2.0f); gl.Vertex(-2.0f, 1.5f, 2.0f); gl.Vertex(0.0f, 2.5f, 0.0f); gl.Color(1f, 0.4f, 0.0f); gl.Vertex(0.0f, 2.5f, 0.0f); gl.Vertex(2.0f, 1.5f, -2.0f); gl.Vertex(-2.0f, 1.5f, -2.0f); gl.Color(1f, 0.1f, 0.0f); gl.Vertex(0.0f, 2.5f, 0.0f); gl.Vertex(-2.0f, 1.5f, 2.0f); gl.Vertex(2.0f, 1.5f, 2.0f); gl.End();
gl.LookAt(5, 8, 0, 0, 1, 0, 0, 1, 0);
Получаем следующее изображение нашей крыши:
5. Рисуем стены и землю используя полигоны
Добавим следующий элемент кода после треугольника, который нарисует стену:
gl.Begin(OpenGL.GL_POLYGON); gl.Color(1f, 0.8f, 0f); gl.Vertex(2f, 0f, -2f); gl.Vertex(2f, 0f, 2f); gl.Vertex(2f, 1.5f, 2f); gl.Vertex(2f, 1.5f, -2f); gl.End();
gl.LookAt(5, 6, 0, 0, 1, 0, 0, 1, 0);
Получаем следующее изображение:
gl.LookAt(5, 6, 4, 0, 1, 0, 0, 1, 0);
Как мы видим, на данный момент у нас всего одна стена, поэтому дорисуем остальные стены и добавим двери на самую светлую сторону. Полигоны всех четырёх стен имеют следующие координаты и цвета:
// передняя часть дома gl.Begin(OpenGL.GL_POLYGON); gl.Color(1f, 1f, 0f); gl.Vertex(2f, 1.5f, -2f); gl.Vertex(2f, 0f, -2f); gl.Vertex(-2f, 0f, -2f); gl.Vertex(-2f, 1.5f, -2f); gl.End(); // правая часть дома gl.Begin(OpenGL.GL_POLYGON); gl.Color(1f, 0.8f, 0f); gl.Vertex(2f, 0f, -2f); gl.Vertex(2f, 0f, 2f); gl.Vertex(2f, 1.5f, 2f); gl.Vertex(2f, 1.5f, -2f); gl.End(); // задняя часть дома gl.Begin(OpenGL.GL_POLYGON); gl.Color(1f, 0.7f, 0f); gl.Vertex(2f, 0f, 2f); gl.Vertex(-2f, 0f, 2f); gl.Vertex(-2f, 1.5f, 2f); gl.Vertex(2f, 1.5f, 2f); gl.End(); // левая часть дома gl.Begin(OpenGL.GL_POLYGON); gl.Color(1f, 0.9f, 0f); gl.Vertex(-2f, 0f, -2f); gl.Vertex(-2f, 0f, 2f); gl.Vertex(-2f, 1.5f, 2f); gl.Vertex(-2f, 1.5f, -2f); gl.End(); // дверь (передняя стена) gl.Begin(OpenGL.GL_POLYGON); gl.Color(1f, 0.5f, 0f); gl.Vertex(0.3f, 0f, -2.01f); gl.Vertex(-0.3f, 0f, -2.01f); gl.Vertex(-0.3f, 1.2f, -2.01f); gl.Vertex(0.3f, 1.2f, -2.01f); gl.End();
gl.LookAt(5, 6, 4, 0, 1, 0, 0, 1, 0);
gl.LookAt(5, 6, -7, 0, 1, 0, 0, 1, 0);
Нарисуем землю с помощью полигона:
// рисуем землю gl.Begin(OpenGL.GL_POLYGON); gl.Color(0f, 1f, 0f); gl.Vertex(-10f, 0f, -10f); gl.Vertex(10f, 0f, -10f); gl.Vertex(10f, 0f, 10f); gl.Vertex(-10f, 0f, 10f); gl.End();
gl.LookAt(5, 6, -7, 0, 1, 0, 0, 1, 0);
6. Вращение вокруг заданной оси
Перед функцией public SharpGLForm() инициализируем переменную rotation (угол поворота).
float rotation = 0.0f; public SharpGLForm() { InitializeComponent(); }
Затем добавим (в openGLControl_OpenGLDraw()) функцию поворота и укажем ось, вокруг которой нам нужно вращать картинку. После написания кода, укажем насколько градусов разворачивать изображение за 1 кадр.
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); // Загружаем единичную матрицу gl.LoadIdentity(); // Указываем оси вращения (x, y, z) gl.Rotate(rotation, 0.0f, 1.0f, 0.0f); //---- Код ----- rotation += 1.5f;
Запускаем и получаем следующее изображение:
В итоге мы получили код, который целиком выглядит следующим образом:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using SharpGL; namespace OpenGL_lesson_CSharp { public partial class SharpGLForm : Form { float rotation = 0.0f; // переменная, которая будет задавать угол поворота public SharpGLForm() { InitializeComponent(); } // Функция, которая используется для рисования нашего объекта private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e) { // Возьмём OpenGL объект OpenGL gl = openGLControl.OpenGL; // Очищаем буфер цвета и глубины gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); // Загружаем единичную матрицу gl.LoadIdentity(); // Указываем оси вращения (x, y, z) gl.Rotate(rotation, 0.0f, 1.0f, 0.0f); // рисуем крышу gl.Begin(OpenGL.GL_TRIANGLES); gl.Color(1f, 0.2f, 0.0f); // здесь задаём цвет для каждой плоскости gl.Vertex(0.0f, 2.5f, 0.0f); gl.Vertex(2.0f, 1.5f, -2.0f); gl.Vertex(2.0f, 1.5f, 2.0f); gl.Color(1f, 0.3f, 0.0f); gl.Vertex(-2.0f, 1.5f, -2.0f); gl.Vertex(-2.0f, 1.5f, 2.0f); gl.Vertex(0.0f, 2.5f, 0.0f); gl.Color(1f, 0.4f, 0.0f); gl.Vertex(0.0f, 2.5f, 0.0f); gl.Vertex(2.0f, 1.5f, -2.0f); gl.Vertex(-2.0f, 1.5f, -2.0f); gl.Color(1f, 0.1f, 0.0f); gl.Vertex(0.0f, 2.5f, 0.0f); gl.Vertex(-2.0f, 1.5f, 2.0f); gl.Vertex(2.0f, 1.5f, 2.0f); gl.End(); // передняя часть дома gl.Begin(OpenGL.GL_POLYGON); gl.Color(1f, 1f, 0f); gl.Vertex(2f, 1.5f, -2f); gl.Vertex(2f, 0f, -2f); gl.Vertex(-2f, 0f, -2f); gl.Vertex(-2f, 1.5f, -2f); gl.End(); // правая часть дома gl.Begin(OpenGL.GL_POLYGON); gl.Color(1f, 0.8f, 0f); gl.Vertex(2f, 0f, -2f); gl.Vertex(2f, 0f, 2f); gl.Vertex(2f, 1.5f, 2f); gl.Vertex(2f, 1.5f, -2f); gl.End(); // задняя часть дома gl.Begin(OpenGL.GL_POLYGON); gl.Color(1f, 0.7f, 0f); gl.Vertex(2f, 0f, 2f); gl.Vertex(-2f, 0f, 2f); gl.Vertex(-2f, 1.5f, 2f); gl.Vertex(2f, 1.5f, 2f); gl.End(); // левая часть дома gl.Begin(OpenGL.GL_POLYGON); gl.Color(1f, 0.9f, 0f); gl.Vertex(-2f, 0f, -2f); gl.Vertex(-2f, 0f, 2f); gl.Vertex(-2f, 1.5f, 2f); gl.Vertex(-2f, 1.5f, -2f); gl.End(); // дверь (передняя стена) gl.Begin(OpenGL.GL_POLYGON); gl.Color(1f, 0.5f, 0f); gl.Vertex(0.3f, 0f, -2.01f); gl.Vertex(-0.3f, 0f, -2.01f); gl.Vertex(-0.3f, 1.2f, -2.01f); gl.Vertex(0.3f, 1.2f, -2.01f); gl.End(); // рисуем землю gl.Begin(OpenGL.GL_POLYGON); gl.Color(0f, 1f, 0f); gl.Vertex(-10f, 0f, -10f); gl.Vertex(10f, 0f, -10f); gl.Vertex(10f, 0f, 10f); gl.Vertex(-10f, 0f, 10f); gl.End(); rotation += 1.5f; // угол разворота за 1 кадр } // Эту функцию используем для задания некоторых значений по умолчанию private void openGLControl_OpenGLInitialized(object sender, EventArgs e) { // Возьмём OpenGL объект OpenGL gl = openGLControl.OpenGL; // Фоновый цвет по умолчанию (в данном случае цвет голубой) gl.ClearColor(0.1f, 0.5f, 1.0f, 0); } // Данная функция используется для преобразования изображения // в объёмный вид с перспективой private void openGLControl_Resized(object sender, EventArgs e) { // Возьмём OpenGL объект OpenGL gl = openGLControl.OpenGL; // Зададим матрицу проекции gl.MatrixMode(OpenGL.GL_PROJECTION); // Единичная матрица для последующих преобразований gl.LoadIdentity(); // Преобразование gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 100.0); // Данная функция позволяет установить камеру и её положение gl.LookAt( -5, 3, -6, // Позиция самой камеры (x, y, z) 0, 1, 0, // Направление, куда мы смотрим 0, 2, 0); // Верх камеры // Зададим модель отображения gl.MatrixMode(OpenGL.GL_MODELVIEW); } } }
Прикрепленный файл | Размер |
---|---|
Duma_OpenGL_lesson_CSharp.rar | 1.11 Мб |