Add/Remove glow from Spatial

I’ve got a Spatial which is controlled by a CharacterControl. I’m trying to set up a system whereby the character will glow when the mouse hovers and stop glowing when the mouse moves. I’ve seen several suggestions on how to do this and I’m hung up trying to implement one.

Here’s what I’ve got in my update loop:


Vector3f origin = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.0f);
Vector3f direction = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.3f);
direction.subtractLocal(origin).normalizeLocal();
Ray ray = new Ray(origin, direction);
CollisionResults results = new CollisionResults();
currentZone.collideWith(ray, results);

    highlightedSpatial.removeLight(ambientLight);
    if (results.size() != 0) {
        results.getClosestCollision().getGeometry().getParent().addLight(ambientLight);
       resultsToUse.getClosestCollision().getGeometry().getMaterial().setColor("GlowColor", ColorRGBA.Yellow);
        highlightedSpatial = results.getClosestCollision().getGeometry().getParent();
    }

That successfully adds/remove the ambient light and will add the GlowColor to a material on hover. However, the model (Sinbad) has multiple materials and the whole model does not glow on hover, just the bit you happened to hover on. Also, I cannot for the life of me figure out how to remove the GlowColor.

For reference, I’m creating the character Spatial in a pretty standard way: npcBobControl = new NpcControl(bulletAppState); npcBobSpatial = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.j3o"); npcBobSpatial.scale(0.5f, 0.5f, 0.5f); npcBobSpatial.setLocalTranslation(npcBobControl.getNpcStartingPosition()); npcBobSpatial.setName("bob"); npcBobSpatial.addControl(new NpcControl(bulletAppState)); npcNode.attachChild(npcSpatial);

Also, in case anyone else wants to try this in the future, here’s how I set up the glow during initialization:

ambientLight.setColor(ColorRGBA.Yellow);
FilterPostProcessor fpp=new FilterPostProcessor(assetManager);
BloomFilter bloom= new BloomFilter(BloomFilter.GlowMode.Objects);
fpp.addFilter(bloom);
viewPort.addProcessor(fpp);

Can anyone help me out? Thanks.

If you want to add it to all of the sinbad, then you’ll need to get the top most node of sinbad, and traverse all geometries and set the glow color on all of them. To remove the glow color material.clearParm(“GlowColor”), should work, although I’ve never actually tried removing a parameter. I think setting it to ColorRGBA.BLACK would work as well, if I remember correctly.

That’s exactly what I’ve been trying to do. For example, the following:

for(Spatial child : node.getChildren()){
child.getMaterial.setColor(“GlowColor”, ColorRGBA.Yellow);
}

Spatial is what getChildren returns but it does not have a getMaterial() method, so that’s not working. I’m sure there’s a better way to do this, I just don’t know it.

Also, how do I get the Material of my highlightedSpatial in order to clear its GlowColor param?

Thanks for your help.

only Geometries have a material. Theres a scene graph traversal method, you can use to work on all the geometries of a node:

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:traverse_scenegraph

I got this working. In case anyone in the future is interested in how, here’s what I did…


  private void highlightOnHover() {
        // Add glow to objects when the mouse hovers on them
        Vector3f origin = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.0f);
        Vector3f direction = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.3f);
        direction.subtractLocal(origin).normalizeLocal();
        Ray ray = new Ray(origin, direction);
        CollisionResults results = new CollisionResults();
        currentZone.collideWith(ray, results);
        // Remove the sky from the collision detection
        CollisionResults resultsToUse = new CollisionResults();
        for (CollisionResult collision : results) {
            if (!collision.getGeometry().getName().contains("sky") && !collision.getGeometry().getName().contains("level-geom")) {
                resultsToUse.addCollision(collision);
            }
        }

        if(resultsToUse.size() == 0 && glowIsOn) {
//            highlightedNode.removeLight(ambientLight);
            glowIsOn = false;
            highlightedNode.depthFirstTraversal(geometryGlowVisitor);
        } else if(resultsToUse.size() > 0) {
            glowIsOn = true;
            resultsToUse.getClosestCollision().getGeometry().getParent().depthFirstTraversal(geometryGlowVisitor);
//            resultsToUse.getClosestCollision().getGeometry().getParent().addLight(ambientLight);
            highlightedNode = resultsToUse.getClosestCollision().getGeometry().getParent();
        }
    }

    SceneGraphVisitorAdapter geometryGlowVisitor = new SceneGraphVisitorAdapter() {
        @Override
        public void visit(Geometry geom) {
            logger.info("visiting geomety " + geom.getName() + " with " + Boolean.toString(glowIsOn));
            if(glowIsOn) {
                geom.getMaterial().setColor("GlowColor", new ColorRGBA(0.7f, 0.7f, 0.6f, 1.0f));
            } else {
                geom.getMaterial().clearParam("GlowColor");
            }
        }
    };

Edit: I know some of this is hacky. This is just how I got it to work and it can easily be cleaned up a lot.

Depending on how your glow/bloom filter is configured it might be enough to just add a bright ambientlight to sinbad to highlight him.

1 Like