Height field normals using Noise derivatives

category: code [glöplog]
Using a 2d noise function based off iq's more noise article to generate a height field. I know the normal.x = dx, and normal.z = dy but how do you calculate normal.y without sampling neighboring points in the height field?
added on the 2012-02-22 05:08:49 by jazz jazz
Suppose your height field is z=f(x,y) form and you can get df(x,y)/dx and df(x,y)/dy.

You can get 2 tangent vectors:
vec3 tx = (1, 0, df(x,y)/dx)
vec3 ty = (0, 1, df(x,y)/dy)

vec3 normal = cross(tx, ty) = (-df(x,y)/dx, -df(x,y)/dy, 1)

Can/May I use partial differential symbol or other math symbols in japanese charactor set in pouet?
partial differential symbol:∂
other math symbols:Δ×∇∑∫∬⇔≠≒⇒∵∃∀⊆⊇∪∩∋∈
added on the 2012-02-22 08:32:55 by tomohiro tomohiro
just use a constant that looks good and normalize the normal ;) It's all about looking good instead of beeing accurate :D
added on the 2012-02-22 09:17:53 by xTr1m xTr1m
this is what it looks like here:
BB Image
added on the 2012-02-22 10:36:38 by rudi rudi
for shading you really need something that is as close as possible to the real normal. if you manage to find the derivatives for the noise function you still need to evaluate them. So id say its not more efficient than sampling 2 extra points which is simpler to write and looks good too.
added on the 2012-02-22 10:42:32 by mu6k mu6k
What xTr1m said.
added on the 2012-02-22 11:02:57 by pommak pommak
just use a constant that looks good and normalize the normal ;) It's all about looking good instead of beeing accurate :D
added on the 2012-02-22 11:12:04 by ferris ferris
oh he only wants normal.y... CONSTANT!
added on the 2012-02-22 11:30:51 by mu6k mu6k
The analytic derivative shares a lot of calculations with noise value itself. Thus the analytic derivative of Perlin in 3d is way faster than using a 6 points stencil .
Thank you for your reply.
Your image is same to the display of my brower(Opera).
It seems super set symbol is converted to different string.
added on the 2012-02-22 12:22:28 by tomohiro tomohiro
yep, start at a constant of 0.5, will look good already, depending on your light-vector.
from there just tweak around. i use some 0.1 and i like it, but thats a personal taste ;)
pouet does split long strings, so if you use lots of unicode characters, it may get split at a bad position. just use spaces after some symbols and you're fine.
added on the 2012-02-22 15:24:47 by bartman bartman
Thank you!
I added spaces between each unicode characters.
∂ Δ × ÷ ∇ ∑ ∫ ∬ ⇔ ≠ ≒ ⇒ ∵ ∃ ∀ ⊆ ⊇ ∪ ∩ ∋ ∈ α β γ π

(´ ・ Д ・ )
added on the 2012-02-22 16:17:46 by tomohiro tomohiro
BB Image (firefox/nightly)

ye :)
added on the 2012-02-22 17:01:12 by rudi rudi
Thanks guys, yeh was having a hard time finding a constant that look good everywhere.

tomohiro: Yeh, was thinking of something similar. Will give it a try.
added on the 2012-02-22 22:03:15 by jazz jazz
Maybe some one can help. The normals still look like crap. Doing a quadtree terrain using a 2D grid to render it.

Vertex Shader

Code: VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; float3 gridPosition = input.Position.x * Tangent + input.Position.y * Binormal; float4 worldPosition = mul(float4(gridPosition, 1), World); float3 noise = saturate(fbm(float2(worldPosition.x, worldPosition.z) / 32.0, 3, 2.0, .5)); worldPosition.xyz += noise.x * Height * Normal; float4 viewPosition = mul(worldPosition, View); output.Position = mul(viewPosition, Projection); output.Normal = normalize(float3(-noise.y, 1.0 , -noise.z)); output.WorldPosition = worldPosition.xyz; return output; }

Pixel Shader

Code: float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { float3 lightDir = float3(0, 1024, 0); float4 diffuseLightColor = float4(.8, .8, 1, 0); float4 ambientLightColor = float4(.2, .2, .2, 0); float3 directionToLight = normalize(lightDir - input.WorldPosition); float diffuseIntensity = saturate( dot(directionToLight, input.Normal)); float4 diffuse = diffuseLightColor * diffuseIntensity; float4 color = diffuse + ambientLightColor; color.a = 1.0; return color; }
added on the 2012-02-23 00:09:56 by jazz jazz
This is what i'm using for noise on the GPU:

// http://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl
float random(float a,float b) {
return frac(sin(dot(float2(a,b) ,float2(12.9898,78.233))) * 43758.5453);

// http://www.iquilezles.org/www/articles/morenoise/morenoise.htm
float3 dnoise2f(float2 p) {
float i = floor(p.x), j = floor(p.y);
float u = p.x-i, v = p.y-j;

float du = 30.*u*u*(u*(u-2.)+1.);
float dv = 30.*v*v*(v*(v-2.)+1.);


float a = random( i, j );
float b = random( i+1., j);
float c = random( i, j+1.);
float d = random( i+1., j+1.);

float k0 = a;
float k1 = b-a;
float k2 = c-a;
float k3 = a-b-c+d;

return float3(
k0 + k1*u + k2*v + k3*u*v,
du * (k1 + k3*v),
dv * (k2 + k3*u)

float3 fbm(float2 p, int octaves, float persistence, float gain){
float f = 0.0;
float w = 0.5;
float dx = 0.0;
float dz = 0.0;
for( int i=0; i < octaves; i++ )
float3 n = dnoise2f(p);
dx += n[1];
dz += n[2];
f += w * n[0] / (1.0 + dx*dx + dz*dz); // replace with "w * n[0]" for a classic fbm()
w *= gain;
p *= persistence;
return float3(f, dx, dz);
added on the 2012-02-23 00:23:52 by jazz jazz
Hey Jazz, did you ever get this working for the normal?
I'm at the same stage and would like to speed up my terrain by not calling the height map 3 times to get a normal.
I'm guessing your fmb function above doesn't call return the correct derivatives?
How did you do it in the end?
added on the 2012-05-21 16:53:48 by Dave Dave
thing is, unless you are doing very simple noise-based terrains (simple fbm, etc), your height function won't be analytically derivable anyway, so in the end you must resort to the numerical method. plus by the time you introduce noise based wrapping, several noise modulations etc etc, computing the derivatives analytically can get more expensive that just sampling. and complexifying your noise constructions is what you want to get beautiful terrains. i mean, an analytic-derivative based fbm() terrain rendes super fast, but looks awful, so you don't want to make a demo with it anyway. so in the end of the day, imho, both for speed and aesthetic reasons, you just have to forget the analytic normals and sample the 4 points and get your gradient....
added on the 2012-05-21 18:59:12 by iq iq
Thanks iq. In the document...
...you imply that I don't need to evaluate 4 times, and then you show the equivalent code to jazz's above. So in 'Elevated' are you not actually using the derivatives?
Sampling only once gave me an overall 2X render speed up, so I'm keen to know if that's what you did. :)
added on the 2012-05-21 19:24:17 by Dave Dave
jazz's code (which he copied from my website here: http://www.iquilezles.org/www/articles/morenoise/morenoise.htm) was used for the heightfield. The normals were computed by sampling the field 4 times. You cannot sample only once. Perhaps you can sample it 3 times (center, right and bottom) instead of 4 (left, right, top and bottom), but it's not that much of a saving.
added on the 2012-05-21 20:32:14 by iq iq
Ah OK you were talking about the 4 corners of the height field algorithm, and I got confused by this whole thread! Shame. And yeah I use three corners and it looks fine.
Here's a sneaky link to my stuff using 3 tests at variable widths depending on camera distance, which prevents aliasing issues.
http://www.youtube.com/watch?v=tw1GncYrowc : )
Thanks again for the help and code inspiration.
added on the 2012-05-21 21:24:46 by Dave Dave
Bah. Real coders integrate the surface from normals instead of the other way around.
added on the 2012-05-21 21:48:59 by 216 216
Is there any way you can explain what you mean? Or was that just a shrug off?
I'm sorry if I'm a 'fake' programmer, I've only been selling my software for 35 years, I'll try harder next time.

added on the 2012-05-21 21:54:57 by Dave Dave
in fact, i think that if you manage to do a procedural integration algorithm (without height maps), then you have your way open for real implicit procedural erosion, a siggraph paper, and eternal glory.
added on the 2012-05-21 22:39:27 by iq iq