Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to calculate the normal from partial derivatives? #6

Open
piranha771 opened this issue Mar 29, 2018 · 6 comments
Open

How to calculate the normal from partial derivatives? #6

piranha771 opened this issue Mar 29, 2018 · 6 comments

Comments

@piranha771
Copy link

Currently I use the sobel operator to get the normal from the noise values, but I could skip that when I would know how to use the partial derivatives.

How is the normal calculated from dx,dy?

@stegu
Copy link
Owner

stegu commented Mar 30, 2018 via email

@piranha771
Copy link
Author

piranha771 commented Mar 30, 2018

Okay I may have been confusing with this sobel stuff.
Currently I use sobel to build normals out of noise. It's super simple:

float3 height_to_normal(sampler2D tex, float size, float2 uv, float strength) 
{
	float step = 1.0/_Resolution;

	// Get 8 UVs around the current UV;
	float2 tlv = float2(uv.x - step, uv.y + step); 
	float2 lv  = float2(uv.x - step, uv.y 	    );
	float2 blv = float2(uv.x - step, uv.y - step);	
	float2 tv  = float2(uv.x 	,uv.y + step); 
	float2 bv  = float2(uv.x 	,uv.y - step);
	float2 trv = float2(uv.x + step, uv.y + step); 
	float2 rv  = float2(uv.x + step, uv.y       );
	float2 brv = float2(uv.x + step, uv.y - step);

	// Get the values from these 8 UVs
	float tl = tex2D(tex, tlv).a; 
	float l  = tex2D(tex, lv ).a;
	float bl = tex2D(tex, blv).a;	
	float t  = tex2D(tex, tv ).a; 
	float b  = tex2D(tex, bv ).a;
	float tr = tex2D(tex, trv).a; 
	float r  = tex2D(tex, rv ).a;
	float br = tex2D(tex, brv).a;

	// Do the sobel operation
	float dx = tl + 2.0 * l + bl - tr - 2.0 * r - br;
	float dy = tl + 2.0 * t + tr - bl - 2.0 * b - br;

	// Convert to normal
	return normalize(float3(dx, -dy, 1.0/strength));
}

So what it does is this:

h2n

This is what I'm currently doing. But I saw in your wiki page that it is possible to calculate the normal map directly from the analytical derivative, so I can skip the noise2normal stuff and use the analytical derivative to create a normal map instead.

  	// 2-D tiling simplex noise with rotating gradients and analytical derivative.
  	// The first component of the 3-element return vector is the noise value,
  	// and the second and third components are the x and y partial derivatives.
  	//
  	float3 psrdnoise(float2 pos, float2 per, float rot)

What to do with the derivatives to get a normal map?

d2n

I tried to normalize them normalize(float3(dx, dy, 1.0)) but its not a valid normal map.

@stegu
Copy link
Owner

stegu commented Apr 2, 2018 via email

@piranha771
Copy link
Author

piranha771 commented Apr 2, 2018

analytic derivatives give you the local idealized rate of change across one unit of distance (1.0)
[...]
you paint a pattern using 0.3noise(4.0u, 6.0v), the local gradient in
texture coords is 0.3
vec2(4.0,6.0) times the analytic gradient.

This was the answer I was looking for! Thank you so much!
Works and looks perfect now :)

@stegu
Copy link
Owner

stegu commented Apr 3, 2018 via email

@stegu
Copy link
Owner

stegu commented Oct 14, 2020

Even though the issue was resolved, I am keeping the thread open because it's informative.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants