For example, I want to draw circcle around unit representing its range (or even non circle range, that takes into account shooter and target altitude).
Or I want to draw “area” cursor on terrain, instead of 3d object that is put on terrain (which can look ugly, if there are high height diferences under cursor) or cursor on “screen” (which badly represents area).
But first, lets concetrate on drawing itself.
So far, I came up with 2 similar approaches
draw another image on desired position
Add texture, X,Y parameters to material and when computing pixel, substract X and Y from coordinates
draw actual lines/arcs
Add X,Y,R1^2,R2^2 and COLOR parameters and all pixels with R^2 between R1^2 and R2^2 (R is distance from X,Y) draw in COLOR (or current color modify by it, maybe take into account how far from circle edge it is)
both of them I can do for one (or preselected few) drawing, but I want to be able to draw multiple marks on map.
Using this approach, I need have float parameter, is it possible?
What are drawbacks of this approach? Is there better approach?
Currently there isn’t a decal implementation in jme3, but we would love one that worked well. There are a few ways to go about doing this.
An old way, would be to create a mesh with the same resolution as the terrain that is the size you desire for your decal, then test each point in that mesh with the height of the terrain below it and adjust it so it is just above the terrain. This shouldn’t be an expensive operation and will be quite scalable for many decals. The only problem is the decal isn’t right on the terrain. You could set each point as the same height as the terrain and then render that mesh in the Transparent render queue, you would have to play with the depth testing/writing so you don’t get it drawing over other objects.
The other, more modern, way would be to modify the terrain shader, add a post process to it to draw a decal. This will probably yield better performance. I can provide some more details about this if you would like. Haven’t tested it though
Well, to get this to scale up, you’ll want to think about some things:
First, how many decals do you expect there to be per terrain patch? If this is going to be an RTS or something similar, then can you select 200 units and them all fit on the same terrain patch? Is it possible that the entire patch is covered with decals? Or is it going to be more like 3-5 decals per terrain patch?
Either way, you’ll want to recurse down the quad tree, putting only decal centers in the uniform array that are actually on that terrain patch (and yes, you can use arrays of floats or vec3’s or even structs as uniforms in glsl, though I’m not 100% sure how to load them yet with jME). Then, at the top of your shader, you’ll want to loop through the array and find which TexMark to use, then proceed as you have. I’m not exactly sure what you are doing with that TexMark texture. If you have it set to tile, then it would be tiling that texture over the whole patch. Maybe you have it set to clamp, and the edges are transparent, so you don’t see it, but you are doing unnecessary calculations. You should probably bring sampling and mixing the TexMark texture inside the if statement.
You may also want to consider using manhattan distance as a metric instead of euclidean distance to remove some unnecessary multiplies. Your selected areas will be square instead of circular, but you can put the color in the TexMark texture, and have its alpha channel fade out in a circular pattern.
However, using this approach means that every pixel has to look at every mark on the patch to find the closest one. If there are 200 marks on one patch, this means you are doing something like 1000 instructions per pixel… that won’t work. To make it work, you’ll need to store the positions in a Luminance/Alpha float texture, say 32x32 in size. Each pixel in the texture represents the closest mark on the TerrainPatch to the location that would be sampled by that pixel. Make sure to set the filter to nearest, no mipmap so that the values won’t get interpolated, and use a -1 or something like that to signify that there are no marks near enough to this texel to be included. Then, in your shader, just sample the texture using the terrainPatches texCoords, and you know what the closest decal is, and can go on from there as you have above.
This method will show the lines between the texels as two decals meeting and switching from one to the other at the same place, even as the decals move, when there are two decals close enough that they are in neighboring texels. You can deal with this by sampling all the neighboring texels from the texture as well, and mixing in the overlapping decals. You also have the problem of, what happens when two decals should occupy the same texel. You can solve this by increasing the resolution of the texture until it is not possible (assuming there is some sort of collision detection going on), or us an RGBA32F texture to store the 2 closest decals to each texel, or even 2 or 4 of them so you can store the 4 or 8 closest marks (use a 3D texture to only use one sampler). Then you wouldn’t have to sample neighboring texels. Depending on how detailed your marks are, at some point, the whole texel will just be filled with color, and it won’t really matter any more. Either way, with this technique you can have thousands of marks, and still only have a few samples and a few comparisons for each pixel. The only downside is the CPU-side filling of the texture and uploading each frame. It may even be worth it to use both methods, and only switch to the texture method when there are more than ~10 marks on the terrain patch.