Hi, I’ve been trying to get a shader online that maintains a quad wireframe even if vertices are moved. I’m creating a low poly 3d modeling tool for mobile but I’ve been stuck trying to get quad wireframe but all of them don’t maintain quad when vertices are moved. They somehow revert to triangles when vertices are moved too far from each other.
I don’t want to dive deep into shaders but if I can’t get an answer here I feel like I might have to because I can figure out other stuff with this app like edge loops, Vertex editing and extruding but wireframes requires knowledge of shaders and I don’t want to have to learn all of that.
Here’s the script I’m working with
Shader "Custom/Geometry/Wireframe"
{
Properties
{
[PowerSlider(3.0)]
_WireframeVal ("Wireframe width", Range(0., 0.5)) = 0.05
_FrontColor ("Front color", color) = (1., 1., 1., 1.)
_BackColor ("Back color", color) = (1., 1., 1., 1.)
[Toggle] _RemoveDiag("Remove diagonals?", Float) = 0.
}
SubShader
{
Tags { "Queue"="Geometry" "RenderType"="Opaque" }
Pass
{
Cull Front
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma geometry geom
// Change "shader_feature" with "pragma_compile" if you want set this keyword from c# code
#pragma shader_feature __ _REMOVEDIAG_ON
#include "UnityCG.cginc"
struct v2g {
float4 worldPos : SV_POSITION;
};
struct g2f {
float4 pos : SV_POSITION;
float3 bary : TEXCOORD0;
};
v2g vert(appdata_base v) {
v2g o;
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
[maxvertexcount(3)]
void geom(triangle v2g IN[3], inout TriangleStream<g2f> triStream) {
float3 param = float3(0., 0., 0.);
#if _REMOVEDIAG_ON
float EdgeA = length(IN[0].worldPos - IN[1].worldPos);
float EdgeB = length(IN[1].worldPos - IN[2].worldPos);
float EdgeC = length(IN[2].worldPos - IN[0].worldPos);
if(EdgeA > EdgeB && EdgeA > EdgeC)
param.y = 1.;
else if (EdgeB > EdgeC && EdgeB > EdgeA)
param.x = 1.;
else
param.z = 1.;
#endif
g2f o;
o.pos = mul(UNITY_MATRIX_VP, IN[0].worldPos);
o.bary = float3(1., 0., 0.) + param;
triStream.Append(o);
o.pos = mul(UNITY_MATRIX_VP, IN[1].worldPos);
o.bary = float3(0., 0., 1.) + param;
triStream.Append(o);
o.pos = mul(UNITY_MATRIX_VP, IN[2].worldPos);
o.bary = float3(0., 1., 0.) + param;
triStream.Append(o);
}
float _WireframeVal;
fixed4 _BackColor;
fixed4 frag(g2f i) : SV_Target {
if(!any(bool3(i.bary.x < _WireframeVal, i.bary.y < _WireframeVal, i.bary.z < _WireframeVal)))
discard;
return _BackColor;
}
ENDCG
}
Pass
{
Cull Back
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma geometry geom
// Change "shader_feature" with "pragma_compile" if you want set this keyword from c# code
#pragma shader_feature __ _REMOVEDIAG_ON
#include "UnityCG.cginc"
struct v2g {
float4 worldPos : SV_POSITION;
};
struct g2f {
float4 pos : SV_POSITION;
float3 bary : TEXCOORD0;
};
v2g vert(appdata_base v) {
v2g o;
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
[maxvertexcount(3)]
void geom(triangle v2g IN[3], inout TriangleStream<g2f> triStream) {
float3 param = float3(0., 0., 0.);
#if _REMOVEDIAG_ON
float EdgeA = length(IN[0].worldPos - IN[1].worldPos);
float EdgeB = length(IN[1].worldPos - IN[2].worldPos);
float EdgeC = length(IN[2].worldPos - IN[0].worldPos);
if(EdgeA > EdgeB && EdgeA > EdgeC)
param.y = 1.;
else if (EdgeB > EdgeC && EdgeB > EdgeA)
param.x = 1.;
else
param.z = 1.;
#endif
g2f o;
o.pos = mul(UNITY_MATRIX_VP, IN[0].worldPos);
o.bary = float3(1., 0., 0.) + param;
triStream.Append(o);
o.pos = mul(UNITY_MATRIX_VP, IN[1].worldPos);
o.bary = float3(0., 0., 1.) + param;
triStream.Append(o);
o.pos = mul(UNITY_MATRIX_VP, IN[2].worldPos);
o.bary = float3(0., 1., 0.) + param;
triStream.Append(o);
}
float _WireframeVal;
fixed4 _FrontColor;
fixed4 frag(g2f i) : SV_Target {
if(!any(bool3(i.bary.x <= _WireframeVal, i.bary.y <= _WireframeVal, i.bary.z <= _WireframeVal)))
discard;
return _FrontColor;
}
ENDCG
}
}
}