Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • 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 this unlit wireframe shader, which is a solid wireframe shader, which I read up on.

Here's the code:

 Shader "SuperSystems/Wireframe-Shaded-Unlit"
 {
     Properties
     {
         _MainTex ("MainTex", 2D) = "white" {}
         _WireThickness ("Wire Thickness", 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 _WireThickness;
             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 wireThickness = 800 - _WireThickness;
 
                 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 * wireThickness;
                 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 * wireThickness;
                 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 * wireThickness;
                 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 ((which 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 this shader for a custom mesh that I define in a script, so I could also use this 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 this 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 this 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 this:

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

we do this:

 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.

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

Where do I put this shader code? Getting weird error? 1 Answer

Fog not working in my Shader~ 0 Answers

Header for material properties in inspector? 2 Answers

Shader Color 1 Answer

Addition to Standard Shader stopping it from batching? 0 Answers


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