如何为基于JOGL的Java 3D项目Jug3D添加键鼠适配器实现模型移动
解决JOGL NEWT窗口下的3D模型键鼠控制问题
看起来你混淆了AWT的事件适配器和JOGL NEWT的事件处理机制——因为你用的是com.jogamp.newt.Window,所以不能直接用AWT的MouseAdapter/KeyboardAdapter,得用NEWT原生的事件监听器。下面我会给你修改后的完整代码,一步步解释怎么实现模型的键鼠移动:
1. 修正依赖导入
首先替换掉AWT相关的事件导入,改用NEWT的事件类:
package Jug3D; import com.jogamp.newt.Window; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.KeyListener; import com.jogamp.newt.event.MouseEvent; import com.jogamp.newt.event.MouseListener; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLProfile; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.util.FPSAnimator;
2. 添加模型位置变量与事件监听器
在你的主渲染类中添加控制模型位置的成员变量,然后实现NEWT的MouseListener和KeyListener接口:
public class Jug3DMain implements GLEventListener, MouseListener, KeyListener { // 模型的位置坐标,初始让模型处于视野内(Z轴负方向) private float modelX = 0.0f; private float modelY = 0.0f; private float modelZ = -5.0f; // 鼠标拖动的临时记录变量 private int lastMouseX, lastMouseY; public static void main(String[] args) { GLProfile profile = GLProfile.getDefault(); com.jogamp.opengl.GLCapabilities capabilities = new com.jogamp.opengl.GLCapabilities(profile); GLWindow window = GLWindow.create(capabilities); window.setSize(800, 600); window.setTitle("Jug3D - 键鼠控制模型"); Jug3DMain renderer = new Jug3DMain(); window.addGLEventListener(renderer); // 绑定鼠标与键盘监听器 window.addMouseListener(renderer); window.addKeyListener(renderer); FPSAnimator animator = new FPSAnimator(window, 60); animator.start(); window.setVisible(true); } // --- GLEventListener 实现方法 --- @Override public void init(GLAutoDrawable drawable) { GL2 gl = drawable.getGL().getGL2(); gl.glEnable(GL2.GL_DEPTH_TEST); // 开启深度测试,保证模型前后层级正确 gl.glClearColor(0.1f, 0.1f, 0.1f, 1.0f); // 设置深色背景 } @Override public void display(GLAutoDrawable drawable) { GL2 gl = drawable.getGL().getGL2(); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); // 先应用模型位置偏移,再绘制模型 gl.glTranslatef(modelX, modelY, modelZ); // 替换成你自己的3D模型绘制代码,这里用立方体做示例 drawSampleCube(gl); } @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { GL2 gl = drawable.getGL().getGL2(); gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); float aspectRatio = (float) width / height; // 设置透视投影,适配窗口比例 gl.glFrustumf(-aspectRatio, aspectRatio, -1, 1, 1, 100); gl.glMatrixMode(GL2.GL_MODELVIEW); } @Override public void dispose(GLAutoDrawable drawable) {} // --- 辅助绘制方法 --- private void drawSampleCube(GL2 gl) { gl.glBegin(GL2.GL_QUADS); // 前面(红色) gl.glColor3f(1.0f, 0.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); gl.glVertex3f(1.0f, -1.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, 1.0f); // 后面(绿色) gl.glColor3f(0.0f, 1.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, -1.0f); gl.glVertex3f(-1.0f, 1.0f, -1.0f); gl.glVertex3f(1.0f, 1.0f, -1.0f); gl.glVertex3f(1.0f, -1.0f, -1.0f); // 其余四个面可自行补充 gl.glEnd(); } // --- MouseListener 实现方法(处理鼠标拖动平移)--- @Override public void mousePressed(MouseEvent e) { // 记录鼠标按下时的初始位置 lastMouseX = e.getX(); lastMouseY = e.getY(); } @Override public void mouseDragged(MouseEvent e) { // 计算鼠标拖动的偏移量 int deltaX = e.getX() - lastMouseX; int deltaY = e.getY() - lastMouseY; // 转换为模型移动的增量(系数控制灵敏度) modelX += deltaX * 0.01f; modelY -= deltaY * 0.01f; // Y轴反转,符合视觉直觉 // 更新鼠标位置记录 lastMouseX = e.getX(); lastMouseY = e.getY(); } // 其余MouseListener方法留空实现 @Override public void mouseClicked(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} // --- KeyListener 实现方法(处理WASDQE按键移动)--- @Override public void keyPressed(KeyEvent e) { float moveSpeed = 0.1f; switch(e.getKeyCode()) { case KeyEvent.VK_W: modelZ += moveSpeed; break; // 向前移动 case KeyEvent.VK_S: modelZ -= moveSpeed; break; // 向后移动 case KeyEvent.VK_A: modelX -= moveSpeed; break; // 向左移动 case KeyEvent.VK_D: modelX += moveSpeed; break; // 向右移动 case KeyEvent.VK_Q: modelY += moveSpeed; break; // 向上移动 case KeyEvent.VK_E: modelY -= moveSpeed; break; // 向下移动 } } // 其余KeyListener方法留空实现 @Override public void keyReleased(KeyEvent e) {} @Override public void keyTyped(KeyEvent e) {} }
3. 关键要点说明
- NEWT事件体系:JOGL的NEWT窗口是独立于AWT的,必须使用
com.jogamp.newt.event包下的监听器,不能混用AWT的适配器类。你可以让渲染类直接实现接口,也可以写内部类单独处理事件。 - 模型变换逻辑:在
display方法中,必须先调用glTranslatef应用位置偏移,再执行模型绘制,这样才能让模型跟随输入移动。 - 灵敏度调整:鼠标拖动的
0.01f和键盘的0.1f是移动速度系数,你可以根据需求放大或缩小,优化操控手感。 - 深度测试:一定要开启
GL_DEPTH_TEST,否则模型的前后层级会显示错乱。
你只需要把示例中的drawSampleCube替换成你自己的3D模型绘制代码,就能实现键鼠控制模型移动了。
内容的提问来源于stack exchange,提问作者Khalid
相关产品推荐
相关产品推荐

