【问题标题】:LWJGL Tilerenderer only renders one type of tile/one textureLWJGL Tilerenderer 只渲染一种瓷砖/一种纹理
【发布时间】:2019-04-11 19:43:51
【问题描述】:

我正在按照我发现的this 教程学习 LWJGL 和 OpenGL,我尽我所能更改代码以与从未有过的版本兼容,并且到目前为止还没有问题。但是现在我的Tilerenderer 不会为 VBO 渲染超过一种类型的瓷砖/一种纹理,我尝试从 3 天开始修复它(一开始它根本没有渲染任何东西)但找不到任何解决了这个问题。

我正在使用 Java 9.0.4 和 LWJGL 3.2.1 build 12 以及 JOML 1.9.13、GLFW、OpenGL 和 stb。

到目前为止,我尝试更改涉及此问题的整个代码并更改着色器的不同变量,但到目前为止似乎没有任何效果。

这是我认为可能与问题有关的所有类。

主类

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

import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.opengl.GL;

public class Main {



    public static void main(String[] args) {

        int speed = 5;

        Window.setCallbacks();

        if (!glfwInit()) {

            throw new IllegalStateException("Failed to init GLFW");

        }

        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);

        Window window = new Window();
        window.setSize(640, 480);
        window.setFullscreen(false);
        window.createWindow("GAME");

        GL.createCapabilities();

        Camera camera = new Camera(window.getWidth(), window.getHeight());

        glEnable(GL_TEXTURE_2D);

        TileRenderer tiles = new TileRenderer();

        Shader shader = new Shader("shader");

        World world = new World();

        world.setTile(Tile.test_tile, 0, 0);

        double frameCap = 1.0 / 60.0;
        double frameTime     = 0;
        double time = Timer.getTime();
        double unprocessed = 0;

        int frames = 0;

        while(!window.shouldClose()) {

            boolean canRender = false;

            double time2 = Timer.getTime();
            double passed = time2 - time;
            unprocessed+=passed;

            frameTime += passed;

            time = time2;

            while (unprocessed >= frameCap) {

                canRender = true;

                unprocessed-=frameCap;

                if(window.getInput().isMouseButtonDown(0)) {

                    glfwSetWindowShouldClose(window.getWindow(), true);

                }   

                if (window.getInput().isKeyPressed(GLFW_KEY_ESCAPE)) {

                    glfwSetWindowShouldClose(window.getWindow(), true);

                }

                if(window.getInput().isKeyDown(GLFW_KEY_W)) {

                    camera.addPosition(new Vector3f(0, -speed, 0));

                }

                if(window.getInput().isKeyDown(GLFW_KEY_A)) {

                    camera.addPosition(new Vector3f(speed, 0, 0));

                }

                if(window.getInput().isKeyDown(GLFW_KEY_S)) {

                    camera.addPosition(new Vector3f(0, speed, 0));

                }

                if(window.getInput().isKeyDown(GLFW_KEY_D)) {

                    camera.addPosition(new Vector3f(-speed, 0, 0));

                }

                if(window.getInput().isKeyDown(GLFW_KEY_O)) {

                    speed = 5;

                }

                if(window.getInput().isKeyDown(GLFW_KEY_P)) {

                    speed = 25;

                }

                window.update();

                if (frameTime >= 1.0) {

                    frameTime = 0;
                    System.out.println("FPS:" + frames);
                    frames = 0;

                }
            }

            if (canRender) {

                glClear(GL_COLOR_BUFFER_BIT);

                world.render(tiles, shader, camera);

                window.swapBuffers();

                frames++;

            }
        }

        glfwTerminate();

    }
}

世界级

import org.joml.Matrix4f;
import org.joml.Vector3f;

public class World {

    private byte[] tiles;

    private int width;
    private int height;

    private Matrix4f world;

    public World () {

        width = 16;
        height = 16;

        tiles = new byte [width * height];

        world = new Matrix4f().setTranslation(new Vector3f(0));
        world.scale(32);
    }

    public void render(TileRenderer renderer, Shader shader, Camera camera) {

        for (int x = 0; x < height; x++) {

            for (int y = 0; y < width; y++) {

                renderer.renderTile(tiles[x + y * width], y, -x, shader, world, camera);

            }

        }

    }

    public void setTile (Tile tile, int x, int y) {

        System.err.println(tile.getId());
        tiles[x + y * width] = tile.getId();


    }

}

Tilerenderer 类

import java.util.HashMap;

import org.joml.Matrix4f;
import org.joml.Vector3f;

public class TileRenderer {

        private HashMap<String, Texture> tileTextures;

        private Model tileModel;

        public TileRenderer() {
            tileTextures = new HashMap<>();
            float[] vertices = new float[]{
                -1f, 1f, 0, // TOP LEFT 0
                1f, 1f, 0,  // TOP RIGHT 1
                1f, -1f, 0, // BOTTOM RIGHT 2
                -1f, -1f, 0,// BOTTOM LEFT 3
            };

            float[] texture = new float[]{0, 0, 1, 0, 1, 1, 0, 1,};

            int[] indices = new int[]{0, 1, 2, 2, 3, 0};

            tileModel = new Model(vertices, texture, indices);

            for (int i = 0; i < Tile.tiles.length; i++) {
                if (Tile.tiles[i] != null) {
                    if (!tileTextures.containsKey(Tile.tiles[i].getTexture())) {
                        String tex = Tile.tiles[i].getTexture();
                        tileTextures.put(tex, new Texture(tex + ".png"));
                    }
                }
            }
        }

        public void renderTile (byte id, int x, int y, Shader shader, Matrix4f world, Camera camera) { 

            shader.bind();

            if (tileTextures.containsKey(Tile.tiles[id].getTexture())) {

                tileTextures.get(Tile.tiles[id].getTexture()).bind(0);

            }

            Matrix4f tilePos = new Matrix4f().translate(new Vector3f(x*2, y*2, 0));
            Matrix4f target = new Matrix4f();

            camera.getProjection().mul(world, target);
            target.mul(tilePos);

            shader.setUniform("sampler", 0);
            shader.setUniform("projection", target);

            tileModel.render();

        }   
}

平铺类

public class Tile {

    public static Tile tiles[] = new Tile[16];

    public static final Tile testTile = new Tile((byte)0, "Test");
    public static final Tile testTile2 = new Tile((byte)1, "Test2");

    private byte id;
    private String texture;

    public Tile(byte id, String texture) {

        this.id = id;
        this.texture = texture;

        if (tiles[id] != null) {

            throw new IllegalStateException("Tiles at: [" + id + "] is already being used!");

        }

        tiles[id] = this;

    }

    public byte getId () {return id;}
    public String getTexture () {return texture;}

}

模型类

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

import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import org.lwjgl.BufferUtils;

public class Model {

    private int draw_count;
    private int v_id;
    private int t_id;
    private int i_id;

    public Model (float[] vertices, float[] tex_coords, int[] indices) {

        draw_count = indices.length;

        IntBuffer buffer = BufferUtils.createIntBuffer(indices.length);
        buffer.put(indices);
        buffer.flip();

        v_id = glGenBuffers();

        glBindBuffer(GL_ARRAY_BUFFER, v_id);
        glBufferData(GL_ARRAY_BUFFER, createBuffer(vertices), GL_STATIC_DRAW);

        t_id = glGenBuffers();

        glBindBuffer(GL_ARRAY_BUFFER, t_id);
        glBufferData(GL_ARRAY_BUFFER, createBuffer(tex_coords), GL_STATIC_DRAW);

        i_id = glGenBuffers();

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_id);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    }

    public void render() {

        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);

        glBindBuffer(GL_ARRAY_BUFFER, v_id);
        glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);

        glBindBuffer(GL_ARRAY_BUFFER, t_id);
        glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_id);
        glDrawElements(GL_TRIANGLES, draw_count, GL_UNSIGNED_INT, 0);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);

    }

    private FloatBuffer createBuffer(float[] data) {

        FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
        buffer.put(data);
        buffer.flip();
        return buffer;

    }
}

纹理类

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import static org.lwjgl.stb.STBImage.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.*;

import org.lwjgl.BufferUtils;

public class Texture {

    private int id;
    private int width;
    private int heigth;

    public Texture (String filename) {

        IntBuffer width = BufferUtils.createIntBuffer(1);
        IntBuffer heigth = BufferUtils.createIntBuffer(1);
        IntBuffer comp = BufferUtils.createIntBuffer(1);

        ByteBuffer data = stbi_load("./res/" + filename, width, heigth, comp, 4);

        this.width = width.get();
        this.heigth = heigth.get();

        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this.width, this.heigth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);   

        stbi_image_free(data);

    }

    public void bind (int sampler) {

        if (sampler >= 0 && sampler <= 31) {

            glActiveTexture(GL_TEXTURE0 + sampler);
            glBindTexture(GL_TEXTURE_2D, sampler);

        }
    }
}

着色器类

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

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.FloatBuffer;

import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;

public class Shader {

    private int program;
    private int vs;
    private int fs;

    public Shader (String filename) {

        program = glCreateProgram();

        vs = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vs, readFile(filename + ".vs"));
        glCompileShader(vs);
        if (glGetShaderi(vs, GL_COMPILE_STATUS) != 1) {

            System.err.println(glGetShaderInfoLog(vs));
            System.exit(1);

        }

        fs = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fs, readFile(filename + ".fs"));
        glCompileShader(fs);
        if (glGetShaderi(fs, GL_COMPILE_STATUS) != 1) {

            System.err.println(glGetShaderInfoLog(fs));
            System.exit(1);

        }

        glAttachShader(program, vs);
        glAttachShader(program, fs);

        glBindAttribLocation(program, 0, "vertices");
        glBindAttribLocation(program, 1, "textures");

        glLinkProgram(program);
        if (glGetProgrami(program, GL_LINK_STATUS) != 1) {

            System.err.println(glGetProgramInfoLog(program));
            System.exit(1);

        }

        glValidateProgram(program);
        if (glGetProgrami(program, GL_VALIDATE_STATUS) != 1) {

            System.err.println(glGetProgramInfoLog(program));
            System.exit(1);

        }
    }

    public void bind () {

        glUseProgram(program);

    }

    private String readFile (String filename) {

        StringBuilder string = new StringBuilder();

        BufferedReader br;

        try {

            br = new BufferedReader(new FileReader(new File("./shaders/" + filename)));
            String line;

            while((line = br.readLine()) != null) {

                string.append(line);
                string.append("\n");

            }

        } catch (IOException e ) {e.printStackTrace();}

        return string.toString();

    }

    public void setUniform (String name, int value) {

        int location = glGetUniformLocation(program, name);

        if (location != -1) {

            glUniform1i(location, value);

        }
    }

    public void setUniform (String name, Matrix4f value) {

        int location = glGetUniformLocation(program, name);

        FloatBuffer buffer = BufferUtils.createFloatBuffer(16); 

        value.get(buffer);

        if (location != -1) {

            glUniformMatrix4fv(location, false, buffer);

        }
    }
}

片段着色器

#version 120

uniform sampler2D sampler;

varying vec2 tex_coords;

void main () {
    gl_FragColor = texture2D(sampler, tex_coords);
}

顶点着色器

#version 120

attribute vec3 vertices;
attribute vec2 textures;

varying vec2 tex_coords;

uniform mat4 projection;

void main() {
    tex_coords = textures;
    gl_Position = projection*vec4(vertices, 1);
}

到目前为止,我正在创建所有具有相同纹理的 16x16 瓷砖,但它应该将瓷砖更改为 0、0(左上角)以具有不同的纹理

【问题讨论】:

    标签: java opengl glsl shader lwjgl


    【解决方案1】:

    关于纹理在 OpenGL 中的工作原理存在一个基本的误解。

    您必须通过glGenTextures 为每个纹理创建一个单独的纹理对象。 (另见Java Code Examples for org.lwjgl.opengl.GL11.glTexImage2D())。

    int textureObject = glGenTextures();
    

    这个纹理对象必须在加载纹理和渲染网格之前绑定。纹理绑定到由glActiveTexture设置的活动纹理单元。

    int textureUnitIndex = 0; // e.g
    glActiveTexture(GL_TEXTURE0 + textureUnitIndex);
    glBindTexture(GL_TEXTURE_2D, textureObject);
    

    纹理单元是着色器程序的绑定点。着色器程序中的纹理采样器必须与相同的绑定点相关联。这可以通过glUniform1i来完成:

    GLSL:

    uniform sampler2D sampler;
    

    Java:

    int location = glGetUniformLocation(program, "sampler");
    glUniform1i(location, textureUnitIndex);
    

    旁注:由于 GLSL 版本 4.2,这可以通过指定 binding points 在片段着色器中完成 - 请参阅 OpenGL Shading Language 4.20 Specification - 4.4.4 Opaque-Uniform Layout Qualifiers; page 60

    #version 420
    
    layout (binding = 0) uniform sampler2D sampler;
    

    在您的代码中永远不会生成纹理对象。因此默认纹理对象 0 用于所有纹理。这会导致您的代码不起作用。

    更改类Texture,以某种方式如下解决问题:

    public class Texture {
    
        private int textureObject;
        private int width;
        private int heigth;
    
        public Texture (String filename) {
    
            IntBuffer width = BufferUtils.createIntBuffer(1);
            IntBuffer heigth = BufferUtils.createIntBuffer(1);
            IntBuffer comp = BufferUtils.createIntBuffer(1);
    
            ByteBuffer data = stbi_load("./res/" + filename, width, heigth, comp, 4);
    
            this.width = width.get();
            this.heigth = heigth.get();
    
            textureObject = glGenTextures(); // generate texture name
            glBindTexture(GL_TEXTURE_2D, textureObject);
    
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this.width, this.heigth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);   
    
            stbi_image_free(data);
    
        }
    
        public void bind (int sampler) {
    
            if (sampler >= 0 && sampler <= 31) {
    
                glActiveTexture(GL_TEXTURE0 + sampler);
                glBindTexture(GL_TEXTURE_2D, textureObject); // bind texture object 
            }
        }
    }
    

    【讨论】:

    • 非常感谢!我想我实际上已经尝试过了,但那时我可能还有其他问题,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多