一起绘制时,OpenGL 纹理出现在错误的位置
OpenGL textures appear in wrong places when drawn together
我是 OpenGL 的新手,正在尝试绘制两个具有不同纹理的正方形。我使用 lwjgl 3 作为 OpenGL 的接口,但我相信对于使用其他语言的 OpenGL 的人来说,OpenGL 调用应该看起来很熟悉。我的主循环如下所示:
while (glfwWindowShouldClose(windowId) == GLFW_FALSE) {
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgramId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
// DRAW TEXTURE 1
specifyVertexAttributes(shaderProgramId);
glBindTexture(GL_TEXTURE_2D, texture1.getId());
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// DRAW TEXTURE 2
specifyVertexAttributes(shaderProgramId);
glBindTexture(GL_TEXTURE_2D, texture2.getId());
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(windowId);
glfwPollEvents();
}
当我注释掉绘制纹理 2 的代码时,纹理 1 绘制在正确的位置:
当我注释掉绘制纹理 1 的代码时,纹理 2 绘制在正确的位置:
但是当我尝试绘制两个纹理时,它们交换了位置:
我意识到上面的代码片段可能不足以诊断此问题。我创建了一个独立的 java class,其中包含我为绘制这些纹理所做的所有 OpenGL 调用:StandaloneMultiTextureExample。包含该文件的 repo 也使用 gradle 构建。对于任何愿意帮助检查 repo 和 运行 那个例子 class.
的人来说应该很容易
编辑:StandaloneMultiTextureExample.java 的副本(不导入)
public class StandaloneMultiTextureExample {
private final GLFWErrorCallback errorCallback = new LoggingErrorCallback();
private final GLFWKeyCallback keyCallback = new ApplicationClosingKeyCallback();
public void run() {
if ( glfwInit() != GLFW_TRUE ) {
throw new IllegalStateException("Unable to initialize GLFW");
}
glfwSetErrorCallback(errorCallback);
int width = 225;
int height = 200;
long windowId = createWindow(width, height);
glfwSetKeyCallback(windowId, keyCallback);
glfwShowWindow(windowId);
GL.createCapabilities();
Texture texture1 = createTexture("multiTextureExample/texture1.png");
Texture texture2 = createTexture("multiTextureExample/texture2.png");
int shaderProgramId = createShaderProgram(
"multiTextureExample/textureShader.vert",
"multiTextureExample/textureShader.frag");
IntBuffer elements = BufferUtils.createIntBuffer(2 * 3);
elements.put(0).put(1).put(2);
elements.put(2).put(3).put(0);
elements.flip();
int ebo = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elements, GL_STATIC_DRAW);
float x1 = 0;
float y1 = 0;
float x2 = x1 + texture1.getWidth();
float y2 = y1 + texture1.getHeight();
float x3 = 25;
float x4 = x3 + texture2.getWidth();
FloatBuffer texture1Vertices = BufferUtils.createFloatBuffer(4 * 7);
texture1Vertices.put(x1).put(y1).put(1).put(1).put(1).put(0).put(0);
texture1Vertices.put(x2).put(y1).put(1).put(1).put(1).put(1).put(0);
texture1Vertices.put(x2).put(y2).put(1).put(1).put(1).put(1).put(1);
texture1Vertices.put(x1).put(y2).put(1).put(1).put(1).put(0).put(1);
texture1Vertices.flip();
FloatBuffer texture2Vertices = BufferUtils.createFloatBuffer(4 * 7);
texture2Vertices.put(x3).put(y1).put(1).put(1).put(1).put(0).put(0);
texture2Vertices.put(x4).put(y1).put(1).put(1).put(1).put(1).put(0);
texture2Vertices.put(x4).put(y2).put(1).put(1).put(1).put(1).put(1);
texture2Vertices.put(x3).put(y2).put(1).put(1).put(1).put(0).put(1);
texture2Vertices.flip();
int vbo1 = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBufferData(GL_ARRAY_BUFFER, texture1Vertices, GL_STATIC_DRAW);
int vbo2 = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBufferData(GL_ARRAY_BUFFER, texture2Vertices, GL_STATIC_DRAW);
specifyUniformVariables(windowId, shaderProgramId);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
while (glfwWindowShouldClose(windowId) == GLFW_FALSE) {
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgramId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
specifyVertexAttributes(shaderProgramId);
glBindTexture(GL_TEXTURE_2D, texture1.getId());
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
specifyVertexAttributes(shaderProgramId);
glBindTexture(GL_TEXTURE_2D, texture2.getId());
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(windowId);
glfwPollEvents();
}
}
private void specifyUniformVariables(long windowId, int shaderProgramId) {
int uniModel = getUniform(shaderProgramId, "model");
FloatBuffer model = BufferUtils.createFloatBuffer(16);
new Matrix4f().get(model);
glUniformMatrix4fv(uniModel, false, model);
FloatBuffer view = BufferUtils.createFloatBuffer(16);
new Matrix4f().get(view);
int uniView = getUniform(shaderProgramId, "view");
glUniformMatrix4fv(uniView, false, view);
WindowSize windowSize = getWindowSize(windowId);
int uniProjection = getUniform(shaderProgramId, "projection");
FloatBuffer projection = BufferUtils.createFloatBuffer(16);
new Matrix4f().ortho2D(0, windowSize.getWidth(), 0, windowSize.getHeight()).get(projection);
glUniformMatrix4fv(uniProjection, false, projection);
}
private void specifyVertexAttributes(int shaderProgramId) {
int stride = 7 * Float.BYTES;
int posAttrib = getAttribute(shaderProgramId, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, false, stride, 0);
int colAttrib = getAttribute(shaderProgramId, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, false, stride, 2 * Float.BYTES);
int texAttrib = getAttribute(shaderProgramId, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, false, stride, 5 * Float.BYTES);
}
public long createWindow(int width, int height) {
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
long windowId = glfwCreateWindow(width, height, "Hello World!", NULL, NULL);
if (windowId == NULL) {
throw new RuntimeException("Failed to create the GLFW window");
}
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
windowId,
(vidmode.width() - width) / 2,
(vidmode.height() - height) / 2
);
// Make the OpenGL context current
glfwMakeContextCurrent(windowId);
// Enable v-sync
glfwSwapInterval(1);
return windowId;
}
public WindowSize getWindowSize(long windowId) {
IntBuffer width = BufferUtils.createIntBuffer(1);
IntBuffer height = BufferUtils.createIntBuffer(1);
GLFW.glfwGetFramebufferSize(windowId, width, height);
return new WindowSize(width.get(), height.get());
}
public Texture createTexture(String textureResource) {
int textureId = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ARGBImage image = new ImageService().loadClasspathImage(textureResource);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA8,
image.getWidth(),
image.getHeight(),
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
image.getContents());
return new Texture(textureId, image.getWidth(), image.getHeight());
}
public int createShaderProgram(String vertexResource, String fragmentResource) {
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
String vertexSource = getClasspathResource(vertexResource);
glShaderSource(vertexShader, vertexSource);
glCompileShader(vertexShader);
validateShaderCompilation(vertexShader);
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
String fragmentSource = getClasspathResource(fragmentResource);
glShaderSource(fragmentShader, fragmentSource);
glCompileShader(fragmentShader);
validateShaderCompilation(fragmentShader);
int shaderProgramId = glCreateProgram();
glAttachShader(shaderProgramId, vertexShader);
glAttachShader(shaderProgramId, fragmentShader);
glLinkProgram(shaderProgramId);
validateShaderProgram(shaderProgramId);
glUseProgram(shaderProgramId);
return shaderProgramId;
}
private static String getClasspathResource(String resourceName) {
URL url = Resources.getResource(resourceName);
try {
return Resources.toString(url, Charsets.UTF_8);
} catch (IOException e) {
throw Throwables.propagate(e);
}
}
private static void validateShaderCompilation(int shader) {
int status = glGetShaderi(shader, GL_COMPILE_STATUS);
if (status != GL_TRUE) {
throw new RuntimeException(glGetShaderInfoLog(shader));
}
}
private static void validateShaderProgram(int shaderProgram) {
int status = glGetProgrami(shaderProgram, GL_LINK_STATUS);
if (status != GL_TRUE) {
throw new RuntimeException(glGetProgramInfoLog(shaderProgram));
}
}
public int getUniform(int shaderProgramId, String uniformName) {
int location = glGetUniformLocation(shaderProgramId, uniformName);
if (location == -1) {
throw new IllegalArgumentException("Could not find uniform: "
+ uniformName + " for shaderProgramId: " + shaderProgramId);
} else {
return location;
}
}
public int getAttribute(int shaderProgramId, String attribute) {
int location = glGetAttribLocation(shaderProgramId, attribute);
if (location == -1) {
throw new IllegalArgumentException("Could not find attribute: "
+ attribute + " for shaderProgramId: " + shaderProgramId);
} else {
return location;
}
}
public static void main(String[] args) {
new StandaloneMultiTextureExample().run();
}
}
您在错误的时间绑定顶点缓冲区,从而错误地设置了顶点数组。
当您使用顶点数组对象 (VAO) 渲染 [1] 时,读取 GL_ARRAY_BUFFER
绑定的唯一时间是 glVertexAttribPointer
调用。调用 glVertexAttribPointer
获取当前绑定的 GL_ARRAY_BUFFER
对象的名称并将其与属性和 VAO 相关联;在那之后,GL_ARRAY_BUFFER
绑定根本不重要,绑定另一个数组缓冲区将不会以任何方式修改 VAO。
在您的代码中,您在调用 glBindBuffer
之前 调用 specifyVertexAttributes
来设置您的 VAO。这意味着 glVertexAttribPointer
保存的数组缓冲区是以前使用的。在您的前两个示例中,您在任何时间点只绑定一个数组缓冲区,它 "works" 因为前一帧的绑定缓冲区仍然存在并在下一帧中读取;如果您在第一帧暂停程序,它可能会是黑色的。
您的解决方案很简单;将 glBindBuffer
调用移至 specifyVertexAttributes
调用上方,以便您的 glVertexAttribPointer
调用读取正确的缓冲区。
请注意,这 不适用于 GL_ELEMENT_ARRAY_BUFFER
绑定;每当您绑定新绑定时,绑定都会保存在 VAO 中。
[1] 从技术上讲,您使用的是默认 VAO,它仅在兼容性上下文中受支持,但创建和绑定一直使用的全局 VAO 很容易。
我是 OpenGL 的新手,正在尝试绘制两个具有不同纹理的正方形。我使用 lwjgl 3 作为 OpenGL 的接口,但我相信对于使用其他语言的 OpenGL 的人来说,OpenGL 调用应该看起来很熟悉。我的主循环如下所示:
while (glfwWindowShouldClose(windowId) == GLFW_FALSE) {
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgramId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
// DRAW TEXTURE 1
specifyVertexAttributes(shaderProgramId);
glBindTexture(GL_TEXTURE_2D, texture1.getId());
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// DRAW TEXTURE 2
specifyVertexAttributes(shaderProgramId);
glBindTexture(GL_TEXTURE_2D, texture2.getId());
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(windowId);
glfwPollEvents();
}
当我注释掉绘制纹理 2 的代码时,纹理 1 绘制在正确的位置:
当我注释掉绘制纹理 1 的代码时,纹理 2 绘制在正确的位置:
但是当我尝试绘制两个纹理时,它们交换了位置:
我意识到上面的代码片段可能不足以诊断此问题。我创建了一个独立的 java class,其中包含我为绘制这些纹理所做的所有 OpenGL 调用:StandaloneMultiTextureExample。包含该文件的 repo 也使用 gradle 构建。对于任何愿意帮助检查 repo 和 运行 那个例子 class.
的人来说应该很容易编辑:StandaloneMultiTextureExample.java 的副本(不导入)
public class StandaloneMultiTextureExample {
private final GLFWErrorCallback errorCallback = new LoggingErrorCallback();
private final GLFWKeyCallback keyCallback = new ApplicationClosingKeyCallback();
public void run() {
if ( glfwInit() != GLFW_TRUE ) {
throw new IllegalStateException("Unable to initialize GLFW");
}
glfwSetErrorCallback(errorCallback);
int width = 225;
int height = 200;
long windowId = createWindow(width, height);
glfwSetKeyCallback(windowId, keyCallback);
glfwShowWindow(windowId);
GL.createCapabilities();
Texture texture1 = createTexture("multiTextureExample/texture1.png");
Texture texture2 = createTexture("multiTextureExample/texture2.png");
int shaderProgramId = createShaderProgram(
"multiTextureExample/textureShader.vert",
"multiTextureExample/textureShader.frag");
IntBuffer elements = BufferUtils.createIntBuffer(2 * 3);
elements.put(0).put(1).put(2);
elements.put(2).put(3).put(0);
elements.flip();
int ebo = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elements, GL_STATIC_DRAW);
float x1 = 0;
float y1 = 0;
float x2 = x1 + texture1.getWidth();
float y2 = y1 + texture1.getHeight();
float x3 = 25;
float x4 = x3 + texture2.getWidth();
FloatBuffer texture1Vertices = BufferUtils.createFloatBuffer(4 * 7);
texture1Vertices.put(x1).put(y1).put(1).put(1).put(1).put(0).put(0);
texture1Vertices.put(x2).put(y1).put(1).put(1).put(1).put(1).put(0);
texture1Vertices.put(x2).put(y2).put(1).put(1).put(1).put(1).put(1);
texture1Vertices.put(x1).put(y2).put(1).put(1).put(1).put(0).put(1);
texture1Vertices.flip();
FloatBuffer texture2Vertices = BufferUtils.createFloatBuffer(4 * 7);
texture2Vertices.put(x3).put(y1).put(1).put(1).put(1).put(0).put(0);
texture2Vertices.put(x4).put(y1).put(1).put(1).put(1).put(1).put(0);
texture2Vertices.put(x4).put(y2).put(1).put(1).put(1).put(1).put(1);
texture2Vertices.put(x3).put(y2).put(1).put(1).put(1).put(0).put(1);
texture2Vertices.flip();
int vbo1 = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBufferData(GL_ARRAY_BUFFER, texture1Vertices, GL_STATIC_DRAW);
int vbo2 = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBufferData(GL_ARRAY_BUFFER, texture2Vertices, GL_STATIC_DRAW);
specifyUniformVariables(windowId, shaderProgramId);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
while (glfwWindowShouldClose(windowId) == GLFW_FALSE) {
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgramId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
specifyVertexAttributes(shaderProgramId);
glBindTexture(GL_TEXTURE_2D, texture1.getId());
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
specifyVertexAttributes(shaderProgramId);
glBindTexture(GL_TEXTURE_2D, texture2.getId());
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(windowId);
glfwPollEvents();
}
}
private void specifyUniformVariables(long windowId, int shaderProgramId) {
int uniModel = getUniform(shaderProgramId, "model");
FloatBuffer model = BufferUtils.createFloatBuffer(16);
new Matrix4f().get(model);
glUniformMatrix4fv(uniModel, false, model);
FloatBuffer view = BufferUtils.createFloatBuffer(16);
new Matrix4f().get(view);
int uniView = getUniform(shaderProgramId, "view");
glUniformMatrix4fv(uniView, false, view);
WindowSize windowSize = getWindowSize(windowId);
int uniProjection = getUniform(shaderProgramId, "projection");
FloatBuffer projection = BufferUtils.createFloatBuffer(16);
new Matrix4f().ortho2D(0, windowSize.getWidth(), 0, windowSize.getHeight()).get(projection);
glUniformMatrix4fv(uniProjection, false, projection);
}
private void specifyVertexAttributes(int shaderProgramId) {
int stride = 7 * Float.BYTES;
int posAttrib = getAttribute(shaderProgramId, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, false, stride, 0);
int colAttrib = getAttribute(shaderProgramId, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, false, stride, 2 * Float.BYTES);
int texAttrib = getAttribute(shaderProgramId, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, false, stride, 5 * Float.BYTES);
}
public long createWindow(int width, int height) {
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
long windowId = glfwCreateWindow(width, height, "Hello World!", NULL, NULL);
if (windowId == NULL) {
throw new RuntimeException("Failed to create the GLFW window");
}
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
windowId,
(vidmode.width() - width) / 2,
(vidmode.height() - height) / 2
);
// Make the OpenGL context current
glfwMakeContextCurrent(windowId);
// Enable v-sync
glfwSwapInterval(1);
return windowId;
}
public WindowSize getWindowSize(long windowId) {
IntBuffer width = BufferUtils.createIntBuffer(1);
IntBuffer height = BufferUtils.createIntBuffer(1);
GLFW.glfwGetFramebufferSize(windowId, width, height);
return new WindowSize(width.get(), height.get());
}
public Texture createTexture(String textureResource) {
int textureId = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ARGBImage image = new ImageService().loadClasspathImage(textureResource);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA8,
image.getWidth(),
image.getHeight(),
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
image.getContents());
return new Texture(textureId, image.getWidth(), image.getHeight());
}
public int createShaderProgram(String vertexResource, String fragmentResource) {
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
String vertexSource = getClasspathResource(vertexResource);
glShaderSource(vertexShader, vertexSource);
glCompileShader(vertexShader);
validateShaderCompilation(vertexShader);
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
String fragmentSource = getClasspathResource(fragmentResource);
glShaderSource(fragmentShader, fragmentSource);
glCompileShader(fragmentShader);
validateShaderCompilation(fragmentShader);
int shaderProgramId = glCreateProgram();
glAttachShader(shaderProgramId, vertexShader);
glAttachShader(shaderProgramId, fragmentShader);
glLinkProgram(shaderProgramId);
validateShaderProgram(shaderProgramId);
glUseProgram(shaderProgramId);
return shaderProgramId;
}
private static String getClasspathResource(String resourceName) {
URL url = Resources.getResource(resourceName);
try {
return Resources.toString(url, Charsets.UTF_8);
} catch (IOException e) {
throw Throwables.propagate(e);
}
}
private static void validateShaderCompilation(int shader) {
int status = glGetShaderi(shader, GL_COMPILE_STATUS);
if (status != GL_TRUE) {
throw new RuntimeException(glGetShaderInfoLog(shader));
}
}
private static void validateShaderProgram(int shaderProgram) {
int status = glGetProgrami(shaderProgram, GL_LINK_STATUS);
if (status != GL_TRUE) {
throw new RuntimeException(glGetProgramInfoLog(shaderProgram));
}
}
public int getUniform(int shaderProgramId, String uniformName) {
int location = glGetUniformLocation(shaderProgramId, uniformName);
if (location == -1) {
throw new IllegalArgumentException("Could not find uniform: "
+ uniformName + " for shaderProgramId: " + shaderProgramId);
} else {
return location;
}
}
public int getAttribute(int shaderProgramId, String attribute) {
int location = glGetAttribLocation(shaderProgramId, attribute);
if (location == -1) {
throw new IllegalArgumentException("Could not find attribute: "
+ attribute + " for shaderProgramId: " + shaderProgramId);
} else {
return location;
}
}
public static void main(String[] args) {
new StandaloneMultiTextureExample().run();
}
}
您在错误的时间绑定顶点缓冲区,从而错误地设置了顶点数组。
当您使用顶点数组对象 (VAO) 渲染 [1] 时,读取 GL_ARRAY_BUFFER
绑定的唯一时间是 glVertexAttribPointer
调用。调用 glVertexAttribPointer
获取当前绑定的 GL_ARRAY_BUFFER
对象的名称并将其与属性和 VAO 相关联;在那之后,GL_ARRAY_BUFFER
绑定根本不重要,绑定另一个数组缓冲区将不会以任何方式修改 VAO。
在您的代码中,您在调用 glBindBuffer
之前 调用 specifyVertexAttributes
来设置您的 VAO。这意味着 glVertexAttribPointer
保存的数组缓冲区是以前使用的。在您的前两个示例中,您在任何时间点只绑定一个数组缓冲区,它 "works" 因为前一帧的绑定缓冲区仍然存在并在下一帧中读取;如果您在第一帧暂停程序,它可能会是黑色的。
您的解决方案很简单;将 glBindBuffer
调用移至 specifyVertexAttributes
调用上方,以便您的 glVertexAttribPointer
调用读取正确的缓冲区。
请注意,这 不适用于 GL_ELEMENT_ARRAY_BUFFER
绑定;每当您绑定新绑定时,绑定都会保存在 VAO 中。
[1] 从技术上讲,您使用的是默认 VAO,它仅在兼容性上下文中受支持,但创建和绑定一直使用的全局 VAO 很容易。