Normal of sine

Started by
12 comments, last by alkisbkn 11 years, 8 months ago
Hello,

I have been developing a simple ocean wave "heightfield" composed out of 6 sine waves. Now, I need to find the normal of each vertex, and I am stuck basically. How I calculate my waves:
[source lang="cpp"]
float2 dir = float2(1.0f, 0.0f);
float dir_vertex = dot(dir, wave_vertex.xz);

float wave1 = 25.0f * pow(sin( (2 * PI / 800) * dir_vertex - time * 2 * PI / 45.0f - 105.0f),2);

// .... and so on for the others ...

vertex.y = wave1 + wave2 + wave3 + wave4 + wave5 + wave6;
[/source]
(I know looks ugly, but it works)

Is there a computationally cheap way to find the normal (this is for an iOS game).

Thanks a bunch!
Advertisement
If my maths does not fail me, the slope of the normal = the derivative, and the derivative of sin(x) is cos(x).
Since you seem to have your surface expressed as y = F(x,z), you can compute two tangent vectors as (1,Fx(x,z),0) and (0,Fz(x,z),1), where Fx and Fz are the derivatives of F with respect to x and z respectively. You can then compute the cross product of these two vectors to get a normal vector. And then you probably need to normalize the resulting vector.

Post again if you try to do that for a while and don't succeed.
Hi and thanks!

It does make sense now. However, I don't think I am getting the correct results. How I calculate my wave, tangent, bitangent and normal:
[source lang="c++"]
float2 dir = float2(1.0f, 0.0f);
float dir_vertex = dot(dir, wave_vertex.xz);

float wave1 = 25.0f * pow(sin( (2 * PI / 800) * dir_vertex - time * 2 * PI / 45.0f - 105.0f),2);

float3 tan1 = float3(1.0, 2 * cos( (2 * PI / 800) * dir_vertex - time * 2 * PI / 45.0f - 105.0f), 0.0);

float3 bitan1 = float3(0.0, 2 * cos( (2 * PI / 800) * dir_vertex - time * 2 * PI / 45.0f - 105.0f), 1.0);

float3 normal1 = normalize(cross(bitan1, tan1));
[/source]
Maybe my derivation is wrong. A power exponent goes in front of the base number when we derive, correct? Also the constant = 1, thus the amplitude is removed from the tan1 and bitan1 equations. I have attached a screenshot of the current output (for 2 perpendicular waves). To my understanding, when the wave is at full amplitude, the normal should be (0,1,0) (green colour), however it doesn't seem so in the screenshot.

Moreover, to get the final vertex normal, I do:
normal = normalize(normal1 + normal2);
The way you compute wave1(x,z) uses dir_vertex, which itself is a function of (x,z). The way you compute tan1 and bitan1 neglect this fact! Notice that alvaro hinted at computing the derivates dF(x,z)/dx and dF(x,z)/dz.

In fact, the formula you use is something like
wave1(x,z) := ( sin( f[sub]s[/sub] * ( dir[sub]x[/sub] * x + dir[sub]z[/sub] * z ) + f[sub]t[/sub] * t + p ) )[sup]2[/sup]
where f[sub]s[/sub] denoting a spatial frequency, f[sub]t[/sub] denoting a temporal frequency, and p denoting a phase.

For the purpose of spatial derivative the term f[sub]t[/sub] * t + p =: c[sub]t[/sub] is a constant, and f[sub]x[/sub] := f[sub]s[/sub] * dir[sub]x[/sub], f[sub]z[/sub] := f[sub]s[/sub] * dir[sub]z[/sub] can be used for simplicity. Then IIRC the derivatives are
tan1 := d wave(x,z) / d x = ( sin( f[sub]x[/sub] * x + f[sub]z[/sub] * z + c[sub]t[/sub] ) )[sup]2 [/sup]/ d x = 2 sin( f[sub]x[/sub] * x + f[sub]z[/sub] * z + c[sub]t[/sub] ) * cos( f[sub]x[/sub] * x + f[sub]z[/sub] * z + c[sub]t[/sub] ) * f[sub]x[/sub]
and
bitan1 := d wave(x,z) / d z = ( sin( f[sub]x[/sub] * x + f[sub]z[/sub] * z + c[sub]t[/sub] ) )[sup]2[/sup] / d z = 2 sin( f[sub]x[/sub] * x + f[sub]z[/sub] * z + c[sub]t[/sub] ) * cos( f[sub]x[/sub] * x + f[sub]z[/sub] * z + c[sub]t[/sub] ) * f[sub]z[/sub]
due to the chain rule. Please check this twice.
Hi haegarr,

I am now testing using 1 wave only and by implementing the equation you mentioned before. The problem is that the normal seems to always be (0,1,0) using this implementation:
[source lang="cpp"]
float2 dir = float2(1.0, 0.0);
float dir_vertex = dot(dir, wave_vertex.xz);

float fs = 2 * PI / 800.0f;
float t = time * 2 * PI / 45.0f;

float wave1 = 30.0f * pow(sin(fs * dir_vertex + t), 2);

float fx = dir.x * fs;
float fz = dir.y * fs;

float3 tan1 = float3(1.0,
2 * sin(fx * wave_vertex.x + fz * wave_vertex.z + t) *
cos (fx * wave_vertex.x + fz * wave_vertex.z + t) * fx,
0.0);

float3 bitan1 = float3(0.0,
2 * sin(fx * wave_vertex.x + fz * wave_vertex.z + t) *
cos (fx * wave_vertex.x + fz * wave_vertex.z + t) * fz,
1.0);

float3 normal1 = normalize(cross(bitan1, tan1));
[/source]
resulting in a green fragment color.
sad.png
Well, using the correspondence
2 * sin(k) * cos(k) = sin(2k)
simplifies the implementation. In your given case there is fz = 0.0, giving
tan1 = [ 1, sin( 2 * fx * wave_vertex.x + 2 * t ), 0 ]
bitan1 = [ 0, 0, 1 ]

Here tan1 shouldn't be constant over x, should it? Hmmm. Perhaps using a graph plotter with that sine function gives an answer...
This appears to be tricky afterall. Shouldn't the vertex and direction z be affecting the tan1 as well?

Edit:
I changed the wave function to something more simple for now, I basically removed the power to 2.
So, the derivative of:


float wave1 = 30.0f * sin(fs * dir_vertex + t);


should now be:

float tan1y = cos(fs * dir.x * wave_vertex.x)
float bitan1y = cos(fs * dir.y * wave_vertex.z);

(is t in the derivative equation? I think not, as it's constant)

However this too doesn't give me a correct result.
Okay, it seems that the correct derivative of "wave1" equation is the following:

float3 tan1 = float3(1.0, 30.0 * fs * cos(fs * waveVertex.x + t), 0.0);
float3 bitan1 = float3(0.0, 30.0 * fs * cos(fs * waveVertex.x + t), 1.0);

for tan and bitan. Then I do

normal = normalize(cross(bitan1, tan1));

For 1 wave it seems to be correct, however how should I go about adding many wave's normals together? Just summing them and normalizing the result?
Normals don't add up, but derivatives do. So compute the derivatives, add them together and then use the cross product to compute the normal.

This topic is closed to new replies.

Advertisement