How to find normal on wave

I want to add the method ‘wave:getNormal(x, z, t)’, where x and z are coordinates and t is the time in seconds. The method should return a unit normal of a given point on the mathematical function specified in ‘wave:getValue(x, z, t)’. ‘self.CONFIG’ contains some wave parameters like HEIGHT and LENGTH. This is the relevant code:

local wave = {}

-- This method is used for giving a direction to the wave
function wave:getP(x, z, t)
	return Vector2.new(Vector2.new(x, z):Dot(self.config.DIRECTION), Vector2.new(z, x):Dot(self.config.DIRECTION)) * math.pi / self.config.LENGTH
end

-- This method is used to get the height of the wave
function wave:getValue(x, z, t)
	local LENGTH = self.config.LENGTH
	
	local p = self:getP(x, z, t)
    -- This is the maths function that should be related to wave:getNormal(x, z, t)
	return math.sin(p.x - t * self.config.SPEED) * math.sin((p.x + p.y) / 5) * self.config.HEIGHT + self.config.BIAS
end

function wave:getNormal(x, z, t)
	-- Not sure how to calculate this
end

The problem is that I do not know how to calculate the unit normal. All I know is that it has something to do with derivatives and the tangent line of the wave’s maths function. Here is an illustration of what I want to calculate, where the blue part is my wave:

I have tried to mess around with derivatives, but I have come to the conclusion that I do not have enough knowledge about derivatives and vectorial equations.

I should probably post this on a maths forum, but I thought I can at least try to ask it here.

2 Likes

The easiest way would be to just estimate it:

function wave:getNormal(x, z, t)
	-- some small number
	local h = 0.001

	-- value at the point
	local v = self:getValue(x, z, t)

	-- value slightly to the right of the point
	local vx = self:getValue(x + h, z, t)

	-- value slightly behind the point
	local vz = self:getValue(x, z + h, t)

	-- vector from v -> v_x
	local v_vx = Vector3.new(h, vx - v, 0)

	-- vector from v -> v_z
	local v_vz = Vector3.new(0, vz - v, h)

	-- normal vector
	return v_vz:Cross(v_vx).Unit
end

The other way would be to figure out the partial derivative of wave:getValue w.r.t x and z and then your normal is proportional to

Vector3.new(dfdx(x, z), 1, dfdz(x, z))

Apparently, according to Normal Vector -- from Wolfram MathWorld

But that sounds hard, and estimating is probably good enough.

2 Likes

Thanks, I will try to implement this and see how it goes. I will mark this as the solution if everything is correct.

I think that I will actually use both methods, since I organized my waves into seperate modules. I can use the approximation if the chosen wave does not have a ‘getNormal’ method.

The + h parts should be - h, but everything seems to work! I will soon make a ‘Cool Creations’ post about my latest project. Then you will be able to revisit your contribution.

1 Like