调整窗口大小时无法保持统一的比例,OpenGL + Java=JOGL

发布于 2024-12-07 09:43:57 字数 4197 浏览 1 评论 0原文

我第一次使用 JOGL(Java OpenGL 包装器),我有一个无法解决的问题,我不确定这是否与 JOGL 或 OpenGL 一般相关。

我在 JForm 内的 JPanel 内的 GLCanvas 上进行渲染(该程序的重​​点是混合 OpenGL 和 SWING)。截至目前,我正在绘制简单的 2D(正交)三角形(它们将是图块),我希望它们根据视口(面板?)的大小进行缩放。 我实现了缩放,但由于某种原因图像被拉伸,就好像当我调整窗口大小时 X 分量和 Y 分量的缩放比例不同。 即它们应该保持相同的平方比,但它们却被拉伸了。

正如您在代码中看到的,我对 X 和 Y 使用相同的缩放系数。

我不明白错误是在我的 OpenGL 代码中还是在我的 SWING-JOGL 代码中。 有人能指出我正确的方向吗?

一张图片胜过千言万语: 调整窗口大小后的拉伸效果

以下是一些代码:

OpenGL 代码

class Graphics {

/**
 * The default ratio between the screen size and the tile size, before zoom is applied
 */
final static float DEFAULT_TILE_TO_SCREEN = 0.5f;

/**
 * The parent engine
 */
protected Engine myEngine; 

Graphics(Engine e)
{
    myEngine = e;
}

/**
 * Sets up viewport
 * @param gl2
 * @param width
 * @param height 
 */
void setup( GL2 gl2, int width, int height ) {
    gl2.glMatrixMode( GL2.GL_PROJECTION );
    gl2.glLoadIdentity();

    // coordinate system origin at lower left with width and height same as the window
    GLU glu = new GLU();
    glu.gluOrtho2D( 0.0f, width, 0.0f, height );

    gl2.glMatrixMode( GL2.GL_MODELVIEW );
    gl2.glLoadIdentity();

    gl2.glViewport( 0, 0, width, height );
}

/**
 * Renders viewport
 * @param gl2
 * @param width
 * @param height 
 */
void render( GL2 gl2, int width, int height ) {
    final float zoomFactor = DEFAULT_TILE_TO_SCREEN * myEngine.myZoomLevel;
    final float zoom = Math.max(height *  zoomFactor, width * zoomFactor);
    gl2.glClear( GL.GL_COLOR_BUFFER_BIT );

    // draw a triangle filling the window
    gl2.glLoadIdentity();
    gl2.glScalef(zoom, zoom, 1);
    gl2.glBegin( GL.GL_TRIANGLES );
    for(int x = 0; x < myEngine.myWorldTiles.maxTileX; ++x)
    {
        for(int y = 0; y < myEngine.myWorldTiles.maxTileY; ++y)
        {
            gl2.glColor3f( 1, 0, 0 );
            gl2.glVertex2f( x + 0.f, y + 0.f );
            gl2.glVertex2f( x + 1.f, y + 0.f );
            gl2.glVertex2f( x + 1.f, y + 1.f );

            gl2.glColor3f( 0, 0, 1 );
            gl2.glVertex2f( x + 0.f, y + 0.f );
            gl2.glVertex2f( x + 1.f, y + 1.f );
            gl2.glVertex2f( x + 0.f, y + 1.f );
        }
    }
     gl2.glEnd();
}

}

SWING 集成代码

public class Engine {

/**
 * The internal rendering canvas
 */
private GLCanvas    myCanvas;
/**
 * The graphics used for rendering
 */
private Graphics    myGraphics;   

/**
 * The zoom level of the graphics
 */
float       myZoomLevel = 1;
/**
 * The world map
 */
TileList    myWorldTiles;

/**
 * The currently centered tile
 */
Point       myCenteredTile;

public Engine(TileList worldTile)
{
    myWorldTiles = worldTile;
    GLProfile glprofile = GLProfile.getDefault();
    GLCapabilities glcapabilities = new GLCapabilities( glprofile );
    myCanvas = new GLCanvas( glcapabilities );

    myGraphics = new Graphics(this);
    myCanvas.addGLEventListener( new GLEventListener() {

        @Override
        public void reshape( GLAutoDrawable glautodrawable, int x, int y, int width, int height ) {
        }

        @Override
        public void init( GLAutoDrawable glautodrawable ) {
            myGraphics.setup( glautodrawable.getGL().getGL2(), glautodrawable.getWidth(), glautodrawable.getHeight() );
        }

        @Override
        public void dispose( GLAutoDrawable glautodrawable ) {
        }

        @Override
        public void display( GLAutoDrawable glautodrawable ) {
            myGraphics.render( glautodrawable.getGL().getGL2(), glautodrawable.getWidth(), glautodrawable.getHeight() );
        }
    });

}

/**
 * Sets the zoom level for the screen
 * @param zoom 
 */
public void setZoomLevel(float zoom)
{
    myZoomLevel = zoom;
}

/**
 * Gets the 3D canvas, should be placed in user-defined form/window/panel 
 */
public java.awt.Component getCanvas()
{
    return myCanvas;
}

/**
 * Centers the screen on the given tile
 * @param p 
 */
public void centerOnTile(Point p)
{
    myCenteredTile = p;
}
}

同样

在 JFrame 初始化代码中

contentPanel.add(myWorld.myEngine.getCanvas(), BorderLayout.CENTER);

I'm using JOGL (Java OpenGL wrapper) for the first time and I have an issue I can't figure out, I'm not sure if this is related to JOGL or OpenGL in general.

I render on a GLCanvas inside a JPanel inside a JForm (the whole point of the program is to mix OpenGL and SWING). As of now I'm drawing simple 2D (ortho) triangles (they'll be tiles), I would like them to scale according to the size of the viewport (panel?).
I achieved scaling but for some reason the image is stretched, as if scale ratio was not the same on the X component and the Y component, when I resize the window.
I.e. they should maintain the same square ratio, but they get stretched instead.

As you can see in the code, I use the same zoom factor for X and Y.

I don't understand if the error is in my OpenGL code or in my SWING-JOGL code.
Can anyone point me in the right direction?

An image is better than a thousands words:
The streching effect after resizing the window

Here's some code:

The OpenGL code

class Graphics {

/**
 * The default ratio between the screen size and the tile size, before zoom is applied
 */
final static float DEFAULT_TILE_TO_SCREEN = 0.5f;

/**
 * The parent engine
 */
protected Engine myEngine; 

Graphics(Engine e)
{
    myEngine = e;
}

/**
 * Sets up viewport
 * @param gl2
 * @param width
 * @param height 
 */
void setup( GL2 gl2, int width, int height ) {
    gl2.glMatrixMode( GL2.GL_PROJECTION );
    gl2.glLoadIdentity();

    // coordinate system origin at lower left with width and height same as the window
    GLU glu = new GLU();
    glu.gluOrtho2D( 0.0f, width, 0.0f, height );

    gl2.glMatrixMode( GL2.GL_MODELVIEW );
    gl2.glLoadIdentity();

    gl2.glViewport( 0, 0, width, height );
}

/**
 * Renders viewport
 * @param gl2
 * @param width
 * @param height 
 */
void render( GL2 gl2, int width, int height ) {
    final float zoomFactor = DEFAULT_TILE_TO_SCREEN * myEngine.myZoomLevel;
    final float zoom = Math.max(height *  zoomFactor, width * zoomFactor);
    gl2.glClear( GL.GL_COLOR_BUFFER_BIT );

    // draw a triangle filling the window
    gl2.glLoadIdentity();
    gl2.glScalef(zoom, zoom, 1);
    gl2.glBegin( GL.GL_TRIANGLES );
    for(int x = 0; x < myEngine.myWorldTiles.maxTileX; ++x)
    {
        for(int y = 0; y < myEngine.myWorldTiles.maxTileY; ++y)
        {
            gl2.glColor3f( 1, 0, 0 );
            gl2.glVertex2f( x + 0.f, y + 0.f );
            gl2.glVertex2f( x + 1.f, y + 0.f );
            gl2.glVertex2f( x + 1.f, y + 1.f );

            gl2.glColor3f( 0, 0, 1 );
            gl2.glVertex2f( x + 0.f, y + 0.f );
            gl2.glVertex2f( x + 1.f, y + 1.f );
            gl2.glVertex2f( x + 0.f, y + 1.f );
        }
    }
     gl2.glEnd();
}

}

The SWING integration code

public class Engine {

/**
 * The internal rendering canvas
 */
private GLCanvas    myCanvas;
/**
 * The graphics used for rendering
 */
private Graphics    myGraphics;   

/**
 * The zoom level of the graphics
 */
float       myZoomLevel = 1;
/**
 * The world map
 */
TileList    myWorldTiles;

/**
 * The currently centered tile
 */
Point       myCenteredTile;

public Engine(TileList worldTile)
{
    myWorldTiles = worldTile;
    GLProfile glprofile = GLProfile.getDefault();
    GLCapabilities glcapabilities = new GLCapabilities( glprofile );
    myCanvas = new GLCanvas( glcapabilities );

    myGraphics = new Graphics(this);
    myCanvas.addGLEventListener( new GLEventListener() {

        @Override
        public void reshape( GLAutoDrawable glautodrawable, int x, int y, int width, int height ) {
        }

        @Override
        public void init( GLAutoDrawable glautodrawable ) {
            myGraphics.setup( glautodrawable.getGL().getGL2(), glautodrawable.getWidth(), glautodrawable.getHeight() );
        }

        @Override
        public void dispose( GLAutoDrawable glautodrawable ) {
        }

        @Override
        public void display( GLAutoDrawable glautodrawable ) {
            myGraphics.render( glautodrawable.getGL().getGL2(), glautodrawable.getWidth(), glautodrawable.getHeight() );
        }
    });

}

/**
 * Sets the zoom level for the screen
 * @param zoom 
 */
public void setZoomLevel(float zoom)
{
    myZoomLevel = zoom;
}

/**
 * Gets the 3D canvas, should be placed in user-defined form/window/panel 
 */
public java.awt.Component getCanvas()
{
    return myCanvas;
}

/**
 * Centers the screen on the given tile
 * @param p 
 */
public void centerOnTile(Point p)
{
    myCenteredTile = p;
}
}

Also

in the JFrame init code

contentPanel.add(myWorld.myEngine.getCanvas(), BorderLayout.CENTER);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

十秒萌定你 2024-12-14 09:43:57

每次调整窗口大小时都必须设置投影矩阵。我以前没有使用过 JOGL,但我认为您应该在代码中的 reshape 方法中执行此操作。

You have to setup the projection matrix each time the window resizes. I haven't used JOGL before but I think you should do it in that reshape method in the code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文