Reputation: 51
I'm trying to learn about creating and using analytical derivatives of perlin noise to quickly generate normals. I've been experimenting with code from one of Catlike Coding's tutorials, and while I get the idea of assuming the 'up' axis is 1 and normalizing when sampling on a 2D plane I can't find any information about what to do when sampling on a 3D surface.
This is what I'm after (this uses central difference normals):
And this is what those normals look like in world space:
But the derivatives I'm getting look like this:
It seems like they might be relative to the surface of the undisplaced sphere, so would that mean I need to reorient them with the undisplaced sphere's normals? And how would I turn the derivatives into normals after doing that?
Upvotes: 2
Views: 1073
Reputation: 51
I figured out a solution. What I did was construct a rotation quaternion using the world-space surface normal, rotate the derivative vector by the inverse of that rotation, then turn it into a normal as you would on a plane and rotate it back with the normal rotation again.
Using the derivatives as surface normals now looks like this
And now mixing octaves based on the slope of the normals looks like this...
And here's some of the code that finds the normal and slope:
float3 qRotateVector(float3 v, float4 q) {
float3 t = 2.0 * cross(q.xyz, v);
return v + q.w * t + cross(q.xyz, t);
}
float4 qFromToRotation(float3 v) {
float3 up = float3(0.0, 1.0, 0.0);
float d = dot(up, v);
if (d < -0.999999) {
return float4(0.0, 0.0, 1.0, 0.0);
}
else if (d > 0.999999) {
return float4(0.0, 0.0, 0.0, 1.0);
}
else {
return normalize(float4(cross(up, v), d + 1.0));
}
}
float noiseSlope(float3 derivatives, float3 normal) {
float4 noiseRotation = qFromToRotation(normal);
float3 derivativeNormal = qRotateVector(derivatives, float4(-noiseRotation.xyz, noiseRotation.w));
return abs(dot(normalize(float3(-derivativeNormal.x, 1.0, -derivativeNormal.z)), float3(0.0, 1.0, 0.0)));
}
(I originally tried using matrices but I kept having problems with gimbal locking)
After I experimented with that I discovered Inigo Quilez also has an example of mixing by slope by dividing the height with 1 + dot(derivative.yz, derivative.yz) instead of rotating the noise, which I'm going to try messing with too.
Upvotes: 3