You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:36:07