Search code examples
xnashaderhlslvertexoutline

HLSL How to properly outline a flat-shaded model


I have a question and hope you can help me with it. I've been busy making a game with xna and have recently started getting into shaders (hlsl). There's this shader that i like, use, and would like to improve.

The shader creates an outline by drawing the back faces of a model (in black), and translating the vertex along its normal. Now, for a smooth-shaded model, this is fine. I, however, am using flat-shaded models (I'm posting this from my phone, but if anyone is confused about what that means, I can upload a picture later). This means that the vertices are translated along the normal of its corresponding face, resulting in visible gaps between the faces.

Now, the question is: is there a way to calculate (either in the shader or in xna), how i should translate each vertex, or is the only viable option just making a copy of the 3d model, but with smooth shading?

Thanks in advance, hope you can educate me!

EDIT: Alternatively, I could load only a smooth-shaded model, and try to flat-shade it in the shader. That would, however, mean that I have to be able to find the normals of all vertices of the corresponding face, add their normals, and normalize the result. Is there a way to do this?

EDIT2: So far, I've found a few options that don't seem to work in the end: setting "shademode" in hlsl is now deprecated. Setting the fillmode to "wireframe" would be neat (while culling front faces), if only I would be able to set the line thickness.

I'm working on a new idea here. I could maybe iterate through vertices, find their position on the screen, and draw 2d lines between those points using something like the RoundLine library. I'm going to try this, and see if it works.


Solution

  • Ok, I've been working on this problem for a while and found something that works quite nicely.

    Instead doing a lot of complex mathematics to draw 2d lines at the right depth, I simply did the following: Set a rasterizer state that culls front faces, draws in wireframe, and has a slightly negative depth bias. Now draw the model in all black (I modified my shader for this) Set a rasterizer state that culls back faces, draws in fillmode.solid and has a 0 depth bias. Now draw the model normally.

    Since we can't change the thickness of wireframe lines, we're left with a very slim outline. For my purposes, this was actually not too bad.

    I hope this information is useful to somebody later on.