inline float4 AngleAxis (float radians, float3 axis)
{
radians *= 0.5;
axis = axis * sin(radians);
return float4(axis.x, axis.y, axis.z, cos(radians));
}
inline float3 Rotate (float4 rot, float3 v)
{
float3 a = rot.xyz * 2.0;
float3 r0 = rot.xyz * a;
float3 r1 = rot.xxy * a.yzz;
float3 r2 = a.xyz * rot.w;
return float3(
dot(v, float3(1.0 - (r0.y + r0.z), r1.x - r2.z, r1.y + r2.y)),
dot(v, float3(r1.x + r2.z, 1.0 - (r0.x + r0.z), r1.z - r2.x)),
dot(v, float3(r1.y - r2.y, r1.z + r2.x, 1.0 - (r0.x + r0.y))));
}
inline float SampleHeight (float3 normal) { return texCUBE(_Cube, normal).r; }
float3 CalculateNormal (float3 n, float4 t, float textureSize)
{
float pixel = 3.14159265 / textureSize;
float3 binormal = cross(n, t.xyz) * (t.w * unity_WorldTransformParams.w);
float3 x0 = Rotate(AngleAxis(-pixel, binormal), n);
float3 x1 = Rotate(AngleAxis(pixel, binormal), n);
float3 z0 = Rotate(AngleAxis(-pixel, t.xyz), n);
float3 z1 = Rotate(AngleAxis(pixel, t.xyz), n);
float4 samp;
samp.x = SampleHeight(x0);
samp.y = SampleHeight(x1);
samp.z = SampleHeight(z0);
samp.w = SampleHeight(z1);
samp = samp * _Displacement + 1.0;
x0 *= samp.x;
x1 *= samp.y;
z0 *= samp.z;
z1 *= samp.w;
float3 right = (x1 - x0);
float3 forward = (z1 - z0);
float3 normal = cross(right, forward);
normal = normalize(normal);
if (dot(normal, n) <= 0.0) normal = -normal;
return normal;
}