Шейдеры
GLShader — OpenGL шейдерная программа
Управляет компиляцией, линковкой и использованием GLSL шейдеров.
Создание из исходника
// Исходник вершинного шейдера
const string vertexSource = @"
#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 texCoord;
uniform mat4 uModel;
uniform mat4 uView;
uniform mat4 uProjection;
out vec2 vTexCoord;
void main()
{
gl_Position = uProjection * uView * uModel * vec4(position, 1.0);
vTexCoord = texCoord;
}
";
// Фрагментный шейдер
const string fragmentSource = @"
#version 330 core
in vec2 vTexCoord;
uniform sampler2D uTexture;
out vec4 FragColor;
void main()
{
FragColor = texture(uTexture, vTexCoord);
}
";
// Создание программы
var shader = context.CreateShader(new List<ShaderScript>
{
new(ShaderType.Vertex, vertexSource),
new(ShaderType.Fragment, fragmentSource)
});
Процесс компиляции
При создании из исходника:
- Создаётся программа
glCreateProgram() - Каждый шейдер компилируется
glCompileShader() - Если ошибка — информация выводится в консоль
- Шейдеры прикрепляются
glAttachShader() - Программа линкуется
glLinkProgram() - Объекты шейдеров удаляются
glDeleteShader()
Создание из скомпилированного кода
// Загрузка из кеша (намного быстрее)
var compiled = GetCachedBinary(); // вы сохраняли это из Export()
var shader = context.CreateShader(new CompiledShaderProgram
{
Binary = compiled.Binary,
Format = compiled.Format
});
Кеширование шейдеров
// При первой загрузке: компилируем и экспортируем
var shader = context.CreateShader(shaderScripts);
var compiled = shader.Export();
File.WriteAllBytes("cache/shader.bin", compiled.Binary);
// File.WriteAllText("cache/shader.fmt", compiled.Format.ToString());
// При следующей загрузке: берём из кеша
var cachedBinary = File.ReadAllBytes("cache/shader.bin");
var shader = context.CreateShader(new CompiledShaderProgram
{
Binary = cachedBinary,
Format = 0x8F65 // посмотрите в коде Save
});
Uniform переменные
Установка значений
shader.Apply(); // сделать текущей программой
// Скалярные значения
shader.SetUniform("uTime", 1.5f);
shader.SetUniform("uCount", 42);
shader.SetUniform("uIsActive", 1u);
// Векторы
shader.SetUniform("uColor", new FVector3(1f, 0f, 0f));
shader.SetUniform("uOffset", new FVector2(10, 20));
shader.SetUniform("uLightPos", new FVector4(0, 5, 0, 1));
// Матрицы
var model = FMatrix4x4.Identity;
shader.SetUniform("uModel", model, transpose: false);
shader.SetUniform("uView", viewMatrix, transpose: false);
shader.SetUniform("uProjection", projMatrix, transpose: false);
Информация об uniforms
// Получить описание всех uniforms
var uniforms = shader.GetUniformsInfo();
foreach (var (name, info) in uniforms)
{
Console.WriteLine($"{name}: {info.Type} (size={info.Size})");
// Output: uModel: 35676 (size=1)
// uTime: 5126 (size=1)
// uColor: 35665 (size=1)
}
Атрибуты вершин
Получение индекса
shader.Apply();
// Получить индекс атрибута
uint posIndex = shader.GetAttributeLocation("position"); // обычно 0
uint uvIndex = shader.GetAttributeLocation("texCoord"); // обычно 1
uint normalIndex = shader.GetAttributeLocation("normal"); // обычно 2
// Использовать при описании VAO
vao.AddAttribute(posIndex, 3, VertexAttribPointerType.Float, false, 32, 0);
vao.AddAttribute(uvIndex, 2, VertexAttribPointerType.Float, false, 32, 12);
vao.AddAttribute(normalIndex, 3, VertexAttribPointerType.Float, false, 32, 20);
Типовый цикл рендера
Igdrasil.OnRender += (ctx, dt) =>
{
// Очистка
ctx.ClearColor(new FVector4(0.1f, 0.1f, 0.1f, 1f));
ctx.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
// Применяем шейдер
shader.Apply();
// Устанавливаем матрицы
var model = FMatrix4x4.Translation(position);
var view = FMatrix4x4.LookAt(eye, center, up);
var proj = FMatrix4x4.Perspective(fov, aspect, near, far);
shader.SetUniform("uModel", model, transpose: false);
shader.SetUniform("uView", view, transpose: false);
shader.SetUniform("uProjection", proj, transpose: false);
// Устанавливаем параметры
shader.SetUniform("uTime", (float)dt);
shader.SetUniform("uColor", color);
// Устанавливаем текстуру
ctx.SetActiveTexture(TextureUnit.Texture0);
texture.Bind();
shader.SetUniform("uTexture", 0); // номер текстурного блока
// Отрисовка
vao.Bind();
ctx.DrawElements(PrimitiveType.Triangles, 0, indexCount, DrawElementsType.UnsignedInt);
};
Очистка
// Освобождение GPU-ресурсов
shader.Dispose();
Версия: 1.0