Matrix inversion
float4x4 inverse(float4x4 mat)
{
	float4x4 M=transpose(mat);
	float m01xy=M[0].x*M[1].y-M[0].y*M[1].x;
	float m01xz=M[0].x*M[1].z-M[0].z*M[1].x;
	float m01xw=M[0].x*M[1].w-M[0].w*M[1].x;
	float m01yz=M[0].y*M[1].z-M[0].z*M[1].y;
	float m01yw=M[0].y*M[1].w-M[0].w*M[1].y;
	float m01zw=M[0].z*M[1].w-M[0].w*M[1].z;
	float m23xy=M[2].x*M[3].y-M[2].y*M[3].x;
	float m23xz=M[2].x*M[3].z-M[2].z*M[3].x;
	float m23xw=M[2].x*M[3].w-M[2].w*M[3].x;
	float m23yz=M[2].y*M[3].z-M[2].z*M[3].y;
	float m23yw=M[2].y*M[3].w-M[2].w*M[3].y;
	float m23zw=M[2].z*M[3].w-M[2].w*M[3].z;
	float4 adjM0,adjM1,adjM2,adjM3;
	adjM0.x=+dot(M[1].yzw,float3(m23zw,-m23yw,m23yz));
	adjM0.y=-dot(M[0].yzw,float3(m23zw,-m23yw,m23yz));
	adjM0.z=+dot(M[3].yzw,float3(m01zw,-m01yw,m01yz));
	adjM0.w=-dot(M[2].yzw,float3(m01zw,-m01yw,m01yz));
	adjM1.x=-dot(M[1].xzw,float3(m23zw,-m23xw,m23xz));
	adjM1.y=+dot(M[0].xzw,float3(m23zw,-m23xw,m23xz));
	adjM1.z=-dot(M[3].xzw,float3(m01zw,-m01xw,m01xz));
	adjM1.w=+dot(M[2].xzw,float3(m01zw,-m01xw,m01xz));
	adjM2.x=+dot(M[1].xyw,float3(m23yw,-m23xw,m23xy));
	adjM2.y=-dot(M[0].xyw,float3(m23yw,-m23xw,m23xy));
	adjM2.z=+dot(M[3].xyw,float3(m01yw,-m01xw,m01xy));
	adjM2.w=-dot(M[2].xyw,float3(m01yw,-m01xw,m01xy));
	adjM3.x=-dot(M[1].xyz,float3(m23yz,-m23xz,m23xy));
	adjM3.y=+dot(M[0].xyz,float3(m23yz,-m23xz,m23xy));
	adjM3.z=-dot(M[3].xyz,float3(m01yz,-m01xz,m01xy));
	adjM3.w=+dot(M[2].xyz,float3(m01yz,-m01xz,m01xy));
	float invDet=rcp(dot(M[0].xyzw,float4(adjM0.x,adjM1.x,adjM2.x,adjM3.x)));
	return transpose(float4x4(adjM0*invDet,adjM1*invDet,adjM2*invDet,adjM3*invDet));
}