I have a ProceduralTextureGenerator holding 3 textures so I can have a different texture at different heights, the problem is I can't seem to figure out how to scale them down so They are not stretched across the terrain. after all the textures are loaded I tried tried something like …
tb.scaleTextureCoordinates(0, 20);
I seem to be on the right track because the texture does get scaled … but only once It is not tiled over the terrain. the rest of the terrain is still just a blur. with a bunch of lines going in the x a z direction at the width on the tiled texture. I wanted to provide a screenshot so everyone can understand but forgot how.
Hmm,…I don't think you can achieve it by scaling cause if you don't want it to be streched you need a huge texture that might explode your graphics adapter. Actually I didn't use ProceduralTextureGenerator too much. There might be a way to increase the texture-size in proceduralgenerator to decrease the effect a bit…Tiling wouldn't help here cause the calculated Texture fits only as whole on the mesh. e.g. you might have a snowarea in a valley…
What you are looking for might be found with TextureSplatting ( e.g. TestIsland in jmetest's terrain-package ). It is using a different approach. This uses different detailed textures and repeats. So here you have the tiles. Every detail layer have an alphamap telling jME which detail-layer to be shown in a certain intensity.
Did you have a look at mapspinner yet?
http://www.jmonkeyengine.com/forum/index.php?topic=9880.0
http://code.google.com/p/mapspinner/
Hope that helped a bit.
cu,ToM
ok, but how would I achieve different textures at different heights … such as snowy mountain tops and grassy valleys if I don't use ProceduralTextureGenerator ??
You would have to do that manually! Lets say you have 3 detailmaps:1)dirt 2)stone 3)snow
Every of this has an alphamap (beside the first one), that alphavalue is zero. That means only the first texture would be visible. If you want at a certain place a grass "valley" you have to increase the alphavalue at that place. If you want snow you have to increase the alphavalue of texture 3's alphamap. That is for sure not easy if you want to do that in a paint tool! You could do that in your modeller (if you use one).
I can just suggest (if you really want to try this advanced step) to have a good look at the TestTerrainSplatting-Class (jmetest.terrain). There you see all the textures (colormaps and alphamaps) that are used! Look at them and try to understand the code.
Hope that helped a bit,…can't do much more about that topic.
EDIT:
Did you increase the texturesize? (e.g. pt.createTexture(1024) ) I know this is not what you wnated but might be that fastest. Do you use detail-textures like in TestHillHeightMap?
ttrocha said:
You would have to do that manually! Lets say you have 3 detailmaps:1)dirt 2)stone 3)snow
Every of this has an alphamap (beside the first one), that alphavalue is zero. That means only the first texture would be visible. If you want at a certain place a grass "valley" you have to increase the alphavalue at that place. If you want snow you have to increase the alphavalue of texture 3's alphamap. That is for sure not easy if you want to do that in a paint tool! You could do that in your modeller (if you use one).
...
Right on about the runtime workings, ToM. But it definitely does not have to be done manually. The alpha values can be set according to elevation by straight-forward ImageBuffer coding. As a matter of fact, I intend to add that feature to my new terrain system within the next week.
If the manual painting route is taken, the paint tool side is easy if you use a good program like Gimp so you can paint over top of a read-only height-map layer. It takes some Java image coding work to break different colors into multiple alpha image maps, but this work is also straight-forward. You can see an early example of this technique in my post here.
ttrocha said:
You would have to do that manually! Lets say you have 3 detailmaps:1)dirt 2)stone 3)snow
Every of this has an alphamap (beside the first one), that alphavalue is zero. That means only the first texture would be visible. If you want at a certain place a grass "valley" you have to increase the alphavalue at that place. If you want snow you have to increase the alphavalue of texture 3's alphamap. That is for sure not easy if you want to do that in a paint tool! You could do that in your modeller (if you use one).
I can just suggest (if you really want to try this advanced step) to have a good look at the TestTerrainSplatting-Class (jmetest.terrain). There you see all the textures (colormaps and alphamaps) that are used! Look at them and try to understand the code.
Hope that helped a bit,...can't do much more about that topic.
EDIT:
Did you increase the texturesize? (e.g. pt.createTexture(1024) ) I know this is not what you wnated but might be that fastest. Do you use detail-textures like in TestHillHeightMap?
I knew you were going to say something like this ... I know about creating separate alfa maps ... I've done it before but would really LOVE to avoid this step. The ProceduralTextureGenerator class seamed like the perfect solution ... I do have my texture size set to 1024 ... and I am using pretty much the same idea as TestHillHeightMap which looks really good ... I guess if I keep playing around with my code I could get the same results.
Fine…so you can do it like blaine told…all straight forward…
well as I said I'd rather not have to open an image program … how about a little more info about the ImageBuffer coding you mentioned Blane. Is there an example in the JME project??
phmenard said:
well as I said I'd rather not have to open an image program ... how about a little more info about the ImageBuffer coding you mentioned Blane. Is there an example in the JME project??
I beleve there is for the alpha texture splatting part. Look for a demo of texture splatting using an alpha image. Once you understand that, you use BufferedImages to generate the low-res alpha images programmatically, using the output alpha images exactly the same as "provided" alpha images. If you are going to do that, I can give you details. If you're not going to go that route, I would rather not waste my time. I don't mean to be negative-- I just don't have time to write documentation that won't be read.
I don't think it's possible to merge low-res area specification + high-res tiling like you want with the Procedural* class. If I understand correctly, real texture splatting is required for that.
I'm very interested in that! When I understand right you mean to create for each detaillayer a new image with BufferedImage (TYPE_4BYTE_ABGR?) with the same resolution as the heightmap. And then create an alpha value corresponding to the greyscale-value that is in the detail-level's value-spectrum. (I think this might be the same as in proceduraltexturemanager). Sounds logic for me. Or missed I anything…
ok so it seems I'll have to go with the BufferedImages way, I've seen the example you spoke of and that's really not the way I want to go … I can create a heightmap very easily but when it comes to making extra alpha maps I've always had trouble they never seem to come out the way I want. I'd like to learn more about the BufferedImage way if its possible … this may be faster for me than constantly adjusting an alpha image I make in gimp.
phmenard said:
ok so it seems I'll have to go with the BufferedImages way, I've seen the example you spoke of and that's really not the way I want to go ... I can create a heightmap very easily but when it comes to making extra alpha maps I've always had trouble they never seem to come out the way I want. I'd like to learn more about the BufferedImage way if its possible ... this may be faster for me than constantly adjusting an alpha image I make in gimp.
I explained the general steps in the immediately-preceding reply to ToM. I think what you need beyond that is specific implementation tips about generating the final alpha image to be CombinerFunction'ed.
There is no reason to write anything to disk. Just create a BufferedImage and create your jME Texture with that.
Here's some production code that shows how to set pixel values in a way appropriate for an alpha image:
static {
int[] whiteAlphaColorMap = new int[] {0, 0xFFFFFFFF};
whiteAlphaColorModel = new IndexColorModel(
2, whiteAlphaColorMap.length,
whiteAlphaColorMap, 0, true, 0, DataBuffer.TYPE_BYTE);
}
...
int[] ia = new int[10];
int[] one = new int[] {1};
Raster inRaster = inImg.getData();
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++) {
inRaster.getPixel(x, y, ia);
if (ia[0] == wRasters.length) continue;
used[ia[0]] = true;
wRasters[ia[0]].setPixel(x, y, one);
}
....
outImages[i] = new BufferedImage(
ImgUtil.whiteAlphaColorModel, wRaster, false, null);
ttrocha said:
I'm very interested in that! When I understand right you mean to create for each detaillayer a new image with BufferedImage (TYPE_4BYTE_ABGR?) with the same resolution as the heightmap. And then create an alpha value corresponding to the greyscale-value that is in the detail-level's value-spectrum. (I think this might be the same as in proceduraltexturemanager). Sounds logic for me. Or missed I anything...
I finally made time to review my old texturizing work to make sure that I don't misinform you.
I can't make sense out of your explanation. But in any case, it's not what I was suggesting.
With terrain the UV mapping is done per Block, because those are the Geometries which have the texcoords. In each block, the U and V values range from 0 to 1. Seems like an unnecessary (and inconvenient) constraint, but with jME 2, texCoord quantity generally matches vert quantity. The typical way is to just linearly interpolate the U and V range across the vertexes (see TerrainBlock.buildTextureCoordinates() for an example, but there are reasons you may want to capture linear 3D distance instead of lateral distance, though that has its own difficulties). For uniform tiling of the same texture across the landscape, you just set a TextureState as an ancestor of all of the Tiles and set the scale of the texture as you want it. The same TextureState is applied the same to all of the Blocks that have the same exact texcoord values. That's trivial. What we want to do is multiplex multiple tiled images selectively over a set of blocks.
I know that neither you nor phmenard are asking about use of static alphas, but there is no way you can understand the dynamic method without first understanding the static method. Starting with the most laborious method: For each texture that you want to able to apply to the landscape, create a Texture to be shared. If you want to be able to have textures for grass + dirt + moss + water, you would just need 4 tilable images which you will load into 4 Textures. There is no reason to have an alpha channel in these images. Since the size of a blade of grass should be the same anywhere in your world, you set the scale for each texture once in the corresponding Texture object. Now you need to make one alpha image for each desired texture for each terrain block, because the borders of each distinct texture may be different within each block. The great performance advantage here is that the resolution of the alpha images can be much lower than the texture images (for a single block). Just how low depends on how fine you want your texture border edges to be. Every block has one PassNodeState with a TextureState for each texture needed in that block. (The block and the PassNodeStates for that block are tied together by a PassNode). Each TextureState uses a combiner function to merge the shared Texture with the block-unique + texture-specific alpha Texture. Since we are not using our alpha maps for continuous blending, the lower the bits/channel the better (each pixel will just signify whether the texture should be displayed or not).
Don't infer from the fact that an image is used as an alpha map that it should have an alpha channel. I find it is usually more convenient to use a regular opaque channel. The discriminant is that the pixel values are used to determine alpha in the game world.
Refinement #1: Instead of managing 100 X number-of-textures alpha map image files for 100 blocks, manage just one very large alpha map file covering the whole world for each texture. For our 4 desired textures, you would manage just 4 alpha map files. Use ImageMagick (which you can invoke from a script or from Java) to split up your global map into your needed 100 X 4 alpha map images.
Refinement #2: Since each spec of land in the game world may display only one texture, combine your number-of-textures global alpha maps for one global alpha map. I suggest using an indexed image to make it idiot-proof. Indexed color X => Texture Y. To make it intuitive, I always use green for grass, brown for dirt, blue for water, etc. Continuing our 100 block, 4 texture example, Use ImageMagick to split your 1 global image map file into 4 global image maps before splitting these 4 into the 400 as explained in Refinement #1.
Refinement #3: Use Java's BufferedImage and related classes to do the work of Refinement #1 and Refinement #2 within your application. You write pixel values based on color indexes and scaled block offsets into the global alpha file. You only need to distribute one alpha map file with your game.
Finally, refinement #4. Just like refinement #3, except instead of generating a final, block-specific alpha file from a global alpha map file, you calculate the pixel values from the vertex Y values of the same block.
ttrocha said:
I'm very interested in that! When I understand right you mean to create for each detaillayer a new image with BufferedImage (TYPE_4BYTE_ABGR?) with the same resolution as the heightmap. And then create an alpha value corresponding to the greyscale-value that is in the detail-level's value-spectrum. (I think this might be the same as in proceduraltexturemanager)...
I forgot most of what I knew about the ProceduralTextureGenerators. I had to review that to have all available techniques fresh in my mind for adding the texturing system to my Procedural Terrain System.
ProceduralTextureGenerator is a poor man's approach to applying multiple textures. May work ok for small scale game worlds, but it doesn't approach the scalability and flexibility of real multi-pass texture splatting.
The first limitation of the ProceduralTextureGenerators is that they do not leverage the great runtime benefits of tiling. The output of a ProceduralTextureGenerator is a single texture image that you apply to a Geometry. Since it is a single texture with game-world-location-specific texturing, such as snow at your game world location of (x=341,z=7311) it is impossible to tile the output texture. Instead of benefiting from tiling every time that the game world renders the textures, the tiling is applied once when the Generator generates the output texture.
When you do multi-pass splatting, you optimize the sizes of the images used at runtime. The tiled textures like moss and dirt can be very large relative to the game-world area that the image will correspond to, because hardware will efficiently tile this image to cover areas thousands or millions of times that large. The alpha images will not be tiled and must have a much higher scale (lower res) than the tiled images, with the final alpha image(s) still being quite large. With the TextureGenerators, the output image necessarily has one resolution/scale.
For both strategies, you must somehow generate a single alpha image for each terrain block, since alpha images can only be applied to Geometries, and the alpha images must be unique for each block (because you want your terrain texture to vary across your world). For the ProceduralTextureGenerators, you need to split up a humongo output image into texture images which are ready to be applied to each block. For multi-pass splatting, you split up just the alpha image with-resolution/scale-optimized-for-its-precise-purpose into alpha images which individually need to be combined with the shared tile texture images for each block.
phmenard said:
ok so it seems I'll have to go with the BufferedImages way, I've seen the example you spoke of and that's really not the way I want to go ... I can create a heightmap very easily but when it comes to making extra alpha maps I've always had trouble they never seem to come out the way I want. I'd like to learn more about the BufferedImage way if its possible ... this may be faster for me than constantly adjusting an alpha image I make in gimp.
My new terrain system has a real texture splatting HeightDerivedTextureProcedure. See the product announcement.