Decal Generator

Here again the add() method. Java bbcode found it yummy in my last post:

Edit: DAMN! Here you go:

I’m still working on the decal generator and I’m looking forward to release it as a module in the same way as “Projective Texture Mapping”.

I’d like to also make a GDE plugin. If possible, I’d not make a separate editor but integrate into Scene Explorer / Composer. Therefore, I created a ”JmeDecalProjectorControl extends AbstractSceneExplorerNode” which represents the projector (camera) and which is supposed to inject the decal geometry into the scene. To display the frustum of the decal projector, I created a ”JmeDecalProjectorControlLookupListener implements LookupListener” which reacts on selection of JmeDecalProjectorControl nodes and should display the projector frustum in the ”toolNode” of the ”SceneApplication”.

Is that a viable way? At the moment, the default constructor of ”JmeDecalProjectorControl” gets called by the GDE but the control is not listed in the context menu “Add Control…” of the Scene Explorer for some reason. The LookupListener works as expected.

I followed these tutorials:
https://wiki.jmonkeyengine.org/legacy/doku.php/sdk:development:sceneexplorer
https://wiki.jmonkeyengine.org/legacy/doku.php/sdk:development:scene

Edit: Found it myself:
[java]
@org.openide.util.lookup.ServiceProvider(service = NewControlAction.class)
public class NewDecalProjectorAction extends AbstractNewControlAction
{
// …
}
[/java]

8 Likes

Hey @survivor :
As what I see in the Demo you got a nice Decals system already!

Did you remember the things I suggested in my old post? About the way to optimize get LOD with decal mesh. :stuck_out_tongue: A must-have feature.

The second thing is, from my experience in optimized game, especially those who run on Android => Decals with different type and purpose and usage should be considered to render differently: Static vs Dynamic, customized mesh, shader and such…
Please take a look in the Decal system of Unity, they’ve done it nicely.
http://www.unitymagic.com/shop/en/unity-decal-framework/

3rd is a way to get 2 feature above to work nicely with Terrain.

I willing to help in this Decal system… In fact I already got Dynamic decal work, implemented after:
Applying Decals to Arbitrary Surfaces in Game Programming Gems 2
I also tried to get it hook into a LOD system and Terrain, we should exchange ideas :stuck_out_tongue:

Hi @atomix,

thanks for replying! We should discuss features and future plans after I released v0.1, so we have something to talk about. In fact, my decal generator is not a decal system. At the moment, it’s just a modular, extensible decal mesh generator. And it’s actually three. I extended the basic generator, which just generates a mesh with texture coordinates and normals, two times. In extension one, I added the generation of tangents and in extension two, I made the generator also provide the original texture coordinates in “VertexBuffer.Type.TexCoord2”, so you can create a shader that blends the original material with the decal material as you like. You could for example use steep parallax mapping on both materials and combine color, normals and height like in the web demo of unity decal framework you mentioned.

These extensions are only a few lines of code because they are mostly done by overriding methods of the basic generator where necessary. I also focused on high throughput, good multithreading scalability and memory stability (preventing massive garbage through pooling). That’s why it took me so long for so little (visual) results. I’m not completely satisfied with the design yet and might do another re-design. I’ll keep LoD in mind when doing that.

As I said in my initial post, I was inspired by Wolfire and the Unity Decal System from Edelweiss Interactive. So the GDE integration is definitely on my list. But I still have the problem I mentioned in my previous post, but I haven’t yet investigated deeper.

So long
Stefan

Yeah, i see. Your “system” is already usable, I’m not seeing so much things to change indeed :stuck_out_tongue:

One thing to clarify:
If it’s just a Decal “Mesh” Generator, what kind of material your decal can use, a special DecalMatDef or it can also use normal LightingMat ?.. This is also pretty important from the designer POV, we need to make sure it adaptable as more usecases come right away when it get published.

Talking about improvement or re-design if needed:
GDE integration is awesome.
Consider the Decal thingy is represented as a Control [I can not agree more].

My thoughts:

== GeometryList ===
=== Default ===

  • Whenever is attach to a Node, the attachted GeometryList of the Decal expand to all the Node’s children.
  • In constrast, if it only attached to a Geometry, only that Geometry in the List.
    === Dynamic ===
  • The control can keep a dynamic list of Geometry in its list. This should involve UI for GDE like a geometry selector, filter.
    [I can help in this. The point is i’m always want GDE to work much better as it is currently, I add a few things in it to handle Spatial Selection and Filter, Layering…etc]

== Other Control/AppState/Processor Aware ===
=== Terrain Aware ===

  • If Terrain are attached in the List, cares should be taken: LOD, consider Terrain a big Mesh, extract just few tiles from the TerrainQuad.
    I have another kind of Terrain, made from block (not cube), it’s like War-craft style. The way my DecalMesh hook into such ExTerrain system and also current Terrain system is to communicate with them via a TerrainAdaptor , an interface in which spatial learn about general characterics of terrain and adapt. It has the same idea with ManagedSpatial in @tonegod general LOD system.

=== LOD Control ===

  • As said above, by default, the DecalControl should aware of LODControl of Terrain or normal Spatial.
    === Animation Control ===
  • This one is great, if DecalControl can corporate with AnimControl.
    === AppState ===
  • As this going big, we should make a whole AppState ready to manage and cleanup the Decals in case.
    === Other libs ===
  • As in other libs, like Forestor, the author also want to corporate imposters and decal to his vegetable system. To make sure, thousand of Decals wont cause a performance issue can corprate seamlessly to thoose libs. Now consider 2 levels of integration, simple to complicated as we go on in development road.
    At first, they should live well together.
    ++ Know each other for example: can be notified of changes and update by Forestor or its alike.
    ++ Live in the same time, means the same thread, same phase of logic’s update. No cross reference issuses.
    That’s the simplest integration. Further:
    ++ As thing go even bigger, I tent to corportate my incubation research project- TopoMesh library, focus in robust way to create LOD, optimize, tessalation, and creating geometric mesh [loft,lattice,slice,boolean operation] in JME. This can not be use in current JME because we don’t have Geometry shader and its requirement yet. Consider its a future promising feature, because in fact, my DecalMesh is in one package in this lib.
    == Deferred rendering==
    Yes, Decal and DR are very cool things to sit together. :stuck_out_tongue: Just saying. I don’t have any plan on investigate more in DR for now, but have my own demo other than ones from @kwando and his teammate.

It can also project Arbitrary Poligon into Arbitrary Surfaces! Not just a cropped plane as a Trick like we doing here!

In conlusion, some important things above are not so hard, in fact few more classes to your code and we ready to go. Few others are just promising features, I also thought we don’t even need it in real game but we should think about it from design step.

Glad to hear your opinions,

Cheers,

My decal mesh generator just generates a mesh of the target geometry that is hit by the decal projector “camera”. In the bullet hole video demo, I simply attach this mesh to a geometry with a standard Lighting material. The material has the bullet hole diffuse, specular and normal map with an appropriate alpha threshold. The geometry is then attached to a BatchNode. Since all bullet holes use the same material, they are batchable to a single mesh and should require just one draw call.

If you want to blend between the original and the decal material textures, you have to use the extended decal mesh generator that also delivers the original texture coordinates in TexCoords2 and create a shader that does the blending. Maybe I’ll create such a shader and package it with the module / plugin in the future.

Since I’m not a quick coder, I focus on basic stuff and try to use as much of the engine and sdk as possible. Someone with fast fingers can then use it to create something awesome (or say “this is all crap, I’ll do it completely different”). I think decals work a bit different when it comes to Deferred Rendering (see here). Thanks for sharing your ideas though.

Regards

I’ve know about that decal mesh a generate arcording to the box represent the fustum of its camera, but is it more appropriate to have “shotable” geometry list, in which some geometry can be “damage”, some not. Futher, above visual meaning, it’s also away to decrease the travel cost need to generate decal mesh. That’s the idea behind GeometryList i mentioned.

So, I will wait for the release… Another great contribution (if I not repeat my self) , congratulation!!!

Of course I have this “TargetGeometryList”. Sorry for being unclear in this case.

[java]
public IP[] createInputs(final Spatial spatial)
{
List<IP> inputs = new ArrayList<IP>();
this.fillInputsList(inputs, spatial);
IP[] result = createInputs(inputs.size());
return inputs.toArray(result);
}

public IP[] createInputs(final List<Spatial> spatials)
{
List<IP> inputs = new ArrayList<IP>();
for (Spatial spatial : spatials)
{
this.fillInputsList(inputs, spatial);
}

return (IP[])inputs.toArray();

}

public void fillInputsList(final List<IP> inputs, final Spatial spatial)
{
if (spatial instanceof Node)
{
Node node = (Node) spatial;
for (Spatial sp : node.getChildren())
{
this.fillInputsList(inputs, sp);
}
}
else if (spatial instanceof Geometry)
{
Geometry geom = (Geometry) spatial;
Mesh mesh = geom.getMesh();
if (mesh.getMode() == Mesh.Mode.Triangles)
{
inputs.add(this.createInputCore(geom, mesh));
}
else
{
logger.log(Level.WARNING, “{0} not (yet) supported!”, mesh.getMode().name());
}
}
}

protected IP createInputCore(final Geometry geom, final Mesh mesh)
{
IP inp = this.createInput();
inp.IndexData = IndexBuffer.wrapIndexBuffer(mesh.getBuffer(VertexBuffer.Type.Index).getDataReadOnly());
inp.PositionData = (FloatBuffer) mesh.getBuffer(VertexBuffer.Type.Position).getDataReadOnly();
inp.NormalData = (FloatBuffer) mesh.getBuffer(VertexBuffer.Type.Normal).getDataReadOnly();
inp.WorldMatrix = geom.getWorldMatrix().clone();
if (inp.IndexData.size() % 3 != 0)
{
logger.warning(“IndexBuffer corrupt!”);
}

return inp;

}
[/java]

As you can see, I’m making heavy use of generics (“IP[]”) to be extensible. But this comes at the price of a bit messy code. My plan is to clean it up before release (ETA one month). But I might move to my google code jme repo, so you can see it sooner.

Edit: Here you can see the overriden method of the extendend decal mesh generator that delivers the original texture coordinates in TexCoord2. Of cource, IP is different than before. It’s extended by the field “TexCoordData”.
[java]
@Override
protected IP createInputCore(final Geometry geom, final Mesh mesh)
{
IP inp = super.createInputCore(geom, mesh);
inp.TexCoordData = (FloatBuffer) mesh.getBuffer(VertexBuffer.Type.TexCoord).getDataReadOnly();
return inp;
}
[/java]

I had an interesting thought.

It should be possible to use the new particle system to generate decals quite easily simply by emitting a particle in the location for the decal to appear, pointing in the direction of the normal, and pushed forwards slightly on the normal to move it in front of the thing getting the decals.

That way you wouldn’t need to create a mesh for the target, it just creates a quad for each bullet hole or whatever.

That might be a good solution for shooting bullet holes into flat walls, but when it comes to complex geometry, there’s no other way (except projective texture mapping which costs a draw call per decal).

<cite>@zarch said:</cite> It should be possible to use the new particle system to generate decals quite easily simply by emitting a particle in the location for the decal to appear, pointing in the direction of the normal, and pushed forwards slightly on the normal to move it in front of the thing getting the decals.

That way you wouldn’t need to create a mesh for the target, it just creates a quad for each bullet hole or whatever.

Instead of pushing it along normal, poly offset can be used. Anyway, this will work only for decals on flat surfaces, like bullet holes in the wall. Think about decals like blood splashes on terrain/models - they need to follow original geometry.

Yes, I use poly offset in the bullet hole demo, but there’s also an option to offset the decal in projector direction (or doing anything you want by overriding certain methods). But I’m still experimenting with some kind of small random offset to prevent z-fighting when shooting like 10 overlapping bullet holes. Since poly offset is a material parameter, it’s the same for all bullet holes (since the use they same material).

<cite>@abies said:</cite> Instead of pushing it along normal, poly offset can be used. Anyway, this will work only for decals on flat surfaces, like bullet holes in the wall. Think about decals like blood splashes on terrain/models - they need to follow original geometry.

Yes, that’s a good point. I was just trying to think of a way to simplify things :slight_smile:

You could still do it in the new particle system but the gains are much less obvious in this case.

@survivor :
Quick one: My first thought about the code above in the sense of modulizing and extensible, you certainly will need a general BufferUtil corporate with Mesh functions. I also do one and it was the start of the TopoMesh library. Embed too detail of low level operation into specific DecalMesh is not a wise choice.

The IP[] is fine, but why not more 1.5 Java feature? As I said, the API for user should use a list, and you use Array internally. Anyway, I think you are thoughtful enough to realize this a bit messy like you said. :stuck_out_tongue:

Poly offset: Don’t use it. But modify your projector paramaters a little bit for each shoot. This also mentioned in the Game Graphics Gem 2 I’ve mentioned. The point is the Depth image of hardware has float resolution issuses, therefore not a good choice. That’s why we should do it pre-phase in CPU calculating. If you want I can send you that code.

Thanks

Poly offset: Don't use it. But modify your projector paramaters a little bit for each shoot. This also mentioned in the Game Graphics Gem 2 I've mentioned. The point is the Depth image of hardware has float resolution issuses, therefore not a good choice. That's why we should do it pre-phase in CPU calculating. If you want I can send you that code.

I had to give up on polygonOffset, because for some magic reason, any negative displacement (to bring decals to front) was making them very dark. I ended up with hacky

[java]
#ifdef DECAL
gl_Position = g_WorldViewProjectionMatrix * modelSpacePos + vec4(0,0,-0.0001,0);
#else
gl_Position = g_WorldViewProjectionMatrix * modelSpacePos;
#endif
[/java]
instead, which is bad, but probably enough for me to survive till proper decal system is available.

Surely that will only work in one direction? Try shooting the back of an object…

Your direction are good but not the math. You can not just add a vector (fixed direction) to another vector after it projected.
I think I should send you the orginal code of the calculation.
[java]
//============================================================================
//
// Listing 9.1
//
// Mathematics for 3D Game Programming and Computer Graphics, 3rd ed.
// By Eric Lengyel
//
// The code in this file may be freely used in any software. It is provided
// as-is, with no warranty of any kind.
//
//============================================================================

void LoadOffsetMatrix(float l, float r, float b, float t,
float n, float f, float delta, float pz)
{
float matrix[16];

// Set up standard perspective projection.
glMatrixMode(GL_PROJECTION);
glFrustum(l, r, b, t, n, f);

// Retrieve the projection matrix.
glGetFloatv(GL_PROJECTION_MATRIX, matrix);

// Calculate epsilon with Equation (9.7).
float epsilon = –2.0F * f * n * delta / ((f + n) * pz * (pz + delta));

// Modify entry (3,3) of the projection matrix.
matrix[10] *= 1.0F + epsilon;

// Send the projection matrix back to OpenGL.
glLoadMatrix(matrix);

}
[/java]

The explanation can be found in Mathematics for 3D Game Programming and Computer Graphics, Second Edition. Chapter 9.
Happy coding!

Assuming that f and n are known and constant (after all, I control them in game), the real difference is that instead of doing positon.z += epsilon, I’m suposed to do position.z *= (1+epsilon) ? All the rest of computation is just making code generic enough it works with any kind of frustrum parameters?

oops,
glFrustum(l, r, b, t, n, f);
left right bottom top near far :stuck_out_tongue: was it not obviously? I guess you never do C++ openGL yet. so no problem, clearer now dude?

The diffirent that the guy only change the 3,3 position in the 4x4 matrix, so call the projection matrix is a good way to optimize calculation, that’s all, you don’t have to do a whole Matrix multiply Matrix.

Hello,

is this cool generator or sourcecode for it anywhere available :)?

1 Like