- Home /

# Calculate ripple normals

Hey I'm generating wave ripples with this function

```
public Vector3 GetSurfacePosition(Vector3 point) {
Vector3 ripplePosition = (initPosition * -1) * 2;
float offset = ((point.x * point.x) + (point.z * point.z));
offset += ((point.x * ripplePosition.x) + (point.z * ripplePosition.z));
var value = amplitude * Mathf.Sin(timer * speed + offset * frequency);
if(Vector3.Distance(point, initPosition) < rippleDistance)
return new Vector3(0, (value * amplitude), 0);
return Vector3.zero;
}
```

It works well for getting the positions of the ripples, but now i would like to also get the normals. I have tried with this function, but it doesn't seem to return the correct values.

```
public Vector3 GetSurfaceNormal(Vector3 point) {
Vector3 ripplePosition = (initPosition * -1) * 2;
float offset = ((point.x * point.x) + (point.z * point.z));
offset += ((point.x * ripplePosition.x) + (point.z * ripplePosition.z));
float x = -1 * speed * amplitude * Mathf.Cos(-1 * timer * speed + offset * frequency);
float y = 1;
float z = speed * amplitude * Mathf.Cos(-1 * timer * speed + offset * frequency);
if(Vector3.Distance(point, initPosition) < rippleDistance)
return new Vector3(x,y,z).normalized * 2;
return Vector3.zero;
}
```

Here's a screenshot of what I have right now.

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.

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.

**Answer** by syltefar
·
Jan 31, 2017 at 02:43 PM

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;
}
```

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)
```

nice! i realized my 'use cos() to get the normal' was oversimplifying a bit.

Thanks for that very thorough answer! It works like a charm. You are indeed a mathematical wizzard!

### Your answer

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.

### Follow this Question

### Related Questions

Change Camera Clipping/Culling Mode 1 Answer

Why does inverting two components of a normal break them? 1 Answer

How to determine if a line intersects with a frustum 2 Answers

Retrieve 2d primitives from 3d colliders 1 Answer

How to calculate the 3D vector perpendicular to a polygon surface in a specific direction 1 Answer