How to keep Waves in sync when loading new waves? - GerstnerWave

I’m using the GerstnerWave module for an oceans project I’m making right now. I’m using EditableMeshes to achieve the wave effect. Basically, I’m struggling with re-syncing waves after deleting one and then readding it (essential for an LOD system)


As you can see, it seems to be resetting the clock on the wave despite the fact that I’m passing tick() as an argument to GerstnerWave. This makes me think it’s a change that needs to be made to the module, but I’m not smart enough to understand that module fully yet.

Do you have any suggestions for how I could resync the wave? Here’s the GerstnerWave module:

local GerstnerWave = {
	WaveInfo = {},
	System = {}
}

type WaveInfo = { any }

local tableInsert = table.insert

local twoPi = 2 * math.pi

local sqrt = math.sqrt
local cos = math.cos
local sin = math.sin
local atan2 = math.atan2

local vector3New = Vector3.new
local vector3Zero = Vector3.zero
local vector3XAxis = Vector3.xAxis
local vector3ZAxis = Vector3.zAxis

local vector2New = Vector2.new

function GerstnerWave.WaveInfo.new( direction: Vector2, waveLength: number, steepness: number, gravity: number ): WaveInfo
	return {
		direction or vector3New(1, 0),
		waveLength or 100,
		steepness or 0.3,
		gravity or 9.8
	}
end

function GerstnerWave:GetTransform( waves: { WaveInfo }, position: Vector2, runTime: number )
	local transform = vector3Zero
	
	for _, wave: WaveInfo in next, waves do
		transform += GerstnerWave.System:CalculateTransform(position, runTime, false, GerstnerWave.System:CalculateWave(unpack(wave)))
	end
	
	return transform
end

function GerstnerWave:GetHeightAndNormal( waves: { WaveInfo }, position: Vector2, runTime: number )
	local transform = vector3Zero
	local tangent = vector3XAxis
	local binormal = vector3ZAxis

	for _, wave: WaveInfo in next, waves do
		local resultTransform, resultTangent, resultBiNormal = GerstnerWave.System:CalculateTransform(position, runTime, true, GerstnerWave.System:CalculateWave(unpack(wave)))
		
		transform += resultTransform
		tangent += resultTangent
		binormal += resultBiNormal
	end

	return transform, tangent, binormal
end

function GerstnerWave:GetRotationAngle(transform1: Vector3, transform2: Vector3, rotationFactor: number)
	return atan2((transform1 - transform2).Y, rotationFactor)
end

function GerstnerWave.System:CalculateWave(...)
	local _, waveLength, steepness, gravity = ...
	
	local waveNumber = twoPi/waveLength
	local waveSpeed = sqrt(gravity/waveNumber)
	local waveAmplitude = steepness/waveNumber
	
	return waveNumber, waveSpeed, waveAmplitude, ...
end

function GerstnerWave.System:CalculateTransform(
	position: Vector2,
	runTime: number,
	calculateNormals: boolean,
	waveNumber: number,
	waveSpeed: number,
	waveAmplitude: number,
	waveDirection: Vector2,
	_, 
	steepness: number
)
	local wavePhase = waveNumber * (waveDirection:Dot(vector2New(position.X, position.Y)) - waveSpeed * runTime)
	
	local cosf = cos(wavePhase)
	local sinf = sin(wavePhase)
	
	local tangent, binormal
	if calculateNormals then
		local steepSinF = (steepness * sinf)
		local directionX = waveDirection.X
		local directionY = waveDirection.Y
		
		tangent = vector3New(-directionX * directionX * steepSinF, directionX * (steepness * cosf), -directionX * directionY * steepSinF)
		binormal = vector3New(-directionY * directionY * steepSinF, directionY * (steepness * cosf), -directionY * directionY * steepSinF)
	end
	
	return vector3New(waveDirection.X * (waveAmplitude * cosf), waveAmplitude * sinf, waveDirection.Y * (waveAmplitude * cosf)), tangent, binormal
end

return GerstnerWave

Here’s the section of my code that sets the wave: (Let me know if you need to see more. I can DM you the full code.)

for _, VertexID in Vertices do
	local Position = EditableMesh:GetPosition(VertexID)
	local WorldPosition = Object.CFrame:PointToWorldSpace(Position * Object.Size / Object.MeshSize)
	local GeneratePosition = Vector2.new(WorldPosition.X, WorldPosition.Z)
					
	EditableMesh:SetPosition(VertexID, Position + (GerstnerWaves:GetTransform(Waves, GeneratePosition, tick()) * Vector3.new(0,1,0)))
end

Thanks guys!! :smiley:

Hi,

I am not sure myself but maybe try to set the start time and then subtract the start time of the current time:

local startTime = os.clock() -- a start time vairable at the top of the programm
EditableMesh:SetPosition(VertexID, Position + (GerstnerWaves:GetTransform(Waves, GeneratePosition, os.clock() - startTime) * Vector3.new(0,1,0)))

1 Like

I found out the reason.
The Gerstner waves module works off of displacement. Instead of just setting a hard value, it looks at the previous position of the wave and bases the next position off of that.

I ended up just hunkering down and learning how the module works. I created my own version that uses algorithms to set a hard value based on tick() instead of using displacement.

Thanks for your help, though! This post was really just my attempt at not having to learn that module :rofl:. But once I learned it was a displacement issue, I knew the only solution would be a re-program of the module.

1 Like

The most problems solve itself when you actually learn how it works :+1:
Nice to hear that it works now!

1 Like