Unity3d - How to show model edges in game? - unity3d

I want the same effect as the Unity editor when an object clicked, same as the top on the picture.
The camera view at bottom show that no any edges on model.
I google a bit, there are many topic about wireframe and edge detection, but i cant find anything useful about showing the inner edges.

You need a wireframe shader. That link is one of many (and free).
For your specific use-case, you also want...
Rendering the object normally while the wireframe is visible
Be able to enable/disable the wireframe
Which means you need a method of knowing what object is "selected" and enabling either a shader tag which you can set once or rendering the object a second time with a new material, but have to draw the object manually every frame.

Since I had same, I wrote custom shader.
Code Listing :
Shader "DESS/WireframeShader"
{
Properties
{
_WireColor("Edges Color", Color) = (0,0,0,1)
_WireThickness("Edge Thickness", RANGE(0, 800)) = 100
_WireSmoothness("Edge Smoothness", RANGE(0, 20)) = 3
_AlbedoColor("Albedo Color", Color) = (1,1,1,1)
_MainTex("Albedo (RGB)", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 200
Pass
{
CGPROGRAM
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
#include "UnityCG.cginc"
#pragma vertex vert
#pragma fragment frag
#pragma geometry geom
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
struct Input
{
float2 uv_MainTex;
};
fixed4 _WireColor;
fixed4 _AlbedoColor;
uniform float _WireThickness;
uniform float _WireSmoothness;
struct appdata
{
float4 vertex : POSITION;
float2 texcoord0 : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2g
{
float4 projSpaceVertex : SV_POSITION;
float2 uv0 : TEXCOORD0;
float4 worldSpacePosition : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
struct g2f
{
float4 projSpaceVertex : 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.projSpaceVertex = 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].projSpaceVertex.xy / i[0].projSpaceVertex.w;
float2 p1 = i[1].projSpaceVertex.xy / i[1].projSpaceVertex.w;
float2 p2 = i[2].projSpaceVertex.xy / i[2].projSpaceVertex.w;
float2 edge0 = p2 - p1;
float2 edge1 = p2 - p0;
float2 edge2 = p1 - p0;
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.projSpaceVertex = i[0].projSpaceVertex;
o.dist.xyz = float3((area / length(edge0)), 0.0, 0.0) * o.projSpaceVertex.w * wireThickness;
o.dist.w = 1.0 / o.projSpaceVertex.w;
UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(i[0], o);
triangleStream.Append(o);
o.uv0 = i[1].uv0;
o.worldSpacePosition = i[1].worldSpacePosition;
o.projSpaceVertex = i[1].projSpaceVertex;
o.dist.xyz = float3(0.0, (area / length(edge1)), 0.0) * o.projSpaceVertex.w * wireThickness;
o.dist.w = 1.0 / o.projSpaceVertex.w;
UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(i[1], o);
triangleStream.Append(o);
o.uv0 = i[2].uv0;
o.worldSpacePosition = i[2].worldSpacePosition;
o.projSpaceVertex = i[2].projSpaceVertex;
o.dist.xyz = float3(0.0, 0.0, (area / length(edge2))) * o.projSpaceVertex.w * wireThickness;
o.dist.w = 1.0 / o.projSpaceVertex.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 = _AlbedoColor * 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
}
}
FallBack "Diffuse"
}

Related

Something goes weird with my decals when I change FOV

I'm on v2019.4.30f1, am using the old render pipeline (i.e. not urp nor hdrp) and using the blood decals from this pack: https://assetstore.unity.com/packages/vfx/particles/volumetric-blood-fluids-173863
The blood decals are done at runtime, like when a play dies some blood spurts out and the decal is created.
Here is how the decal looks at FOV 20, and this is good, how I expect it to look:
Next if I merely change the camera FOV to 15 you'll see something goes really weird with the decal. There are parts that look like they are in the wrong place, almost like some parts have been shifted either up or left or whatever and some parts have been clipped off. But then other parts seems like they are still in the correct place:
If I switch back to FOV 20 again it looks normal again, so it doesn't seem like anything is changing with the decal itself when I change FOV, just that viewed from different FOV it looks completely different.
Here is a screenshot from scene view, showing the decal as well as some inspector info about it:
I've been tearing my hair out this entire week over this and can't seem to figure it out :/
Any advice would be much appreciated. Of course I can provide any other info required if there isn't enough to go on here.
edit: here is the decal shader
Shader "KriptoFX/BFX/BFX_Decal"
{
Properties
{
[HDR] _TintColor("Tint Color", Color) = (1,1,1,1)
_MainTex("NormalAlpha", 2D) = "white" {}
_LookupFade("Lookup Fade Texture", 2D) = "white" {}
_Cutout("Cutout", Range(0, 1)) = 1
_CutoutTex("CutoutDepth(XZ)", 2D) = "white" {}
[Space]
_SunPos("Sun Pos", Vector) = (1, 0.5, 1, 0)
}
SubShader
{
Tags{ "Queue" = "AlphaTest"}
Blend DstColor SrcColor
//Blend SrcAlpha OneMinusSrcAlpha
Cull Front
ZTest Always
ZWrite Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#pragma multi_compile_instancing
#pragma multi_compile _ USE_CUSTOM_DECAL_LAYERS
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _Flowmap;
sampler2D _LookupFade;
sampler2D _CutoutTex;
float4 _MainTex_ST;
float4 _MainTex_NextFrame;
float4 _CutoutTex_ST;
UNITY_INSTANCING_BUFFER_START(Props)
UNITY_DEFINE_INSTANCED_PROP(half4, _TintColor)
UNITY_DEFINE_INSTANCED_PROP(half, _Cutout)
UNITY_DEFINE_INSTANCED_PROP(float, _LightIntencity)
UNITY_INSTANCING_BUFFER_END(Props)
half4 _CutoutColor;
half4 _FresnelColor;
half4 _DistortionSpeedScale;
sampler2D _CameraDepthTexture;
sampler2D _LayerDecalDepthTexture;
half InterpolationValue;
half _AlphaPow;
half _DistortSpeed;
half _DistortScale;
float4 _SunPos;
half _DepthMul;
struct appdata_t {
float4 vertex : POSITION;
float4 normal : NORMAL;
half4 color : COLOR;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f {
float4 vertex : SV_POSITION;
half4 color : COLOR;
float4 screenUV : TEXCOORD0;
float3 ray : TEXCOORD1;
float3 viewDir : TEXCOORD2;
float4 screenPos : TEXCOORD3;
UNITY_FOG_COORDS(4)
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
v2f vert(appdata_t v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_TRANSFER_INSTANCE_ID(v, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.vertex = UnityObjectToClipPos(v.vertex);
o.color = v.color;
o.ray = UnityObjectToViewPos(v.vertex) * float3(-1, -1, 1);
o.screenUV = ComputeScreenPos(o.vertex);
o.viewDir = normalize(ObjSpaceViewDir(v.vertex));
o.screenPos = ComputeGrabScreenPos(o.vertex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
half4 frag(v2f i) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(i);
i.ray *= (_ProjectionParams.z / i.ray.z);
#if USE_CUSTOM_DECAL_LAYERS
float depth = Linear01Depth(tex2Dproj(_LayerDecalDepthTexture, i.screenUV));
float depthMask = Linear01Depth(tex2Dproj(_CameraDepthTexture, i.screenUV));
float fade = 1- saturate(100000 * (depth - depthMask));
#else
float depth = Linear01Depth(tex2Dproj(_CameraDepthTexture, i.screenUV));
#endif
float3 wpos = mul(unity_CameraToWorld, float4(i.ray * depth, 1)).xyz;
float3 opos = mul(unity_WorldToObject, float4(wpos, 1)).xyz;
float3 stepVal = saturate((0.5 - abs(opos.xyz)) * 10000);
half lookupHeight = tex2D(_LookupFade, float2(opos.y + 0.5, 0));
float projClipFade = stepVal.x * stepVal.y * stepVal.z * lookupHeight;
#if USE_CUSTOM_DECAL_LAYERS
projClipFade *= fade;
#endif
float2 uv = opos.xz + 0.5;
float2 uvMain = uv * _MainTex_ST.xy + _MainTex_ST.zw;
float2 uvCutout = (opos.xz + 0.5) * _CutoutTex_ST.xy + _CutoutTex_ST.zw;
half4 normAlpha = tex2D(_MainTex, uvMain);
half4 res = 0;
res.a = saturate(normAlpha.w * 2);
if (res.a < 0.1) discard;
normAlpha.xy = normAlpha.xy * 2 - 1;
float3 normal = normalize(float3(normAlpha.x, 1, normAlpha.y));
half3 mask = tex2D(_CutoutTex, uvCutout).xyz;
half cutout = 0.5 + UNITY_ACCESS_INSTANCED_PROP(Props, _Cutout) * i.color.a * 0.5;
half alphaMask = saturate((mask.r - (cutout * 2 - 1)) * 20) * res.a;
half colorMask = saturate((mask.r - (cutout * 2 - 1)) * 5) * res.a;
res.a = alphaMask;
res.a = saturate(res.a * projClipFade);
float intencity = UNITY_ACCESS_INSTANCED_PROP(Props, _LightIntencity);
float light = max(0.001, dot(normal, normalize(_SunPos.xyz)));
light = pow(light, 150) * 3 * intencity;
light *= (1 - mask.z * colorMask);
float4 tintColor = UNITY_ACCESS_INSTANCED_PROP(Props, _TintColor);
#if !UNITY_COLORSPACE_GAMMA
tintColor = tintColor * 1.35;
#endif
res.rgb = lerp(tintColor.rgb, tintColor.rgb * 0.25, mask.z * colorMask) + light;
half fresnel = (1 - dot(normal, normalize(i.viewDir)));
fresnel = pow(fresnel + 0.1, 5);
UNITY_APPLY_FOG_COLOR(i.fogCoord, res, half4(1, 1, 1, 1));
return lerp(0.5, res, res.a);
return res;
}
ENDCG
}
}
}
Comparing two pictures, I see that BFXShaderAnamation does some precomputation in the beginning of animation, and the results depend on camera settings and geometry. You should look for the code that does this initialization and call it again each time your camera settings or geometry change.
Idea: check if the decal plugin creates an additional hidden camera to do some computations (look into the hierarchy and search by "Camera" type).

Opacity in Unity Shader

I´m trying to make a shader which simulates a warp speed effect, and i think is almost done, only need to know what should i change in the code to make the tunnel effect completely opaque and not see anything behind the tunnel effect.
I have added an alpha slider to see if i can control opacity but still the same result at the end.
Code is here:
Shader "Warp Tunnel Distortion Opaque" {
Properties {
_TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
_Speed("UV Speed", Float) = 1.0
_WiggleX("_WiggleX", Float) = 1.0
_WiggleY("_WiggleY", Float) = 1.0
_WiggleDist("Wiggle distance", Float) = 1.0
_Offset("Vertex offset", float) = 0
_TintColor("Tint", Color) = (1.0, 1.0, 1.0, 1.0)
_MainTex("Distortion map", 2D) = "" {}
_Dist("Distortion ammount", Float) = 10.0
}
Category {
Tags { "Queue"="Geometry" "RenderType"="Opaque" }
Cull Back Lighting Off ZWrite Off
Fog { Color (0,0,0,0) }
ZTest LEqual
SubShader {
GrabPass {
Name "BASE"
Tags { "LightMode" = "Always" }
}
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_particles
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 _TintColor;
struct appdata_t {
float4 vertex : POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 normal : NORMAL;
};
struct v2f {
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 posWorld : TEXCOORD1;
float4 uvgrab : TEXCOORD2;
float4 projPos : TEXCOORD3;
};
float4 _MainTex_ST;
float _Speed;
float _WiggleX, _WiggleY, _WiggleDist;
float _Offset;
float _Dist;
sampler2D _CameraDepthTexture;
float _InvFade;
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
v2f vert (appdata_t v)
{
v2f o;
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
v.vertex.xyz += normalize(v.normal.xyz) * _Offset;
o.vertex = UnityObjectToClipPos(v.vertex);
o.vertex.x += sin(_Time.y * _WiggleX) * _WiggleDist;
o.vertex.y -= sin(_Time.y * _WiggleY) * _WiggleDist;
o.color = v.color;
o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
o.projPos = ComputeScreenPos (o.vertex);
COMPUTE_EYEDEPTH(o.projPos.z);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
i.texcoord.y += _Time.x * _Speed;
float4 packedTex = tex2D(_MainTex, i.texcoord);
float local1 = packedTex.z * 2.4;
float2 local2 = packedTex.rg * 2.25;
packedTex.rg = local1 * local2;
half2 bump = UnpackNormal(packedTex).rg;
float2 offset = bump * _Dist * _GrabTexture_TexelSize.xy;
i.uvgrab.xy = offset * i.uvgrab.z + i.uvgrab.xy;
half4 col = tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(i.uvgrab));
return col;
}
ENDCG
}
}
}
}
Thank you in advance.
Well if you want it completely opaque, that's easy.
Right before the return statement, just add:
col.a = 1;
If you want it to actually care about the alpha slider in the input color, then do this:
col.a = _TintColor.a;
In the first case, _TintColor isn't used at all (there are no other references to it besides its declaration, of which there are 2 at the top (you should remove one of them) and one inside the CGprogram block which links the first one to a property that can be used within the CGprogram).
If you actually want to tint things, you'll have to multiply the _TintColor with the computed color coming from the texture and effect. There are multiple ways of doing it, for example:
col.r *= _TintColor.r;
col.g *= _TintColor.g;
col.b *= _TintColor.b;
How you want to handle it is up to you.

How to change generated mask by texture mask?

I have a shader which generates opacity mask and rotate it.
This is how it looks:
Generated mask looks like this:
I generate a mask via code, but I want to take mask just from a texture2D.
How can I do that?
How do I change mask generating by only texture2D?
Code of my shader:
Shader "Custom/RadialOpacity" {
Properties {
[PerRendererData]_MainTex ("MainTex", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
_OpacityRotator ("Opacity Rotator", Range(-360, 360)) = -360 // 2 full circles
[HideInInspector]_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
}
SubShader {
Tags {
"IgnoreProjector"="True"
"Queue"="Transparent"
"RenderType"="Transparent"
"CanUseSpriteAtlas"="True"
"PreviewType"="Plane"
}
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
Blend One OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ PIXELSNAP_ON
#include "UnityCG.cginc"
#pragma target 3.0
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform float4 _Color;
uniform float _OpacityRotator;
static const float TAU = float(6.283185); // это 2 * PI
struct VertexInput {
float4 vertex : POSITION;
float2 texcoord0 : TEXCOORD0;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv0 : TEXCOORD0;
float3 normalDir : TEXCOORD2;
};
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.uv0 = v.texcoord0;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex );
#ifdef PIXELSNAP_ON
o.pos = UnityPixelSnap(o.pos);
#endif
return o;
}
float4 frag(VertexOutput i) : COLOR {
i.normalDir = normalize(i.normalDir);
float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
float2 oStart = (i.uv0 - 0.5);
float2 oVector = float2(-1, -1);
float oRotatorNormalized = _OpacityRotator / 360.0;
float oRotator_ang = oRotatorNormalized * -TAU;
float oRotator_cos = cos(oRotator_ang);
float oRotator_sin = sin(oRotator_ang);
float2x2 oRotationMatrix = float2x2(oRotator_cos, -oRotator_sin, oRotator_sin, oRotator_cos);
float2 oRotatorComponent = mul(oVector * oStart, oRotationMatrix);
/* generating opacity mask BEGIN_SECTION */
float2 oMaskHorizOrVert = atan2(oRotatorComponent.g, oRotatorComponent.r);
float oAtan2MaskNormalized = (oMaskHorizOrVert / TAU) + 0.5;
float oAtan2MaskRotatable = oRotatorNormalized - oAtan2MaskNormalized;
float oWhiteToBlackMask = ceil(oAtan2MaskRotatable);
/* generating opacity mask END_SECTION */
float oFinalMultiply = _MainTex_var.a * max(oAtan2MaskNormalized, ceil(oWhiteToBlackMask));
/*** (Emissive) ***/
float3 finalColor = _MainTex_var.rgb * _Color.rgb * oFinalMultiply;
return fixed4(finalColor, oFinalMultiply);
}
ENDCG
}
}
FallBack "Diffuse"
}
And I want to get something like that:
Properties {
...
_OpacityMask ("OpacityMask", 2D) = "white" {}
...
}
...
float oWhiteToBlackMask = ceil(OpacityMask);
float oFinalMultiply = _MainTex_var.a * max(oAtan2MaskNormalized, ceil(oWhiteToBlackMask));
...
https://forum.unity3d.com/threads/rotation-of-texture-uvs-directly-from-a-shader.150482/
Ok if I understand your question correctly, you want to add a texture 2D parameter and have it rotate. You'll need to rotate the UV coordinates over time, which you can probably accomplish using the code in the link above.
I'm not sure how you get that exact fade at the end with a texture 2D but maybe some clever usage of time you can figure out the animation.

How to draw circle in unity by shader and anti-aliasing

I have drawn a circle by shader, but I can't get anti-aliasing to work.
I tried finding an answer here http://answers.unity3d.com/questions/521984/how-do-you-draw-2d-circles-and-primitives.html, but I have to use discard to draw circle.
Here is a picture of my current shader result and the shader code:
Shader "Unlit/CircleSeletor"
{
Properties
{
_BoundColor("Bound Color", Color) = (1,1,1,1)
_BgColor("Background Color", Color) = (1,1,1,1)
_MainTex("Albedo (RGB)", 2D) = "white" {}
_BoundWidth("BoundWidth", float) = 10
_ComponentWidth("ComponentWidth", float) = 100
}
SubShader{
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag Lambert alpha
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
sampler2D _MainTex;
float _BoundWidth;
fixed4 _BoundColor;
fixed4 _BgColor;
float _ComponentWidth;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
float4 _MainTex_ST;
v2f vert(appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
float antialias(float w, float d, float r) {
return 1-(d-r-w/2)/(2*w);
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 c = tex2D(_MainTex,i.uv);
float x = i.uv.x;
float y = i.uv.y;
float dis = sqrt(pow((0.5 - x), 2) + pow((0.5 - y), 2));
if (dis > 0.5) {
discard;
} else {
float innerRadius = (_ComponentWidth * 0.5 - _BoundWidth) / _ComponentWidth;
if (dis > innerRadius) {
c = _BoundColor;
//c.a = c.a*antialias(_BoundWidth, dis, innerRadius);
}
else {
c = _BgColor;
}
}
return c;
}
ENDCG
}
}
}
It's really easy to apply anti-alias to a circle.
1.First, you need 3 variables to do this. Get the radius, distance of the circle. Also create a float value(let's called that borderSize) that can be used to determine how far the anti-alias should go. The radius, distance and borderSize are the three variables.
2.Find the t with smoothstep function using those 3 variables from #1.
float t = smoothstep(radius + borderSize, radius - borderSize, distance);
3.Mix the color before returning it.
Let's say that _BoundColor is the circle fill color and _BgColor is the background color.
If using GLSL using the mix function. If using Unity, use the lerp function. Both function are interchanging and the parameters are the-same.
col = lerp(_BoundColor, _BgColor, t);
The t is from #2. You can now return col in the fragment function.
These are the 3 steps put together:
if (dis > radius) {
float t = smoothstep(radius + borderSize, radius - borderSize, distance);
col = lerp(_BoundColor, _BgColor, t);
}
else {
float t = smoothstep(radius + borderSize, radius - borderSize, distance);
col = lerp(_BoundColor, _BgColor, t);
}
return col;
OUTPUT WITHOUT ANTI-ALIASING:
OUTPUT WITH ANTI-ALIASING(4.5 Threshold):
Finally, the whole code(Tested on PC and Android but should work on iOS too)
Shader "Unlit/Circle Anti-Aliasing"
{
Properties
{
_BoundColor("Bound Color", Color) = (0,0.5843137254901961,1,1)
_BgColor("Background Color", Color) = (0.1176470588235294,0,0.5882352941176471,1)
_circleSizePercent("Circle Size Percent", Range(0, 100)) = 50
_border("Anti Alias Border Threshold", Range(0.00001, 5)) = 0.01
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
float _border;
fixed4 _BoundColor;
fixed4 _BgColor;
float _circleSizePercent;
struct v2f
{
float2 uv : TEXCOORD0;
};
v2f vert(
float4 vertex : POSITION, // vertex position input
float2 uv : TEXCOORD0, // texture coordinate input
out float4 outpos : SV_POSITION // clip space position output
)
{
v2f o;
o.uv = uv;
outpos = UnityObjectToClipPos(vertex);
return o;
}
float2 antialias(float radius, float borderSize, float dist)
{
float t = smoothstep(radius + borderSize, radius - borderSize, dist);
return t;
}
fixed4 frag(v2f i, UNITY_VPOS_TYPE screenPos : VPOS) : SV_Target
{
float4 col;
float2 center = _ScreenParams.xy / 2;
float maxradius = length(center);
float radius = maxradius*(_circleSizePercent / 100);
float dis = distance(screenPos.xy, center);
if (dis > radius) {
float aliasVal = antialias(radius, _border, dis);
col = lerp(_BoundColor, _BgColor, aliasVal); //NOT needed but incluse just incase
}
else {
float aliasVal = antialias(radius, _border, dis);
col = lerp(_BoundColor, _BgColor, aliasVal);
}
return col;
}
ENDCG
}
}
}
Try this:
Shader "Unlit/CircleSeletor"
{
Properties
{
_BoundColor("Bound Color", Color) = (1,1,1,1)
_BgColor("Background Color", Color) = (1,1,1,1)
_MainTex("Albedo (RGB)", 2D) = "white" {}
_BoundWidth("BoundWidth", float) = 10
_ComponentWidth("ComponentWidth", float) = 100
}
SubShader
{
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag Lambert alpha
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
sampler2D _MainTex;
float _BoundWidth;
fixed4 _BoundColor;
fixed4 _BgColor;
float _ComponentWidth;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
float4 _MainTex_ST;
v2f vert(appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
float antialias(float w, float d, float r) {
return 1 - (d - r - w / 2) / (2 * w);
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 c = tex2D(_MainTex,i.uv);
float x = i.uv.x;
float y = i.uv.y;
float dis = sqrt(pow((0.5 - x), 2) + pow((0.5 - y), 2));
if (dis > 0.5) {
c.a = 0;
discard;
}
else {
float innerRadius = (_ComponentWidth * 0.5 - _BoundWidth) / _ComponentWidth;
if (dis > innerRadius) {
c = _BoundColor;
//c.a = c.a*antialias(_BoundWidth, dis, innerRadius);
}
else {
c = _BgColor;
}
}
return c;
}
ENDCG
}
GrabPass{
"_MainTex2"
}
Pass
{
Blend One zero
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
fixed4 color : COLOR;
};
struct v2f
{
float4 pos : SV_POSITION;
fixed4 color : COLOR;
float4 scrPos : TEXCOORD0;
};
float4 _MainTex_ST;
v2f vert(appdata v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.scrPos = ComputeScreenPos(o.pos);
o.color = v.color;
return o;
}
sampler2D _MainTex2;
float4 _MainTex2_TexelSize;
fixed4 frag(v2f i) : SV_Target
{
float2 uv = (i.scrPos.xy / i.scrPos.w);
fixed4 c = tex2D(_MainTex2, uv );
fixed4 up = tex2D(_MainTex2, uv + fixed2(0, _MainTex2_TexelSize.y));
fixed4 down = tex2D(_MainTex2, uv - fixed2(0, _MainTex2_TexelSize.y));
fixed4 left = tex2D(_MainTex2, uv - fixed2(_MainTex2_TexelSize.x, 0));
fixed4 right = tex2D(_MainTex2, uv + fixed2(_MainTex2_TexelSize.x, 0));
c.rgb = (c.rgb + up.rgb + down.rgb + left.rgb + right.rgb) / 5;
c.a = (c.a + up.a + down.a + left.a + right.a) / 5;
return c;
}
ENDCG
}
}
}
After first pass I GrabPass result and apply anti-alias in second pass by averaging border pixels.

CG/Unity: Toy Shader For Duplicating Object

I'm new to writing shaders and I'm working on a practice geometry shader. The goal of the shader is to make the "normal" pass produce transparent pixels such that the object is invisible, while the "geometry" pass will take each triangle, redraw in the same place as the original but colored black. Thus, I expect the output to be the original object, but black. However, my geometry pass seems to not produce any output I can see:
Here is the code I currently have for the shader.
Shader "Outlined/Silhouette2" {
Properties
{
_Color("Color", Color) = (0,0,0,1)
_MainColor("Main Color", Color) = (1,1,1,1)
_Thickness("Thickness", float) = 4
_MainTex("Main Texture", 2D) = "white" {}
}
SubShader
{
Tags{ "Queue" = "Geometry" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
Cull Back
ZTest always
Pass
{
Stencil{
Ref 1
Comp always
Pass replace
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct v2g
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 viewT : TANGENT;
float3 normals : NORMAL;
};
struct g2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 viewT : TANGENT;
float3 normals : NORMAL;
};
float4 _LightColor0;
sampler2D _MainTex;
float4 _MainColor;
v2g vert(appdata_base v)
{
v2g OUT;
OUT.pos = mul(UNITY_MATRIX_MVP, v.vertex);
OUT.uv = v.texcoord;
OUT.normals = v.normal;
OUT.viewT = ObjSpaceViewDir(v.vertex);
return OUT;
}
half4 frag(g2f IN) : COLOR
{
//this renders nothing, if you want the base mesh and color
//fill this in with a standard fragment shader calculation
float4 texColor = tex2D(_MainTex, IN.uv);
float3 normal = mul(float4(IN.normals, 0.0), _Object2World).xyz;
float3 normalDirection = normalize(normal);
float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz * -1);
float3 diffuse = _LightColor0.rgb * _MainColor.rgb * max(0.0, dot(normalDirection, lightDirection));
texColor = float4(diffuse,1) * texColor;
//
//return texColor;
return float4(0, 0, 0, 0);
}
ENDCG
}
Pass
{
Stencil{
Ref 0
Comp equal
}
CGPROGRAM
#include "UnityCG.cginc"
#pragma target 4.0
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
half4 _Color;
float _Thickness;
struct v2g
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 local_pos: TEXCOORD1;
float3 viewT : TANGENT;
float3 normals : NORMAL;
};
struct g2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 viewT : TANGENT;
float3 normals : NORMAL;
};
v2g vert(appdata_base v)
{
v2g OUT;
OUT.pos = mul(UNITY_MATRIX_MVP, v.vertex);
OUT.local_pos = v.vertex;
OUT.uv = v.texcoord;
OUT.normals = v.normal;
OUT.viewT = ObjSpaceViewDir(v.vertex);
return OUT;
}
[maxvertexcount(12)]
void geom(triangle v2g IN[3], inout TriangleStream<g2f> triStream)
{
g2f OUT;
OUT.pos = IN[0].pos;
OUT.uv = IN[0].uv;
OUT.viewT = IN[0].viewT;
OUT.normals = IN[0].normals;
triStream.Append(OUT);
OUT.pos = IN[1].pos;
OUT.uv = IN[1].uv;
OUT.viewT = IN[1].viewT;
OUT.normals = IN[1].normals;
triStream.Append(OUT);
OUT.pos = IN[2].pos;
OUT.uv = IN[2].uv;
OUT.viewT = IN[2].viewT;
OUT.normals = IN[2].normals;
triStream.Append(OUT);
}
half4 frag(g2f IN) : COLOR
{
_Color.a = 1;
return _Color;
}
ENDCG
}
}
FallBack "Diffuse"
}
Since all I'm doing is taking the same triangles I've been given and appending them to the triangle stream I'm not sure what I could be doing wrong to cause nothing to appear. Anyone know why this is happening?
I notice that you don't call
triStrem.RestartStrip(); after feeding in 3 vertices of a triangle in your geometry shader.
This informs the stream that a particular triangle strip has ended, and a new triangle strip will begin. If you don't do this, each (single) vertex passed to the stream will add on to the existing triangle strip, using the triangle strip pattern: https://en.wikipedia.org/wiki/Triangle_strip
I'm fairly new to geo-shaders myself, so I'm not sure if this is your issue or not, I don't THINK the RestartStrip function is called automatically at the end of each geomerty-shader, but have not tested this. Rather I think it gets called automatically only when you you reach the maxvertexcount. For a single triangle, I would set the maxvertexcount to 3, not the 12 you have now.
(I also know it can be tough to get ANY shader answers so figgured I'd try to help.)