Help on making a simulated ocean with Gerstner Waves

After much trial and error, I’ve decided to see if I can get help here…
I’ve been trying to make a custom ocean (not smooth terrain) using Gerstner Waves similar to tyridge77’s and RawEggTheGreatIX’s. – i don’t know if RawEggTheGreatIX used Gerstner Waves, but it has the affect I’m looking for.

I’ve been looking for a bunch of ways to do it, and I simply cannot figure out how to work it. The farthest I’ve gotten so far is making the plane mesh with bones, but have failed to fathom how to loop through the bones and work them with the Gerstner Wave formula. I’ve messed around with a few different fluid scripts such as this one.

Thanks for the help!

p.s. don’t be too hard on me, first post!

1 Like

I have had the opposite problem as you lol, i know how to get the valeus but not set those values and transform them to a mesh. It isnt gerstner its perlin however the concept is the same

As far as the mesh goes, I made a 10mx10m (x,z) plane and put a bone on every vertice (did this using a python script to save time)… perlin seems like a very interesting way to do it but I am still unsure as to how I would make it work with the bones.

Imported using avatar importer. waterplane.rbxm (66.1 KB)

I think this is what you want?

Roblox Plave File.rbxl (87.9 KB)

Not what I want
1 Like

Usually what you should to is make a function for returning a Y position of a certain X&Z, (or atleast thats how I did it)

something like this:

local function GetYFromWave(pos)
    local result = -- use noise, gerstner or other generation method
    return Vector3.new(pos.X,result,pos.Z)
end

Now to generate something, you can use multiple methods. I use a mix of noise and a module that creates patterns similar to gerstner waves

For noise, you would do something like this:

local function GetYFromWave(pos)
    local result = math.noise((pos.X+offset)/width, (pos.Z+offset)/width, seed)
    return Vector3.new(pos.X,result,pos.Z)
end

for gerstner, something like this im pretty sure:

local function GetYFromWave(pos)
    local resultX = math.sin(pos.X)
    local resultZ = math.sin(pos.Z)
    return Vector3.new(pos.X+resultX,resultX+result.Z,pos.Z+resultZ)
end

4 Likes

What would you typically use as an offset/how would you get it?

either tick() or a numberValue/Attribute that the server updates every post simulation. The number increases/decreases determines “speed” of the waves

1 Like

Not sure why, but this is incredibly laggy in game. The waves are very slow to update but everything else runs fine.

It works fine in studio though…

I made it clientsided using RunService.RenderStepped, will probably make it work that way… and connect it to the server in whatever way

I’ve heard good stuff with parralell luau for this, then again never done it. I don’t code resource intensive stuff on roblox i use opengl :smile:

Did you ever figure this out? I’d love to purchase this for a front page game I’m working on!

Hey there, sorry for the annoyance, but I just wanted to ask that how would I go about putting it into the mesh, I’ve been trying but didnt get it. I used the heartbeat even for it but it doesnt move, so could you help me with that?
My current script is this:

local function GetYFromWave(pos)
	local resultX = math.sin(pos.X)
	local resultZ = math.sin(pos.Z)
	return Vector3.new(pos.X+resultX, resultX+resultZ + 20, pos.Z+resultZ)
end

local ocean = workspace.Ocean.Plane
local bones = ocean:GetChildren()
game:GetService("RunService").Heartbeat:Connect(function(dt)
	for i, v in pairs(bones) do
		v.WorldPosition = GetYFromWave(v.WorldPosition)
	end
end)

Please note that I havent been taught about things such as sin, cosine, gerstner and all that so I might act dumb at times, sorry for that.

was the mesh rigged in blender?

Yeah it was, I used a python script to add bones at every vertex and parent it and all stuff

dont re-write the worldposition. Instead, change the Bone.Transform by using the worldposition as reference

1 Like

I got it working but forgot to reply, thanks.

Also, how exactly would you go about adding a direction vector to this formula? The waves are pretty good but would look even better if there is some way to change their direction.

Here’s my current code (works nicely)

local bones = workspace.Ocean.Plane:GetChildren()
local speedCounter = 0

local function GetYFromWave(pos)
	local amplitude = script:GetAttribute("Amplitude")
	local frequency = script:GetAttribute("Frequency")
	speedCounter += script:GetAttribute("Speed") / 10 -- dividing just to prevent extremely small numbers.
	
	local resultX = amplitude * math.sin(pos.X * frequency + speedCounter)
	local resultZ = amplitude * math.sin(pos.Z * frequency + speedCounter)
	
	return Vector3.new(pos.X + resultX, resultX + resultZ, pos.Z + resultZ)
end

game:GetService("RunService").Heartbeat:Connect(function()
	for i, bone in pairs(bones) do
		if bone:IsA("Bone") then
			bone.Transform = CFrame.new(GetYFromWave(bone.Position))
		end
	end
end)