Java LWJGL OpenGL 异常访问冲突 0xc0000005
Java LWJGL OpenGL Exception Access Violation 0xc0000005
调用 glDrawElements() 时出现错误,我无法弄清楚原因:/ 我是 OpenGL 的新手,我正在尝试了解它的工作原理。
注意:我正在使用这个库将 OBJ 文件转换为 OpenGL 应该能够使用的数组:https://github.com/korre/java-obj-to-opengl/blob/master/MeshObjectLoader.java
public class Mesh {
private int vaoId;
private List<Integer> vboIdList = new ArrayList<>();
@Getter
@Setter
private float scale = 1;
@Getter
@Setter
private Vector3f position = new Vector3f(0, 0, 0);
@Getter
@Setter
private Vector3f rotation = new Vector3f(0, 0, 0);
@Getter
@Setter
private String textureKey;
private int vertexCount;
private Mesh(MeshObjectLoader.MeshArrays meshArrays) {
vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
var vboId = 0;
vertexCount = meshArrays.getNumVertices();
// Load vertices
vboId = glGenBuffers();
vboIdList.add(vboId);
var vertexBuffer = (FloatBuffer) meshArrays.getVertices();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0 ,0);
// Load texture coordinates
vboId = glGenBuffers();
vboIdList.add(vboId);
var textureCoordsBuffer = (FloatBuffer) meshArrays.getTexCoords();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, textureCoordsBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
// Clean everything up
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
public static Mesh loadFromObjFile(String resourcePath) throws IOException {
try (var resourceStream = Mesh.class.getResourceAsStream(resourcePath)) {
return new Mesh(MeshObjectLoader.loadModelMeshFromStream(resourceStream));
}
}
public void render(int textureId) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureId);
glBindVertexArray(vaoId);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnable(GL_DEPTH_TEST);
glDrawElements(GL_TRIANGLES, vertexCount, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
}
public void cleanup() {
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
for (int vboId : vboIdList) {
glDeleteBuffers(vboId);
}
glBindVertexArray(0);
glDeleteVertexArrays(vaoId);
}
}
崩溃的原因是您从未将缓冲区对象绑定到 VAO 的 GL_ELEMENT_ARRAY_BUFFER
绑定点,因此 glDrawElements(..., 0)
的最后一个参数被解释为 host-address指针而不是任何元素数组缓冲区中的 byte-offset。
当然,取消引用 0
地址会失败。
无论何时调用索引绘图调用,如 glDrawElements
,您还需要一个元素数组缓冲区(也称为“索引缓冲区”)。
库 returns 位置、纹理坐标和法线的列表,您只需通过 glDrawArrays()
进行 non-indexed 绘图调用。这也是非常典型的 Wavefront OBJ 加载器,因为 Wavefront OBJ 格式有位置、法线和纹理坐标的单独索引,所以典型的加载无论如何都会对所有面部索引进行 cross-product,并为您提供 linear/duplicated顶点数据列表。
所以:改为 glDrawArrays
。
调用 glDrawElements() 时出现错误,我无法弄清楚原因:/ 我是 OpenGL 的新手,我正在尝试了解它的工作原理。
注意:我正在使用这个库将 OBJ 文件转换为 OpenGL 应该能够使用的数组:https://github.com/korre/java-obj-to-opengl/blob/master/MeshObjectLoader.java
public class Mesh {
private int vaoId;
private List<Integer> vboIdList = new ArrayList<>();
@Getter
@Setter
private float scale = 1;
@Getter
@Setter
private Vector3f position = new Vector3f(0, 0, 0);
@Getter
@Setter
private Vector3f rotation = new Vector3f(0, 0, 0);
@Getter
@Setter
private String textureKey;
private int vertexCount;
private Mesh(MeshObjectLoader.MeshArrays meshArrays) {
vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
var vboId = 0;
vertexCount = meshArrays.getNumVertices();
// Load vertices
vboId = glGenBuffers();
vboIdList.add(vboId);
var vertexBuffer = (FloatBuffer) meshArrays.getVertices();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0 ,0);
// Load texture coordinates
vboId = glGenBuffers();
vboIdList.add(vboId);
var textureCoordsBuffer = (FloatBuffer) meshArrays.getTexCoords();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, textureCoordsBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
// Clean everything up
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
public static Mesh loadFromObjFile(String resourcePath) throws IOException {
try (var resourceStream = Mesh.class.getResourceAsStream(resourcePath)) {
return new Mesh(MeshObjectLoader.loadModelMeshFromStream(resourceStream));
}
}
public void render(int textureId) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureId);
glBindVertexArray(vaoId);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnable(GL_DEPTH_TEST);
glDrawElements(GL_TRIANGLES, vertexCount, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
}
public void cleanup() {
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
for (int vboId : vboIdList) {
glDeleteBuffers(vboId);
}
glBindVertexArray(0);
glDeleteVertexArrays(vaoId);
}
}
崩溃的原因是您从未将缓冲区对象绑定到 VAO 的 GL_ELEMENT_ARRAY_BUFFER
绑定点,因此 glDrawElements(..., 0)
的最后一个参数被解释为 host-address指针而不是任何元素数组缓冲区中的 byte-offset。
当然,取消引用 0
地址会失败。
无论何时调用索引绘图调用,如 glDrawElements
,您还需要一个元素数组缓冲区(也称为“索引缓冲区”)。
库 returns 位置、纹理坐标和法线的列表,您只需通过 glDrawArrays()
进行 non-indexed 绘图调用。这也是非常典型的 Wavefront OBJ 加载器,因为 Wavefront OBJ 格式有位置、法线和纹理坐标的单独索引,所以典型的加载无论如何都会对所有面部索引进行 cross-product,并为您提供 linear/duplicated顶点数据列表。
所以:改为 glDrawArrays
。