Level of Detail: Removing all triangles

Hey together,

I made some LODs for one geometry. But I noticed that I cannot remove ALL triangles, so that nothing of the geometry is rendered. When I make LODs and let’s say use PROPORTIONAL “mode” where you have to enter values between 0 and 1, the value 1 (= which should remove all triangles) is not “accepted” (same for CONSTANT mode) . This means the level is either ignored or becomes a level with the lowest count of triangles. The values in between do work and appear in the list after assigning the LODs to the mesh, except of that one level which should remove all triangles.

My goal is to create a LOD where all triangles are removed, so that the geometry is only visible at a certain distance (for example).

I think I can’t do this with LodGenerator because of the algorithm which is behind the Lod creation.

What I want to know is whether it is possible to create this “last” level afterwards. I would create LODs as usual and would add this “last” level afterwards with a control if possible.

I could extend / change the current LodControl for my needs. I have no idea how to “remove” the whole mesh though, except of setCullHint(Spatial.CullHint.Always); which seems pretty “brutal” for me.

Anyway, maybe someone from you does know how to do it in a proper way.

Greetings,
Domenic

Personally I think that’s how I would do it. Doing it this way makes it easy to make the spatial visible again, while if you want to remove the mesh or the index buffer (the link between the vertices), you would always have to keep it somewhere in memory to be able to make the spatial visible. I’m not sure whats “brutal” about using setCullHint(Spatial.CullHint.Always);

Hey, thanks for the quik answer. Maybe you are right, I just thought I could use the way the LODs are generated with index buffers and stuff like that. But I also think the easiest way for me at least is to create a control which handles this with cull hint. I will start working on that later and post the result!

LOD is not supposed to make your model disappear…
A lod level where all the triangles are removed is just and empty index buffer. Just add one in your lod buffer list.

Hey @nehon
What would be the correct way then? The way I talked about earlier or something else?

Yeah. The Cull Hint.
It’s not really brutal but possibly even more performant than a zero-index-buffer because several things aren’t done there (e.g. checking if it’s culled) and maybe even the sub-nodes (which are by default CullHint.Inherit) aren’t rendered, where a IndexBuffer is only possible for Geometries.

Another thing to mention though is the far clipping plane. Everything behind is automatically “culled” so you already have that 0-tri LoD Level, only farer away I guess
(Correct me if I’m wrong, but I guess that’s another thing)

Sorry, what exactly is this far clipping plane for?

I was right: It’s a parameter of the Camera Projection and it defines the visible range.
Even for non-german-speaking ppl the graphic might explain everything:

Edit: And I wanted to say that when you still need a LoD with 0 triangles, your far plane is too far away.
Or you only want to hide selective objects and not everything at that distance (e.g. the terrain should be visible but nothing else)

1 Like

Wow, thanks! Didn’t know you are German. Dankeschön mein Freund xD

1 Like

You can try that, there is no real “correct” way… just pick one that works.

Hey @nehon I extended your control a little bit. It does work with cull hint. Another cool thing is that I can now add the control directly as custom control to the geometry and can tweak the parameters for that model.

import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.LodControl;
import java.io.IOException;

/**
 * @author Domenic
 */
public class NewLodControl extends LodControl {

    private boolean canDisappear;
    private float disappearDistance;
    private Camera cam;

    public NewLodControl() {
        super();
    }    

    @Override
    protected void controlUpdate(float tpf) {
        if (canDisappear && cam != null) {
            if (spatial.getWorldTranslation().distance(cam.getLocation()) >= disappearDistance) {
                spatial.setCullHint(Spatial.CullHint.Always);
            } else if (spatial.getCullHint() == Spatial.CullHint.Always) {
                spatial.setCullHint(Spatial.CullHint.Inherit);
            }
        }
    }

    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {
        if (cam == null) {
            cam = vp.getCamera();
        }
        super.controlRender(rm, vp); 
    }

    /**
     * @return the canDisappear
     */
    public boolean isCanDisappear() {
        return canDisappear;
    }

    /**
     * @param canDisappear the canDisappear to set
     */
    public void setCanDisappear(boolean canDisappear) {
        this.canDisappear = canDisappear;
    }

    /**
     * @return the disappearDistance
     */
    public float getDisappearDistance() {
        return disappearDistance;
    }

    /**
     * @param disappearDistance the disappearDistance to set
     */
    public void setDisappearDistance(float disappearDistance) {
        this.disappearDistance = disappearDistance;
    }

    @Override
    public void write(JmeExporter ex) throws IOException {
        OutputCapsule capsule = ex.getCapsule(this);
        capsule.write(canDisappear, "canDisapear", false);
        capsule.write(disappearDistance, "disapearDistance", 50);
        super.write(ex); 
    }

    @Override
    public void read(JmeImporter im) throws IOException {
        InputCapsule capsule = im.getCapsule(this);
        canDisappear = capsule.readBoolean("canDisapear", false);
        disappearDistance = capsule.readFloat("disapearDistance", 50);
        super.read(im); 
    }    
}

By the way I had a look at the Mesh class and as it seems there is no getter method for that field:
private VertexBuffer[] lodLevels;