Hello there!
I have recently been working on random map generation using Height Maps to generate a scene. However, instead of hand-drawing the maps, I have written an algorithm that writes a BufferedImage in memory. Once the BufferedImage is fully written, it exports .png image. These are then passed to the AssetManager to produce a Texture as in Hello Terrain, etc. That all works well.
I have recently, however, wanted to try to build a dynamic landscape–one that slowly shifts between the landscapes produced by two height maps of the same size. To to this, I am thinking of splitting my one initial height map into many smaller ones, and update each individually over time with the correct replacements. However, at the current point I am unaware of any way to use AssetManager to load a BufferedImage–I have to write to disk first. Unfortunately, this takes a good deal of time (read-write disk access for one 1024 x 1024 pixel image takes .234 seconds) and would create a large amount of files on disk. This time may also be faster than what many users will experience, as I am on an SSD, not spinning disk.
My question is this: is there any way I can pass my BufferedImage (or some other Image-type object) in computer memory, not from a disk file, to AssetManager to load a scene?
In case you need, here are the relevant parts of my code. Note that ColorVector is a class I wrote that stores and allows easy modification of color data until I make a BufferedImage. I recorded the time it took to write to disk, which was .232 seconds.
//Write to disk
System.out.println(System.currentTimeMillis());
try
{
File outputfile = new File(dir);
absolutePath = outputfile.getAbsolutePath();
absoluteDir = absolutePath.substring(0, absolutePath.length() - Runner.HeightMapName().length());
ImageIO.write(bufferedImage, "png", outputfile);
}
catch (IOException e)
{
System.out.println("The heightmap at " + dir + "failed to load:");
System.out.println(e.getMessage());
}
finally
{
System.out.println(System.currentTimeMillis());
}
//Loading the generated images as textures, as in Hello Terrain. Runner is my class with main() that has references to generated images, and gui is an instance of an object I created for on-screen documentation. The time it took to load the image from disk was .02 seconds.
gui.updateStatus("Load height map");
assetManager.registerLocator(Runner.heightMap().absoluteDir(), FileLocator.class);
System.out.println(System.currentTimeMillis());
Texture heightMapImage = assetManager.loadTexture(Runner.HeightMapName());
System.out.println(System.currentTimeMillis());
gui.updateStatus("Loading alpha map");
Material mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
mat_terrain.setTexture("AlphaMap", assetManager.loadTexture(Runner.AlphaMapName()));
gui.updateStatus("Set up texturing");
//Red layer in alphamap
Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
grass.setWrap(WrapMode.Repeat);
mat_terrain.setTexture("DiffuseMap", grass);
mat_terrain.setFloat("DiffuseMap_0_scale", 64f);
//Green layer in alphamap
Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
dirt.setWrap(WrapMode.Repeat);
mat_terrain.setTexture("DiffuseMap_1", dirt);
mat_terrain.setFloat("DiffuseMap_1_scale", 32f);
//Blue layer in alphamap
Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
rock.setWrap(WrapMode.Repeat);
mat_terrain.setTexture("DiffuseMap_2", rock);
mat_terrain.setFloat("DiffuseMap_2_scale", 128f);
gui.updateStatus("Generate map from height image");
AbstractHeightMap heightmap = null;
heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
heightmap.load();
TerrainQuad terrain;
int patchSize = 65;
terrain = new TerrainQuad("my terrain", patchSize, 1025, heightmap.getHeightMap());
gui.updateStatus("Apply scale ratios");
terrain.setMaterial(mat_terrain);
terrain.setLocalTranslation(0, -305 * (COMPRESS * verticalScalar), 0);
terrain.setLocalScale(COMPRESS, verticalScalar, COMPRESS);
gui.updateStatus("Add terrain to rootNode");
geography.attachChild(terrain);
rootNode.attachChild(geography);
gui.updateStatus("Calculate camera info");
TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
terrain.addControl(control);
gui.updateStatus("Load map collision shape");
CollisionShape sceneShape = CollisionShapeFactory.createMeshShape((Node) terrain);
RigidBodyControl mapBody = new RigidBodyControl(sceneShape, 0);
terrain.addControl(mapBody);
bulletAppState.getPhysicsSpace().add(mapBody);