Search code examples
javalwjglskybox

Skybox rendering black while loading textures with LWJGL and PNGDecoder


I'm loading a cube map skybox texture (3D coordinates rather than 2D) and the skybox turns out to be black. I don't receive any errors and the skybox is rendering in at the right locations and all, but something is still not right.

I have a custom class CubeMap which just takes in a String[] for the file names of the textures and loads them with the following code:

public class CubeMap {

    private int cubeMapID;

    public CubeMap (String[] textureFiles) {
        this.cubeMapID = GL11.glGenTextures();
        GL13.glActiveTexture(GL13.GL_TEXTURE0);
        GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, cubeMapID);

        for (int i = 0; i < textureFiles.length; i++) {
            Image data = Loader.decodeTextureFile("res/textures/" + textureFiles[i]);
            GL11.glTexImage2D(GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL11.GL_RGBA, data.getWidth(), data.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, data.getByteBuffer());
        }

        GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
        GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
    }

    public int getCubeMapID() {
        return cubeMapID;
    }

    public void destroy () {
        GL11.glDeleteTextures(cubeMapID);
    }
}

The decodeTextureFile() method in Loader:

public static Image decodeTextureFile (String fileName) {

    int width = 0, height = 0;
    ByteBuffer buffer = null;

    try {

        FileInputStream in = new FileInputStream(fileName);
        PNGDecoder decoder = new PNGDecoder(in);

        width = decoder.getWidth();
        height = decoder.getHeight();
        buffer = ByteBuffer.allocateDirect(4 * width * height);

        decoder.decode(buffer, width * 4, Format.RGBA);

        buffer.flip();
        in.close();

    } catch (IOException e) {
        System.out.println("Error : Decoding in loader failed; IO - Error");
        System.exit(-1);
    }

    return new Image (width, height, buffer);
}

Additionally, I have a SkyBox class which creates a CubeMap and stores the vertices of a preset array into a vertexArray and a vertexBuffer (this part of the code works fine so I don't see the need to add the Model code)

public class SkyBox extends Model {

    private static final float SIZE = 500f;

    private static final float[] VERTICES = {
            -SIZE,  SIZE, -SIZE,
            -SIZE, -SIZE, -SIZE,
            SIZE, -SIZE, -SIZE,
             SIZE, -SIZE, -SIZE,
             SIZE,  SIZE, -SIZE,
            -SIZE,  SIZE, -SIZE,

            -SIZE, -SIZE,  SIZE,
            -SIZE, -SIZE, -SIZE,
            -SIZE,  SIZE, -SIZE,
            -SIZE,  SIZE, -SIZE,
            -SIZE,  SIZE,  SIZE,
            -SIZE, -SIZE,  SIZE,

             SIZE, -SIZE, -SIZE,
             SIZE, -SIZE,  SIZE,
             SIZE,  SIZE,  SIZE,
             SIZE,  SIZE,  SIZE,
             SIZE,  SIZE, -SIZE,
             SIZE, -SIZE, -SIZE,

            -SIZE, -SIZE,  SIZE,
            -SIZE,  SIZE,  SIZE,
             SIZE,  SIZE,  SIZE,
             SIZE,  SIZE,  SIZE,
             SIZE, -SIZE,  SIZE,
            -SIZE, -SIZE,  SIZE,

            -SIZE,  SIZE, -SIZE,
             SIZE,  SIZE, -SIZE,
             SIZE,  SIZE,  SIZE,
             SIZE,  SIZE,  SIZE,
            -SIZE,  SIZE,  SIZE,
            -SIZE,  SIZE, -SIZE,

            -SIZE, -SIZE, -SIZE,
            -SIZE, -SIZE,  SIZE,
             SIZE, -SIZE, -SIZE,
             SIZE, -SIZE, -SIZE,
            -SIZE, -SIZE,  SIZE,
             SIZE, -SIZE,  SIZE
    };

    private CubeMap cubeMap;
    private int vertexArrayID;
    private int vertexCount;

    public SkyBox (String[] textures) {
        cubeMap = new CubeMap(textures);
        vertexArrayID = super.createVertexArray();
        super.storeData(0, 3, VERTICES);

        vertexCount = VERTICES.length / 3;

        GL30.glBindVertexArray(0);
    }

    public CubeMap getCubeMap() {
        return cubeMap;
    }

    public int getVertexArrayID() {
        return vertexArrayID;
    }

    public int getVertexCount() {
        return vertexCount;
    }

    public void destroy () {
        cubeMap.destroy();
    }
}

I have a SkyboxShader class of which I'm fairly certain that it functions properly. The actual rendering of the SkyBox happens in the SkyboxRenderer class:

public class SkyboxRenderer {

    private SkyboxShader shader;

    public SkyboxRenderer (SkyboxShader shader) {
        this.shader = shader;
    }

    public void render (SkyBox skyBox) {
        shader.bind();
        shader.useMatrices();
        GL30.glBindVertexArray(skyBox.getVertexArrayID());
        GL20.glEnableVertexAttribArray(0);

        GL13.glActiveTexture(GL13.GL_TEXTURE0);
        GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, skyBox.getCubeMap().getCubeMapID());

        GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, skyBox.getVertexCount());

        GL20.glDisableVertexAttribArray(0);
        GL30.glBindVertexArray(0);
        shader.unbind();
    }
}

If anyone knows how to fix this problem it would be greatly appreciated. Any additional code will be posted if requested. Thanks in advance!


Edits

Edit: The Image class is custom and just stores a ByteBuffer and width and height ints. Getters are provided but no additional functionality.

Edit: I've even tried refactoring all of my code to no prevail.

Edit: I think the error lies in the cube map, not the textures or other code, as I can get it to kind-of work when I just use 6 different quads to render the box.

Edit: I solved the problem. I forgot to call the method .create() on type shader in the renderer.


Solution

  • CLOSED: I forgot to add the method call shader.create(); in the SkyboxRenderer.init() function so no shader programs were linked.