Heap space issues with array... not sure why though?

So I can create an 3 dimensional array for a ‘chunk’ of terrain: x,y,z. Here’s the code which won’t work:





AssetManager assetManager;



public static int WORLD_HEIGHT = 128;

public static int WORLD_WIDTH = 256;

public static int WORLD_DEPTH = 256;



public ChunkManager(AssetManager assetManager)

{



this.assetManager = assetManager;



Texture heightMapImage = this.assetManager.loadTexture(“Textures/heightmap.jpg”);



// Create an ArrayList of chunks.

ArrayList chunks = new ArrayList();



// Cycle through the first four blocks - 256/2 is the optimal for a 32 bit size chunk… that is up to 4 quads per sector… aka 8 Chunks…

for (int x = 0; x < (WORLD_WIDTH / 2); x+=32)

{

for (int z = 0; z < (WORLD_DEPTH / 2); z+=32)

{

chunks.add(new Chunk(this.assetManager, heightMapImage, x, 0, z, WORLD_WIDTH, WORLD_HEIGHT, WORLD_DEPTH));

}

}



// Setup the chunks.

for (int i = 0; i < chunks.size(); i++)

{

chunks.get(i).loadChunkData();

chunks.get(i).build();

this.attachChild(chunks.get(i));

}



}



However if in the dual for loop, I change the values to x < ( WORLD_WIDTH / 4 ). It’s fine.

I’m not entirely sure why this throws a heap issue as I’ve changed the maximum heap size in jmonkey and technically.



( 256 / 4 ) += 32 shouldn’t be an issue, right?

Ah, solved it. Turns out my calculations were wrong in how much memory I actually needed… It needs 2048 to render the WHOLE chunk data… Probably an idea for me to try and make this more memory efficient…

@MichaelGray

What made you go with an arraylist instead of a nested array? And what exactly are you storing inside those chunks? I assume you’re not storing the positions inside the chunks or you’ll have at least 96 unneccesary bytes per chunk (800 megs using your dimensions).

bits BITS

Alas, I am storing positions within the chunks as I thought that would be the only way in which to do so:



public class Chunk extends Node

{



AbstractHeightMap heightmap = null;

public static float DEFAULT_BLOCK_SIZE = 0.5f;



private int transX = 0;

private int transY = -100;

private int transZ = 0;



// This is the size of the whole world.

int worldX = 256;

int worldY = 125;

int worldZ = 256;



// This is the size of the chunk.

int lengthX = 32;

int lengthY = 125;

int lengthZ = 32;



// The chunks position in relative to the world.

int positionX = 0;

int positionY = 0;

int positionZ = 0;



int mapCells[][][] = new int[worldX][worldY][worldZ];

int lightCells[][][] = new int[worldX][worldY][worldZ];



Mesh mapmesh = new Mesh();



int rightFace = 0;

int leftFace = 1;

int topFace = 2;

int bottomFace = 3;

int frontFace = 4;

int backFace = 5;



ArrayList vertices = new ArrayList(); // points

ArrayList normals = new ArrayList(); // normals

ArrayList texCoord = new ArrayList(); // tex cords

ArrayList indexes = new ArrayList(); // indexes





ArrayList verticesColor = new ArrayList();



//String matDefName = “Common/MatDefs/Misc/ShowNormals.j3md”;

//String matDefName = “Common/MatDefs/Light/Lighting.j3md”;

String matDefName = “Common/MatDefs/Misc/Unshaded.j3md”;



float bsize = 1; // block size





// Texture coordinates

Vector2f [] texCoord2 = new Vector2f[4];



//

AssetManager assetManager;



public Chunk(AssetManager assetManager, Texture heightMapImage, int cx, int cy, int cz, int wx, int wy, int wz)

{

this.assetManager = assetManager;



this.worldX = wx;

this.worldY = wy;

this.worldZ = wz;



this.positionX = cx;

this.positionY = cy;

this.positionZ = cz;



heightmap = new ImageBasedHeightMap(ImageToAwt.convert(heightMapImage.getImage(), false, false, 0));

heightmap.load();



//testHeightMap();

//loadChunkData();

//build();

}

@MichaelGray

Ah ok, was just curious, seems the chunks themselves aren’t the problem. I didn’t know you had nested stuff like that (should have read the code more).



I looked now tho and found something. What are those map and lightcells that require an integer each? Seems they are the real crooks here (~200 mb per chunk).



And sorry, I might have missunderstood, but shouldn’t they be the sizes of the chunk, and not the world, so that there are 32x125x32 map- and lightcells in each chunk?



Now its 256x256x125 light and mapcells per chunk, and judging from that loop you put in the first snippet that makes 16 chunks * 200 megs which is about 3.2 gigs:



public static int WORLD_HEIGHT = 128;
public static int WORLD_WIDTH = 256;
public static int WORLD_DEPTH = 256;

...

for (int x = 0; x < (WORLD_WIDTH / 2); x+=32)
{
for (int z = 0; z < (WORLD_DEPTH / 2); z+=32)
{
chunks.add(new Chunk(this.assetManager, heightMapImage, x, 0, z, WORLD_WIDTH, WORLD_HEIGHT, WORLD_DEPTH));
}
}


It would explain why doing WORLD_WIDTH/4 in the loop gets you below 2 gig heh.

Hope maybe it helped.

The lengthX,…,Z is basically the dimensions of the chunk itself.

The reason why I added worldX,…,Z was to be able to select a “portion” of the current world. This in essence will be defunct once I get the LOD control working on the scene.



The issue is, I can’t seem to get LOD working on the mesh as I’m not entirely sure how JME deals with LOD’s on meshes.

In essence once that’s done I can remove the worldX,…,Z parameters and literally only have chunks load relative to the LOD control.



I’ve removed the light stuff and it seems to be running a lot faster without any memory issues - seems that might have been the root cause at runtime.



Next, question would be - any clues how I can go about implementing LOD onto a Mesh as it seems it needs a camera and a terrainGrid. Of which I’m not using a terrainGrid to render any of this but in fact a chunk made of vertices.

Sorry I still don’t understand why there are 256x256x125 mapcells in each chunk, and why they are integers.



There are many type of lod controls etc. I’d use terrain quads for terrain tho, not just a bunch of verts. Terrainquads are optimized for exactly that.

The mapcells are used here:



// Loads the chunk data into the mapCells array.

public void loadChunkData()

{

for (int z = positionZ; z < (positionZ + lengthZ); z++) {

for(int x = positionX; x < (positionX + lengthX); x++ ) {

for (int y = 0; y < (heightmap.getTrueHeightAtPoint(x, z)*0.08f); y++) {

mapCells[x][y][z] = 1;

}

}

}

}



At the moment in essence I’m only loading one chunk relative to the WHOLE known single heightmap image.



I should probably rethink this part through again and do it again in all honesty as it was a rather quick build.



In relation to terrainQuads, I Wasn’t are you can make the terrain “Block” like with terrainQuads, thought it was auto smoothed?

I don’t particularly want to make smooth terrain but keep that “minecraft” esque-ness to it.

Sounds like you are trying to do a voxel engine. Have a look at some of the other posts about them both here and on the internet and you should find a lot of helpful advice and I think there is even an open source JME3 voxel engine floating around although I’m not sure how complete it is…