How do I draw a Mesh entity that is always visible?

Note: the proposed solution is not natively supported and may not work in all scenarios and versions.

Before reading this article, please consider using the maintained solution to address the issue: Drawing entities above all others entities using TempEntities.

The following is a possible approach to create a Mesh entity that will be drawn over all other entities and will be always visible. As mentioned above, this method is not guaranteed to work in the future.

class OverlayMesh : Mesh
{
    public OverlayMesh(Mesh another) : base(another)
    {
    }

    protected override void Draw(DrawParams data)
    {
        data.RenderContext.PushDepthStencilState();

        // DepthTestAlways means that the depth testing (of the Z-buffer) when drawing the geometry always succeeds, 
        // so the last entity drawn goes over the previous geometries, regardless of its actual depth in the Z-buffer.
        data.RenderContext.SetState(depthStencilStateType.DepthTestAlways);

        base.Draw(data);

        data.RenderContext.PopDepthStencilState();
    }
}

If you are using a rendered display mode, you should override the Render method instead, and you will probably also need to disable shadows since they will not be computed correctly for the overlay mesh.

protected override void Render(RenderParams data)
{
    data.RenderContext.PushDepthStencilState();

    // DepthTestAlways means that the depth testing (of the Z-buffer) when drawing the geometry always succeeds, 
    // so the last entity drawn goes over the previous geometries, regardless of its actual depth in the Z-buffer.
    data.RenderContext.SetState(depthStencilStateType.DepthTestAlways);

    base.Draw(data);

    data.RenderContext.PopDepthStencilState();
}

The code above guarantees the mesh to be always displayed, but it is not sufficient. It is also necessary to prevent those faces which are not visible to the camera to be drawn. To do so we can set:

model1.Backface.ColorMethod = backfaceColorMethodType.Cull;

Here is a possible example, with a cylinder and a red sphere inside.

model1.Backface.ColorMethod = backfaceColorMethodType.Cull;

Mesh m1 = Mesh.CreateCylinder(10, 20, 20);
model1.Entities.Add(m1);

OverlayMesh m2 = new OverlayMesh(Mesh.CreateSphere(5, 5, 5));
m2.Translate(0, 0, 5);
model1.Entities.Add(m2, Color.Red);

model1.ActiveViewport.DisplayMode = displayType.Rendered;
model1.Rendered.ShadowMode = shadowType.None;

overall.gif

Please note that in order for this solution to work correctly, the overlay mesh has to be in the last position of the entity list. To move an entity to the last position you can use the code below.

protected void BringForward(Model model, Entity entity)
{
    // move the entity to the end of the list
    model.Entities.Remove(entity);
    model.Entities.Add(entity);
}

Limitations

This kind of solution has different downsides. First of all, the mesh faces being displayed are chosen based on their normals, without evaluating whether they should be visible or not. This can produce a wrong result, like the one shown in the image below.

mceclip0.png

Secondly, although it is possible to have multiple overlay entities, there will always be one that is displayed over the others, regardless of the position in space. The following picture shows two overlay arrows: the one in the back is wrongly shown over the one closer to the camera.

mceclip1.png

You may also want to read the article how do I draw a Line entity that would be shown above all other entities.

 

Was this article helpful?
0 out of 0 found this helpful
Have more questions? Submit a request

Comments

0 comments

Please sign in to leave a comment.