我正在使用 lwjgl 制作一个 java 3d 项目。
调用 Sphere.getVertices() 方法时,Java 崩溃。但是当我尝试检测两个立方体之间的碰撞时,我看到黑屏没有任何组件,但是java不会崩溃。
日志
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffbbedaa293, pid=2500, tid=1752
#
# JRE version: OpenJDK Runtime Environment Temurin-17.0.7+7 (17.0.7+7) (build 17.0.7+7)
# Java VM: OpenJDK 64-Bit Server VM Temurin-17.0.7+7 (17.0.7+7, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, windows-amd64)
# Problematic frame:
# C [lwjgl_opengl.dll+0xa293]
#
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
# If you would like to submit a bug report, please visit:
# https://github.com/adoptium/adoptium-support/issues
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
--------------- S U M M A R Y ------------
Command Line: -XX:+ShowCodeDetailsInExceptionMessages Main
Host: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz, 8 cores, 7G, Windows 10 , 64 bit Build 19041 (10.0.19041.3155)
Time: Tue Aug 22 12:57:53 2023 RTZ 2 (s 10 , 64 bit Build 19041 (10.0.19041.3155) elapsed time: 0.495254 seconds (0d 0h 0m 0s)
--------------- T H R E A D ---------------
Current thread (0x000001bc95c0e1a0): JavaThread "main" [_thread_in_native, id=1752, stack(0x000000481f200000,0x000000481f300000)]
Stack: [0x000000481f200000,0x000000481f300000], sp=0x000000481f2ff4c8, free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [lwjgl_opengl.dll+0xa293]
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j org.lwjgl.opengl.GL11.glColor3f(FFF)V+0
j Models.Sphere$1.<init>(LModels/Sphere;)V+21
j Models.Sphere.getVertices()Ljava/util/ArrayList;+5
j Engine.Component.checkColision(LEngine/Component;)Z+21
j Main.main([Ljava/lang/String;)V+86
v ~StubRoutines::call_stub
siginfo: EXCEPTION_ACCESS_VIOLATION (0xc0000005), reading address 0x00000000000000b0
Register to memory mapping:
RIP=0x00007ffbbedaa293 lwjgl_opengl.dll
RAX=0x000001bcb84a83e0 points into unknown readable memory: 0x0000000000000000 | 00 00 00 00 00 00 00 00
RBX={method} {0x000001bcb4704b78} 'glColor3f' '(FFF)V' in 'org/lwjgl/opengl/GL11'
RCX=0x0 is NULL
RDX=0x000000481f2ff560 is pointing into the stack for thread: 0x000001bc95c0e1a0
RSP=0x000000481f2ff4c8 is pointing into the stack for thread: 0x000001bc95c0e1a0
RBP=0x000000481f2ff550 is pointing into the stack for thread: 0x000001bc95c0e1a0
RSI=0x000001bcb4007c98 is pointing into metadata
RDI=0x0000000000009c1a is an unknown value
R8 =0x0000000000000002 is an unknown value
R9 =0x0000000000000002 is an unknown value
R10=0x000001bca4c3d5f2 is at code_begin+946 in an Interpreter codelet
method entry point (kind = native) [0x000001bca4c3d240, 0x000001bca4c3dbc0] 2432 bytes
R11=0x00000000894524c0 is an oop: java.lang.Class
{0x00000000894524c0} - klass: 'java/lang/Class']
Component.java代码:
import java.util.ArrayList;
import java.util.List;
import org.joml.Matrix4f;
import org.joml.Vector3f;
public abstract class Component {
private Vector3f pos = new Vector3f(0, 0, 0);
private Vector3f rotate = new Vector3f(0, 0, 0);
private Vector3f scale = new Vector3f(1, 1, 1);
public boolean checkColision(Component component) {
ArrayList<Vector3f> transformedVertices = transformVertices(getVertices(), pos, rotate, scale);
ArrayList<Vector3f> componentTransformedVertices = transformVertices(component.getVertices(), component.getPos(), component.getRotate(), component.getScale()); //The problem is probably here.
Vector3f max = new Vector3f(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE);
Vector3f min = new Vector3f(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE);
for(Vector3f vertex : transformedVertices) {
if(vertex.x > max.x) max.x = vertex.x;
if(vertex.y > max.y) max.y = vertex.y;
if(vertex.z > max.z) max.z = vertex.z;
if(vertex.x < min.x) min.x = vertex.x;
if(vertex.y < min.y) min.y = vertex.y;
if(vertex.z < min.z) min.z = vertex.z;
}
Vector3f componentMax = new Vector3f(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE);
Vector3f componentMin = new Vector3f(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE);
for(Vector3f vertex : componentTransformedVertices) {
if(vertex.x > componentMax.x) componentMax.x = vertex.x;
if(vertex.y > componentMax.y) componentMax.y = vertex.y;
if(vertex.z > componentMax.z) componentMax.z = vertex.z;
if(vertex.x < componentMin.x) componentMin.x = vertex.x;
if(vertex.y < componentMin.y) componentMin.y = vertex.y;
if(vertex.z < componentMin.z) componentMin.z = vertex.z;
}
if (max.x <= componentMin.x || min.x >= componentMax.x) return false;
if (max.y <= componentMin.y || min.y >= componentMax.y) return false;
if (max.z <= componentMin.z || min.z >= componentMax.z) return false;
return true;
}
//some getters and setters.
public abstract ArrayList<Vector3f> getVertices(); //returns an arraylist of object vertex coordinates for collision detection.
private synchronized static ArrayList<Vector3f> transformVertices(ArrayList<Vector3f> vertices, Vector3f position, Vector3f rotation, Vector3f scale) {
ArrayList<Vector3f> transformedVertices = new ArrayList<>();
Matrix4f transformationMatrix = new Matrix4f()
.translate(position)
.rotateX((float) Math.toRadians(rotation.x))
.rotateY((float) Math.toRadians(rotation.y))
.rotateZ((float) Math.toRadians(rotation.z))
.scale(scale);
for (Vector3f vertex : vertices) {
Vector3f transformedVertex = new Vector3f(vertex);
transformedVertex.mulPosition(transformationMatrix);
transformedVertices.add(transformedVertex);
}
return transformedVertices;
}
}
Sphere.java代码:
package Models;
import Engine.Component;
import org.lwjgl.opengl.GL11;
import static org.lwjgl.opengl.GL11.*;
import java.util.ArrayList;
import org.joml.Vector3f;
public class Sphere extends Component {
public float radius = 1.0f;
public int gradation = 100;
public final float PI = (float) Math.PI;
@Override
public void draw() {
float x, y, z, alpha, beta;
for (alpha = 0.0f; alpha < Math.PI; alpha += PI / gradation) {
glBegin(GL_TRIANGLE_STRIP);
GL11.glColor3f(0.7f, 0.7f, 0.7f);
for (beta = 0.0f; beta < 2.01f * Math.PI; beta += PI / gradation) {
x = (float) (radius * Math.cos(beta) * Math.sin(alpha));
y = (float) (radius * Math.sin(beta) * Math.sin(alpha));
z = (float) (radius * Math.cos(alpha));
glTexCoord2f(beta / (2.0f * PI), alpha / PI);
glVertex3f(x, y, z);
x = (float) (radius * Math.cos(beta) * Math.sin(alpha + PI / gradation));
y = (float) (radius * Math.sin(beta) * Math.sin(alpha + PI / gradation));
z = (float) (radius * Math.cos(alpha + PI / gradation));
glTexCoord2f(beta / (2.0f * PI), alpha / PI + 1.0f / gradation);
glVertex3f(x, y, z);
}
glEnd();
}
}
@Override
public ArrayList<Vector3f> getVertices() {
return new ArrayList<Vector3f>() {{
float x, y, z, alpha, beta;
for (alpha = 0.0f; alpha < Math.PI; alpha += PI / gradation) {
GL11.glColor3f(0.7f, 0.7f, 0.7f);
for (beta = 0.0f; beta < 2.01f * Math.PI; beta += PI / gradation) {
x = (float) (radius * Math.cos(beta) * Math.sin(alpha));
y = (float) (radius * Math.sin(beta) * Math.sin(alpha));
z = (float) (radius * Math.cos(alpha));
glTexCoord2f(beta / (2.0f * PI), alpha / PI);
add(new Vector3f(x, y, z));
x = (float) (radius * Math.cos(beta) * Math.sin(alpha + PI / gradation));
y = (float) (radius * Math.sin(beta) * Math.sin(alpha + PI / gradation));
z = (float) (radius * Math.cos(alpha + PI / gradation));
glTexCoord2f(beta / (2.0f * PI), alpha / PI + 1.0f / gradation);
add(new Vector3f(x, y, z));
}
}
}};
}
}
Cube.java代码:
package Models;
import Engine.Component;
import java.util.ArrayList;
import org.joml.Vector3f;
import org.lwjgl.opengl.GL11;
public class Cube extends Component {
public float size = 1.0f;
@Override
public void draw() {
GL11.glBegin(GL11.GL_QUADS);
GL11.glColor3f(0.7f, 0.7f, 0.7f);
GL11.glVertex3f(-size, size, -size);
GL11.glVertex3f(size, size, -size);
GL11.glVertex3f(size, size, size);
GL11.glVertex3f(-size, size, size);
GL11.glVertex3f(-size, -size, -size);
GL11.glVertex3f(-size, -size, size);
GL11.glVertex3f(size, -size, size);
GL11.glVertex3f(size, -size, -size);
GL11.glVertex3f(-size, -size, size);
GL11.glVertex3f(-size, size, size);
GL11.glVertex3f(size, size, size);
GL11.glVertex3f(size, -size, size);
GL11.glVertex3f(-size, -size, -size);
GL11.glVertex3f(size, -size, -size);
GL11.glVertex3f(size, size, -size);
GL11.glVertex3f(-size, size, -size);
GL11.glVertex3f(-size, -size, -size);
GL11.glVertex3f(-size, -size, size);
GL11.glVertex3f(-size, size, size);
GL11.glVertex3f(-size, size, -size);
GL11.glVertex3f(size, -size, -size);
GL11.glVertex3f(size, size, -size);
GL11.glVertex3f(size, size, size);
GL11.glVertex3f(size, -size, size);
GL11.glEnd();
}
@Override
public ArrayList<Vector3f> getVertices() {
return new ArrayList<Vector3f>() {{
add(new Vector3f(-size, size, -size));
add(new Vector3f(size, size, -size));
add(new Vector3f(size, size, size));
add(new Vector3f(-size, size, size));
add(new Vector3f(-size, -size, -size));
add(new Vector3f(-size, -size, size));
add(new Vector3f(size, -size, size));
add(new Vector3f(size, -size, -size));
add(new Vector3f(-size, -size, size));
add(new Vector3f(-size, size, size));
add(new Vector3f(size, size, size));
add(new Vector3f(size, -size, size));
add(new Vector3f(-size, -size, -size));
add(new Vector3f(size, -size, -size));
add(new Vector3f(size, size, -size));
add(new Vector3f(-size, size, -size));
add(new Vector3f(-size, -size, -size));
add(new Vector3f(-size, -size, size));
add(new Vector3f(-size, size, size));
add(new Vector3f(-size, size, -size));
add(new Vector3f(size, -size, -size));
add(new Vector3f(size, size, -size));
add(new Vector3f(size, size, size));
add(new Vector3f(size, -size, size));
}};
}
}
我希望有一个方法,当跨越对象边界时返回 true,而不是崩溃。
看来您在使用 LWJGL 的 Java 3D 项目中面临着挑战。您遇到的崩溃似乎源于
Sphere
类的 getVertices
方法中某些不适当的 OpenGL 使用。让我们一步步解决这个问题:
第 1 步: 细化
Sphere
类的 getVertices
方法,仅专注于构造顶点数据,而不需要任何 OpenGL 调用:
@Override
public ArrayList<Vector3f> getVertices() {
ArrayList<Vector3f> vertices = new ArrayList<>();
float x, y, z, alpha, beta;
for (alpha = 0.0f; alpha < Math.PI; alpha += PI / gradation) {
for (beta = 0.0f; beta < 2.01f * Math.PI; beta += PI / gradation) {
x = (float) (radius * Math.cos(beta) * Math.sin(alpha));
y = (float) (radius * Math.sin(beta) * Math.sin(alpha));
z = (float) (radius * Math.cos(alpha));
vertices.add(new Vector3f(x, y, z));
x = (float) (radius * Math.cos(beta) * Math.sin(alpha + PI / gradation));
y = (float) (radius * Math.sin(beta) * Math.sin(alpha + PI / gradation));
z = (float) (radius * Math.cos(alpha + PI / gradation));
vertices.add(new Vector3f(x, y, z));
}
}
return vertices;
}
第 2 步: 在渲染循环中,一定要在渲染对象之前设置 OpenGL 状态(包括颜色)。这是 OpenGL 调用合适的地方:
while (!glfwWindowShouldClose(window)) {
// Clear the buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set OpenGL state, e.g., color
glColor3f(0.7f, 0.7f, 0.7f);
// Render objects
// ...
// Swap the buffer
glfwSwapBuffers(window);
glfwPollEvents();
}
通过分离设置 OpenGL 状态和渲染调用的过程,您应该能够防止与 OpenGL 使用不当相关的问题。这种方法应该有助于减轻您在项目中遇到的崩溃。如果问题仍然存在,您可能会考虑探索可能解决该问题的 LWJGL 或 OpenGL 驱动程序的潜在更新。有时,有缺陷或过时的驱动程序会导致一系列错误,因此请务必进行检查。