I'm coding a simulated brain and I'd like to make an arrow appear when one cell connects to another cell.

My output without generating an arrow looks like this: showing cells

Where each block rendered represents a cell in a 8x8x1 grid.

The cells are programmed to seek out another cell when they haven't had a pulse in a hundred ticks. When they find another cell I'd like to draw an arrow between them to visualize the link. This arrow is created in my method onAxonConnected()

But at my first attempt to make the arrow as the connection is established it seems to completely wipe the rendering of the existing cell blocks. I've had no issues in creating new cell blocks when a new cell was grown dynamically, so why this gives problems mystifies me.

Just an arrow

As you can see in the below image there is one well defined arrow and what seems to be a lot of stretched out lines that may or may not be the cell blocks.

This is my very first time experimenting with libgdx and i'm eager to learn more about it, but except for LibGDX creating ModelInstance after create() has ended without an answer I haven't found anything that comes close to my scenario.

My Question

What causes the cell blocks to not render when arrows are introduced?

Below is the code I'm using for the rendering.

public class MyGdxGame implements ApplicationListener, IBrainEventListener {

 public void onAxonConnected(Pos one, Pos two) {

  Model lineModel = build.createArrow(one.x, one.y, one.z, two.x, two.y, two.z, 0.15 f, 0.05 f, 5, GL20.GL_TRIANGLES, new Material(), VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal);
  ModelInstance line = new ModelInstance(lineModel);

 protected void addModelInstanceToRender(ModelInstance render) {
  ArrayList < ModelInstance > newlist = new ArrayList < ModelInstance > (this.modelRenders.size() + 1);
  this.modelRenders = newlist;

 protected void addArrowModelInstanceToRender(ModelInstance render) {
  ArrayList < ModelInstance > newlist = new ArrayList < ModelInstance > (this.arrowmodelRenders.size() + 1);
  this.arrowmodelRenders = newlist;

 public synchronized void onCellGrown(Cell cell, Pos pos) {

  ModelInstance render = new ModelInstance(model);
  render.transform.setToTranslation(pos.x, pos.y, pos.z);

  ArrayList < CellRender > newCellRenders = new ArrayList < CellRender > (cellRenders.size() + 1);
  CellRender renderManager = new CellRender(cell, render);

  this.cellRenders = newCellRenders;


 public synchronized void onAxonFired(Cell cell, Axon axon, Pos pos) {


 PerspectiveCamera cam;
 CameraInputController camMove;
 ModelBatch batch;
 Model model;
 ModelBuilder build;
 ModelInstance renderer;
 ArrayList < ModelInstance > modelRenders;
 ArrayList < ModelInstance > arrowmodelRenders;
 Environment enviroment;
 ArrayList < CellRender > cellRenders;

 BrainBoot brainBooter;
 Brain brain;

 Texture texture;
 SpriteBatch spriteBatch;

 public void create() {

  modelRenders = new ArrayList < ModelInstance > ();
  arrowmodelRenders = new ArrayList < ModelInstance > ();
  cellRenders = new ArrayList < CellRender > ();
  texture = new Texture(Gdx.files.internal("android.jpg"));
  spriteBatch = new SpriteBatch();
  brainBooter = new BrainBoot();
  brain = brainBooter.getBrain();

  cam = new PerspectiveCamera(50, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
  cam.position.set(16 f, 8 f, 16 f);
  cam.lookAt(8 f, 8 f, 8 f);

  cam.near = 1 f;
  cam.far = 300 f;

  enviroment = new Environment();
  enviroment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4 f, 0.4 f, 0.4 f, 1 f));
  enviroment.add(new DirectionalLight().set(0.8 f, 0.8 f, 0.8 f, -1 f, -0.8 f, -0.2 f));

  batch = new ModelBatch();
  build = new ModelBuilder();

  model = build.createBox(0.5 f, 0.5 f, 0.5 f,
   new Material(ColorAttribute.createDiffuse(Color.PURPLE)),
   VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal);


  camMove = new CameraInputController(cam);



 public void render() {
  ArrayList < CellRender > cellRenderList = this.cellRenders;
  for (CellRender r: cellRenderList) {
   if (r.dirty) {
  Gdx.gl.glClearColor(1, 1, 1, 1);

  ArrayList < ModelInstance > renderers = modelRenders;
  ArrayList < ModelInstance > arenderers = arrowmodelRenders;


  batch.render(arenderers, enviroment);
  batch.render(renderers, enviroment);



 public void dispose() {

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

 public void pause() {}

 public void resume() {}

1 Answer 1


The problem was caused by giving the command to create the arrow from an event that was triggered from a separate running thread.

This separate running thread was the cause somehow that everything went awry when it fired off an event that instantiated the model and added it to the arraylist for the next rendering cycle.

When I put the separate thread in line with the main render thread I was able to instantiate new arrows without issue.

Lesson learned: don't use threads with Libgdx and if you do, use PostMessages.

  • \$\begingroup\$ This is more of an OpenGL problem than it is a LibGDX problem. You aren't allowed to issue OpenGL commands from another thread that isn't registered as active to the OpenGL context, using the postRunnable function that LibGDX provides for this just executes a runnable on the same thread as the main loop. What exactly did you mean with "When I put the separate thread in line with the main render thread I was able to instantiate new arrows without issue.", did you just execute the code on the main thread? This would be interesting for people with a similar problem. \$\endgroup\$
    – VaTTeRGeR
    Apr 5, 2019 at 9:09
  • 1
    \$\begingroup\$ I merged the threads. Instead of starting the seperate thread I just invoke it in the main thread, and forcing an "update run" in the render() method with a custom built gameloop that creates all neccesary models and drawing instances once every 50ms. Then the render loop draws all neccesary models and intermediate steps for animations. I really dislike the libgdx method of not really being able to seperate rendering and logic updates, but I made it work. \$\endgroup\$ Apr 5, 2019 at 9:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .