Making A Mesh Deformation Ocean

So for the initial position one would do?

local origPosTable = {}

for _, bone in pairs(plane:GetChildren()) do
      if bone:IsA("Bone") then
              origPosTable[bone] = bone.WorldPosition
       end
end

I typed this on mobile so it probably came out wrong lol.

Everyone is talking and showing the formulas for this, and yet no one credits the original source. How come?
Here is an actually good tutorial for the math and code itself:

8 Likes

itā€™s not lua??? I dont understand the math of this and Idk how I can animate the texture : |

1 Like

How would I do this? Do I loop through every bone objectā€™s WorldPosition and add that to a table?

local plane = script.Parent:WaitForChild("Plane")
local origPosTable = {}
local LocalPlayer
local speedCounter = 5
local maxDistance = 10

script.RemoteEvent.OnServerEvent:Connect(function(plr)
	LocalPlayer = plr
end)

for _, bone in pairs(plane:GetChildren()) do
	if bone:IsA("Bone") then
		table.insert(origPosTable,bone.Position)
		origPosTable[bone] = bone.WorldPosition
	end
end

--GerstnerWave(Vector3 SamplePosition, Float Wavelength, Vector2 Direction, Float Steepness, Float Gravity, Float SampleTick)
function GerstnerWave(SamplePosition,Wavelength,Direction,Steepness,Gravity,SampleTick)
	local k = (2 * math.pi) / Wavelength
	local a = Steepness/k
	local d = Direction.Unit
	local c = math.sqrt(Gravity / k)
	local f = k * d:Dot(Vector2.new(SamplePosition.X,SamplePosition.Z)) - c * SampleTick
	local cosF = math.cos(f)

	--Displacement Vectors
	local dX = (d.X * (a * cosF))
	local dY = a * math.sin(f)
	local dZ = ( d.Y * (a * cosF))
	return Vector3.new(dX,dY,dZ)
end

game:GetService("RunService").Heartbeat:Connect(function()
	for _, bone in pairs(plane:GetChildren()) do
		if bone:IsA("Bone") then
			if origPosTable[bone] then
				local SamplePosition = bone.WorldPosition
				
				local Wave1 = GerstnerWave(SamplePosition, 150, Vector2.new(1, 0), .05, 1, speedCounter)
				local Wave2 = GerstnerWave(SamplePosition, 175, Vector2.new(0, .3), .2, 1.25, speedCounter)
				local Wave3 = GerstnerWave(SamplePosition, 200, Vector2.new(1, 1), .1, 1.5, speedCounter)
				local TotalDisplacement = Wave1 + Wave2 + Wave3
				bone.Position = origPosTable[bone] + TotalDisplacement
			end
		end
	end
end)

I dont know if itll work , but uh, someone correct me if i did this wrong

1 Like

Anyone with superficial knowledge in Lua will easily be able to understand how that code functions. I made my ocean explicitly by looking at that page, and I myself only know Lua.

1 Like

Wow. Youā€™ve helped A LOT of people with this tutorial!

Keep it up bro! Really appreciate it!

1 Like

I take algebra 1, so much math i dont think i understand, thats why, and i can barely understand what the tutorial is trying to tell me, and I dont know what they are trying to explain, just makes my brain hurt.

for _, bone in pairs(plane:GetChildren()) do
	if bone:IsA("Bone") then
		table.insert(origPosTable,bone)
	end
end
---bunch of code
bone.Position = origPosTable[bone].Position + TotalDisplacement

this should work, right? or should i findfirstchild the bone in the mesh after getting the boneā€™s name?

(first time working with skinned meshes)

@Frogbottles
Yes it is a LocalScript. Visual effects should always be handled on the client.

@Sb0bster and @intergravitation
You need to save the positions of each bone inside of a dictionary. Like this:

local plane = workspace:WaitForChild("Ocean"):WaitForChild("Plane")
for _, bone in pairs(plane:GetChildren()) do
	if bone:IsA("Bone") then
		origPosTable[bone] = bone.Position
	end
end

This code piece assumes the ā€œPlaneā€ object has the bones inside of it.

@Frogbottles

This doesnā€™t work, as you are referencing the new position every time. You need to store every boneā€™s position, not just the instance.

Here is a place file that should work:
Ocean.rbxl (185.9 KB)
Keep in mind that I havenā€™t really optimized this script. You might have lag on lower end devices.

8 Likes

I noticed that you canā€™t collide to the ocean, is it because it is a localscript?

Skinned meshes donā€™t collide if you change their bones. the solution is to make a custom floating function that takes in an x and z coordinate and spits out a y coordinate. This y coordinate will be how high the object is floating. As stated in the OP:

4 Likes

about a month ago I attempted making an ocean using gerstner waves as well and I got pretty far. https://gyazo.com/d7def53d363c76f7ea9fabfaea16e263 But the only thing that I got stuck on and what led me to quitting was making a swim system with an accurate collision. I know your suppost to apply the formula to the player and use the Y position on a bodyposition to do this but I could never figure out how to sync it up properly ever. https://gyazo.com/3a5a26f8c714175188fe5951d6264502 Basically what I am trying to ask is if you have any idea on how to make an accurate swimming/ floating system for the water could you give me any clues on how to achieve this as well.

Itā€™s hard to know just from looking at the video, but one thing that I encountered was that if you set the wavelength to be too much smaller than the distance between your bones, you lose out on a lot of detail and precision. I donā€™t know why else it would be so out of sync, you are doing it all on the client, right?

yea I am, but the reason its so wacky right now is because of a bunch of failed attempted fixes, usually its just delayed.

edit: Although the way you did yours is a bit different than mine because you added more parameters with gravity and steepness the math is nearly identical, so just out of curiosity how would you go about doing this in relation to your code?

Same with nifty here.

Iā€™m pretty sure the reason I canā€™t seem to link up floating objects in the water and the water itself to have actual physics is because the oceanā€™s bones are using relative position, instead of world position.

If there was some way to find the relative position to maybe the sea itself and the floating object, maybe they would finally be in sync.

Iā€™m also using a client & server time synchronizer, which I checked myself to see if it was really in sync (it is), so in case that isnā€™t the issue. Iā€™m not sure how Desired synched his objects so well with a BP.

Ok I figured it out the reason why I couldnā€™t get it to work. It was because In my script I was just solving for the Y when I was supposed to solve for the entire position and then just use the Y position.

Could you explain more? Did you accurately add in physics?

No all Iā€™m really doing is using a bodyposition to keep the players Y position exactly where it needs to be for it to look like the player is floating in the water. You cant do accurate collisions like OP said because the skinned water mesh acts like a special mesh.

Yeah Iā€™m talking about the equation youā€™re using for the BP. I canā€™t seem to sync up the BP with the ocean even as I am using the HumanoidRootPartā€™s CFrame.