Discard Pixels from Fragment Shader Based on Screen Pos
I'm trying to write a shader for a UI element with a canvas in world space that discards any pixels to the left of a pair of game objects, so that it looks like the text is revealed by the objects moving from right to left. The objects are also at a (variable) angle, so I've used a linear equation in the shader to determine when it is to the left or right.
I'm having trouble with the conversion to screen points in the shader. I read around a little bit and figured out that ComputeScreenPos() gives a range from 0 to 1 when normalized by .w, and then I tried to multiply this by _ScreenParams to get the pixel position that would be equivalent to Unity's Camera.WorldToScreenPoint(), but I'm still not able to get it working. Here is the code:
Shader "UI/TextShader"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
_StencilReadMask ("Stencil Read Mask", Float) = 255
_ColorMask ("Color Mask", Float) = 15
_Point1 ("_Point1", Vector) = (0,0,0,0)
_Point2 ("_Point2", Vector) = (0,0,0,0)
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Stencil
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha
ColorMask [_ColorMask]
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile __ UNITY_UI_ALPHACLIP
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
half2 texcoord : TEXCOORD0;
float4 screenPos : TEXCOORD1;
float3 worldPos : TEXCOORD2;
};
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
uniform float4 _Point1;
uniform float4 _Point2;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
OUT.worldPos = mul(_Object2World, IN.vertex).xyz;
OUT.screenPos = ComputeScreenPos(OUT.vertex);
OUT.texcoord = IN.texcoord;
#ifdef UNITY_HALF_TEXEL_OFFSET
OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1);
#endif
OUT.color = IN.color * _Color;
return OUT;
}
sampler2D _MainTex;
fixed4 frag(v2f IN) : SV_Target
{
IN.screenPos /= IN.screenPos.w;
//Equation of the line
float x1 = _Point1.x;
float x2 = _Point2.x;
float y1 = _Point1.y;
float y2 = _Point2.y;
float m = (y2 - y1)/(x2 - x1);
float b = y1 - (m * x1);
float lineXPosition = (IN.screenPos.y * _ScreenParams.y - b)/m;
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
color.a *= UnityGet2DClipping(IN.worldPos.xy, _ClipRect);
if(_ScreenParams.x * IN.screenPos.x > lineXPosition){
discard;
}
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}
And here is the code for the script that passes the points in to the shader:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class SetTextline : MonoBehaviour {
Transform pointOneTrans;
Transform pointTwoTrans;
Material textMaterial;
// Use this for initialization
void Awake () {
pointOneTrans = GameObject.Find ("Point").GetComponent<Transform> ();
pointTwoTrans = GameObject.Find ("Head").GetComponent<Transform> ();
textMaterial = GameObject.Find ("Poem").GetComponent<Text> ().material;
}
// Update is called once per frame
void Update () {
Vector2 point1 = Camera.main.WorldToScreenPoint (pointOneTrans.position);
Vector2 point2 = Camera.main.WorldToScreenPoint (pointTwoTrans.position);
textMaterial.SetVector ("_Point1", point1);
textMaterial.SetVector ("_Point2", point2);
Debug.Log (point1);
Debug.Log (point2);
}
}
Thanks in advance for any help!
Answer by alxdncn · Sep 13, 2016 at 05:53 PM
This is actually working now, it seems. I don't know what I had setup incorrectly in my scene, but it's all fine now.
Your answer
![](https://koobas.hobune.stream/wayback/20220612092714im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
How do you port old shaders to hlsl so they work with the new post-processing stack? 1 Answer
How to change/fix Shader Graph node connection ports 3 Answers
Material.SetFloat not working 0 Answers
Where is the best place to learn how to write shaders for Unity 5? 0 Answers
UI Missing and Shaders look broken! 0 Answers