Search code examples
javaopengllibgdxperspectivecameraspritebatch

libgdx: SpriteBatch not displayed with PerspectiveCamera


While I do have the basic knowledge of OpenGL I'm just starting with libgdx.

My question is: why, having the exact same code but only switching from OrthographicCamera to PerspectiveCamera has the effect of no longer displaying any of my SpriteBatches ?

Here's the code I use:

the create() method:

public void create() {
    textureMesh = new Texture(Gdx.files.internal("data/texMeshTest.png"));
    textureSpriteBatch = new Texture(Gdx.files.internal("data/texSpriteBatchTest.png"));

    squareMesh = new Mesh(true, 4, 4, 
            new VertexAttribute(Usage.Position, 3, "a_position")
            ,new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoords")

    );

    squareMesh.setVertices(new float[] {
            squareXInitial, squareYInitial, squareZInitial,             0,1,    //lower left
            squareXInitial+squareSize, squareYInitial, squareZInitial,  1,1,    //lower right
            squareXInitial, squareYInitial+squareSize, squareZInitial,  0,0,    //upper left
            squareXInitial+squareSize, squareYInitial+squareSize, squareZInitial,1,0});  //upper right 

    squareMesh.setIndices(new short[] { 0, 1, 2, 3});

    spriteBatch = new SpriteBatch();        
}

and the render() method:

public void render() {
    GLCommon gl = Gdx.gl;

    camera.update();
    camera.apply(Gdx.gl10);
    spriteBatch.setProjectionMatrix(camera.combined);

    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    gl.glEnable(GL10.GL_DEPTH_TEST);

    gl.glEnable(GL10.GL_TEXTURE_2D);
    textureMesh.bind();
    squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0, 4);

    spriteBatch.begin();
    spriteBatch.draw(textureSpriteBatch, -10, 0);
    spriteBatch.end();        
}

Now, if in my resize(int width, int height) method I setup the camera like so:

   public void resize(int width, int height) {
        float aspectRatio = (float) width / (float) height;
        camera = new OrthographicCamera(cameraViewHeight * aspectRatio, cameraViewHeight);

I get this:

enter image description here

But if I change the camera type:

public void resize(int width, int height) {
    float aspectRatio = (float) width / (float) height;
    camera = new PerspectiveCamera(64, cameraViewHeight * aspectRatio, cameraViewHeight);
}       

I get this:

enter image description here

The reason I'm asking is because I really liked libgdx's built in ability to draw text (font) in OpenGL. But in their examples they use a SpriteBatch which they path to the Font instance, and they also always use Ortho Camera. I'd like to know then if SpriteBatch and Font drawing functionality work with PerspectiveCamera.


Solution

  • Well, ok, I solved it:

    Short answer:

    SpriteBatch uses an OrthogonalPerspective internally. If you use PerspectiveCamera you need to pass a custom view matrix to the SpriteBatch. You can do that in the resize(...) method:

    @Override
    public void resize(int width, int height) {
        float aspectRatio = (float) width / (float) height;
        camera = new PerspectiveCamera(64, cameraViewHeight * aspectRatio, cameraViewHeight);
        viewMatrix = new Matrix4();
        viewMatrix.setToOrtho2D(0, 0,width, height);
        spriteBatch.setProjectionMatrix(viewMatrix);
    }
    

    And then there's no need to do anything else with that sprite's projection matrix (unless you want to change how the sprite is displayed on screen):

    public void render() {
        GLCommon gl = Gdx.gl;
    
        camera.update();
        camera.apply(Gdx.gl10);
        //this is no longer needed:
        //spriteBatch.setProjectionMatrix(camera.combined);
        //...
    

    Long answer: since my final goal was to be able to use a SpriteBatch to draw text, while with the above mentioned modification to my code I can do that, in the sense that both the text on the sprite and the mesh with the texture are now visible, I've noticed that if I don't specify a color for the vertices of my mesh, said vertices will get the color I use for the text. In other words, with a textured mesh declared like so:

     squareMesh = new Mesh(true, 4, 4, 
                new VertexAttribute(Usage.Position, 3, "a_position")
                ,new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoords")
    
        );
    
        squareMesh.setVertices(new float[] {
                squareXInitial, squareYInitial, squareZInitial,             0,1,    //lower left
                squareXInitial+squareSize, squareYInitial, squareZInitial,  1,1,    //lower right
                squareXInitial, squareYInitial+squareSize, squareZInitial,  0,0,    //upper left
                squareXInitial+squareSize, squareYInitial+squareSize, squareZInitial,1,0});  //upper right 
    
        squareMesh.setIndices(new short[] { 0, 1, 2, 3});
    

    also having this code in my render(...) method will make the mesh red-tinted:

    font.setColor(Color.RED);
    spriteBatch.draw(textureSpriteBatch, 0, 0);
    font.draw(spriteBatch, (int)fps+" fps", 0, 100);
    

    The fix to this is to set colors on your mesh's vertices right from the start:

    squareMesh = new Mesh(true, 4, 4, 
            new VertexAttribute(Usage.Position, 3, "a_position")
            ,new VertexAttribute(Usage.ColorPacked, 4, "a_color")
            ,new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoords")
    
    );
    
    squareMesh.setVertices(new float[] {
            squareXInitial, squareYInitial, squareZInitial,                         Color.toFloatBits(255, 255, 255, 255),  0,1,    //lower left
            squareXInitial+squareSize, squareYInitial, squareZInitial,              Color.toFloatBits(255, 255, 255, 255),  1,1,    //lower right
            squareXInitial, squareYInitial+squareSize, squareZInitial,              Color.toFloatBits(255, 255, 255, 255),  0,0,    //upper left
            squareXInitial+squareSize, squareYInitial+squareSize, squareZInitial,   Color.toFloatBits(255, 255, 255, 255),  1,0});  //upper right 
    
    squareMesh.setIndices(new short[] { 0, 1, 2, 3});