В данной программе будет реализовано создание пирамиды с переливающимися гранями, куба с разноцветными гранями, их одновременное разобщенное вращение с помощью различных методов технологии OpenGL для языка С# - SharpGL - в проекте Windows Forms.
Работа с OpenGL в WPF почти ничем не отличается, поэтому смело можно использовать описанный в данном уроке материал. О том, как подключить SharpGL в WPF проекте или проекте Windows Forms, читайте тут http://grafika.me/lessons.
Из новых методов стоит отметить gl.Flush();. Этот метод контролирует правильное обновление изображений.
1. Создадим пирамиду
Первое, что необходимо сделать - нарисовать грани. Однако для реализации переливающегося цвета граней нам понадобится задавать цвет каждой вершины отдельно, которые в данном примере будут окрашены в красный, синий и зеленый цвета.
Так как в предыдущем уроке уже было реализовано что-то подобное, сразу зададим вращение нашему объекту. Создадим переменную - значение угла поворота, и будем менять ее на каждой итерации отрисовки. Сам поворот реализуется методом gl.Rotate(angle, X.Xf, Y.Yf, Z.Zf);, где (X.Xf, Y.Yf, Z.Zf) - координаты вектора на оси, вокруг которой будет осуществляться вращение. Для начала просто посмотрим на пирамиду сбоку, для этого просто повращаем фигуру вокруг ее оси Y.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using SharpGL; namespace SharpGL { public partial class Form1 : Form { public Form1() { InitializeComponent(); } float rtri = 0; private void openGLControl1_OpenGLDraw(object sender, RenderEventArgs args) { // Создаем экземпляр OpenGL gl = this.openGLControl1.OpenGL; // Очистка экрана и буфера глубин gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); // Пирамида ///////////////////////////// // Сбрасываем модельно-видовую матрицу gl.LoadIdentity(); // Сдвигаем перо влево от центра и вглубь экрана gl.Translate(0.0f, 0.0f, -5.0f); // Вращаем пирамиду вокруг ее оси Y gl.Rotate(rtri, 0.0f, 1.0f, 0.0f); // Рисуем треугольники - грани пирамиды gl.Begin(OpenGL.GL_TRIANGLES); // Front gl.Color(1.0f, 0.0f, 0.0f); gl.Vertex(0.0f, 1.0f, 0.0f); gl.Color(0.0f, 1.0f, 0.0f); gl.Vertex(-1.0f, -1.0f, 1.0f); gl.Color(0.0f, 0.0f, 1.0f); gl.Vertex(1.0f, -1.0f, 1.0f); // Right gl.Color(1.0f, 0.0f, 0.0f); gl.Vertex(0.0f, 1.0f, 0.0f); gl.Color(0.0f, 1.0f, 0.0f); gl.Vertex(1.0f, -1.0f, -1.0f); gl.Color(0.0f, 0.0f, 1.0f); gl.Vertex(1.0f, -1.0f, 1.0f); // Back gl.Color(1.0f, 0.0f, 0.0f); gl.Vertex(0.0f, 1.0f, 0.0f); gl.Color(0.0f, 1.0f, 0.0f); gl.Vertex(1.0f, -1.0f, -1.0f); gl.Color(0.0f, 0.0f, 1.0f); gl.Vertex(-1.0f, -1.0f, -1.0f); // Left gl.Color(1.0f, 0.0f, 0.0f); gl.Vertex(0.0f, 1.0f, 0.0f); gl.Color(0.0f, 1.0f, 0.0f); gl.Vertex(-1.0f, -1.0f, 1.0f); gl.Color(0.0f, 0.0f, 1.0f); gl.Vertex(-1.0f, -1.0f, -1.0f); gl.End(); // Контроль полной отрисовки следующего изображения gl.Flush(); // Меняем угол поворота rtri -= 3.0f; } } }
Вот что получим на выходе:
Изменим на gl.Rotate(rtri, 0.0f, 0.0f, 1.0f);, т.е. покрутим вокруг оси Z. Естественно, получим просто треугольник, который вращается вокруг своей вершины, в действительности - это вершина пирамиды, не принадлежащая основанию.
Самое интересное - вращение вокруг оси X. Увидим, что дна у пирамиды нет, т.к. оно и не было изначально отрисовано. Тем не менее, грани внутри пирамиды также переливаются.
2. Вращение куба.
Отрисуем грани с помощью метода gl.Begin(OpenGL.GL_QUADS);, зададим вращение вокруг оси (1.0, 1.0, 1.0).
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using SharpGL; namespace SharpGL { public partial class Form1 : Form { public Form1() { InitializeComponent(); } float rquad = 0; private void openGLControl1_OpenGLDraw(object sender, RenderEventArgs args) { // Создаем экземпляр OpenGL gl = this.openGLControl1.OpenGL; // Очистка экрана и буфера глубин gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); // Куб /////////////////////////////// // Сбрасываем модельно-видовую матрицу gl.LoadIdentity(); // Сдвигаем перо вправо от центра и вглубь экрана, но уже дальше gl.Translate(0.0f, 0.0f, -10.0f); // Вращаем куб вокруг его диагонали gl.Rotate(rquad, 1.0f, 1.0f, 1.0f); // Рисуем квадраты - грани куба gl.Begin(OpenGL.GL_QUADS); // Top gl.Color(0.0f, 1.0f, 0.0f); gl.Vertex(1.0f, 1.0f, -1.0f); gl.Vertex(-1.0f, 1.0f, -1.0f); gl.Vertex(-1.0f, 1.0f, 1.0f); gl.Vertex(1.0f, 1.0f, 1.0f); // Bottom gl.Color(1.0f, 0.5f, 0.0f); gl.Vertex(1.0f, -1.0f, 1.0f); gl.Vertex(-1.0f, -1.0f, 1.0f); gl.Vertex(-1.0f, -1.0f, -1.0f); gl.Vertex(1.0f, -1.0f, -1.0f); // Front gl.Color(1.0f, 0.0f, 0.0f); gl.Vertex(1.0f, 1.0f, 1.0f); gl.Vertex(-1.0f, 1.0f, 1.0f); gl.Vertex(-1.0f, -1.0f, 1.0f); gl.Vertex(1.0f, -1.0f, 1.0f); // Back gl.Color(1.0f, 1.0f, 0.0f); gl.Vertex(1.0f, -1.0f, -1.0f); gl.Vertex(-1.0f, -1.0f, -1.0f); gl.Vertex(-1.0f, 1.0f, -1.0f); gl.Vertex(1.0f, 1.0f, -1.0f); // Left gl.Color(0.0f, 0.0f, 1.0f); gl.Vertex(-1.0f, 1.0f, 1.0f); gl.Vertex(-1.0f, 1.0f, -1.0f); gl.Vertex(-1.0f, -1.0f, -1.0f); gl.Vertex(-1.0f, -1.0f, 1.0f); // Right gl.Color(1.0f, 0.0f, 1.0f); gl.Vertex(1.0f, 1.0f, -1.0f); gl.Vertex(1.0f, 1.0f, 1.0f); gl.Vertex(1.0f, -1.0f, 1.0f); gl.Vertex(1.0f, -1.0f, -1.0f); gl.End(); // Контроль полной отрисовки следующего изображения gl.Flush(); // Меняем угол поворота rquad -= 3.0f; } } }
Получим такую анимацию:
3. Совместное вращение
Из приведенных примеров становится ясно, что вращение - достаточно легкая тема, особенно если реализовывать это с помощью технологии OpenGL. Для того, чтобы получить справа ту же вращающуюся пирамиду и тот же куб, нам необходимо скомпоновать примеры и отдельно задать координаты пера.
... // Пирамида. Очищаем матрицу. Сдвигаем перо влево от центра и вглубь gl.LoadIdentity(); Translate(-1.5f, 0.0f, -5.0f); ... // Куб. Очищаем матрицу. Сдвигаем перо вправо от центра и вглубь gl.LoadIdentity(); Translate( 1.5f, 0.0f, -5.0f); ... gl.End();
Для получения анимации просто надо просто скачать проект и запустить.
Можно также поэкспериментировать, кое-где не сбрасывая матрицу, установить вращение только вокруг одной оси, попытаться сделать синхронный поворот, установить прозрачность цветов.
Прикрепленный файл | Размер |
---|---|
Ametov_SharpGL.zip | 390.27 кб |
Комментарии
У меня проблема вот с этим: gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);.
Вылезает ошибка: CS1061 "object" не содержит определения "GL_COLOR_BUFFER_BIT", и не удалось найти доступный метод расширения "GL_COLOR_BUFFER_BIT", принимающий тип "object" в качестве первого аргумента (возможно, пропущена директива using или ссылка на сборку).
Хочу с ней разобраться.