Search code examples
opengllibgdxtextures

Can't turn light off in libgdx


Use the code below, if I turn the light off, the blue box will be black. enter image description here

But there seems no effect on the entity, it is still colorful. What's wrong with the code? Please help thanks. enter image description here

package com.louxiu.game;

/**
 * Created by louxiu on 2/22/16.
 */

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g3d.*;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute;
import com.badlogic.gdx.graphics.g3d.loader.ObjLoader;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.math.Vector3;

public class TestApp implements ApplicationListener {
    private PerspectiveCamera camera;
    private ModelBatch modelBatch;
    private Model box;
    private ModelInstance boxInstance;
    public Model entityModel;
    public ModelInstance entityInstance;
    private Environment environment;

    @Override
    public void create() {
        // Create camera sized to screens width/height with Field of View of 75 degrees
        camera = new PerspectiveCamera(
                75,
                Gdx.graphics.getWidth(),
                Gdx.graphics.getHeight());

        // Move the camera 3 units back along the z-axis and look at the origin
        camera.position.set(0f, 0f, 3f);
        camera.lookAt(0f, 0f, 0f);

        // Near and Far (plane) repesent the minimum and maximum ranges of the camera in, um, units
        camera.near = 0.1f;
        camera.far = 300.0f;

        // A ModelBatch is like a SpriteBatch, just for models.  Use it to batch up geometry for OpenGL
        modelBatch = new ModelBatch();

        // A ModelBuilder can be used to build meshes by hand
        ModelBuilder modelBuilder = new ModelBuilder();

        // It also has the handy ability to make certain premade shapes, like a Cube
        // We pass in a ColorAttribute, making our cubes diffuse ( aka, color ) red.
        // And let openGL know we are interested in the Position and Normal channels
        box = modelBuilder.createBox(2f, 2f, 2f,
                new Material(ColorAttribute.createDiffuse(Color.BLUE)),
                Usage.Position | Usage.Normal
        );

        // A entityModel holds all of the information about an, um, entityModel, such as vertex data and texture info
        // However, you need an entityInstance to actually render it.  The entityInstance contains all the
        // positioning information ( and more ).  Remember Model==heavy ModelInstance==Light
        boxInstance = new ModelInstance(box, 0, 0, 0);

        String entity = "creeper/creeper";
        ObjLoader loader = new ObjLoader();
        entityModel = loader.loadModel(Gdx.files.internal(entity + ".obj"), new ObjLoader.ObjLoaderParameters(true));
        entityInstance = new ModelInstance(entityModel, 0, 0, 0);
        Texture texture = new Texture(Gdx.files.internal(entity + ".png"));
        entityInstance.materials.get(0).set(TextureAttribute.createDiffuse(texture));

        // Finally we want some light, or we wont see our color.  The environment gets passed in during
        // the rendering process.  Create one, then create an Ambient ( non-positioned, non-directional ) light.
        environment = new Environment();
        // environment.add(new DirectionalLight().set(1f, 1f, 1f, -1f, -0.8f, -0.2f));
        // environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.8f, 0.8f, 0.8f, 1.0f));
    }

    @Override
    public void dispose() {
        modelBatch.dispose();
        box.dispose();
    }

    @Override
    public void render() {
        // You've seen all this before, just be sure to clear the GL_DEPTH_BUFFER_BIT when working in 3D
        Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT | GL30.GL_DEPTH_BUFFER_BIT);

        // For some flavor, lets spin our camera around the Y axis by 1 degree each time render is called
        camera.rotateAround(Vector3.Zero, new Vector3(0, 1, 0), 1f);
        // When you change the camera details, you need to call update();
        // Also note, you need to call update() at least once.
        camera.update();

        // Like spriteBatch, just with models!  pass in the box Instance and the environment
        modelBatch.begin(camera);
        modelBatch.render(boxInstance, environment);
        // modelBatch.render(entityInstance, environment);
        modelBatch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }

Solution

  • You wavefront model probably does not have normals, which is required for lighting to work.

    Check the log, there should be an error message showing you that you should not use ObjLoader altogether. Instead use G3dModelLoader or even better: use AssetManager and the g3dj or g3db file format.

    Export your model from your modeling application into e.g. the FBX file format and convert it using fbx-conv. Do not convert your .obj file into a .g3dx file using fbx-conv, that won't work.

    Btw, although not related you might want to take into consideration that:

    your camera far/near ratio is very high, you usually should never use a near value below 1.

    Unlike what your comment says, ModelBatch is not used to batch geometry and not that comparable to SpriteBatch.

    ObjLoader has a loadModel method which accepts a boolean, so you don't have to create ObjLoaderParameters for that (although, as said, you shouldnt be using ObjLoader altogether).

    You are creating a Texture without properly disposing it when no longer needed. This will cause a potential resource leak.

    Creating a new Vector3 every frame is going to pressure the GC and will cause hick-ups. Simply use Vector3.Y instead of new Vector3(0, 1, 0) to fix that.