I am implementing a simplex-noise shader for clouds and I am getting some really weird behaviour in Unity.
You don’t really need to see the rest of the shader, as I’ve narrowed the problem down to these two methods. These are the two methods to generate the noise value for a given UV position.
the method snoise gives a consistent and normal output but it gets flipped (±) when you move the camera angle around. This happens even if you give snoise a constant value… Something inside these methods is upset by the camera angle? WTF.
Could it be a bad variable name or something? I just dont get it!!
void simplex( const in float3 P, out float3 offset1, out float3 offset2 )
{
float3 offset0;
float2 isX = step( P.yz, P.xx ); // P.x >= P.y ? 1.0 : 0.0; P.x >= P.z ? 1.0 : 0.0;
offset0.x = dot( isX, float2( 1.0 ) ); // Accumulate all P.x >= other channels in offset.x
offset0.yz = 1.0 - isX; // Accumulate all P.x < other channels in offset.yz
float isY = step( P.z, P.y ); // P.y >= P.z ? 1.0 : 0.0;
offset0.y += isY; // Accumulate P.y >= P.z in offset.y
offset0.z += 1.0 - isY; // Accumulate P.y < P.z in offset.z
// offset0 now contains the unique values 0,1,2 in each channel
// 2 for the channel greater than other channels
// 1 for the channel that is less than one but greater than another
// 0 for the channel less than other channels
// Equality ties are broken in favor of first x, then y
// (z always loses ties)
offset2 = clamp( offset0, 0.0, 1.0 );
// offset2 contains 1 in each channel that was 1 or 2
offset1 = clamp( --offset0, 0.0, 1.0 );
// offset1 contains 1 in the single channel that was 1
}
float snoise(float3 P) {
// The skewing and unskewing factors are much simpler for the 3D case
// Skew the (x,y,z) space to determine which cell of 6 simplices we're in
float s = (P.x + P.y + P.z) * F3; // Factor for 3D skewing
float3 Pi = floor(P + s);
float t = (Pi.x + Pi.y + Pi.z) * G3;
float3 P0 = Pi - t; // Unskew the cell origin back to (x,y,z) space
Pi = Pi * ONE + ONEHALF; // Integer part, scaled and offset for texture lookup
float3 Pf0 = P - P0; // The x,y distances from the cell origin
// For the 3D case, the simplex shape is a slightly irregular tetrahedron.
// To find out which of the six possible tetrahedra we're in, we need to
// determine the magnitude ordering of x, y and z components of Pf0.
float3 o1;
float3 o2;
simplex(Pf0, o1, o2);
// Noise contribution from simplex origin
float perm0 = tex2D(permTexture, Pi.xy).a;
float3 grad0 = tex2D(permTexture, float2(perm0, Pi.z)).rgb * 4.0 - 1.0;
float t0 = 0.6 - dot(Pf0, Pf0);
float n0;
if (t0 < 0.0) n0 = 0.0;
else {
t0 *= t0;
n0 = t0 * t0 * dot(grad0, Pf0);
}
// Noise contribution from second corner
float3 Pf1 = Pf0 - o1 + G3;
float perm1 = tex2D(permTexture, Pi.xy + o1.xy*ONE).a;
float3 grad1 = tex2D(permTexture, float2(perm1, Pi.z + o1.z*ONE)).rgb * 4.0 - 1.0;
float t1 = 0.6 - dot(Pf1, Pf1);
float n1;
if (t1 < 0.0) n1 = 0.0;
else {
t1 *= t1;
n1 = t1 * t1 * dot(grad1, Pf1);
}
// Noise contribution from third corner
float3 Pf2 = Pf0 - o2 + 2.0 * G3;
float perm2 = tex2D(permTexture, Pi.xy + o2.xy*ONE).a;
float3 grad2 = tex2D(permTexture, float2(perm2, Pi.z + o2.z*ONE)).rgb * 4.0 - 1.0;
float t2 = 0.6 - dot(Pf2, Pf2);
float n2;
if (t2 < 0.0) n2 = 0.0;
else {
t2 *= t2;
n2 = t2 * t2 * dot(grad2, Pf2);
}
// Noise contribution from last corner
float3 Pf3 = Pf0 - float3(1.0-3.0*G3);
float perm3 = tex2D(permTexture, Pi.xy + float2(ONE, ONE)).a;
float3 grad3 = tex2D(permTexture, float2(perm3, Pi.z + ONE)).rgb * 4.0 - 1.0;
float t3 = 0.6 - dot(Pf3, Pf3);
float n3;
if(t3 < 0.0) n3 = 0.0;
else {
t3 *= t3;
n3 = t3 * t3 * dot(grad3, Pf3);
}
// Sum up and scale the result to cover the range [-1,1]
return 32 * (n0 + n1 + n2 + n3) ;
}