Shader: actual view direction/normal?


I only have basic knowledge about shaders, ShaderLab, and CG, and I didn’t find my answer in any docs, examples, or by trial&error, so my hope is one of you could help me out.

I am looking for the actual view direction, i.e. the vector from the camera position through the currently rendered pixel, as I am trying to find the angle between that and the normal of the object at that point/along that ray. Or to put it differently, I am looking for the actual orientation of an object/vertex/pixel with respect to an arbitrary screen location, not with respect to the camera plane (see the following example).

I can use this which gives me some view-dependent object space(?) normal:

float3 viewN = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);

but this vector remains constant, no matter where on the screen the object is (i.e., it uses the constant normal of the camera plane (=the equivalent of transform.forward) for all pixels). And there is something called “viewDir” in surface shaders, if I understand it correctly, but I am not sure what it does precisely.

I don’t care if I need to use a fragment shader or a surface shader for that, I am happy with any solution that works.


I believe that you can get the view direction vector within the surface shader function like so:

struct Input {
    float3 viewDir;
    //whatever else you need to define for Input

void surf (Input IN, inout EditorSurfaceOutput o) {
  float3 temp = IN.viewDir;
  //gives the view direction as a float3, so you can access e.g. IN.viewDir.x

Note that you may have to use a lighting model that takes into account view direction - that's beyond my expertise.

half4 LightingName (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten);

I was able to figure it out here:

struct v2f {
    float4 pos : SV_POSITION;
    float3 normal : TEXCOORD0; //you don't need these semantics except for XBox360
    float3 viewT : TEXCOORD1; //you don't need these semantics except for XBox360

v2f vert (appdata_base v)
    v2f o;
    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    o.normal = normalize(v.normal);
    o.viewT = normalize(WorldSpaceViewDir(v.vertex));//ObjSpaceViewDir is similar, but localspace.
    return o;

Just make sure you have #include "UnityCG.cginc" in there as well.