Comments and answers for "Calculate ripple normals"
http://answers.unity.com/questions/1305264/calculate-ripple-normals.html
The latest comments and answers for the question "Calculate ripple normals"Comment by asger60 on asger60's comment
http://answers.unity.com/comments/1306815/view.html
Thanks for that very thorough answer! It works like a charm. You are indeed a mathematical wizzard!Tue, 31 Jan 2017 18:53:09 GMTasger60Comment by elenzil on elenzil's comment
http://answers.unity.com/comments/1306772/view.html
nice! i realized my 'use cos() to get the normal' was oversimplifying a bit.Tue, 31 Jan 2017 17:57:30 GMTelenzilComment by syltefar on syltefar's answer
http://answers.unity.com/comments/1306700/view.html
Elenzils numerical way of computing the normals is probably the best solution for this type of problem, but I like trying to do it formally as well. Here is the derivation:
Given the following input:
a = amplitude^2
f = frequency
p = timer * speed
x, z = point.x, point.z
rx, rz = ripplePosition.x, ripplePosition.z
offset = x^2 + z^2 + x*rx + z*rz
The surface is given by this function:
y(x,z) = a * sin((x^2 + z^2 + x*rx + z*rz) * f + p)
We assume that the following are constant for a given frame:
initPosition, timer, speed, frequency, ripplePosition rippleDistance, amplitude
For a surface y(x,z), the normal is the cross product of the tangent vectors in x and z directions:
normal(x,z) = tangent_x x tangent_z
tangent_x = (1, dy/dx(x,z), 0)
where dy/dx is the partial derivative of y with respect to x. Similarly, we have:
tangent_z = (0, dy/dz(x,z), 1)
So we need to find the partial derivaties of y with respect to x.
We need a few key derivatives:
sin'(x) = cos(x)
f(g(x))' = f'(g(x))g'(x) [chain rule]
First, let's decompose the function y(x) into the composite f(g(x)):
f(x) = a * sin(x)
g(x) = (x^2 + z^2 + x*rx + z*rz) * f + p
The derivative of f(x):
f'(x) = a * cos(x)
For g(x), we remember that everything but x is a constant. We can rewrite g(x) as the polynomial:
g(x) = f*x^2 + f*rx*x + f*z^2 + f*z*rz + p
In the derived function g'(x), all added constants go away:
g'(x) = f*2x + f*rx
We can then use the chain rule to combine the two:
dy/dx = f(g(x))'
= f'(g(x))g'(x)
= a * cos(f*x^2 + f*rx*x + f*z^2 + f*z*rz + p) * (f*2x + f*rx)
= a * cos((x^2 + z^2 + x*rx + z*rz) * f + p) * (f*2x + f*rx)
Similarly, y derived with respect to z:
dy/dz = a * cos((x^2 + z^2 + x*rx + z*rz) * f + p) * (f*2z + f*rz)Tue, 31 Jan 2017 16:11:30 GMTsyltefarComment by syltefar on syltefar's answer
http://answers.unity.com/comments/1306674/view.html
Looks like this: http://imgur.com/a/Ff3gSTue, 31 Jan 2017 15:43:26 GMTsyltefarAnswer by syltefar
http://answers.unity.com/answers/1306613/view.html
Does this work, Asger?
public Vector3 GetSurfaceNormal(Vector3 point)
{
Vector3 ripplePosition = (initPosition * -1) * 2;
float a = amplitude * amplitude;
float f = frequency;
float x = point.x;
float z = point.z;
float p = timer * speed;
float rx = ripplePosition.x;
float rz = ripplePosition.z;
Vector3 slopeX = new Vector3(1f, a * Mathf.Cos((x*x + z*z + x*rx + z*rz)*f+p) * (f*2*x + f*rx), 0f);
Vector3 slopeZ = new Vector3(0f, a * Mathf.Cos((x*x + z*z + x*rx + z*rz)*f+p) * (f*2*z + f*rz), 1f);
if (Vector3.Distance(point, initPosition) < rippleDistance)
return Vector3.Cross(slopeX, slopeZ).normalized;
else
return Vector3.right;
}Tue, 31 Jan 2017 14:43:18 GMTsyltefarComment by asger60 on asger60's comment
http://answers.unity.com/comments/1306589/view.html
thanks for your reply.
If I where to go with approach 2, how would you do the actual formula? I feel like i'm a little in over my head here, mathematically speaking.Tue, 31 Jan 2017 12:45:34 GMTasger60Comment by elenzil
http://answers.unity.com/comments/1306414/view.html
i think you could take two approaches.
1) calculate the normal based on the geometry.
this has the advantage of working on more complex surfaces,
for example if you had multiple ripples all overlapping.
the typical approach for a vertex normal with smooth-shading
is to calculate two vectors: VSN = vector from south neighbor vertex to north neighbor vertex, VWE = vector from west neighbor vertex to east neighbor, then your normal is the normalized cross-product of VSN and VWE.
the disadvantage with this approach is that it requires neighbors all the way around, so have to fudge the normals for the vertices on the edges of your mesh.
2) find the Radius and Theta of your input point. use Mathf.atan2() to find theta. then calculate the normal as cos (your radius-based formula above), pretending you're only worrying about normals along the X-axis. Then rotate that normal around the Up Vector (Z or Y) by Theta.
the advantage is that it's mathematically capital-C Correct, and works for vertices on the edge as well.
all in all i would suggest taking approach 1.Tue, 31 Jan 2017 01:20:17 GMTelenzil