The Open Toolkit Manual (Russian)

Добро пожаловать на страницы русского перевода руководства по OpenTK. Мы хотим поблагодарить Вас за то, что вы используете нашу библиотеку.
В этом руководстве рассказывается о том, как написать проект при помощи OpenTK. Вы научитесь тому, как создать новый проект, как наилучшим образом применить возможности OpenTK и тому, как распространять проект среди конечных пользователей.
Дополнительно в этом руководстве Вы найдете информацию о том, как создавать производительный код и как сохранить условие кросс-платформенной совместимости.
Руководство написано таким образом, что Вам не обязательно читать его от первой до последней главы. Вы можете свободно пропускать целые главы и потом вернуться к ним в следующий раз. Имейте в виду, что Вы можете добавить комментарий в любом месте руководства – хорошая обратная связь поможет нам вместе сделать это руководство лучше. Это принесет пользу не только Вам, но и будущим пользователям OpenTK.
Мы надеемся, что время, потраченное Вами на чтение руководства, принесет Вам пользу.
Давайте начнем.

Ссылка на оригинальный текст

Vertex Buffer Objects

Введение
Преимущество VBO в том, что мы можем заставить OpenGL сохранять информацию, используемую для рисования – такую как позиция, цвет, координаты текстур и вектора нормали, непосредственно в памяти видеокарты и передавать напрямую каждый раз когда мы хотим отобразить. До сих пор это можно было сделать с помощью Display List, и по сравнению с ним, VBO имеет ряд преимуществ в получении указателя на данные в видеопамяти и в случае необходимости изменять эти данные. Это приводит к сильному повышению производительности для динамических массивов точек и на протяжении многих лет является лучшим решением для хранения статических и динамических массивов.
Как создать
Работа с VBO схожа с объектами текстурами, мы должны вначале создать/удалить указатель на объект, связать его с существующими данными или заполнить новыми данными. В этом уроке нам понадобиться два объекта. Первый это VBO содержащий подробную информацию о Вершинах (в нашем случае это координаты и цвет) и IBO ссылающийся на данные из VBO для создания из вершин треугольников. Преимущество заключается в том, что после загрузки VBO и IBO данными мы можем отобразить всю фигуру с помощью одного вызова GL.DrawElements().
Сначала мы создаем для Объекта для использования
uint[] VBOid = new uint[ 2 ];
GL.GenBuffers( 2, out VBOid );
Маловероятно, но возможно что OpenGL не хватит памяти для загрузки данных или то, что расширение не поддерживается. Это можно проверить вызовом GL.GetError(). Если всё прошло гладко то мы имеем два доступных для работы объекта.
Как удалить
OpenGL должен удалять все свои данные при удалении контекста воспроизведения. Хорошей идеей служит самостоятельное удаление данных после того как они больше не нужны. Мы удаляем созданные объекты путем вызова
GL.DeleteBuffers( 2, ref VBOid );
Как связать
Для того чтобы выбрать с каким объектом мы будем работать, достаточно связать с Version15.ArrayBuffer или Version15.ElementArrayBuffer. Первый используется для хранения положения, UV, нормалей и так далее (VBO), а второй для определения геометрии (IBO).
GL.BindBuffer( Version15.ArrayBuffer, VBOid[ 0 ] );
GL.BindBuffer( Version15.ElementArrayBuffer, VBOid[ 1 ] );
Совсем необязательно использовать два буфера, к примеру ты можешь использовать только VBO и хранить информацию о геометрии в системной памяти. Также, созданные два объекта не обязательно должны быть связаны вместе, ты можешь связать VBO с другим IBO.
Здесь есть две вещи о которых нельзя забывать
1) Во время работы с VBO GL.EnableClientState(EnableCap.VertexArray); должен быть задействован. Если используешь цвет GL.EnableClientState(EnableCap.ColorArray), просто как обычный Vertex Array.
2) Все относящиеся к Vertex Array команды должны использоваться для задействованных объектов, перед использованием необходимо указать на ноль для отключения аппаратного VBO
GL.BindBuffer( Version15.ArrayBuffer, 0 );
GL.BindBuffer( Version15.ElementArrayBuffer, 0 );
Заполнение данными
Есть несколько путей для заполнения объектов данными, в этом уроке мы сфокусируемся на GL.InterleavedArrays и прямой записью в память видеокарты.
1. GL.InterleavedArrays
Начнем с подготовки IBO, здесь нет разницы с чего начинать первыми. Для простоты сделаем то, что быстрее всего.
Мы должны удостоверитьтся в том что правильно связали объекты (этого не требуется если объекты уже были связаны. Здесь мы просто вносим ясность с каким объектом ведется работа)
GL.BindBuffer( Version15.ElementArrayBuffer, VBOid[ 1 ] );
В этом примере используется тип ushort для граней, потому максимальное значение для этого типа 65535 больше чем используемое нами Сторон. При использовании настоящих наборов это число может быть и больше и поэтому стоит задумать об использовании типа наподобие uint. В данном случае используя ushort мы экономим два байта на каждый индекс как если бы мы использовали тип UInt32.

У функции GL.BufferData первый параметр это назначение по которому мы хотим использовать, второй это количество памяти (в байтах) которое мы хотим использовать для хранения своих данных. Третий параметр это указатель на данные которые мы хотим отправить видеокарте, его тип должен быть IntPtr (целочисленный указатель). Здесь можно использовать IntPtr.Zero указатель на ноль если мы заполним данные на последующем этапе с помощью GL.MapBuffer (подробнее об этом позже). Последний параметр это подсказка драйверу видеокарте об оптимизации, это поможет расположить твои данные в наилучшем месте по твоему желанию. В таблице 1 приведен полный список опций.

GL.BufferData( Version15.ElementArrayBuffer, (IntPtr) ( Indices.Length * sizeof( ushort ) ), Indices, Version15.StaticDraw );

На этом всё, OpenGL скопирует доступные грани и мы можем освободить массив на который ссылаясь. Теперь у нас есть Массив Индексов который можно использовать позже.

Итак, мы сохранили индисы в IBO, теперь пора считать Вершины. Еще раз убедимся что связали всё правильно и окончим оптимизацией.

GL.BindBuffer( Version15.ArrayBuffer, VBOid[ 0 ] );
GL.BufferData( Version15.ArrayBuffer, (IntPtr) ( Vertices.Length * 6 * sizeof( float ) ), Vertices, Version15.StaticDraw );

Итак мы сохранили всю информацию о графике и перед вызовом GL.DrawElements должны кое что сделать. Вершины которые мы хотим использовать содержат не только координаты, но и цвета с которыми будут отображаться. GL.InterleavedArrays позволяет включить/выключить необходимое состояние клиента для правильной интерпретации наших загруженных данных OpenGL , первый параметр говорит о том что у нас есть 3 float для описания цвета (C3F) и 3 float для описания позиции (V3F). Второй параметр это шаг с которым должен быть совершен переход от первой вершины ко второй, третьей и так далее. Последний параметр должен быть указатель на Indeces, но мы уже загрузили его в видеопамять, поэтому второй раз указывать не нужно.

GL.InterleavedArrays( InterleavedArrayFormat.C3fV3f, 0, null );

Преимущество этой команды в том что она позволяет ясно объяснить OpenGL с какие данные нужно выводить и также это позволяет оптимизировать память. Запомни что GL.InterleavedArrays сработает только если включены EnableCap.VertexArray, EnableCap.ColorArray или изменялись GL.VertexPointer или GL.ColorPointer. Незабудь включить их обратно иначе ничего не произойдет.

Для более детального описания о состояниях Массива Вершин обращайся к RedBook или к описанию команд OpenGL.

Глава 1 : Установка

Для использования OpenTK требуется .Net 2.0 runtime (Windows) или последняя версия 1.2.x Mono release (Linux/Mac OS X/Windows). При использовании Mono, настоятельно рекомендуем обновиться до последней доступной версии - версии младше, чем 1.2.6, содержат серьезные ошибки, которые могут повлиять на стабильность OpenTK.
Если Вы планируете скомпилировать библиотеку OpenTK самостоятельно из исходных текстов, то для этого Вам понадобиться Nant (в дальнейшем эта зависимость будет удалена)
Последнее и, наверное, самое главное, не забудьте посетить страницу проекта и скачать последнюю версию OpenTK. OpenTK распространяется в виде zip/7z – архива. Установка заключается в извлечении содержимого архива на Ваш жесткий диск. На данный момент не возможно инсталлировать OpenTK в глобальный кеш сборок (GAC).
Для использования OpenTK, необходимо чтобы Ваш проект ссылался на OpenTK.dll. Также поместите файл OpenTK.dll.config в папку проектом для достижения совместимости «скомпилировал один раз – запустил везде».
Следующие страницы посвящены более детальным инструкциям.

Ссылка на оригинальную страницу

Создание приложений на основе Windows.Form + OpenGL

[Статья не закончена]

В этом руководстве рассказывается о том, как написать оконное приложение с помощью OpenTK.

Сперва добавить, потом перемешать

Начнем с того, что создадим пустую форму. Далее щелчком правой кнопки мыши, в любом пустом месте «ToolBox», откроем диалог «Choose Item…». Здесь необходимо нажать на кнопку «Browse» и указать путь к OpenTK.dll. Проверь, появился ли компонент «GLControl» на закладке «.NET Framework Components», так как это показано на рисунке.

После этого добавь компонент GLControl на твою форму, так же как и любой другой .NET компонент. На твоей форме появиться новый компонент GLControl с именем glControl1.
Сразу бросатеся в глаза то, что glControl1 содержит в себе «графический мусор», не думай, что это проблемы связаны с твоей видеокартой. Все дело в том, что под капотом GLControl происходит вызов GLContext (контекст отвечающий за прорисовку изображения), который создается только во время выполнения твоей программы.

Рецепт красоты.

Как уже было сказано, GLContext создается во время выполнения программы. Поэтому получить доступ к свойствам glControl1 можно только после создания GLContext. После запуска приложения, обратиться к glControl можно после того, как было обработано событие Load().
Выполнение команд начинающихся с GL.* возможен в любом месте программы (кроме конструктора формы).
Как проверить был ли создан контекст или нет? Одним из решением этого вопроса служит объявление переменой
bool loaded = false
которая принимает значение true, при обработке Load()

 public partial class Form1 : Form
  {
    bool loaded = false;

    public Form1()
    {
      InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      loaded = true;
    }
  }

Теперь, для того чтобы избавить себя от ошибки обращения к несуществующему контексту, обращением к glControl1, добавим следующие строчки

private void glControl1_Resize(object sender, EventArgs e)
{
      if (!loaded)
        return;
}

Заводим мотор. Минимальное приложение на OpenTK

Пришло время увидеть что-нибудь на экране монитора. В разделе Using добавляем ссылки на пространство имен библиотеки OpenTK и OpenTK.Enums и реализуем обработку события OnPaint()

using OpenTK.OpenGL;
using OpenTK.OpenGL.Enums;

...

private void glControl1_Paint(object sender, PaintEventArgs e)
{
   if (!loaded) //Пока контекст не создан
     return;

   GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
   glControl1.SwapBuffers();
}

Скомпилируй и запусти проект. То что ты видишь это настоящий "Черный Квадрат" от создателей OpenTK.

Теперь давайте добавим немного цвета. Лучшее место для размещения кода задающего «цвет очистки» - в обработке события OnLoad()

   private void Form1_Load(object sender, EventArgs e)
    {
      loaded = true;
      GL.ClearColor(Color.SkyBlue);
    }

Немного настроек

Следующее шаг- это создание желтого треугольника. Для начала (если ты желаешь стать добропорядочным жителем страны OpenGL) установим ортографическую матрицу проекций используя GL.Ortho() и вызовем GL.Viewport().
Добавим новые строки в обработку события Load. Небольшое замечание - будем игнорировать изменение размера окна пользователем.
Для ясности код первоначальной настройки разделен на несколько частей

   private void Form1_Load(object sender, EventArgs e)
    {
      loaded = true;
      GL.ClearColor(Color.SkyBlue);
      SetupViewport();
    }

    private void SetupViewport()
    {
      int w = glControl1.Width;
      int h = glControl1.Height;
      GL.MatrixMode(MatrixMode.Projection);
      GL.LoadIdentity();
      GL.Ortho(0, w, 0, h, -1, 1); // Верхний левый угол имеет кооординаты(0, 0)
      GL.Viewport(0, 0, w, h); // Использовать всю поверхность GLControl под рисование
}

Между инструкциями Clear() и SwapBuffers() разместим код рисующий треугольник:

private void glControl1_Paint(object sender, PaintEventArgs e)
    {
      if (!loaded)
        return;

      GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

      GL.MatrixMode(MatrixMode.Modelview);
      GL.LoadIdentity();
      GL.Color3(Color.Yellow);
      GL.Begin(BeginMode.Triangles);
      GL.Vertex2(10, 20);
      GL.Vertex2(100, 20);
      GL.Vertex2(100, 50);
      GL.End();

      glControl1.SwapBuffers();
    }

Поздравляю ! Теперь к стране OpenGL присоеднился новый гражданин.

Желание управлять

Теперь попробуем управлять треугольником с клавиатуры. Сделаем так, чтобы после нажатия на пробел, треугольник сдвигался на один пиксель вправо.
Для работы с клавиатурой возможно использовать два подхода - обрабабатывать событие Windows.Forms или использовать OpenTK KeyboardDevice. Если GLControl является небольшой частью твоего WinForms приложения, лучше обрабатать стандартное события WinForms.
Введем переменную int x=0; которая будет увеличиваться при наступлении события KeyDown, которое