My 3D object is overlapping itself with alpha when using a custom shader in Unity3D (Unlit version):
It should look something like this instead:
Shader "Custom/Shader1" {
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
}
SubShader {
Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
Pass {
ZWrite On
ColorMask 0
}
Pass {
ZWrite Off // don't write to depth buffer
Blend SrcAlpha OneMinusSrcAlpha // use alpha blending
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
uniform float4 _Color; // define shader property for shaders
uniform sampler2D _MainTex;
uniform float _Cutoff;
struct vertexInput {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct vertexOutput {
float4 pos : SV_POSITION;
float2 tex : TEXCOORD0;
};
vertexOutput vert(vertexInput input) {
vertexOutput output;
output.tex = input.texcoord;
output.pos = UnityObjectToClipPos(input.vertex);
return output;
}
float4 frag(vertexOutput input) : COLOR {
float4 col = tex2D(_MainTex, input.tex) * _Color;
float newOpacity = 1.0;
if (col.a < _Cutoff) {
newOpacity = 0.0;
}
return float4(col.r, col.g, col.b, newOpacity);
}
ENDCG
}
}
}
Did I miss anything? It seems like the transparency alpha overlaps itself.
Edit 1
I removed the first pass, then enabled Zbuffer and removed the if (col.a < _Cutoff) and let it be dynamic according to its texture, but I still get the same result like the 1st image.
Shader "Custom/Shader1" {
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
}
SubShader {
Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
Pass {
ZWrite On
Blend SrcAlpha OneMinusSrcAlpha // use alpha blending
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
uniform float4 _Color; // define shader property for shaders
uniform sampler2D _MainTex;
uniform float _Cutoff;
struct vertexInput {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct vertexOutput {
float4 pos : SV_POSITION;
float2 tex : TEXCOORD0;
};
vertexOutput vert(vertexInput input) {
vertexOutput output;
output.tex = input.texcoord;
output.pos = UnityObjectToClipPos(input.vertex);
return output;
}
float4 frag(vertexOutput input) : COLOR {
float4 col = tex2D(_MainTex, input.tex) * _Color;
return col;
}
ENDCG
}
}
}
The shader is unlit because you use a regular CG shader instead of a Surface shader, whose purpose is to conveniently provide lighting behind the scene. Solution: start fresh from a surface shader template
Alpha blending is not taken advantage of since(col.a < _Cutoff) is always either true or false with no intermediate values, it's always fully shown or fully hidden. On top of that the way you write that condition probably generates some dynamic branching in the shader, try static branching instead float newOpacity = (col.a < _Cutoff) ? 0.0 : 1.0; (in that case the executed code is always the same, only the value changes which is usually much better for perfs).
The shader has 2 passes, which will prevent batching later on and that is pretty bad for performances. One is filling the Zbuffer and the other is doing alpha blending (2 operations that are not really compatible). The prepass is not working properly because it fills the buffer with the raw mesh, without having the information of transparency coming from the texture. Sure you could modify the first pass to do that, but the outcome you look for is essentially just a very straighforward Surface shader with alpha testing on.
You can read on the semantics exposed by Unity to control alpha testing in Surface shaders here: https://docs.unity3d.com/Manual/SL-SurfaceShaders.html , specifically that part :
alphatest:VariableName - Enable alpha cutout transparency. Cutoff
value is in a float variable with VariableName. You’ll likely also
want to use addshadow directive to generate proper shadow caster
pass.
alternatively you can use the clip() method in combination with addshadow, most likely along the lines of clip(col.a - 0.5);
Related
I don't know much about shader :( if someone could help
I am using this free 2d water asset it contains a water shader. I want to edit that shader so it looks more like 2.5d or 3d.
Currently, it looks like this
I want to make it look like
Adding a foam type thing on top and make it little reflective
shader used in the asset to make 2d water
Shader "Water2D/Metaballs_Simple" {
Properties {
_MainTex ("Texture", 2D) = "white" { }
_Color ("Main color", Color) = (1,1,1,1)
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_Stroke ("Stroke alpha", Range(0,1)) = 0.1
_StrokeColor ("Stroke color", Color) = (1,1,1,1)
}
/// <summary>
/// Multiple metaball shader.
/// </summary>
SubShader {
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
GrabPass{}
Pass {
Blend SrcAlpha OneMinusSrcAlpha
// Blend One One // Additive
// Blend One OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float4 _Color;
sampler2D _MainTex;
fixed _Cutoff;
fixed _Stroke;
half4 _StrokeColor;
float2 _screenPos;
float4 _CameraDepthTexture_TexelSize;
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
float4 _MainTex_ST;
v2f vert (appdata_base v){
v2f o;
o.pos = UnityObjectToClipPos (v.vertex);
o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
return o;
};
half4 frag (v2f i) : COLOR{
half4 texcol= tex2D (_MainTex, i.uv);
//half4 finalColor = texcol;
clip(texcol.a - _Cutoff);
if (texcol.a < _Stroke) {
texcol = _StrokeColor;
} else {
texcol = _Color;
}
return texcol;
}
ENDCG
}
}
Fallback "VertexLit"
}
Judging by your shader, it appears as if the fluid has a texture containing an alpha gradient based on the distance to the edge. If this is anything similar to a distance field, then you can use it to reconstruct a screen-space normal based on the derivatives.
float3 normal;
normal.x = ddx(texcol.a);
normal.y = ddy(texcol.a);
normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
Then, you can use this value to calculate some basic blinn-phong specular lighting. This involves using the sum of the vector to the light and the vector to the camera to get a half-way vector.
Since our normal is in camera space, we might want to do all other calculations in camera space too. Ideally, we want to do as many calculations as we can inside the vertex shader and then pass them over to the fragment shader:
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 viewDir : TEXCOORD1;
float3 lightDir : TEXCOORD2;
};
float4 _MainTex_ST;
v2f vert (appdata_base v){
v2f o;
o.pos = UnityObjectToClipPos (v.vertex);
o.viewDir = mul((float3x3)UNITY_MATRIX_MVP, ObjSpaceViewDir(v.vertex));
o.lightDir = mul((float3x3)UNITY_MATRIX_MVP, ObjSpaceLightDir (v.vertex));
o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
return o;
};
I'm assuming that ObjSpaceLightDir works for 2D lights, but i'm not sure.
Inside the fragment shader, we can now get the specular highlights:
float3 lightDir = normalize(i.lightDir);
float3 viewDir = normalize(i.viewDir);
float3 halfDir = normalize(lightDir + viewDir);
float spec = pow(saturate(dot(normal, halfDir)), _Glossiness * 128);
return saturate(_BaseColor + spec);
You can also add some subtle lambert shading to create shadows underneath:
float diff = saturate(dot(normal, lightDir));
// 20% diffuse contribution, because lots of light passes through the liquid.
// Can be tweaked based on artistic needs.
return saturate(_BaseColor * (0.8 + 0.2 * diff) + spec);
Be aware though that this will not properly give the illusion of thickness that your reference has. For this, you need to simulate the thickness of the fluid into a heightmap and generate normals based on that. You can break up the shape of the specular by adding some procedural noise to it, though i haven't tried this. A big challenge when writing shaders is that the GPU doesn't know anything about the context of the pixel other than what you give to it, so things like the distance to the nearest edge have to be pre-computed and fed into the material as textures. I'm honestly not sure how they manage to produce the foam on top - it might be a part of the water texture or a separate sprite rendered in the background.
So I am very new to shader programing (basically just started today) and I got this code from a tutorial on Youtube which works great. It just found the pixel on the edge of a texture, and if so, replace it with a plain color. I want to be able to set the transparency of the color i'm returning.
But it does not seems to be working
Shader "Custom/OutlineShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color("Color", Color) = (1, 1, 1, 1)
_AlphaOffset("Transparency", Range(0,1)) = 1
}
SubShader
{
Tags{ "Queue"="Transparent" "RenderType"="Opaque"}
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag Lambert alpha
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTexelSize;
float _AlphaOffset;
v2f vert (appdata v)
{
v2f OUT;
OUT.vertex = UnityObjectToClipPos(v.vertex);
OUT.uv = v.uv;
return OUT;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col.rgb *= col.a;
fixed4 outlineColor = _Color;
// This is where I want the shader to be transparent or not based on the _AlphaOffset Value
outlineColor.a *= ceil(col.a) * _AlphaOffset;
// This a code just to check is the current pixel is on the edge of the texture
fixed upAlpha = tex2D(_MainTex, i.uv + fixed2(0, _MainTexelSize.y)).a;
fixed downAlpha = tex2D(_MainTex, i.uv - fixed2(0, _MainTexelSize.y)).a;
fixed leftAlpha = tex2D(_MainTex, i.uv - fixed2(_MainTexelSize.x, 0)).a;
fixed rightAlpha = tex2D(_MainTex, i.uv + fixed2(_MainTexelSize.x, 0)).a;
// If it's on the edge, return the color (+ alpha) else, just return the same pixel
return lerp(outlineColor, col, ceil(upAlpha * downAlpha * leftAlpha * rightAlpha));
}
ENDCG
}
}
}
I would like this line
outlineColor.a *= ceil(col.a) * _AlphaOffset; to set the alpha of the pixel I'm returning.
Thanks !
There are primarily two things which are wrong here - firstly, you have set your RenderType to "Opaque", which expectedly makes it render as non-transparent. This should instead be set to "Transparent". Second, you need to specify a blend mode to determine how the color from this object blends with what's already rendered to the buffer. From the Unity manual on blending:
Blend SrcFactor DstFactor: Configure and enable blending. The
generated color is multiplied by the SrcFactor. The color already on
screen is multiplied by DstFactor and the two are added together.
For regular alpha blending, add this statement inside your subshader:
Blend SrcAlpha OneMinusSrcAlpha
For additive blending, which results in a glow-like effect, use this:
Blend One One
In Unity, how can I stop my 3d texts from "glowing" in the dark?
I'm using below shader code, for instance, but the texts turn up much brighter/ self-emissive than other things. Changing to "Lighting On" gets rid of the glow, but will then also get rid of the material color, and turn up black.
How to solve this? Many thanks!
Shader "GUI/3D Text Shader - Cull Back" {
Properties {
_MainTex ("Font Texture", 2D) = "white" {}
_Color ("Text Color", Color) = (1,1,1,1)
}
SubShader {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
Lighting Off Cull Back ZWrite Off Fog { Mode Off }
Blend SrcAlpha OneMinusSrcAlpha
Pass {
Color [_Color]
SetTexture [_MainTex] {
combine primary, texture * primary
}
}
}
Copied from comments, added for context:
I suspect the emissive glow is just the material's unlit color contrasting against a dark/variably lit scene? A lit shader could fix such an issue, however Unity's TextMesh component appears to not generate mesh normals and thus the shader's lighting calculations will corrupt (if at all be compiled). It explains why Lighting On outputs black. Without access to TextMesh internals and confined to the limitations of fixed-function shaders, a custom shader may be your only option.
The following is a basic Surface Shader using the Lambert lightning model. Under the hood it will compile to a standard vertex/fragment shader with Unity's lighting calculations automagically injected. It's been written as a drop-in replacement, so simply add it to your project and drag and drop it onto your material:
Shader "GUI/3D Text Shader - Lit"
{
Properties
{
_Color ("Text Color", Color) = (1,1,1,1)
_MainTex ("Font Texture", 2D) = "white" {}
}
SubShader
{
Tags {"RenderType"="Transparent" "Queue"="Transparent"}
Cull Back
CGPROGRAM
#pragma surface SS_Main Lambert vertex:VS_Main alpha:blend
#pragma target 3.0
uniform fixed4 _Color;
uniform sampler2D _MainTex;
struct Output
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 texcoord2 : TEXCOORD2;
};
struct Input
{
float2 uv_MainTex;
};
void VS_Main (inout Output o)
{
// Generate normals for lighting.
o.normal = float3(0, 0, -1);
}
void SS_Main (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = _Color.rgb;
o.Alpha = c.a;
}
ENDCG
}
}
Unity's excellent Sprites (Unity's excellent new sprites), among other worthy advantages, are in fact double-sided.
In a 2D or 3D use case, you can flip the little bastards around and still see them from behind - they are rendered from both sides.
I also love the unlit shader used on them (ie, Sprite-Default, not Sprite-Diffuse).
However, I have need for an old-fashioned single-sided Sprite.
Fortunately, you can freely download the source of the excellent shader used by Unity ... confusingly, you can't just open it in the Editor, but see here and thence here.
After considerable sustained effort involving inexpensive whisky, I made two (2) modifications to the shader.
I changed the name in the first line of the file to "DefaultSingle" rather than "Default"
I commented away the line Cull Off
(I then made a new Material, called it "Sprite Single Sided", set the shader to this new one, and on Sprites I replace the material slot with that new material.)
in fact, have I screwed-up anything in the shader by making this modification? Can one gaily comment out "Cull off" without causing further problems? Is there some gotchya in changing that usual material used by Sprite (you can't "see" it so I don't know). More broadly, is there a more correct way to achieve single-sided Sprite?
// file "Sprites-DefaultSingle.shader"
Shader "Sprites/DefaultSingle"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
/// Cull Off
Lighting Off
ZWrite Off
Blend One OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ PIXELSNAP_ON
#pragma shader_feature ETC1_EXTERNAL_ALPHA
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
fixed4 _Color;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
#ifdef PIXELSNAP_ON
OUT.vertex = UnityPixelSnap (OUT.vertex);
#endif
return OUT;
}
sampler2D _MainTex;
sampler2D _AlphaTex;
fixed4 SampleSpriteTexture (float2 uv)
{
fixed4 color = tex2D (_MainTex, uv);
#if ETC1_EXTERNAL_ALPHA
// get the color from an external texture ..
color.a = tex2D (_AlphaTex, uv).r;
#endif //ETC1_EXTERNAL_ALPHA
return color;
}
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
c.rgb *= c.a;
return c;
}
ENDCG
}
}
}
That won't cause any problems and is the correct way of doing things. If you want to be really explicit about it you could change the line to Cull Back instead of commenting it out, but back-face culling is defined as the default behaviour so just removing it is fine.
As far as I'm aware, neither of these changes have any effects other than the that which you intended. Also, this is the most correct way to achieve this- it's the only thing Cull is for.
Shader "Custom/1_displayImageOnSlide" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_CutoffX("CutoffX", Range(0.0,1.0)) = 1
_CutoffY("CutoffY", Range(0.0,1.0)) = 1
}
Category {
Cull off
Blend SrcAlpha OneMinusSrcAlpha
Lighting Off
Fog { Mode Off }
SubShader {
// Tags {"LighMode"="ForwardBase"}
Tags {"Queue"="Transparent" "RenderType"="Transparent"}
//UsePass "VertexLit/SHADOWCOLLECTOR"
//UsePass "VertexLit/SHADOWCASTER"
CGPROGRAM
#pragma surface surf Unlit
//#pragma surface surf Lambert
// Inside CGPROGRAM block.
half4 LightingUnlit (SurfaceOutput s, half3 lightDir, half atten) {
half4 c;
c.rgb = s.Albedo;
c.a = s.Alpha;
return c;
}
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
float4 color : Color;
};
fixed _CutoffX;
fixed _CutoffY;
void surf (Input IN, inout SurfaceOutput o) {
half4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = IN.color.rgb * tex.rgb;
o.Alpha = IN.uv_MainTex.x > _CutoffX ? 0 : IN.uv_MainTex.y > _CutoffY ? 0 : IN.color.a*tex.a;
}
ENDCG
}//sub Shader End
}//Categoy End
FallBack "VertexLit" // Use VertexLit's shadow caster/receiver passes.
}
This is the code of my shader file and it is applied to a cube object. The problem is, shader is casting correctly by cube but cube is not receiving shader. Whats wrong in it? I don't have enough knowledge about shader programming so it is requested to share you answer with description