Search Unity

Hidden-Edge Wireframe Shader?

Discussion in 'Shaders' started by AceTheSeeker, Dec 3, 2014.

  1. AceTheSeeker

    AceTheSeeker

    Joined:
    Dec 3, 2014
    Posts:
    6
    Hello I'm fairly new with Unity, I'll get right to the business.
    I wish to make a game (obviously) and I want it to be in wireframe, not in a standard wireframe mode, but in- what Blender 3D calls -"Hidden Wireframe" mode. I have attached an image of the wireframe mode in action. Blender 3D can (as far as I know) only do this in the "editing" state of modelling, aka not in the game-engine.
    What it does is it doesnt draw edges that are behind a face (so the faces look solid). We could of course cheat and make a material that has the same color as the sky/background and just add a wireframe shader on top of that.

    I suspected it should be fairly simple to write a shader that does wireframe like this. I wanted to see if it hadn't already been done, and as far as I could tell it hasn't exactly been done the way I need it. Blender also has this wireframe thing where if an edge is less than say, 45 degrees, it will not draw the edge. This can be nice on cylinders, or faces that have multiple triangles but together make a flat surface. This would be nice if it could be done in a shader as well.

    I'm not gonna act all smart, but I am not stupid. I know what it takes to make games, yet I struggle with textures so I resort to making a game in wireframe (which could look nice and/or unique). I have worked with Blender for over 5 years now and I have done lots of game models for source games and such (as practice)



    Desired Result (with the exception of the four edges that can be seen here but aren't visible in the first picture for Blender reasons)

    Any help is of course appreciated!
     
  2. mouurusai

    mouurusai

    Joined:
    Dec 2, 2011
    Posts:
    350
    You can do it with 2 sets of geometry. 1st geometry set should be drawn in standard mode, with shader which using "offset" parameter to "push" fragments out from camera, and also using "colormask" 0 (not draw in color buffer) but draw into z buffer. 2nd set should be drawn with "MeshTopology.Lines". It's little cumbersome but it's works.
    upd
    Of course you may achieve what you want with postprocess, but I think it's will be much more challenge.
     
    Last edited: Dec 4, 2014
    TomatoesNeverLie likes this.
  3. AceTheSeeker

    AceTheSeeker

    Joined:
    Dec 3, 2014
    Posts:
    6
    I'm sorry, I have absolutely no idea what you're talking about. I have looked around and nothing says anything about "offset parameters" or "colormask".
    I've made a material for my test-model which is a black diffuse shader that doesn't cast or receive shadows, nor does it have a specularity (it doesnt shine, its pitch-black) Then you suggested having a second version of the model which would be rendered using this "MeshTopology.Lines" which -by what I googled myself to- seems to be some script. I have no idea how to attach this script to the model to make it render in wireframe.
    As I mentioned, I'm new to Unity.
     
  4. Flailer

    Flailer

    Joined:
    Apr 1, 2014
    Posts:
    66
    It goes a bit into shader writing, if I'm not mistaking, mouurusai is saying, have one set with a very simple shader that only Z-writes, then draw the second mesh (as in create it yourself) using Meshtopology.lines, (this is scripting - not shader), this would get the wireframe overlay you want. Should work great.
     
  5. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Unity only draws triangles, though, not quads, so you won't be able to get results like that with a shader. If you require quads then there will need to be scripting involved.

    --Eric
     
  6. Flailer

    Flailer

    Joined:
    Apr 1, 2014
    Posts:
    66
  7. AceTheSeeker

    AceTheSeeker

    Joined:
    Dec 3, 2014
    Posts:
    6
    If I could tell Unity to look for edges that are above a certain degree and draw them as lines, that would be neat
     
  8. BBeck

    BBeck

    Joined:
    Jan 12, 2014
    Posts:
    57
    My understanding is that you want the object to be solid by have a wireframe look, like in the picture. The key difference being transparency. And if you've worked in wireframe, you know that seeing through the object can get very visually confusing.

    My first instinct is to merely texture the object as shown. Why not? If you make the texture the background color, Blender or whatever you are UV unwrapping with will export something pretty close to a wireframe for the exported UV texture. I did it just the other day and immediately applied the UV map and got something that looked kinda like what you have there before I actually painted the UV map. It looks to me like that could be a standard texture. Just make the texture color the same as the background color and draw edges in the right places (which should be easy since the UV map probably draws edges in those places already). You could make the edges as thick as you like.

    Now lighting it might be a bit non-standard. You probably want very flat lighting without any specular highlights and possibly not even reactive to lighting at all. For something that truly looks wireframe you would probably just use flat ambient light for the whole scene. In other words, you would have no lights at all. Just an ambient light equally illuminating everything.

    That's the approach I would take.

    Short of that you could probably do some sort of edge-detection shader. But simple is usually the way to go.
     
  9. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Because it will look like a texture on an object, not a wireframe. mouurusai's idea for two objects, one with a shader with colormask 0 (which accomplishes the hidden line removal), and one for the lines themselves, is the way to go.

    --Eric
     
  10. AceTheSeeker

    AceTheSeeker

    Joined:
    Dec 3, 2014
    Posts:
    6
    Yes, I thought so. My game will have extremely low vertex-counts on models and such so it should be no problem having to render the same objects twice. But I still can't find any explanation on how to use MeshTopology.Lines in a script, nor do I know exactly what you mean by "Colormask 0", is it like "0 0 0" in RGB (black)?
     
  11. mouurusai

    mouurusai

    Joined:
    Dec 2, 2011
    Posts:
    350
    http://gyazo.com/fec967446322bd298642a9893dae01d0
    Code (csharp):
    1.  
    2. using System.Linq;
    3. using UnityEngine;
    4.  
    5. public class InputController : MonoBehaviour
    6. {
    7.     private Material mat;
    8.  
    9.     void Start ()
    10.     {
    11.        Mesh oldMesh = GetComponent<MeshFilter>().mesh;
    12.  
    13.         Mesh newMesh = new Mesh();
    14.  
    15.        newMesh.vertices = oldMesh.vertices;
    16.  
    17.        int[] oldTris = oldMesh.triangles;
    18.         int[] indexes = new int[oldTris.Length*2];
    19.  
    20.         for (int i = 0, a = 0; i < oldTris.Length; i+=3)
    21.        {
    22.             indexes[a++] = oldTris[i];
    23.             indexes[a++] = oldTris[i + 1];
    24.             indexes[a++] = oldTris[i + 1];
    25.             indexes[a++] = oldTris[i + 2];
    26.             indexes[a++] = oldTris[i + 2];
    27.             indexes[a++] = oldTris[i];
    28.        }
    29.  
    30.         newMesh.SetIndices(indexes, MeshTopology.Lines, 0);
    31.  
    32.         GameObject newGo = new GameObject();
    33.        newGo.transform.position = transform.position;
    34.         MeshFilter newMeshFilter = newGo.AddComponent<MeshFilter>();
    35.         newMeshFilter.mesh = newMesh;
    36.        newGo.AddComponent<MeshRenderer>();
    37.        newGo.transform.parent = transform;
    38.  
    39.        AddMaterial();
    40.     }
    41.  
    42.     void AddMaterial()
    43.     {
    44.         string shaderText = "Shader \"DephOnly\" " +
    45.                             "{" +
    46.                                 "SubShader" +
    47.                                 "{" +
    48.                                     "pass" +
    49.                                     "{" +
    50.                                         "Tags" +
    51.                                         "{\"RenderType\"=\"Opaque\" \"Queue\"=\"Background\"}" +
    52.                                         "Zwrite on " +
    53.                                         "ColorMask 0" +
    54.                                         "Offset 0.5, 0.5" +
    55.                                     "}" +
    56.                                 "}" +
    57.                             "}";
    58.         GetComponent<MeshRenderer>().sharedMaterial = new Material(shaderText);
    59.     }
    60. }
    61.  
    62.  
     
    nicloay likes this.
  12. AceTheSeeker

    AceTheSeeker

    Joined:
    Dec 3, 2014
    Posts:
    6
    Thank you so much! I'm guessing there's gotta be a way for the script to see what color material the object already has? In order to then render the lines in that color, maybe? If not, then if I could at least change the color to white or black that would be neat. Lastly, are we sure there is no way for Unity to tell which edges have more "sharpness" in degrees than others? So we could sort out the flat edges and make quads and n-gons.
     
  13. mouurusai

    mouurusai

    Joined:
    Dec 2, 2011
    Posts:
    350
    Pink is default error material, i.e. it's pink because no materials on lined mesh, add one.
    You may try cull undesired fragments in shader, I'm not try.
    From my pov is easiest way is wrote some script for 3dsMax which import non hidden edges into file and parse them in unity.
     
  14. AceTheSeeker

    AceTheSeeker

    Joined:
    Dec 3, 2014
    Posts:
    6
    I might be able to live with the triangles.
    Anyway the script works lovely, it now takes whatever material the object has and applies it to the script-made object (the lines) Thanks for the help everybody!