Geometry Batches

Fixed, thanks.



Edit: Well, not quite… having trouble communicating with CVS server. It will be fixed as soon as it lets me.

I'm not coding 3D gfx since long time,

but found this general describtion on problems with too many batches (see point 1.2):

http://www.ogre3d.org/wiki/index.php/CommonMistakes#Performance



but I did not see any performance hits, perhaps because I am using single batch meshes only up to now.

Well, don't use too many batches. But it's still more efficient to use 25.000 batches divided over 1.000 spatials than it is to use 25.000 spatials with 1 batch each. (That is, once the render queue system will understand batches, or if you use batches with the same TextureState as their patent)



It's not like because we didn't have a "batch" system, spatials didn't suffer from the same type of overhead OGRE talks of.

so, to understand the problem:

is a batch a number of triangles that use the same render states and are send together to the hardware renderer?



that would explain a lot…

Yes.


Huh, i just updated from CVS, and i must say it was not a happy surprise. Batches are nice basically, but they have become Geometry, and TriMesh begins to look like Node. Why do batches need bounds? Wasn't it supposed to be a unseparable sub-part of a mesh, rendered a bit differently? Previously it was awkward to put textured triangle lists into separate TriMeshes, because of added burden of fragmented bounds, etc. With batches bounds needed not be at triangle list level and drawing of batches was a tight loop. I understand some of this is necessary for queuing and sharing of batches, but right now batches have all the overhead which TriMesh had before batches. I'd like to know in which direction the development of TriangleBatch will go? I have a bad feeling, i have to rewrite (again) my model code, if i want to stay in sync with CVS.  :( Have to drink a bier now.

http://www.jmonkeyengine.com/jmeforum/index.php?topic=3105.msg25327#msg25327



This is still something in progress… and it probably won't remain this "heavy". There will be more in discussion on this I assume.



As for breaking your code, batches have always been experimental. So… expect that to happen till they become a stable feature.

Speaking of which, get ready for a dump…



There is a big caveat here, CloneCreator is incredibly broken now, and it was a mess to begin with. So, it has been removed. We have plans for this, but for the time being it got yanked.



So, anyways, on topic:



The latest batch extends SceneElement which Spatial also extends. This removes a significant amount of overhead (only the required elements are in SceneElement (which Spatial also extends now).



The bounds were added to better support the render queue sorting for multiple transparent batches, as well as providing the ability to cull batches efficiently.



I'll check in soon.

Trust me, it is not fun to rewrite Batch code multiple times… I know!  Hopefully this is the last major rewrite.  (yes, there will still be bugs…)

CVS giving issues… partial commit, don't update until further notice.

checked in, those using CloneCreator, speak up and we will come up with a solution.

http://www.jmonkeyengine.com/jmeforum/index.php?topic=3276.0



Well, at least now I know that you have issues as well. The old code is broken and in the current one it's removed?



I need at least a "clone everything" method or otherwise I would have to load the same model over and over.

Use SharedNode/SharedMesh/SharedBatch



Also, the old clone code snaked it's way through many of the classes…  If we want a similar system to selective cloning going forward, I believe we could make use of the new Importer/Exporter code since it already contains the field names, defaults and so forth.

I cannot see how SharedNode is supposed to work with animated models. Before I rewrite my model loading code can someone confirm that there are independant instances of controllers on SharedNode?



No luck with SharedNode, there seems to be only one controller on the source node. I changed my code to reload the model for each instance and that works as expected.

A cloning function or a SharedMeshWithControllers would be nice to create masses of animated models.

We can probably leverage the JmeExporter and JmeImporter system for cloning… i.e. rather than saving out to binary, create a copy.



However, SharedMesh/Node/Batch should probably be extended to allow sharing of some items and cloning of others.

Upto 0.10 I found the intersection with


                rootNode.findPick(lineOfSight, bpr);
                for (int i = 0; i < bpr.getNumber(); i++) {
                        TriMesh mesh = (TriMesh)bpr.getPickData(i).getTargetMesh();
                        Vector3f trans = mesh.getWorldTranslation();
                        if (bpr.getPickData(i).getTargetTris().size() > 0) {
                                ArrayList al = bpr.getPickData(i).getTargetTris();
                                Vector3f res = new Vector3f();
                                try {
                                        for (Object j : al) {
                                                mesh.getTriangle((Integer)j, vertices);
                                                if (vertices == null || vertices.length < 3)
                                                        continue;
                                                for (int v = 0; v < 3; v++)
                                                        vertices[v].addLocal(trans);
                                                if (lineOfSight.intersectWhere(vertices[0], vertices[1], vertices[2], res)) {
                                                        float dist = res.subtract(cam.getLocation()).length();
                                                        if (dist < nearestTarget) {
                                                                nearestTarget = dist;
                                                                inTarget = mesh.getParent();
                                                                sceneTarget = res;
                                                        }
                                                }
                                        }
                                } catch (Exception e) {
                                        _log.log(Level.WARNING, "getTargetNodeDistance", e);
                                }
                        }
                }


but with the latest changes this works no longer. Finding the target mesh is not the problem, but how can I get the points where the intersection occured?

Found out some more details:



This code never returns any triangles with latest jME but it worked before:


      TrianglePickResults bpr = new TrianglePickResults();
      bpr.setCheckDistance(true);
      inTarget = null;
      playerBounds.setIsCollidable(false);
      rootNode.findPick(lineOfSight, bpr);
      _log.fine("lineOfSight=" + lineOfSight.getOrigin() + "->" + lineOfSight.getDirection());
      for (int i = 0; i < bpr.getNumber(); i++) {
         float dist = bpr.getPickData(i).getDistance();
         int triangles = 0;
         if (bpr.getPickData(i).getTargetTris() != null)
            triangles = bpr.getPickData(i).getTargetTris().size();
         _log.fine("found " + pathOf(bpr.getPickData(i).getTargetMesh()) + " at dist " + dist
               + ", triangles=" + triangles);
         if (dist < nearestTarget && dist > 0.5) {
            inTarget = (Node)bpr.getPickData(i).getTargetMesh().parentGeom.getParent();
            nearestTarget = dist;
         }



Edit: jmetest.intersection.TestOBBPick NPE on click so this is not only a problem in my application.

I'm on it Galun…  Thanks for bringing it up!

Got the test working.  Let me know if you still have problems Galun.

It looks much better, thanks for having a look.



Sometimes it gets an exception but my height over terrain function works again.



This is the exception I just got:


java.lang.NullPointerException
        at com.jme.scene.batch.TriangleBatch.findTrianglePick(TriangleBatch.java:313)
        at com.jme.intersection.TrianglePickResults.addPick(TrianglePickResults.java:79)
        at com.jme.scene.batch.GeomBatch.findPick(GeomBatch.java:454)
        at com.jme.scene.Geometry.findPick(Geometry.java:583)
        at com.jme.scene.Node.findPick(Node.java:609)
        at com.jme.scene.Node.findPick(Node.java:609)
        at com.jme.scene.Node.findPick(Node.java:609)
        at com.jme.scene.Node.findPick(Node.java:609)
        at de.worldofmystery.client.Client.getTargetNodeDistance(Client.java:861)
        at de.worldofmystery.client.Client.getTargetNodeDistance(Client.java:851)
        at de.worldofmystery.client.Client.onMouseButtonClicked(Client.java:526)
        at de.worldofmystery.client.Client.onButton(Client.java:1163)
        at com.jme.input.lwjgl.LWJGLMouseInput.update(LWJGLMouseInput.java:201)
        at com.jme.input.InputSystem.update(InputSystem.java:67)
        at com.jme.app.BaseGame.start(BaseGame.java:63)
        at de.worldofmystery.client.Client.main(Client.java:161)


It looks like it tries to access a null pointer with batches but I haven't looked deep into it.