How to calculate correct screen coordinates and pass to fragment shader

In a space exploration game I’m developing, I’m experimenting with putting a plane directly in front of the camera, so it occupies the entire screen. I intend to use it for full screen effects (lens flaring and ‘speed particles’, etc). If that’s not standard, please just bear with me.
I have a lens flare effect working in my custom sky box shader, but obviously in-game objects will obscure the effect.
What’s weird is, the calculations I make in that shader - to get both the screen coordinates of the in-game light and the current fragment - don’t seem to be working in the shader for my full-screen plane. Here’s a stripped-back version of the new screen effects shader:

  • Shader “Custom/screen effects”

  • {

  • Properties

  • {

  • _sunDirection (“Sun Direction”, Vector) = (0, 1, 0, 0)

  • _sunRadius (“Sun Radius”, float) = 1000000

  • _starColour (“Star Colour”, Color) = (0.75, 0.6, 0.4, 1)

  • _sunVisibility (“Sun Visibility”, float) = 1

  • }

  • Category {

  • Tags { “Queue”=“Transparent” “IgnoreProjector”=“True” “RenderType”=“Transparent” “PreviewType”=“Plane” }

  • Blend SrcAlpha OneMinusSrcAlpha

  • SubShader

  • {

  • Pass

  • {

  • Fog { Mode Off }

  • CGPROGRAM

  • #pragma vertex vert

  • #pragma fragment frag

  • #include “UnityCG.cginc”

    • float4 _sunDirection;
  • float4 _starColour;

  • float _sunRadius;

  • float _sunVisibility;

  • half4 color;

    • struct vInput
  • {

  • half4 vertex : POSITION;

  • };

      • struct v2f
  • {

  • half4 sunWorldPos : SV_POSITION;

  • float3 worldPos : TEXCOORD0;

  • float4 sunScreenPos : TEXCOORD1;

  • float4 vertScreenPos : TEXCOORD2;

  • };

      • v2f vert(vInput input)
  • {

  • v2f output;

  • output.sunWorldPos = mul(UNITY_MATRIX_MVP, _sunDirection); // <<< unused in this shader so far

  • output.worldPos = mul(unity_ObjectToWorld, input.vertex).xyz;

  • // it’s the following four calculations that I’d like confirmed are correct

  • output.sunScreenPos = mul(UNITY_MATRIX_MVP, _sunDirection);

  • output.sunScreenPos = ComputeScreenPos(output.sunScreenPos);

  • output.vertScreenPos = mul(UNITY_MATRIX_MVP, input.vertex);

  • output.vertScreenPos = ComputeScreenPos(output.vertScreenPos);

  • return output;

  • }

      • half4 frag(v2f input) : COLOR
  • {

  • float3 viewDir = UNITY_MATRIX_IT_MV[2].xyz;

  • float sunDP = saturate(dot(normalize(input.worldPos), normalize(_sunDirection)));

    • // positive-only dot product of player view direction and sun direction
  • float sunCameraDP = saturate(dot(normalize(-viewDir), normalize(_sunDirection)));

    • float sunDistance = length(_sunDirection);
  • float sunSize = atan((_sunRadius * 0.5) / sunDistance) * 0.63662; // multiplied to convert from 0-(PI/2) range to 0-1 range

  • if (sunSize<0.0001) {

  • sunSize = 0.0001;

  • }

    • float sunCameraDPLines = pow(sunCameraDP, 32) * saturate(sunSize * 1000);
    • // exaggerate camera/sun dot product
  • sunCameraDP = ( sunCameraDP / ((1 - saturate(sunCameraDP)) + 0.1) );

  • sunCameraDP = sunCameraDP * pow((sunDP + sunSize), 4);

    • // convert screen coords so 0,0 is screen centre
  • input.sunScreenPos.xy /= input.sunScreenPos.w;

  • input.vertScreenPos.xy /= input.vertScreenPos.w;

  • input.sunScreenPos.x -= 0.5;

  • input.sunScreenPos.y -= 0.5;

  • input.vertScreenPos.x -= 0.5;

  • input.vertScreenPos.y -= 0.5;

    • // account for non-square (16/9) screen dimensions
  • input.sunScreenPos.x = input.sunScreenPos.x * 1.777;

  • input.vertScreenPos.x = input.vertScreenPos.x * 1.777;

    • float angle = atan2(input.sunScreenPos.y - input.vertScreenPos.y, input.sunScreenPos.x - input.vertScreenPos.x);
    • color = angle; // this is just a temporary test to see if angle is being calculated correctly - nothing displays when just this option is used
    • // alternatively, I have also tried using the following values, which I would expect to be blue at the bottom left, purple at top left, blue/green at bottom right and white at top right - unfortunately it displays nothing
  • //color.r = input.sunScreenPos.x;

  • //color.g = input.sunScreenPos.y;

  • //color.b = 1;

    • //color = sunDP; // this correctly displays a gradated ‘glowing’ area in the direction of the light source
  • return color;

    • }
    • ENDCG
  • }

  • }

    • FallBack off
  • }

  • }

I’d like to know if there’s something wrong about how I’m calculating the screen coordinates of the ‘star’ and the current fragment, in the ‘v2f vert’ function. And, if that’s correct - as the answers to the following question seem to imply…

…why doesn’t it work?
Thanks.

OK I’ve figured out part of the problem for the FULL shader.
Part of the problem, I realised is that the mesh for the screen effects shader is a child of my camera so I think that’s why the UNITY_MATRIX_MVP variables weren’t returning varying values (the object was always at a fixed position and rotation ‘inside’ the camera’s moving, rotating transform) - at least for the _sunDirection matrix multiplication.
So, using

  • output.sunScreenPos = mul(UNITY_MATRIX_VP, _sunDirection);
  • output.sunScreenPos = mul(unity_ObjectToWorld, output.sunScreenPos);
  • output.sunScreenPos = ComputeScreenPos(output.sunScreenPos);

…seems to have worked. The next step (for the non-stripped-back shader) is to try now to calculate the view direction. If anyone can follow what I’m trying to do, feel free to let me know.