【问题标题】:OpenGL got black screen with glOrtho lwjglOpenGL 使用 glOrtho lwjgl 得到黑屏
【发布时间】:2014-03-27 14:06:18
【问题描述】:

所以,我制作了一个 2d 平台游戏。我得到了纹理、控件和一切都很好,直到我决定让游戏有一个滚动相机。我读过某处说使用 glOrtho 移动和缩放相机,但是当我调用 glOrtho 时,我的屏幕变黑了,我知道我做错了什么,但不知道该怎么做。

我在游戏循环之前得到了这个:

glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glOrtho(0, GAME_WIDTH, GAME_HEIGHT, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
*enabling texture_2d and others

我在游戏循环中得到了这个,让相机跟随玩家:

glClear(GL_COLOR_BUFFER_BIT);
xOff = player.x - GAME.WIDTH / 2;
yOff = player.y - GAME.HEIGHT / 2;
glOrtho(xOff, xOff + GAME_WIDTH, yOff + GAME_HEIGHT, yOff, 1, -1);

但是它给了我黑屏..虽然我在第一次调用 glOrtho 时更改值很好..我已经在谷歌上搜索了这个问题但找不到任何帮助?

编辑:这是主类

package com.org.Game;

import static org.lwjgl.opengl.GL11.*;

import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

import com.org.Game.Graphics.Draw;
import com.org.Game.Graphics.Sprite;
import com.org.Game.Graphics.Spritesheet;
import com.org.Game.Level.Level;
import com.org.Game.Level.Entity.Mob.Player;

public class Main {

    private static String title = "Platformer";
    private static int WINDOW_WIDTH = 800, WINDOW_HEIGHT = 600;
    private static int GAME_WIDTH = 320, GAME_HEIGHT = 240;

    private boolean exit = false;
    private long lastFPS;
    private int fps;
    private long lastFrame;
    private long delta;
    private boolean fpscap = true;

    private Level lvl;
    private Player player;
    private int xOff, yOff;

    public Main() {
        try {
            Display.setDisplayMode(new DisplayMode(WINDOW_WIDTH, WINDOW_HEIGHT));
            Display.setTitle(title);
            Display.setVSyncEnabled(true);
            DisplayMode[] modes = Display.getAvailableDisplayModes();
            for (int i = 0; i < modes.length; i++) {
                if (modes[i].getWidth() == WINDOW_WIDTH && modes[i].getHeight() == WINDOW_HEIGHT && modes[i].getFrequency() == 60 && modes[i].isFullscreenCapable()) {
                    Display.setDisplayMode(modes[i]);
                    System.out.println(modes[i].getWidth() + " " + modes[i].getHeight() + " " + modes[i].getBitsPerPixel() + " " + modes[i].getFrequency() + " " + modes[i].isFullscreenCapable());
                    break;
                }
            }
            // Display.setFullscreen(true);
            Display.create();
        } catch (LWJGLException e) {
            e.printStackTrace();
            Display.destroy();
            System.exit(0);
        }

        glLoadIdentity();
        glMatrixMode(GL_PROJECTION);
        glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
        glOrtho(0, GAME_WIDTH, GAME_HEIGHT, 0, 1, -1);
        glMatrixMode(GL_MODELVIEW);

        glEnable(GL_TEXTURE_2D);

        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);

        glEnable(GL_BLEND);
        glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_DST_COLOR);

        glPolygonMode(GL_FRONT, GL_FILL);

        lvl = new Level();
        lvl.loadLevel("level0.dat");
        if (lvl == null) System.out.println("NULL");
        player = new Player(16, 16, Sprite.cobalt, lvl);

        start();

        Spritesheet.tiles.tex.release();
        Spritesheet.bg_day.tex.release();
        Display.destroy();
        System.exit(0);
    }

    int a;

    private void render() {
        Draw.clearScreen();

        glLoadIdentity();
        glMatrixMode(GL_PROJECTION);
        glOrtho(xOff, xOff + GAME_WIDTH, yOff + GAME_HEIGHT, yOff, 1, -1);
        glMatrixMode(GL_MODELVIEW);

        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

        Draw.setTexture(Spritesheet.bg_day);
        Draw.drawBackground(GAME_WIDTH, GAME_HEIGHT, Spritesheet.bg_day);

        Draw.setTexture(Spritesheet.tiles);
        lvl.renderLevel(GAME_WIDTH, GAME_HEIGHT, xOff, yOff);

        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        player.render();
    }

    private void update(long delta) {
        player.update(delta);
        if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) exit = true;
        if (Keyboard.isKeyDown(Keyboard.KEY_Z)) fpscap = true;
        if (Keyboard.isKeyDown(Keyboard.KEY_X)) fpscap = false;
    }

    public void start() {
        lastFPS = getTime();
        getDelta();

        while (!Display.isCloseRequested() && !exit) {
            getDelta();

            xOff = (int) player.x - GAME_WIDTH / 2;
            yOff = (int) player.y - GAME_HEIGHT / 2;

            render();
            update(delta);

            updateFPS();
            Display.update();
            if (fpscap) Display.sync(120);
        }
    }

    private void getDelta() {
        long now = getTime();
        delta = now - lastFrame;
        lastFrame = now;
    }

    private void updateFPS() {
        fps++;
        if (getTime() - lastFPS > 1000) {
            lastFPS += 1000;
            Display.setTitle(title + " FPS: " + fps);
            fps = 0;
        }
    }

    private long getTime() {
        return Sys.getTime() * 1000 / Sys.getTimerResolution();
    }

    public static void main(String[] args) {
        new Main();
    }

}

【问题讨论】:

  • 所以你也在模型视图堆栈上放置一个正交投影矩阵?为什么?
  • 所以你是说我需要在第二个 glOrtho 之前切换到 gl_projection ?
  • @Greffin28:您的方法存在一些潜在问题,但如果没有进一步的代码,很难判断发生了什么。如果将该矩阵放在两个堆栈上,它们将被应用两次。这不会给您期望的结果,glOrtho 只会创建一个组合的缩放和平移矩阵。
  • @derhass 你想看代码吗?如果第二个 glOrtho 结合了之前的状态,我怎么能用 glOrtho 让相机跟随玩家?

标签: java opengl lwjgl


【解决方案1】:

据我所知,这里的问题是,在切换正交投影之前,您没有将矩阵模式更改为 GL_PROJECTION - 因为您的第二个代码 sn-p 没有矩阵模式状态更改。所以,试试这个:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
xOff = player.x - GAME.WIDTH / 2;
yOff = player.y - GAME.HEIGHT / 2;
glOrtho(xOff, xOff + GAME_WIDTH, yOff + GAME_HEIGHT, yOff, 1, -1);
glMatrixMode(GL_MODELVIEW);

请记住,这段代码 sn-p 将重置您的转换矩阵,因此任何 glTransform() 或 glRotate() 调用或 glScale() 调用当然会被取消,但因为这是在游戏循环的开始,并且运行每个滴答声我怀疑这不应该是一个问题。

【讨论】:

  • 好吧,你正在调用 glClear(GL_COLOR_BUFFER_BIT) 来清除屏幕。
  • 等等.. 什么.. 但是我在清除屏幕后调用了 glOrtho,它没有做任何改变吗?
  • 我想我有点困惑。您可以给我一个带有渲染循环的 pastebin,还是在您的问题中添加更多代码?
  • 主课就到这里
  • @SDLeffler:是的,glLoadIdentity 只影响最近调用 glMatrixMode 时选择的矩阵。
【解决方案2】:

您的代码有两个问题:您正在执行“OpenGL 初始化”。为什么? OpenGL 是一个状态机,它不会被初始化。您将 OpenGL 置于您需要的状态,就在您需要的时候。构造函数中的大部分 OpenGL 调用都是不必要的,并且没有任何效果。大多数 OpenGL 的东西应该只在渲染函数中完成。

对于渲染方法试试这个:

private void render() {
            // glViewport does not depend on the matrix state
    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

    Draw.clearScreen();

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(xOff, xOff + GAME_WIDTH, yOff + GAME_HEIGHT, yOff, 1, -1);

    glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();

    glEnable(GL_TEXTURE_2D);

    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

            // probably don't want to blend the background
            // actually get your blending stuff right, I removed it entirely
            // because it's completely unclear from your code what you want
            // to blend which way
    glDisable(GL_BLEND); 
    Draw.setTexture(Spritesheet.bg_day);
    Draw.drawBackground(GAME_WIDTH, GAME_HEIGHT, Spritesheet.bg_day);

    Draw.setTexture(Spritesheet.tiles);
    lvl.renderLevel(GAME_WIDTH, GAME_HEIGHT, xOff, yOff);

            // probably needs its texture set.
    player.render();
}

【讨论】:

  • 哦,是的,这也有效.. 但我可能更愿意调用一些永远不会再改变的东西.. 哦,是的,谢谢你提醒我在背景之前禁用混合 :)
  • @Greffin28:设置投影矩阵的成本是如此之小,以至于每次显示调用都设置它的好处远远超过它。同样,迟早您会遇到这样一种情况,即您需要在整个渲染帧的过程中多次更改投影参数,并且如果您的程序是围绕“仅设置一次投影”构建的,那么它最终会变得一团糟,试图跟踪什么以什么顺序改变什么。相信我,你想重置每一帧的投影渲染。
  • 不,我不是指投影矩阵,而是另一个喜欢启用 gl_texture_2d
  • @Greffin28:纹理启用状态比投影设置更不稳定。除了带有纹理的几何体之外,渲染没有纹理的几何体是司空见惯的。一般来说,OpenGL中“一次性状态设置”的整个想法是完全错误的。所有的 OpenGL 状态都应该在每次绘图迭代开始时从一个干净的状态开始设置。唯一的一次性初始化是针对不改变其内容的数据对象,例如纹理图像或静态绘制 VBO。
  • 哦,好吧,现在我对 opengl 有了更多了解:p
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多