viewDir up vector

Just wondering if there’s a way to return an Up Vector with the viewDir input. Currently I’m writing a surface shader that casts a shadow in the right-hand side of an object relative to the position of the camera. Unfortunately I see no way to accomplish this unless viewDir returned a quaternion. :neutral:

Can you get the worldspace viewDir and then gram-schmidt a world up-vector to that?

In vertex shader…

float3 worldViewDir = WorldSpaceViewDir(v.vertex);
float3 worldUp = float3(0,1,0);
float3 worldViewUpDir = worldViewDir - worldUp * dot(worldViewDir, worldUp);
float3 objectViewUpDir = mul((float3x3) _World2Object, worldViewUpDir);
TANGENT_SPACE_ROTATION
float3 tangentViewUpDir = mul(rotation, objectViewUpDir);

This is off the top of my head, not sure if it’ll work in practice :stuck_out_tongue:

It might go a bit flaky if the viewdir is straight up or down…

Wow, that was quick.

Would this approach work with a surface shader, it’s not necessary I’m just curious.

Overall this solution would be a good compromise. If I understand correctly this would limit me to an fps style camera right?

Should work with a surface shader, yeah.

It won’t limit you to an FPS style camera… it’ll get the up vector relative to whatever camera you’re using. It will, however, not work if your camera has roll (i.e. if it’s got rotation on it’s local Z axis) because it’s still going to use a world up and not view up.

Not sure but this might work better? Matrixes tend to blag my head a little :stuck_out_tongue:

float3 viewUp = mul((float3x3)UNITY_MATRIX_P, float3(0,1,0));

So I was talking bollocks.

This should work…

Shader "Custom/View Up" {

	Properties {
	}

	SubShader {

		Pass {
			Tags {"Queue" = "Geometry" "RenderType" = "Opaque"}
			
			CGPROGRAM

				#pragma vertex vert
				#pragma fragment frag
				#include "UnityCG.cginc"

				struct appdata {
					float4 vertex : POSITION;
					float3 normal : NORMAL;
				};

				struct v2f {
					float4 pos : SV_POSITION;
					float3 normal : TEXCOORD0;
					float3 viewUp : TEXCOORD1;
					float3 viewRight : TEXCOORD2;
					float3 viewFront : TEXCOORD3;
				};

				float4x4 _CameraToWorld;

				v2f vert (appdata v) {
					v2f o;
					o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
					o.normal = v.normal;
					
					// Convert from camera to world space.
					float3 viewUpW = mul((float3x3)_CameraToWorld, float3(0,1,0));
					float3 viewRightW = mul((float3x3)_CameraToWorld, float3(1,0,0));
					float3 viewFrontW = mul((float3x3)_CameraToWorld, float3(0,0,-_ProjectionParams.x));
					
					// Convert from world to object space.
					o.viewUp = mul((float3x3)_Object2World, viewUpW);
					o.viewRight = mul((float3x3)_Object2World, viewRightW);
					o.viewFront = mul((float3x3)_Object2World, viewFrontW);
					
					return o;
				}

				fixed4 frag(v2f i) : COLOR {
					// Normalized for smoothness.
					i.normal = normalize(i.normal);
					i.viewUp = normalize(i.viewUp);
					i.viewRight = normalize(i.viewRight);
					i.viewFront = normalize(i.viewFront);
					
					fixed4 c = 0;
					c.r = dot(i.normal, i.viewRight);
					c.g = dot(i.normal, i.viewUp);
					c.b = dot(i.normal, i.viewFront);
					return c;
				}

			ENDCG
		}
	}
}

Wow I was hoping someone would help me with my query but I didn’t expect them to write the whole shader for me XD. Thanks!

Heh, it was something I’d messed with previously, got curious as to how it’d be done :stuck_out_tongue: