I’m trying to create a procedurally generated map. I already have designed my own noise function which looks quite good (trough it needs some work around the edges). However now I need to apply the right texture to the right position. I already have what type of texture I want to be presented at each location in a 2d array (well I have a 2d array with objects (512*512) which hold the right values as floats). Does anyone know how to now produce a texture for my map(or have a turorial)?
I’m not entirely sure what you mean but I think you want to generate a texture and there is a classed called ImageRaster to help you do that.
You could do what I did if it suits your goals.
Create an image for the AlphaMap and fill the image with either Red, Green, Blue or Alpha (or a blend of) values to represent up to 4 diffuse textures, a second AlphaMap image for another 4 diffuse textures if needed.
When I generate my initial terrains I set the AlphaMap to assign one of 3 textures depending on height, later I go in and repaint them to fine-tune and add others such as roads etc
If this suits you it’s pretty easy to create the Image as kwando said with ImageRaster or the like and paint it to suit your terrain, assign it to the Terrain or TerrainLighting material along with the diffuse textures and generate it.
There’s plenty of info on the tutorials to get the mapping right and use the JavaDoc for the rest. Failing that I could dig up my code if needed.
Sorry if it’s not your goal but let me know if you need more info on the above.
Thanks.
It looks like the ImageRaster is indeed what I’m looking for thank you. I’m going to try that today (by the way what are some good tutorials as I keep finding the hello serries but the rest is difficult to find).
Honestly, I think if your generating procedural terrain… your best bet is going to be splatting tiles base on normal angle.
Sec… lemme find an example:
[java]
vec4 compositeTerrain(in vec2 newTexCoord, in vec4 diffuseColor) {
vec4 ret = vec4(diffuseColor);
vec3 blending = abs( vtNormal );
blending = (blending -0.2) * 0.7;
blending = normalize(max(blending, 0.00001));
float b = (blending.x + blending.y + blending.z);
blending /= vec3(b, b, b);
vec4 coords = vtVertex;
vac4 col1;
vac4 col2;
vec4 col3;
col1 = texture2D( m_DiffuseMap2, coords.yz * m_DiffuseScale2 );
col2 = texture2D( m_DiffuseMap1, coords.xz * m_DiffuseScale1 );
col3 = texture2D( m_DiffuseMap2, coords.xy * m_DiffuseScale2 );
ret = col1 * blending.x;
ret += col3 * blending.z;
ret += col2 * blending.y;
return ret;
}
[/java]
Actually, after this… you could alphamap specific splats. But, I still think the above produces the coolest results for nice looking terrain.
There is also a plugin in the SDK called ImagePainter that gives you more facilities than ImageRaster if you need more advanced stuff.
Yeah, just paint the splat alpha map with ImagePainter and just use the splatting feature of the terrain, thats what I’d do for a start.
The content of this post is meant to be read as a straight information or question without an implicit dismissive stance or interest in having the other party feel offended unless there’s emotes that hint otherwise or there’s an increased use of exclamation marks and all-capital words.
I don’t think I have to work with normals as in order to generate my random map I already produced the derivatives of the terrain hight (basically I first generated a fairly simple and predictable noise map then estimated the antiderivatives from that and used that as a map). Basically I already have a on pixel to pixel basis everything I need (in 512*512 format) and just need to map the right textures to the right place. (I’m now looking for a way of creating the base image on which I can then build the DefaultImageRaster)
@thijser2 said: I don't think I have to work with normals as in order to generate my random map I already produced the derivatives of the terrain hight (basically I first generated a fairly simple and predictable noise map then estimated the antiderivatives from that and used that as a map). Basically I already have a on pixel to pixel basis everything I need (in 512*512 format) and just need to map the right textures to the right place. (I'm now looking for a way of creating the base image on which I can then build the DefaultImageRaster)
Are you only generating this once? Or is this something you will update frequently?
And, any chance of a screen shot? Would love to see how the technique is working for you.
It seems I now need to find a way to set the format of a brand new image into something other then null. (Or use another way of trasfering the DefaultImageRaster to a texture).
t0neg0d You wanted some screen shots?
when I run it as is with smoothing and z scaling.
When I turn of smoothing and z scaling. (so it’s only this algorithm).
I only need to fix the border as 2 of the border have a habit of looking weird.
The screenshots were made with the hello terrain textures as I’m still working on generating my own.
Hi,
Gone quiet so may as well post my bit of code for you to chew on, or spit
I’m up to a similar point on my software so only wrote this last night, very early work…
[java]
// TODO Create a proper material for it
// Create a new blank image as RGBA8 (4 bytes per pixel)
Image imgAlphaMap = new Image(Image.Format.RGBA8, tileQuadSize,
tileQuadSize, ByteBuffer.allocate(tileQuadSizetileQuadSize4));
// Create a ImageRaster to modify it
ImageRaster imgRaster = ImageRaster.create(imgAlphaMap);
// change the pixels
ColorRGBA red = new ColorRGBA(1f, 0f, 0f, 0f);
ColorRGBA blu = new ColorRGBA(0f, 1f, 0f, 0f);
ColorRGBA grn = new ColorRGBA(0f, 0f, 1f, 0f);
ColorRGBA alp = new ColorRGBA(0f, 0f, 0f, 1f);
for (int iy=0; iy < tileQuadSize; iy++) {
for (int ix=0; ix < tileQuadSize; ix++) {
// TODO implement nicer paint ideas
float h = hMap[ix + (iy * (tileQuadSize+1))];
if (h < 50f) {
imgRaster.setPixel(ix, tileQuadSize-iy-1, red); // DiffuseMap
} else if (h < 100f) {
imgRaster.setPixel(ix, tileQuadSize-iy-1, blu); // DiffuseMap_1
} else if (h < 150f) {
imgRaster.setPixel(ix, tileQuadSize-iy-1, grn); // DiffuseMap_2
} else {
imgRaster.setPixel(ix, tileQuadSize-iy-1, alp); // DiffuseMap_3
}
// (try painting alpha values in a paint program!!)
// (or colours without the alpha! ;))
}
}
Material mat = new Material(app.getAssetManager(),
“Common/MatDefs/Terrain/TerrainLighting.j3md”);
// load diffuse map 0 - TODO Add Normal map
Texture diffuse_0 = app.getAssetManager().loadTexture(“Textures/diffuse_0.png”);
diffuse_0.setWrap(WrapMode.Repeat);
mat.setTexture(“DiffuseMap”, diffuse_0);
mat.setFloat(“DiffuseMap_0_scale”, 0.0625f);
// load diffuse map 1 - TODO Add Normal map
Texture diffuse_1 = app.getAssetManager().loadTexture(“Textures/diffuse_1.png”);
diffuse_1.setWrap(WrapMode.Repeat);
mat.setTexture(“DiffuseMap_1”, diffuse_1);
mat.setFloat(“DiffuseMap_1_scale”, 0.0625f);
// load diffuse map 2 - TODO Add Normal map
Texture diffuse_2 = app.getAssetManager().loadTexture(“Textures/diffuse_2.png”);
diffuse_2.setWrap(WrapMode.Repeat);
mat.setTexture(“DiffuseMap_2”, diffuse_2);
mat.setFloat(“DiffuseMap_2_scale”, 0.0625f);
// load diffuse map 3 - TODO Add Normal map
Texture diffuse_3 = app.getAssetManager().loadTexture(“Textures/diffuse_3.png”);
diffuse_3.setWrap(WrapMode.Repeat);
mat.setTexture(“DiffuseMap_3”, diffuse_3);
mat.setFloat(“DiffuseMap_3_scale”, 0.0625f);
// Create a Texture for the AlphaMap image and load it
Texture texAlpha = new Texture2D(imgAlphaMap);
mat.setTexture("AlphaMap", texAlpha);
mat.setBoolean("WardIso",true);
mat.setBoolean("useTriPlanarMapping",true);
// set new Material to the terrainQuad
tQuad.setMaterial(mat);
[/java]
And screen shot for the result (TerrainGenerator is very early work so ignore the unseamed tiles
Hope it helps!
Enjoy!
Somewhat based on your example I tried the following:
[java] public Texture Gettexture1(){
Image alphamap = new Image(Image.Format.ABGR8,sidesize,sidesize,ByteBuffer.allocate(sidesizesidesize4));
ImageRaster imgRaster= ImageRaster.create(alphamap);
for (int i=0; i<sidesize-2; i++){
for (int j=0; j<sidesize-2; j++){
float a=geoarray[i][j].height/255f;
float r=(float) (geoarray[i][j].dzdx/50);
float g=1f;
float b=(float) (geoarray[i][j].dzdy/50);
ColorRGBA apply=new ColorRGBA(af,r,g,b);
imgRaster.setPixel(i,j,apply);
}
}
Texture2D ret = new Texture2D();
ret.setImage(alphamap);
return ret;
}[/java]
However running this generates a illegal argument exception on ByteBuffer is not direct. This error is generated outside of my code but by using print statements I was able to locate it to the line imgRaster.setPixel(i,j,apply);.
Sidesize is the size of each side of my heightmap which is 2 larger then what I end up loading so it's currently 514.
geoarray is an array of Geonodes which contain their height as well as the angle on both the x and y axis (as well as several other variables such as their neighbours).
So what am I doing wrong?
Use the BufferUtils to create the buffer.
I’m not very familiar with buffers yet so I was just copying the example can you explain more about BufferUtils?
Never mind found it!
Now to find a way to repaint only a part of the map (to save on cycles). As well as maybe adding some trees.
Sorry to hijack this thread, but I played a little with terrains, and never got the “seaming” solved. Any advice on how to do this properly ?
@yang71 said: Sorry to hijack this thread, but I played a little with terrains, and never got the "seaming" solved. Any advice on how to do this properly ?You can look at TerrainGrid, it works at least in so far as it manages to seamlessly combine the tiles ;) The content of this post is meant to be read as a straight information or question without an implicit dismissive stance or interest in having the other party feel offended unless there's emotes that hint otherwise or there's an increased use of exclamation marks and all-capital words.
The trouble is I was using TerrainGrid :((.
But there was a very thin gap between patches.