How to render 3D object within a Libgdx Actor?

2019-09-14 00:11发布

Most of the Libgdx tutorials I found show how to add 2D elements in a 3D world, but I would like to know how to the the opposite, adding 3D elements in a 2D Stage.

I tried adding a background image to the Stage, then adding to the Stage an Actor that renders the model batch and the 3D instances in its draw() method.

But instead, the image isn't drawn and part of the 3D object is hidden.

SimpleGame class

public class SimpleGame extends ApplicationAdapter {

    Stage stage;

    @Override
    public void create () {
        stage = new Stage();

        InputMultiplexer im = new InputMultiplexer(stage);
        Gdx.input.setInputProcessor( im );

        Image background = new Image(new Texture("badlogic.jpg"));
        background.setSize(stage.getWidth(), stage.getHeight());
        stage.addActor(background);

        setup();
    }

    private void setup() {
        SimpleActor3D group = new SimpleActor3D();
        group.setSize(stage.getWidth(), stage.getHeight());
        group.setPosition(0, 0);
        stage.addActor(group);
    }

    @Override
    public void render () {
        stage.act();

        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        Gdx.gl.glClear( GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT );

        stage.draw();
    }
}

SimpleActor3D class

public class SimpleActor3D extends Actor {

    public Environment environment;
    public PerspectiveCamera camera;

    public ModelBatch modelBatch;
    public ModelInstance boxInstance;

    public SimpleActor3D() {
        environment = SimpleUtils.createEnvironment();
        camera = SimpleUtils.createCamera();
        boxInstance = SimpleUtils.createModelInstance(Color.GREEN);

        modelBatch = new ModelBatch();
    }

    @Override
    public void draw(Batch batch, float parentAlpha) {
        Gdx.gl.glViewport((int)getX(), (int)getY(), (int)getWidth(), (int)getHeight());

        modelBatch.begin(camera);
        modelBatch.render( boxInstance, environment );
        modelBatch.end();

        super.draw(batch, parentAlpha);
    }
}

SimpleUtils class

public class SimpleUtils {

    public static Environment createEnvironment() {
        Environment environment = new Environment();
        environment.set( new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f) );

        DirectionalLight dLight = new DirectionalLight();
        Color lightColor = new Color(0.75f, 0.75f, 0.75f, 1);
        Vector3 lightVector = new Vector3(-1.0f, -0.75f, -0.25f);
        dLight.set( lightColor, lightVector );
        environment.add( dLight ) ;

        return environment;
    }

    public static PerspectiveCamera createCamera() {
        PerspectiveCamera camera = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        camera.position.set(10f, 10f, 10f);
        camera.lookAt(0,0,0);
        camera.near = 1f;
        camera.far  = 300f;
        camera.update();

        return camera;
    }

    public static ModelInstance createModelInstance(Color color) {
        ModelBuilder modelBuilder = new ModelBuilder();

        Material boxMaterial = new Material();
        boxMaterial.set( ColorAttribute.createDiffuse(color) );

        int usageCode = VertexAttributes.Usage.Position + VertexAttributes.Usage.ColorPacked + VertexAttributes.Usage.Normal;

        Model boxModel = modelBuilder.createBox( 5f, 5f, 5f, boxMaterial, usageCode );

        return new ModelInstance(boxModel);
    }
}

What I would like :

What I would like

What I have instead :

What I have instead

I have tried rendering the model batch directly in the ApplicationAdapter render() method and it works perfectly, so the problems must lie somewhere with the Stage but I can't find how.

1条回答
爷、活的狠高调
2楼-- · 2019-09-14 00:36

I had the same problem but I needed to render 3d object only once so I came with an idea to render 3d model as a Sprite. In order to do that I rendered my model via modelBatch to frame buffer object instead of default screen buffer and then created a sprite from FBO color buffer.

Sample code below:

FrameBuffer frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), true);

Sprite renderModel(ModelInstance modelInstance) {
    frameBuffer.begin(); //Capture rendering to frame buffer.

    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT | (Gdx.graphics.getBufferFormat().coverageSampling ? GL20.GL_COVERAGE_BUFFER_BIT_NV : 0))
    modelBatch.begin(camera);
    modelBatch.render(modelInstance);
    modelBatch.end();

    frameBuffer.end();

    return new Sprite(frameBuffer.getColorBufferTexture());
}

You can always update your sprite texture in a render loop with use of sprite.setTexture(); method. You can also create an Image from a texture -> new Image(frameBuffer.getColorBufferTexture()); and use it in Scene2d.

查看更多
登录 后发表回答