Не могу заставить VAO визуализировать ... Может кто-нибудь помочь мне увидеть, что я сделал не так? - PullRequest
1 голос
/ 22 октября 2019

Итак, интересная вещь в этой проблеме: я пытался использовать RenderDoc, но RenderDoc зависал при попытке загрузить захваченный кадр, это происходило каждый раз, когда я пытался, поэтому казалось бы, что инструменты отладки графикине поможет мне в этой ситуации ...

Я использую C # и хороший набор привязок OpenGL и GLFW под названием CSGL (https://github.com/ThatOneCheetah/CSGL)

Вот мой код рендеринга (моя игра используетпроцедурные сплошные цветные прямоугольники в качестве графической основы, класс ниже предназначен для пакетирования всех моих вызовов отрисовки.)

using System;
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

using static CSGL.OpenGL;

namespace BoxBlight
{
    class BoxRenderer
    {
        public const int MAX_RECTANGLES = 500;
        static Rectangle[] rectangles = new Rectangle[MAX_RECTANGLES];
        static int index = 0;

        static uint VAO = 250;
        static uint VBO = 250;
        static uint CBO = 250;

        static bool err = false;

        const string vertShader = @"
#version 150
in  vec3 in_Position;
in  vec4 in_Color;
out vec4 ex_Color;

void main(void) {
    gl_Position = vec4(in_Position.x, in_Position.y, in_Position.z, 1.0);
    ex_Color = in_Color;
}
";

        const string fragShader = @"
#version 150
precision highp float;

in  vec4 ex_Color;
out vec4 gl_FragColor;

void main(void) {
    gl_FragColor = ex_Color;
}
";

        static uint shaderProg = 250;
        static uint vs = 0;
        static uint fs = 0;

        public static void draw(Rectangle rectangle, int offsetX, int offsetY)
        {
            Rectangle r2 = new Rectangle(rectangle);
            r2.x += offsetX;
            r2.y += offsetY;
            rectangles[index++] = r2;
        }

        public static void init()
        {

            if (VAO == 250)
            {
                glGenVertexArrays(1, ref VAO);
            }

            if (VBO == 250)
            {
                glGenBuffers(1, ref VBO);
            }

            if (CBO == 250)
            {
                glGenBuffers(1, ref CBO);
            }

            if (shaderProg == 250)
            {
                shaderProg = glCreateProgram();

                uint vertShd = glCreateShader(GL_VERTEX_SHADER);

                IntPtr str = Marshal.AllocHGlobal(vertShader.Length);
                Marshal.Copy(Encoding.ASCII.GetBytes(vertShader), 0, str, vertShader.Length);

                int length = vertShader.Length;

                glShaderSource(vertShd, 1, ref str, ref length);
                glCompileShader(vertShd);

                Marshal.FreeHGlobal(str);

                int isCompiled = 0;

                glGetShaderiv(vertShd, GL_COMPILE_STATUS, ref isCompiled);

                if (isCompiled == 0)
                {
                    int loglen = 0;
                    glGetShaderiv(vertShd, GL_INFO_LOG_LENGTH, ref loglen);

                    IntPtr log = Marshal.AllocHGlobal(loglen);

                    glGetShaderInfoLog(vertShd, loglen, ref loglen, log);

                    char[] chrs = new char[loglen];
                    string logs = "";
                    Marshal.Copy(log, chrs, 0, loglen);
                    logs.Concat(chrs.AsEnumerable());
                    Marshal.FreeHGlobal(log);
                    Console.Error.WriteLine(logs);

                    err = true;
                    return;
                }

                uint fragShd = glCreateShader(GL_FRAGMENT_SHADER);

                str = Marshal.AllocHGlobal(fragShader.Length);
                Marshal.Copy(Encoding.ASCII.GetBytes(fragShader), 0, str, fragShader.Length);

                length = fragShader.Length;

                glShaderSource(fragShd, 1, ref str, ref length);
                glCompileShader(fragShd);

                Marshal.FreeHGlobal(str);

                isCompiled = 0;

                glGetShaderiv(fragShd, GL_COMPILE_STATUS, ref isCompiled);

                if (isCompiled == 0)
                {
                    int loglen = 0;
                    glGetShaderiv(fragShd, GL_INFO_LOG_LENGTH, ref loglen);

                    IntPtr log = Marshal.AllocHGlobal(loglen);

                    glGetShaderInfoLog(fragShd, loglen, ref loglen, log);

                    char[] chrs = new char[loglen];
                    string logs = "";
                    Marshal.Copy(log, chrs, 0, loglen);
                    logs.Concat(chrs.AsEnumerable());
                    Marshal.FreeHGlobal(log);
                    Console.Error.WriteLine(logs);

                    err = true;
                    return;
                }

                glAttachShader(shaderProg, vertShd);
                glAttachShader(shaderProg, fragShd);

                glLinkProgram(shaderProg);

                int isLinked = 0;

                glGetProgramiv(shaderProg, GL_LINK_STATUS, ref isLinked);
                if (isLinked == 0)
                {
                    int loglen = 0;
                    glGetProgramiv(shaderProg, GL_INFO_LOG_LENGTH, ref loglen);

                    IntPtr log = Marshal.AllocHGlobal(loglen);

                    glGetProgramInfoLog(shaderProg, loglen, ref loglen, log);

                    char[] chrs = new char[loglen];
                    string logs = "";
                    Marshal.Copy(log, chrs, 0, loglen);
                    logs.Concat(chrs.AsEnumerable());
                    Marshal.FreeHGlobal(log);
                    Console.Error.WriteLine(logs);

                    err = true;
                    return;
                }

                vs = vertShd;
                fs = fragShd;
            }
        }

        public static void flush(int xoffset, int yoffset, Rectangle camera)
        {
            if (err)
            {
                index = 0;
                return;
            }

            double[] verts = new double[index * 18];
            double[] colrs = new double[index * 24];

            int indecies = 0;

            for(int i = 0; i < index; i++)
            {
                Rectangle rect = rectangles[i];

                rect.x += xoffset;
                rect.y += yoffset;

                if(camera.Intersects(rect))
                {
                    double x1, y1, x2, y2;
                    x1 = (double)rect.x / camera.w * 2 - 1;
                    x2 = ((double)rect.x + rect.w) / camera.w * 2 - 1;
                    y1 = (1 - (double)rect.y / camera.h) * 2 - 1;
                    y2 = (1 - ((double)rect.y + rect.h) / camera.h) * 2 - 1;

                    verts[i * 18 + 0 ] = x1;
                    verts[i * 18 + 1 ] = y1;
                    verts[i * 18 + 2 ] = 1;

                    verts[i * 18 + 3 ] = x2;
                    verts[i * 18 + 4 ] = y1;
                    verts[i * 18 + 5 ] = 1;

                    verts[i * 18 + 6 ] = x1;
                    verts[i * 18 + 7 ] = y2;
                    verts[i * 18 + 8 ] = 1;

                    verts[i * 18 + 9 ] = x2;
                    verts[i * 18 + 10] = y1;
                    verts[i * 18 + 11] = 1;

                    verts[i * 18 + 12] = x1;
                    verts[i * 18 + 13] = y2;
                    verts[i * 18 + 14] = 1;

                    verts[i * 18 + 15] = x1;
                    verts[i * 18 + 16] = y2;
                    verts[i * 18 + 17] = 1;

                    for (int j = 0; j < 6; j++)
                    {
                        colrs[i * 24 + j * 4 + 0] = (double)rect.c.R / 255;
                        colrs[i * 24 + j * 4 + 1] = (double)rect.c.G / 255;
                        colrs[i * 24 + j * 4 + 2] = (double)rect.c.B / 255;
                        colrs[i * 24 + j * 4 + 3] = (double)rect.c.A / 255;
                    }

                    indecies += 6;
                }
            }

            glBindVertexArray(VAO);

            IntPtr data0 = Marshal.AllocHGlobal(verts.Length * sizeof(double));
            Marshal.Copy(verts, 0, data0, verts.Length);

            glBindBuffer(GL_VERTEX_ARRAY, VBO);
            glBufferData(GL_VERTEX_ARRAY, verts.Length * sizeof(double), data0, GL_DYNAMIC_DRAW);

            glEnableVertexAttribArray(VBO);
            glVertexAttribPointer(VBO, 3, GL_DOUBLE, GL_FALSE, 0, IntPtr.Zero);

            IntPtr data1 = Marshal.AllocHGlobal(colrs.Length * sizeof(double));
            Marshal.Copy(colrs, 0, data1, colrs.Length);

            glBindBuffer(GL_VERTEX_ARRAY, CBO);
            glBufferData(GL_VERTEX_ARRAY, colrs.Length * sizeof(double), data1, GL_DYNAMIC_DRAW);

            glEnableVertexAttribArray(CBO);
            glVertexAttribPointer(CBO, 4, GL_DOUBLE, GL_FALSE, 0, IntPtr.Zero);

            glUseProgram(shaderProg);
            glBindAttribLocation(shaderProg, VBO, "in_Position");
            glBindAttribLocation(shaderProg, CBO, "in_Color");

            glDrawArrays(GL_TRIANGLES, 0, indecies);
            glFlush();

            Marshal.FreeHGlobal(data0);
            Marshal.FreeHGlobal(data1);

            glUseProgram(0);
            glDisableVertexAttribArray(VBO);
            glDisableVertexAttribArray(CBO);

            index = 0;
            rectangles = new Rectangle[MAX_RECTANGLES];
        }

        public static void clean()
        {
            glDetachShader(shaderProg, vs);
            glDetachShader(shaderProg, fs);

            glDeleteProgram(shaderProg);

            glDeleteShader(vs);
            glDeleteShader(fs);

            glDeleteBuffers(1, ref VBO);
            glDeleteBuffers(1, ref CBO);

            glDeleteVertexArrays(1, ref VAO);

            rectangles = new Rectangle[0];
            index = 0;
            err = true;
        }
    }
}

Вот мой основной игровой класс:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static CSGL.CSGL;
using static CSGL.OpenGL;
using static CSGL.Glfw3;
using System.Drawing;

namespace BoxBlight
{
    class Program
    {
        public static IntPtr window = IntPtr.Zero;
        public static bool running = true;
        public const long FPS = 60;

        public static long CurrentTimeMS { get => DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; }

        static void Main(string[] args)
        {
            csglLoadGlfw();

            if(glfwInit() != GLFW_TRUE)
            {
                Console.Error.WriteLine("Failed to initialize GLFW!");
            }

            glfwDefaultWindowHints();
            window = glfwCreateWindow(1024, 768, "Box Blight (v1.0.0)", IntPtr.Zero, IntPtr.Zero);

            if(window == IntPtr.Zero)
            {
                Console.Error.WriteLine("Failed to create window!");
            }

            glfwMakeContextCurrent(window);

            csglLoadGL();
            glInitNames();

            long lastTime = CurrentTimeMS;

            glViewport(0, 0, 1024, 768);

            BoxRenderer.init();

            while(running)
            {
                glOrtho(0, 1024, 768, 0, 0.1, 3);

                BoxRenderer.draw(new Rectangle(0, 0, 1024, 768, Color.HotPink), 0, 0);
                BoxRenderer.draw(new Rectangle(16, 16, 16, 16, Color.White), 0, 0);

                BoxRenderer.flush(0, 0, new Rectangle(0, 0, 1024, 768, Color.Black));

                glfwSwapBuffers(window);
                glfwPollEvents();

                while (lastTime + FPS / 1000 > CurrentTimeMS) ;
            }

            BoxRenderer.clean();

            glfwTerminate();
        }
    }
}

1 Ответ

0 голосов
/ 22 октября 2019

параметры glVertexAttribPointer соответственно glEnableVertexAttribArray являются индексами атрибутов, а не объектами буфера. Буферный объект должен быть текущим буферным объектом (должен быть связан), когда генерируется массив данных общего атрибута вершины. Индекс атрибута можно получить по glGetAttribLocation из связанного программного объекта. Цель для буфера массива вершин - GL_ARRAY_BUFFER, а не GL_VERTEX_ARRAY (GL_VERTEX_ARRAY указывает состояние возможности для устаревших атрибутов фиксированной функции OpenGL и не является допустимой целью буфера).

int vertex_index = glGetAttribLocation(shaderProg, "in_Position");
int color_index  = glGetAttribLocation(shaderProg, "in_Color");

glBindVertexArray(VAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, verts.Length * sizeof(double), data0, GL_DYNAMIC_DRAW);

glEnableVertexAttribArray(vertex_index);
glVertexAttribPointer(vertex_index, 3, GL_DOUBLE, GL_FALSE, 0, IntPtr.Zero);

glBindBuffer(GL_ARRAY_BUFFER, CBO);
glBufferData(GL_ARRAY_BUFFER, colrs.Length * sizeof(double), data1, GL_DYNAMIC_DRAW);

glEnableVertexAttribArray(color_index);
glVertexAttribPointer(color_index, 4, GL_DOUBLE, GL_FALSE, 0, IntPtr.Zero);

Обратите внимание, что индексы атрибутов можно установить с помощью glBindAttribLocation, но это необходимо сделать до того, как программа будет связана. Индекс атрибута является ресурсом программы и не может быть изменен после связывания программы. Кроме того, индекс атрибута не является буферным объектом. Буфер и индекс атрибута ассоциируются при вызове glVertexAttribPointer и сохраняются в векторе состояния объекта массива вершин

...