OpenGL шейдеры. Простой шейдер на GLSL в C# OpenTK

Когда-то я ознакомился с уроком "Простой шейдер на GLSL", и это вдохновило на изучение шейдеров в OpenGL и сам современный OpenGL в частности. В основном я работаю с C# поэтому после ознакомления с кодом на C++ и его сборкой, приступил к переводу его в С#. Эта заметка как раз о том, как перенести код из урока на C#. Для доступа к OpenGL будет использоваться современная версия враппера OpenTK.

И так сперва создадим консольный проект на C#:
SimpleShaderOpenTk1.PNG

Подключим OpenTk через nuget
SimpleShaderOpenTk1_1.PNG

SimpleShaderOpenTk1_2.PNG

SimpleShaderOpenTk1_4.PNG
если не нашло OpenTk то нужно включить репоизоторий в настройках:
SimpleShaderOpenTk1_3.PNG

Используем следующий код:


/*http://esate.ru, badcat*/

using System;
using System.Drawing;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;

namespace openTk1
{
 class Game : GameWindow
 {

 //! Переменные с индентификаторами ID
 //! ID шейдерной программы
 int Program;
 //! ID атрибута
 int Attrib_vertex;
 //! ID юниформ переменной цвета
 int Unif_color;
 //! ID Vertex Buffer Object
 int VBO;

 //! Вершина
 struct Vertex
 {
 public float x;
 public float y;
 };

 public Game()
 : base(640, 480, new GraphicsMode(new ColorFormat(32), 16), "Simple shaders on OpenTK!")
 {

 }

 protected override void OnLoad(EventArgs e)
 {
 base.OnLoad(e);

 GL.ClearColor(Color.Black);

 //! Инициализация
 InitVBO();
 InitShader();
 }

 protected override void OnUnload(EventArgs e)
 {
 base.OnUnload(e);

 //! Освобождение ресурсов
 FreeShader();
 FreeVBO();
 }

 //! Функция печати лога шейдера
 static void ShaderLog(string tag, int shader)
 {
 string infoLog;

 GL.GetShaderInfoLog(shader, out infoLog);

 if (infoLog.Length > 1)
 Console.WriteLine(tag + " InfoLog: " + infoLog + "\n\n\n");
 }

 //! Проверка ошибок OpenGL, если есть то вывод в консоль тип ошибки
 static void CheckOpenGLerror()
 {
 ErrorCode errCode = GL.GetError();
 if (errCode != ErrorCode.NoError)
 Console.WriteLine("OpenGl error! - {0}", errCode);
 }

 private void InitShader()
 {
 //! Исходный код шейдеров
 const string vsSource = @"attribute vec2 coord;
 void main() {
 gl_Position = vec4(coord, 0.0, 1.0);
 };";
 const string fsSource = @"uniform vec4 color;
 void main() {
 gl_FragColor = color;
 }";

 //! Переменные для хранения идентификаторов шейдеров
 int vShader, fShader;

 //! Создаем вершинный шейдер
 vShader = GL.CreateShader(ShaderType.VertexShader);
 //! Передаем исходный код
 GL.ShaderSource(vShader, vsSource);
 //! Компилируем шейдер
 GL.CompileShader(vShader);

 ShaderLog("vertex shader", vShader);

 //! Создаем фрагментный шейдер
 fShader = GL.CreateShader(ShaderType.FragmentShader);
 //! Передаем исходный код
 GL.ShaderSource(fShader, fsSource);
 //! Компилируем шейдер
 GL.CompileShader(fShader);

 ShaderLog("fragment shader", fShader);

 //! Создаем программу и прикрепляем шейдеры к ней
 Program = GL.CreateProgram();
 GL.AttachShader(Program, vShader);
 GL.AttachShader(Program, fShader);

 //! Линкуем шейдерную программу
 GL.LinkProgram(Program);

 //Единственное, что не перевел на OpenTK:
 //! Проверяем статус сборки 
 //int link_ok;
 //GL.GetProgramiv(Program, GL_LINK_STATUS, &link_ok);
 //if(!link_ok)
 //{
 // std::cout << "error attach shaders \n";
 // return;
 //}

 //! Вытягиваем ID атрибута из собранной программы 
 const string attr_name = "coord";
 Attrib_vertex = GL.GetAttribLocation(Program, attr_name);
 if (Attrib_vertex == -1)
 {
 Console.WriteLine("could not bind attrib {0}", attr_name);
 return;
 }
 //! Вытягиваем ID юниформ
 const string unif_name = "color";
 Unif_color = GL.GetUniformLocation(Program, unif_name);
 if (Unif_color == -1)
 {
 Console.WriteLine("could not bind uniform {0}", unif_name);
 return;
 }

 CheckOpenGLerror();
 }

 //! Инициализация VBO
 void InitVBO()
 {
 GL.GenBuffers(1, out VBO);
 GL.BindBuffer(BufferTarget.ArrayBuffer, VBO);
 //! Вершины нашего треугольника
 Vertex[] triangle =
 {
 new Vertex {x = -1.0f, y = -1.0f},
 new Vertex {x = 0.0f, y = 1.0f},
 new Vertex {x = 1.0f, y = -1.0f}
 };
 //! Передаем вершины в буфер, 8 - количество байт в структуре 4 байта на 1 float, их у нас 2
 GL.BufferData(BufferTarget.ArrayBuffer, triangle.Length * 8, triangle, BufferUsageHint.StaticDraw);

 CheckOpenGLerror();
 }

 //! Освобождение шейдеров
 void FreeShader()
 {
 //! Передавая ноль, мы отключаем шейдрную программу
 GL.UseProgram(0);
 //! Удаляем шейдерную программу
 GL.DeleteProgram(Program);
 }

 //! Освобождение шейдеров
 void FreeVBO()
 {
 GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
 GL.DeleteBuffers(1, ref VBO);
 }

 protected override void OnRenderFrame(FrameEventArgs e)
 {
 base.OnRenderFrame(e);

 GL.Clear(ClearBufferMask.ColorBufferBit);
 //! Устанавливаем шейдерную программу текущей
 GL.UseProgram(Program);

 //! Передаем юниформ в шейдер
 GL.Uniform4(Unif_color, 1.0f, 0.0f, 0.0f, 1.0f);

 //! Включаем массив атрибутов
 GL.EnableVertexAttribArray(Attrib_vertex);
 //! Подключаем VBO
 GL.BindBuffer(BufferTarget.ArrayBuffer, VBO);
 //! Указывая pointer 0 при подключенном буфере, мы указываем что данные в VBO
 GL.VertexAttribPointer(Attrib_vertex, 2, VertexAttribPointerType.Float, false, 0, 0);
 //! Отключаем VBO
 GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
 //! Передаем данные на видеокарту(рисуем)
 GL.DrawArrays(PrimitiveType.Triangles, 0, 3); // 3 вершины

 //! Отключаем массив атрибутов
 GL.DisableVertexAttribArray(Attrib_vertex);

 //! Отключаем шейдерную программу
 GL.UseProgram(0);

 SwapBuffers();
 }

 protected override void OnResize(EventArgs e)
 {
 base.OnResize(e);

 GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
 }
 }

 class Program
 {
 static void Main(string[] args)
 {
 var g = new Game(); //Создание окна
 g.Run(30.0f);
 }
 }
}

 

Также нужно добавить System.Drawing:
SimpleShaderOpenTk1_5.PNG



Код хорошо описан в оригинальной статье, тут он делает тоже самое, структуру кода старался оставить такой же, так что проблем с пониманием быть не должно.

Результат работы программы:
SimpleShaderOpenTk1_6.PNG


Надеюсь заметка окажется полезной. Ошибки орфографии и оформления прошу слать в личку.
0.136      5770        11.09.2017 01:43:19        4

^
Регистрация
Регистрируясь, вы принимаете правила сайта. Если вы не получили код подтв. регистрации - не забудьте проверить папку спам.
Логин*
Email*
Пароль*
Подтверждение пароля*
 
Логин*
Код*
 
×
Восстановление пароля
Пожалуйста, заполните поля, после чего вы получите код подтверждения на ваш Email. Если код не пришел в течении нескольких минут - проверьте папку спам.
Логин

или Email
Логин*
Код подтверждения*
Новый пароль*
Подтверждение пароля*
×
Авторизация
  • Используйте вашу учетную запись на Facebook.com для входа на сайт.
  • Используйте вашу учетную запись VKontakte для входа на сайт.
  • Используйте вашу учетную запись Google для входа на сайт.
Авторизуйтесь с помощью соц. сети или с помощью аккаунта на сайте:
×