似乎无法让 VAO 渲染...有人可以帮我看看我做错了什么吗?
Can't seem to get a VAO to render... Can someone help me see what I did wrong?
关于这个问题的一个有趣的事情是,我 尝试 使用 RenderDoc 但是当我尝试加载我捕获的帧时 RenderDoc 崩溃了,每次尝试都会发生这种情况,所以在这种情况下,图形调试工具似乎帮不了我...
我正在使用 C#,以及一组很好的 OpenGL 和 GLFW 绑定,称为 CSGL (https://github.com/ThatOneCheetah/CSGL)
这是我的渲染代码(我的游戏使用程序纯色矩形作为图形基础,下面的 class 用于批处理我的所有绘制调用。)
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;
}
}
}
这是我的主要游戏class:
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();
}
}
}
glVertexAttribPointer
respectively 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
, but this has to be done before the program is linked. The attribute index is a program resource and can't be changed after the program was linked. Furthermore, the attribute index is not the buffer object. The buffer and an attribute index are associate when glVertexAttribPointer
is called and is stored in the state vector of the Vertex Array Object
设置属性索引
关于这个问题的一个有趣的事情是,我 尝试 使用 RenderDoc 但是当我尝试加载我捕获的帧时 RenderDoc 崩溃了,每次尝试都会发生这种情况,所以在这种情况下,图形调试工具似乎帮不了我...
我正在使用 C#,以及一组很好的 OpenGL 和 GLFW 绑定,称为 CSGL (https://github.com/ThatOneCheetah/CSGL)
这是我的渲染代码(我的游戏使用程序纯色矩形作为图形基础,下面的 class 用于批处理我的所有绘制调用。)
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;
}
}
}
这是我的主要游戏class:
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();
}
}
}
glVertexAttribPointer
respectively 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
, but this has to be done before the program is linked. The attribute index is a program resource and can't be changed after the program was linked. Furthermore, the attribute index is not the buffer object. The buffer and an attribute index are associate when glVertexAttribPointer
is called and is stored in the state vector of the Vertex Array Object