Libgdx Mesh render optimization

I am now stuck again…
I am trying to render more objects but calling mesh.render() every frame is eating everything up
so i need to make a method that binds an object and then render all the same objects and then unbind it for multiple times
How would i do this in Libgdx?

When rendering 500 objects on

PC: just about 110 FPS
Android (Samsung Galaxy Ace 2) about 7 FPS

The only solution i have found is using the Renderable which is provided via Libgdx but the problem i have found with that is i cannot use my own shader and i keep getting this error “Cannot use offsets when Element Array Buffer Object is disabled”

Code i have attempted (Making my own rendering system)

	for (Entity e : preparedEntity) {
				Mesh mesh = e.getModel().getModel().getMesh().getMeshData();
				Gdx.gl20.glEnable(GL20.GL_ARRAY_BUFFER_BINDING);
				
				Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, Usage.Position); // <-- not sure if that is the VBO ID
				Gdx.gl30.glVertexAttribIPointer(GL20.GL_ELEMENT_ARRAY_BUFFER, mesh.getNumVertices(), GL20.GL_FLOAT, 0, 0);
				
				Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, Usage.Normal);
				VertexAttribute normal = mesh.getVertexAttribute(Usage.Normal);
				Gdx.gl30.glVertexAttribIPointer(GL20.GL_ELEMENT_ARRAY_BUFFER, mesh.getNumVertices(), GL20.GL_FLOAT, 0,normal.offset);
				
				Gdx.gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, Usage.TextureCoordinates);
				VertexAttribute tex = mesh.getVertexAttribute(Usage.TextureCoordinates);
				Gdx.gl30.glVertexAttribIPointer(GL20.GL_ELEMENT_ARRAY_BUFFER, mesh.getNumVertices(), GL20.GL_FLOAT, 0,tex.offset);
				
				Gdx.gl.glDrawElements(GL20.GL_TRIANGLES, mesh.getNumIndices(), GL20.GL_UNSIGNED_INT, mesh.getIndicesBuffer());

My code before (Using Mesh.render) which is provided with libgdx

				e.getModel().getTexture().bind(0);
				shader.setUniformMatrix(Utils.TRANSFORM_UNIFORM, e.getModel().getModel().getTransform().getTransformationMatrix());
				shader.setUniformf(Utils.COLOUR_UNIFORM, e.getModel().getModel().getColour());
				if (MasterRenderer.getRenderCollisionMesh()) {
					e.getCollisionMesh().unsignedRender(GameWindow.getDefaultShader(), GameWindow.getCamera());
				}
				e.getModel().unsignedRender(GameWindow.getDefaultShader(), GameWindow.getCamera(), false);

Inside render

			int type = GL20.GL_LINE_STRIP;
			if(wireframe == false){
				type = GL20.GL_TRIANGLES;
			}
			rawModel.getMesh().getMeshData().render(shader, type);

This is what i get when using Renderable and ModelBatch
I am trying to render the player from my other posts

Code Create

		player = new TexturedModel(new RawModel(MeshBuilder.createRectangle(1,1), new Vector3(0, 0, -1), new Vector3(0.05f, 0.1f, -0.05f)), Utils.loadTexture(Gdx.files.internal("textures/p1.png"), false));
		
		batch = new ModelBatch();
		playerRenderable = new Renderable();
		playerRenderable.material = new Material(new TextureAttribute(TextureAttribute.Ambient,Utils.loadTexture(Gdx.files.internal("textures/p1.png"), false)));
		playerRenderable.mesh = player.getModel().getMesh().getMeshData();
		playerRenderable.meshPartOffset = 0;
		playerRenderable.meshPartSize = player.getModel().getMesh().getMeshData().getNumVertices();
		playerRenderable.worldTransform.set(player.getModel().getTransform().getTransformationMatrix());
		playerRenderable.primitiveType = GL20.GL_TRIANGLES;

Render

		batch.begin(GameWindow.getCamera());
		{
			batch.render(playerRenderable);
		}
		batch.end();

Okay i have manage to get something working but i have changed it to the grass instead so i can see better whats going on as it is a bigger object

modelTest = new TexturedModel(new RawModel(MeshBuilder.createPlane(1, 1), new Vector3(0, 0, -2f), new Vector3(2, 0.0001f, -2)), Utils.loadTexture(Gdx.files.internal("textures/ground.png"), true));
		groundE = new Entity(modelTest,new CollisionMesh(CollisionMesh.CUBEMESHCOLLISION, modelTest));
		
		Environment e = new Environment();
		DirectionalLight light = new DirectionalLight();
		light.set(Color.WHITE, 0, -2, 0);
		e.directionalLights.add(light);
		
		Material m = new Material();
		//m.set(new ColorAttribute(ColorAttribute.Diffuse, new Color(1,0,1,1)));
		m.set(new TextureAttribute(TextureAttribute.createDiffuse(texture = Utils.loadTexture(Gdx.files.internal("textures/ground.png"), false))));
		batch = new ModelBatch();
		playerRenderable = new Renderable();
		playerRenderable.mesh = modelTest.getModel().getMesh().getMeshData();
		playerRenderable.meshPartOffset = 0;
		playerRenderable.meshPartSize = modelTest.getModel().getMesh().getMeshData().getMaxVertices();
		playerRenderable.worldTransform.set(modelTest.getModel().getTransform().getTransformationMatrix());
		playerRenderable.primitiveType = GL20.GL_TRIANGLES;
		playerRenderable.environment = e;
		playerRenderable.material = m;

Can anyone help I have been working on this all day and I have got no where ??? ??? ??? ??? ???

Wow! Libgdx why you make things soo complicated
I figured it out, basically Libgdx binds textures via index so 0,1,2,3,4 so you can have multiple textures in one shader (Mesh)
so i had to change my mesh attribe for texture to

	public static final String POSITION_ATTRIBUTE = "a_position";
	public static final String NORMAL_ATTRIBUTE = "a_normal";
	public static final String TEXCOORD_ATTRIBUTE = "a_texCoord";
	public static final int COMPONENTS = 3+3+2;
	
	private static final VertexAttributes attribs = new VertexAttributes(
			new VertexAttribute(Usage.Position,3,POSITION_ATTRIBUTE),
			new VertexAttribute(Usage.Normal,3,NORMAL_ATTRIBUTE),
			new VertexAttribute(Usage.TextureCoordinates,2,TEXCOORD_ATTRIBUTE+"0") // Notice the number
	);

Instead of

	public static final String POSITION_ATTRIBUTE = "a_position";
	public static final String NORMAL_ATTRIBUTE = "a_normal";
	public static final String TEXCOORD_ATTRIBUTE = "a_texCoord";
	public static final int COMPONENTS = 3+3+2;
	
	private static final VertexAttributes attribs = new VertexAttributes(
			new VertexAttribute(Usage.Position,3,POSITION_ATTRIBUTE),
			new VertexAttribute(Usage.Normal,3,NORMAL_ATTRIBUTE),
			new VertexAttribute(Usage.TextureCoordinates,2,TEXCOORD_ATTRIBUTE)
	);

Well the new rendering system using batch didn’t do much of an effect as i thought it would
So i added frustum culling here are my results

500 Objects
Android(Samsung Galaxy Ace 2) = barely 15FPS
Desktop = 120FPS