• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Nyhtian · Apr 07, 2020 at 07:09 AM · shadershadersshader programmingshader writingwireframe

Wireframe shader with constant width and no diagonals

Hello, I'm very new to shader code so forgive me for my ignorance.

I'm wanting to create a wireframe shader that has lines of constant width (in world or screenspace), as well as no diagonal lines, such that it generates quads instead of tris.

I tried to start basing my shader off of t$$anonymous$$s unlit wireframe shader, w$$anonymous$$ch is a solid wireframe shader, w$$anonymous$$ch I read up on.

Here's the code:

 Shader "SuperSystems/Wireframe-Shaded-Unlit"
 {
     Properties
     {
         _MainTex ("MainTex", 2D) = "w$$anonymous$$te" {}
         _WireT$$anonymous$$ckness ("Wire T$$anonymous$$ckness", RANGE(0, 800)) = 100
         _WireSmoothness ("Wire Smoothness", RANGE(0, 20)) = 3
         _WireColor ("Wire Color", Color) = (0.0, 1.0, 0.0, 1.0)
         _BaseColor ("Base Color", Color) = (0.0, 0.0, 0.0, 1.0)
     }
 
     SubShader
     {
         Tags {
             "RenderType"="Opaque"
         }
 
         Pass
         {
             // Wireframe shader based on the the following
             // http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf
 
             CGPROGRAM
             #pragma vertex vert
             #pragma geometry geom
             #pragma fragment frag
 
             #include "UnityCG.cginc"
 
             uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
             uniform float _WireT$$anonymous$$ckness;
             uniform float _WireSmoothness;
             uniform float4 _WireColor; 
             uniform float4 _BaseColor;
 
             struct appdata
             {
                 float4 vertex : POSITION;
                 float2 texcoord0 : TEXCOORD0;
                 UNITY_VERTEX_INPUT_INSTANCE_ID
             };
 
             struct v2g
             {
                 float4 projectionSpaceVertex : SV_POSITION;
                 float2 uv0 : TEXCOORD0;
                 float4 worldSpacePosition : TEXCOORD1;
                 UNITY_VERTEX_OUTPUT_STEREO
             };
 
             struct g2f
             {
                 float4 projectionSpaceVertex : SV_POSITION;
                 float2 uv0 : TEXCOORD0;
                 float4 worldSpacePosition : TEXCOORD1;
                 float4 dist : TEXCOORD2;
                 UNITY_VERTEX_OUTPUT_STEREO
             };
             
             v2g vert (appdata v)
             {
                 v2g o;
                 UNITY_SETUP_INSTANCE_ID(v);
                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                 o.projectionSpaceVertex = UnityObjectToClipPos(v.vertex);
                 o.worldSpacePosition = mul(unity_ObjectToWorld, v.vertex);
                 o.uv0 = TRANSFORM_TEX(v.texcoord0, _MainTex);
                 return o;
             }
             
             [maxvertexcount(3)]
             void geom(triangle v2g i[3], inout TriangleStream<g2f> triangleStream)
             {
                 float2 p0 = i[0].projectionSpaceVertex.xy / i[0].projectionSpaceVertex.w;
                 float2 p1 = i[1].projectionSpaceVertex.xy / i[1].projectionSpaceVertex.w;
                 float2 p2 = i[2].projectionSpaceVertex.xy / i[2].projectionSpaceVertex.w;
 
                 float2 edge0 = p2 - p1;
                 float2 edge1 = p2 - p0;
                 float2 edge2 = p1 - p0;
 
                 // To find the distance to the opposite edge, we take the
                 // formula for finding the area of a triangle Area = Base/2 * Height, 
                 // and solve for the Height = (Area * 2)/Base.
                 // We can get the area of a triangle by taking its cross product
                 // divided by 2.  However we can avoid dividing our area/base by 2
                 // since our cross product will already be double our area.
                 float area = abs(edge1.x * edge2.y - edge1.y * edge2.x);
                 float wireT$$anonymous$$ckness = 800 - _WireT$$anonymous$$ckness;
 
                 g2f o;
                 
                 o.uv0 = i[0].uv0;
                 o.worldSpacePosition = i[0].worldSpacePosition;
                 o.projectionSpaceVertex = i[0].projectionSpaceVertex;
                 o.dist.xyz = float3( (area / length(edge0)), 0.0, 0.0) * o.projectionSpaceVertex.w * wireT$$anonymous$$ckness;
                 o.dist.w = 1.0 / o.projectionSpaceVertex.w;
                 UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(i[0], o);
                 triangleStream.Append(o);
 
                 o.uv0 = i[1].uv0;
                 o.worldSpacePosition = i[1].worldSpacePosition;
                 o.projectionSpaceVertex = i[1].projectionSpaceVertex;
                 o.dist.xyz = float3(0.0, (area / length(edge1)), 0.0) * o.projectionSpaceVertex.w * wireT$$anonymous$$ckness;
                 o.dist.w = 1.0 / o.projectionSpaceVertex.w;
                 UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(i[1], o);
                 triangleStream.Append(o);
 
                 o.uv0 = i[2].uv0;
                 o.worldSpacePosition = i[2].worldSpacePosition;
                 o.projectionSpaceVertex = i[2].projectionSpaceVertex;
                 o.dist.xyz = float3(0.0, 0.0, (area / length(edge2))) * o.projectionSpaceVertex.w * wireT$$anonymous$$ckness;
                 o.dist.w = 1.0 / o.projectionSpaceVertex.w;
                 UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(i[2], o);
                 triangleStream.Append(o);
             }
 
             fixed4 frag (g2f i) : SV_Target
             {
                 float minDistanceToEdge = min(i.dist[0], min(i.dist[1], i.dist[2])) * i.dist[3];
 
                 float4 baseColor = _BaseColor * tex2D(_MainTex, i.uv0);
 
                 // Early out if we know we are not on a line segment.
                 if(minDistanceToEdge > 0.9)
                 {
                     return fixed4(baseColor.rgb,0);
                 }
 
                 // Smooth our line out
                 float t = exp2(_WireSmoothness * -1.0 * minDistanceToEdge * minDistanceToEdge);
                 fixed4 finalColor = lerp(baseColor, _WireColor, t);
                 finalColor.a = t;
 
                 return finalColor;
             }
             ENDCG
         }
     }
 }


I figured to get a constant width, I should multiply the minDistanceToEdge by the full length (in world space) of the barycentric axis that the minDistanceToEdge is derived from, to sort of 'un-normalise' it (if that makes any sense whatsoever). I'm not sure if that is correct, and if it is, then how to implement that.

In regard to removing the diagonals (apologies for the double question, I just didn't want to ask two seperate questions and then inevitably fail to consolidate the two scripts), I have seen solutions that do not display an edge based on its length (I am dealing with right-angles, so the hypotenuse ((w$$anonymous$$ch I do not want to display)) will always be the longest), however, in the nVidia paper, they describe not displaying an edge based on its index in the primitive. I am using t$$anonymous$$s shader for a custom mesh that I define in a script, so I could also use t$$anonymous$$s solution, however, again, I'm not too sure how to implement either of these options.
If anyone could help me out as a newbie in t$$anonymous$$s field, that would be greatly appreciated!

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by Bunny83 · Apr 09, 2020 at 11:20 AM

Well, I recommend to have a look at t$$anonymous$$s tutorial of Catlike coding. About removing the diagonal since we use barycentric coordinates we can simply ignore one of them. For example the implicit calculated "z". Now all we have to do is ensure the right "order" when we create our new triangle in the geometry shader. So make sure you calculate the barycentric coordinates the right way. The two vertices that are at each end of the longest line has to get the "1". The vertex opposite to the hypotenuse gets the (0, 0) coordinate.


When calculating the minBary value we just ignore z. However instead of t$$anonymous$$s:

 float minBary = min(barys.x, min(barys.y, barys.z));

we do t$$anonymous$$s:

 float minBary = min(barys.x, barys.y);

That should get rid of the longest line (if you ordered your vertices correctly in the geometry shader).

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

201 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Possible for a shader to have two decal slots? 2 Answers

Triplanar shaders that use the position and rotation of the attached object (or local Triplanar shaders) 0 Answers

CRT shader but NOT for camera 0 Answers

How can i add a alpha value to this shader? 1 Answer

Parse error: syntax error, unexpected '}' in line 69 with URP shader. 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges