Well first off, when you are trying to see if you can "see" a face, there are two ways to do it (generally speaking). You can do frustum culling. LibGDX provides a few methods like this one:
That allow you to check if a certain object is viewable on the screen currently. There is also a frustum check from LibGDX that allows you to use bounding boxes, so you may or may not choose to use that over the point check.
You can also loop through all your cubes in the chunk and check whether or not the chunk is visible to "air". For instance (some psuedo code):
for (int x = startChunkX; x < endChunkX; x++)
if(blocks[x][y][z].hasBlock(x + 1, y, z)
facesVisible = false;
facesVisible = true;
if(facesVisible[0 to 5] = false
You can also only render faces which are visible. So you can add only faces to the renderer instead of whole blocks (if you already aren't doing so). I would also not update blocks every frame. I would only update them if a block touching them suddenly changes. For instance, if you have a water block and you remove a solid block that was blocking it, update the blocks directly touching the water. You can even go further and say only update blocks that can be affected by water. So, if water interacts with sand, only update the sand blocks that are touching the new water block, don't update any of the blocks that don't interact with water. I'm getting pretty specific now, so I'll stop and let you contemplate those ideas.
The next thing you have to consider is making your own block class and using shaders to do your rendering. I imagine you're still using the model builder that LibGDX provides, but you have to realize this probably isn't going to be enough. I guess it may be if you aren't looking to make a super amazing game, I just imagine the model builder isn't the most efficient thing ever. It might actually be, I have no idea considering I've never used the new 3D API, so take my word with a grain of salt.
I'll try to find some resources on frustum culling, if you have any questions feel free to ask!