Список работ

Шейдер частиц

Содержание

Шейдеры вершин и фрагментов

Шейдер вершин получает из программы число секунд, прошедших с момента старта часов watch, и формирует цвет и позицию вершины (частицы):

// Particles vertex shader (файл particlesVS.glsl)
varying vec4 color;
uniform float time;

void main()
{
 float vel = 0.05; // Скорость частицы
 vec3 pos = gl_Vertex.xyz * vel * time;
 color = vec4(max(abs(pos.x), 0.1), max(abs(pos.y), 0.1), max(abs(pos.z), 0.1), 1.0);
 gl_Position = gl_ModelViewProjectionMatrix * vec4(pos, 1.0);
}

Частицы перемещаются дискретно, меняя позициию каждую секунду. Часы watch обнуляются каждые 60 с.

Шейдер фрагментов получает от шейдера вершин цвет и закрашивает им частицу.

// Particles fragment shader (файл particlesFS.glsl)
varying vec4 color;

void main()
{
 gl_FragColor = color;
}

На рис. 1 показаны частицы через 36 с после запуска программы.

Частицы

Рис. 1. Частицы через 36 с после запуска программы

Реализация на C# – OpenTK

using System;
using System.IO;
using System.Diagnostics; // Stopwatch
using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace ParticlesShader
{
    public class Particles_shader: GameWindow
    {
        public Particles_shader() : base(400, 300) { }
        // Шейдеры вершин и фрагментов
        int VertexShaderObject, FragmentShaderObject, ProgramObject;
        const string VertexShaderFilename = "particlesVS.glsl";
        const string FragmentShaderFilename = "particlesFS.glsl";
        const int numParticles = 500;
        Vector4d[] pAttr = new Vector4d [numParticles];
        float time;
        Stopwatch watch = new Stopwatch();
        Random rnd = new Random();

        private int readShader(string shaderFilename, ShaderType st, string vs)
        {
            string LogInfo;
            int shaderObject = GL.CreateShader(st);
            using (StreamReader sr = new StreamReader(shaderFilename))
            {
                GL.ShaderSource(shaderObject, sr.ReadToEnd());
                GL.CompileShader(shaderObject);
                return shaderObject;
            }
            GL.GetShaderInfoLog(shaderObject, out LogInfo);
            if (LogInfo.Length > 0 & !LogInfo.Contains("hardware"))
                Console.WriteLine("Ошибка компиляции шейдера " + vs + "\nLog:\n" + LogInfo);
            else
                Console.WriteLine("Компиляция шейдера " + vs + " завершена успешно");
        }
        protected override void OnLoad(EventArgs e)
        {
            string LogInfo;
            int[] temp = new int[1];
            // Загрузка и компиляция шейдеров вершин и фрагментов
            VertexShaderObject = readShader(VertexShaderFilename, ShaderType.VertexShader, "вершин");
            FragmentShaderObject = readShader(FragmentShaderFilename, ShaderType.FragmentShader, "фрагментов");
            // Связываем шейдеры с рабочей программой
            ProgramObject = GL.CreateProgram();
            GL.AttachShader(ProgramObject, VertexShaderObject);
            GL.AttachShader(ProgramObject, FragmentShaderObject);
            // Связываем все вместе
            GL.LinkProgram(ProgramObject);
            // Удаляем ранее созданные шейдеры
            GL.DeleteShader(VertexShaderObject);
            GL.DeleteShader(FragmentShaderObject);
            GL.GetProgram(ProgramObject, GetProgramParameterName.LinkStatus, out temp[0]);
            Console.WriteLine("Связывание программ (" + ProgramObject + ") " + ((temp[0] == 1) ? "выполнено." : "НЕ ВЫПОЛНЕНО"));
            if (temp[0] != 1) // В случае неудачи при связывании
            {
                GL.GetProgramInfoLog(ProgramObject, out LogInfo);
                Console.WriteLine("Информация:\n" + LogInfo);
            }
            GL.GetProgram(ProgramObject, GetProgramParameterName.ActiveAttributes, out temp[0]);
            Console.WriteLine("Зарегестрировано " + temp[0] + " атрибута");
            Console.WriteLine("Создание шейдера завершено. GL-ошибка: " + GL.GetError());
            Console.WriteLine("");
            // Генерация массива частиц
            for (int i = 0; i < numParticles; i++)
                pAttr[i] = new Vector4d(0.5 - rnd.NextDouble(), 0.5 - rnd.NextDouble(), 0.5 - rnd.NextDouble(), 0.5 - rnd.NextDouble());
            watch.Start();
            GL.ClearColor(0f, 0f, 0f, 1f); // Цвет фона
            GL.PointSize(6f); // Размер частицы
            GL.Enable(EnableCap.PointSmooth);
        }
        protected override void OnUnload(EventArgs e)
        {
            GL.DeleteProgram(ProgramObject);
            base.OnUnload(e);
        }
        // Обработчик изменения размеров окна графического вывода
        protected override void OnResize(EventArgs e)
        {
            GL.Viewport(0, 0, Width, Height);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadIdentity();
            base.OnResize(e);
        }
        // Обработчик обновления
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);
        }
        // Обработчик воспроизведения
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            GL.Clear(ClearBufferMask.ColorBufferBit);
            time = watch.Elapsed.Seconds;
            this.Title = "Particles shader. Time " + time;
            GL.UseProgram(ProgramObject);
            GL.Uniform1(GL.GetUniformLocation(ProgramObject, "time"), time);
            GL.Begin(PrimitiveType.Points);
            for(int i = 0; i < numParticles; i++) GL.Vertex4(pAttr[i]);
            GL.End();
            GL.UseProgram(0);
            this.SwapBuffers();
        }
        // Точка входа
        [STAThread]
        public static void Main()
        {
            using (Particles_shader ps = new Particles_shader())
            {
                ps.Title = "Particles shader";
                ps.Run(10.0, 2.0);
            }
        }
    }
}

Источники

  1. Боресков А. В. Разработка и отладка шейдеров. – СПб.: БХВ-Петербург, 2006. – 496 с.
  2. OpenTK: вывод частиц

Список работ

Рейтинг@Mail.ru