java - 将 GL_TEXTURE_RECTANGLE_ARB 用于带有 LWJGL 的 spritesheet 时出现闪烁

标签 java opengl lwjgl flicker sprite-sheet

当我尝试使用 LWJGL 开发游戏时,遇到了一些奇怪的闪烁问题。我正在尝试按照本教程中的建议使用 GL_TEXTURE_RECTANGLE_ARB:http://youtu.be/Xj_qZ3Cw08Q .

这是该问题的简短视频:http://youtu.be/WUr_8aqoOrk .

在我看来,当相机移动时(通过 glTransformf()),为每个图 block 绘制的 Sprite 偶尔会显示一些相邻的纹理,就像这里导致问题的原因一样:LWJGL random lines inbenween shapes 。不过,我已经将 MIN_FILTER 和 MAG_FILTER 设置为 GL_NEAREST,所以这似乎不是问题。

我已经尽可能简化了游戏来演示问题,而没有太多无关的细节。您可以在此处获取 .zip:https://dl.dropbox.com/u/22396951/Copy%20of%20Fezless.zip .

编辑:这是快速浏览的代码。

Fezless.java

package com.mrmikeanderson.fezless;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

import de.matthiasmann.twl.utils.PNGDecoder;
import static org.lwjgl.opengl.ARBTextureRectangle.*;
import static org.lwjgl.opengl.GL11.*;

public class Fezless {

    int w, h;
    boolean running;
    final int FPS = 60;
    double t = 0.0;
    final double dt = 1.0 / 60.0;
    Sprite currentSprite;
    Player player;
    Map<String, Sprite> spriteMap;
    int tiles;
    float camX, camY, shakeX, shakeY;

    String[] tileGrid = { "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "grass", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "dirt", "air", "air", "tardis", "air", "air", "air", "air", "air", "air", "air", "air", "air", "grass", "grass", "grass", "grass", "grass", "grass", "grass", "grass", "air", "air", "air", "air", "dirt", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "air", "air", "air", "air", "deadplant", "dirt", "air", "air", "air", "air",
            "air", "air", "plant", "air", "air", "air", "air", "air", "air", "air", "air", "stone", "dirt", "dirt", "stone", "air", "air", "air", "deadplant", "dirt", "dirt", "grass", "grass", "grass", "grass", "grass", "grass", "grass", "grass", "grass", "air", "air", "air", "air", "air", "air", "air", "stone", "air", "air", "air", "air", "air", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "grass", "grass", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "dirt", "dirt", "dirt", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "dirt", "dirt", "dirt", "dirt", "grass", "grass", "grass", "air", "air", "air", "air", "air", "air", "deadplant", "dirt", "dirt", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "dirt", "dirt", "dirt", "dirt", "dirt", "grass", "air", "air", "air", "air", "air", "dirt", "dirt", "dirt", "stone", "stone", "stone", "stone",
            "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "dirt", "dirt", "dirt", "dirt", "dirt", "grass", "plant", "air", "air", "air", "dirt", "dirt", "dirt", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "grass", "grass", "grass", "air", "air", "air", "dirt", "dirt", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "grass", "air", "air", "dirt", "dirt", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "dirt", "air", "air", "dirt", "dirt", "dirt", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "dirt", "dirt",
            "dirt", "dirt", "air", "air", "air", "air", "dirt", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "dirt", "dirt", "dirt", "air", "air", "air", "air", "air", "air", "stone", "stone", "stone", "stone", "dirt", "dirt", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "dirt", "dirt", "air", "air", "air", "air", "air", "air", "air", "air", "air", "dirt", "dirt", "dirt", "dirt", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "dirt", "dirt", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "stone", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "dirt", "stone", "stone", "stone", "dirt", "stone",
            "stone", "stone", "stone", "stone", "stone", "stone", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "air", "dirt", "dirt", "dirt", "dirt", "stone", "stone", "stone", "stone", "stone", "stone" };

    public Fezless(int w, int h) {
        this.w = w;
        this.h = h;
    }

    public void start() {
        init();
        running = true;
        run();
    }

    void init() {
        initDisplay();
        initGL();
        initSprites();
        player = new Player(13f, 4f, this);
//      level = new Level(player, this);
        camX = 14f;
        camY = -6f;
        shakeX = shakeY = 0f;
    }

    void initDisplay() {
        try {
            Display.setDisplayMode(new DisplayMode(w, h));
            Display.create();
        } catch (LWJGLException e) {
            e.printStackTrace();
        }
    }

    void initGL() {
        glMatrixMode(GL_PROJECTION);
        double w = Display.getWidth() / 8;
        double h = Display.getHeight() / 8;
        glOrtho(-w / 2, w / 2, h / 2, -h / 2, -1f, 1f);
        glClearColor(.4f, .769f, 1f, 1f);
        glEnable(GL_TEXTURE_RECTANGLE_ARB);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glMatrixMode(GL_MODELVIEW);
    }

    void initSprites() {
        spriteMap = new HashMap<String, Sprite>();
        int texture = glGenTextures();
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
        InputStream in = null;
        try {
            in = new FileInputStream("res/tiles.png");
            PNGDecoder decoder = new PNGDecoder(in);
            ByteBuffer buffer = BufferUtils.createByteBuffer(4 * decoder.getWidth() * decoder.getHeight());
            decoder.decode(buffer, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);
            buffer.flip();
            in.close();
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
        tiles = loadSpritesheet();
        spriteMap.put("air", new Sprite("air", 0, 0, 8, 8));
        spriteMap.put("gonzo", new Sprite("gonzo", 0, 8, 8, 16));
        spriteMap.put("grass", new Sprite("grass", 8, 0, 8, 8));
        spriteMap.put("plant", new Sprite("plant", 16, 8, 8, 8));
        spriteMap.put("deadplant", new Sprite("deadplant", 16, 16, 8, 8));
        spriteMap.put("dirt", new Sprite("dirt", 8, 8, 8, 8));
        spriteMap.put("stone", new Sprite("stone", 8, 16, 8, 8));
        spriteMap.put("platform", new Sprite("platform", 24, 0, 8, 8));
        spriteMap.put("obsidian", new Sprite("obsidian", 16, 0, 8, 8));
        spriteMap.put("tardis", new Sprite("tardis", 32, 0, 16, 24));
    }

    void run() {
        while (running && !Display.isCloseRequested()) {
            shakeX = (float) Math.sin(t + 100);
            shakeY = (float) Math.cos(t);

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glLoadIdentity();
            glTranslatef(-camX * 8 + shakeX, camY * 8 + shakeY, 0f);

            for (int x = 0; x < 25; x++) {
                for (int y = 0; y < 21; y++) {
                    drawSprite(tileGrid[x + y * 25], x, y);
                }
            }
            player.render();

            t += dt;
            Display.update();
            Display.sync(FPS);
            Display.setVSyncEnabled(true);
        }
        cleanUp(false);
    }

    public void drawSprite(String name, float x, float y) {
        x *= 8;
        y *= 8;
        currentSprite = spriteMap.get(name);
        int u = currentSprite.x;
        int v = currentSprite.y;
        int u2 = currentSprite.x2;
        int v2 = currentSprite.y2;
        int w = currentSprite.w;
        int h = currentSprite.h;
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tiles);
        glBegin(GL_QUADS);
        glTexCoord2f(u, v);
        glVertex2f(x, y);
        glTexCoord2f(u, v2);
        glVertex2f(x, y + h);
        glTexCoord2f(u2, v2);
        glVertex2f(x + w, y + h);
        glTexCoord2f(u2, v);
        glVertex2f(x + w, y);
        glEnd();
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
    }

    int loadSpritesheet() {
        int texture = glGenTextures();
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
        InputStream in = null;
        try {
            in = new FileInputStream("res/tiles.png");
            PNGDecoder decoder = new PNGDecoder(in);
            ByteBuffer buffer = BufferUtils.createByteBuffer(4 * decoder.getWidth() * decoder.getHeight());
            decoder.decode(buffer, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);
            buffer.flip();
            in.close();
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
        return texture;
    }

    void cleanUp(boolean error) {
        Display.destroy();
        System.exit(error ? 1 : 0);
    }

    public static void main(String[] args) {
        Fezless f = new Fezless(800, 600);
        f.start();
    }
}

Player.java

package com.mrmikeanderson.fezless;

import java.awt.Rectangle;

public class Player {

    Fezless f;
    float x, y;
    boolean falling = false;
    String sprite;
    Rectangle boundingBox;

    public Player(float x, float y, Fezless f) {
        this.x = x;
        this.y = y;
        this.f = f;
        sprite = "gonzo";
    }

    public void render() {
        f.drawSprite(sprite, x, y);
    }
}

Sprite.java

package com.mrmikeanderson.fezless;

public class Sprite {

    String name;
    int x, y, x2, y2, w, h;

    public Sprite(String name, int x, int y, int w, int h) {
        this.name = name;
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        x2 = x + w;
        y2 = y + h;
    }
}

最佳答案

这可能是 Z-Buffer 战斗。

您是否尝试过使用 glDisable(GL_DEPTH_TEST); 禁用 Z 测试?或者将背景清除到更远的距离(Reference 关于glClearDepth)?如果您选择使用 Z 缓冲区测试,您还应该将玩家人物移近相机。

关于java - 将 GL_TEXTURE_RECTANGLE_ARB 用于带有 LWJGL 的 spritesheet 时出现闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12455512/

相关文章:

java - 未找到 HTTP 请求与 URI 的映射

java - LWJGL 纹理加载/映射问题

java - 外部 jar 中的资源加载不起作用

java - 如何使用 VBO 使用 OpenGL(特别是 LWJGL)绘制圆

java - 如何在JSP或JAVA中分割字符串?

java - 浏览器未向 weblogic 服务器发送正确的 jsessionId?

java - 是否可以在没有 If 的情况下检查接收到的字段是否为空或 Null

c - OpenGL 的未知类型工件

c++ - 为什么我的 openGL 顶点缓冲对象不绘制任何东西?

c++ - 具有缩放拉伸(stretch)纵横比的 glm 旋转