simpleUpdate is too slow? Or what am I doing wrong?

I have a problem and I don’t know exactly what I’m doing wrong, so I’m unsure where to begin to fix it. In simpleUpdate I am placing 8 boxes on each of the 8 corners of another box, and every tick I adjust those boxes so that when I move the first box, the 8 boxes update their position accordingly. The problem is that the 8 boxes seem to lag behind the bigger box when I move it. I have made a video to explain this: - YouTube

I know this can be easily accomplished by attaching the 8 boxes to the bigger box via nodes but I still want to know why I’m having an issue doing it this way.

Here is the code that shows how I am getting the positions of the 8 corners each tick:


corner1 = geomPos.add(geomRot.mult(new Vector3f(boundingBox.getXExtent(),boundingBox.getYExtent(),boundingBox.getZExtent())));
corner2 = geomPos.add(geomRot.mult(new Vector3f(boundingBox.getXExtent(),-boundingBox.getYExtent(),boundingBox.getZExtent())));
corner3 = geomPos.add(geomRot.mult(new Vector3f(-boundingBox.getXExtent(),boundingBox.getYExtent(),boundingBox.getZExtent())));
corner4 = geomPos.add(geomRot.mult(new Vector3f(-boundingBox.getXExtent(),-boundingBox.getYExtent(),boundingBox.getZExtent())));
corner5 = geomPos.add(geomRot.mult(new Vector3f(boundingBox.getXExtent(),boundingBox.getYExtent(),-boundingBox.getZExtent())));
corner6 = geomPos.add(geomRot.mult(new Vector3f(boundingBox.getXExtent(),-boundingBox.getYExtent(),-boundingBox.getZExtent())));
corner7 = geomPos.add(geomRot.mult(new Vector3f(-boundingBox.getXExtent(),boundingBox.getYExtent(),-boundingBox.getZExtent())));
corner8 = geomPos.add(geomRot.mult(new Vector3f(-boundingBox.getXExtent(),-boundingBox.getYExtent(),-boundingBox.getZExtent())));

Where geomPos is the WorldTranslation of the bigger box, geomRot is the WorldRotation of the bigger box, and boundingBox is the bigger box’s ModelBounds.

Any ideas?

Post the complete code please.

I hope this is enough. Here is the simpleUpdate method used to update the 8 boxes’ locations, or to show the blue highlight box if nothing currently selected:


public void simpleUpdate(float lastTimePerFrame)
{
    if(this.selectedEntity != null)
    {
        selectedEntity.updateGeometricState();
        selectedEntity.updateModelBound();
        
        BoundingBox boundingBox = (BoundingBox) selectedEntity //Gets the BoundingBox of the bigger box
                .getComponentByType(GeometryComponent.class)
                .getGeometry().getModelBound();
        Vector3f camTranslation = getParentEntity().getComponentByType( //Gets the players cameras World Translation.
                FirstPersonCameraComponent.class)
                .getWorldCameraTranslation();
        
        Vector3f corner1, corner2, corner3, corner4, corner5, corner6, corner7, corner8;
        
        Quaternion geomRot = selectedEntity.getComponentByType(GeometryComponent.class).getGeometry().getWorldRotation(); //Gets the bigger boxs World Rotation
        Vector3f geomPos = selectedEntity.getComponentByType(GeometryComponent.class).getGeometry().getWorldTranslation(); //Gets the bigger boxs World Translation
        
        corner1 = geomPos.add(geomRot.mult(new Vector3f(boundingBox.getXExtent(),boundingBox.getYExtent(),boundingBox.getZExtent())));
        corner2 = geomPos.add(geomRot.mult(new Vector3f(boundingBox.getXExtent(),-boundingBox.getYExtent(),boundingBox.getZExtent())));
        corner3 = geomPos.add(geomRot.mult(new Vector3f(-boundingBox.getXExtent(),boundingBox.getYExtent(),boundingBox.getZExtent())));
        corner4 = geomPos.add(geomRot.mult(new Vector3f(-boundingBox.getXExtent(),-boundingBox.getYExtent(),boundingBox.getZExtent())));
        corner5 = geomPos.add(geomRot.mult(new Vector3f(boundingBox.getXExtent(),boundingBox.getYExtent(),-boundingBox.getZExtent())));
        corner6 = geomPos.add(geomRot.mult(new Vector3f(boundingBox.getXExtent(),-boundingBox.getYExtent(),-boundingBox.getZExtent())));
        corner7 = geomPos.add(geomRot.mult(new Vector3f(-boundingBox.getXExtent(),boundingBox.getYExtent(),-boundingBox.getZExtent())));
        corner8 = geomPos.add(geomRot.mult(new Vector3f(-boundingBox.getXExtent(),-boundingBox.getYExtent(),-boundingBox.getZExtent())));
        
        if(cube1Geo != null)
        {
            cube1Geo.removeFromParent();
            cube2Geo.removeFromParent();
            cube3Geo.removeFromParent();
            cube4Geo.removeFromParent();
            cube5Geo.removeFromParent();
            cube6Geo.removeFromParent();
            cube7Geo.removeFromParent();
            cube8Geo.removeFromParent();
        }
        
        cube1Geo = IrisGame.instance.putShape(new Box(0.2f, 0.2f, 0.2f), ColorRGBA.Red);
        cube2Geo = IrisGame.instance.putShape(new Box(0.2f, 0.2f, 0.2f), ColorRGBA.Orange);
        cube3Geo = IrisGame.instance.putShape(new Box(0.2f, 0.2f, 0.2f), ColorRGBA.Yellow);
        cube4Geo = IrisGame.instance.putShape(new Box(0.2f, 0.2f, 0.2f), ColorRGBA.Green);
        cube5Geo = IrisGame.instance.putShape(new Box(0.2f, 0.2f, 0.2f), ColorRGBA.Cyan);
        cube6Geo = IrisGame.instance.putShape(new Box(0.2f, 0.2f, 0.2f), ColorRGBA.Blue);
        cube7Geo = IrisGame.instance.putShape(new Box(0.2f, 0.2f, 0.2f), ColorRGBA.Magenta);
        cube8Geo = IrisGame.instance.putShape(new Box(0.2f, 0.2f, 0.2f), ColorRGBA.Pink);
        
        cube1Geo.setLocalTranslation(corner1);
        cube2Geo.setLocalTranslation(corner2);
        cube3Geo.setLocalTranslation(corner3);
        cube4Geo.setLocalTranslation(corner4);
        cube5Geo.setLocalTranslation(corner5);
        cube6Geo.setLocalTranslation(corner6);
        cube7Geo.setLocalTranslation(corner7);
        cube8Geo.setLocalTranslation(corner8);
    }
    else
    { //This section just creates the highlight around the box which the crosshairs are hovered over.
        CollisionResults results = getCollisionResults();
        if(results.size() > 0)
        {
            CollisionResult closest = results.getClosestCollision();
            Geometry closestGeom = closest.getGeometry();
            if(tempHighlightGeom != null)
            {
                tempHighlightGeom.removeFromParent();
                tempHighlightGeom = null;
            }
            tempHighlightGeom = closestGeom.clone();
            tempHighlightGeom.scale(1.05f);
            
            Material wireMaterial = new Material(
                    IrisGame.instance.getAssetManager(),
                    "Common/MatDefs/Misc/Unshaded.j3md");
            wireMaterial.setColor("Color", new ColorRGBA(0f, 0f,
                    1f, 0.2f));
            wireMaterial.getAdditionalRenderState().setBlendMode(
                    BlendMode.Alpha);
            tempHighlightGeom.setMaterial(wireMaterial);
            tempHighlightGeom.setQueueBucket(Bucket.Translucent);
            
            IrisGame.instance.getRootNode().attachChild(
                    tempHighlightGeom);
        }
        else
        {
            if(tempHighlightGeom != null)
            {
                tempHighlightGeom.removeFromParent();
                tempHighlightGeom = null;
            }
        }
    }
}

If you need any other code let me know. The bigger box is attached to the player’s cameraNode when they click on it, so that’s how the big box follows the player as they turn.

OK, the problem is that you are using previous frame’s data for the current frame, that’s what causing the “lag”.


 selectedEntity.updateGeometricState();
 selectedEntity.updateModelBound();

This is not doing what you think it does.
First, calling updateModelBound here is useless because it’s called in updateGeometricState.
Then calling selectedEntity.updateGeometricState, won’t update its world transforms, because world transforms are computed from the parent node’s world transforms, and updateGeometricState was not called on the parent.
As a rule of thumb, calling updateGeometricState on a sub part of the scene graph is wrong in 99% of the cases. You should always call it on the root of the scene (most probably the rootNode here).

BUT calling updateGeometricState yourself on the rootNode is wrong 99% of the times (yeah doesn’t let you a lot of space to do right :stuck_out_tongue: ). This is done for you in the SimpleApplication.
In your case, calling rootNode.updateGeometricState() would work. But that’s wrong. Because it will still be called afterward, so you’ll do the work twice.

So yeah as you said, an obvious solution is to use a node and attach those boxes to it and let the engine do the work.

But if you really want to do it differently, you’d better use the simpleRender method and render your boxes on the spot instead of adding them to the scene graph.
At this moment the world transforms of the big box will be correctly updated with this frame data.
That’s how we usually render debug views in JME and what you’re trying to do looks a lot like this.

To render a stand alone (not attached to the scene-graph) geometry in the simpleRender you have to set its local transforms, then call updateGeometricState() on it, then call renderManager.renderGeometry(geom)

And if you want to be completely in the “right”, you should do this in an appState render() method.

That was extremely helpful. I understand what is going on now and where I am going wrong. Thank you so much!! :slight_smile: