#Ocean Script Help

1 messages · Page 1 of 1 (latest)

fast arrow
#

I've been working on a skinned mesh ocean for quite a bit of time and I'm having some bugs. The ocean looks and functions like how I want however I tried to make it so that if any parts were in a folder called Buoyancy, they would look like their floating by sitting at the top of the skinned mesh ocean based on the parts X and Z location. It kind of works but not that well. First of all it's close, but not accurate and idk if I can improve that. Also the further a part is from 0,0 the more inaccurate it tends to be and is also buggy, and any big parts are buggy and I have no clue why. Sorry for the yap, I'm just not at all a good coder and would like some help to just know if I did anything wrong or should add something. Thanks!

Video:
https://youtu.be/Hni86dVk2bI

#

Server Script in SSS (Part 1):

local meshPart = workspace:WaitForChild("OceanMesh")
local buoyancyFolder = workspace:WaitForChild("Buoyancy")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local latencyPing = ReplicatedStorage:FindFirstChild("LatencyPing") or Instance.new("RemoteFunction")
latencyPing.Name = "LatencyPing"
latencyPing.Parent = ReplicatedStorage

latencyPing.OnServerInvoke = function()
    return true
end

local WaveLength = 200
local Gravity = 9.81
local Steepness = 0.25
local TimeModifier = 20
local ShallowThreshold = 100
local IntermediateThreshold = 250
local LerpSpeed = 8

local MaxEffectiveDistance = 350
local MinEffectFactor = 0.1

local waveDirX = 1
local waveDirZ = 0.5

local function GetWaveHeightAtPos(x, z, origin, time)
    local pos2D = Vector2.new(x, z)
    local distance = (pos2D - origin).Magnitude

    local k = (2 * math.pi) / WaveLength
    local speed = math.sqrt(Gravity / k)
    local steepness = Steepness

    if distance < ShallowThreshold then
        steepness = steepness * 0.4
        speed = speed * 0.5
    elseif distance < IntermediateThreshold then
        steepness = steepness * 0.7
        speed = speed * 0.75
    end

    local a = steepness / k
    local phase = k * (waveDirX * (x - origin.X) + waveDirZ * (z - origin.Y)) - speed * time
    local y = a * math.sin(phase)
    return y
end

local function CalculateNormal(p1, p2, p3)
    local v1 = p2 - p1
    local v2 = p3 - p1
    return v1:Cross(v2).Unit
end

local previousCFrames = {}
solemn vector
#

what is that

fast arrow
#

bro discord limiting messages is killing me D:

#

Part 2:

RunService.Heartbeat:Connect(function(dt)
    local currentTime = workspace:GetServerTimeNow() / TimeModifier
    local origin2D = Vector2.new(meshPart.Position.X, meshPart.Position.Z)

    for _, part in ipairs(buoyancyFolder:GetChildren()) do
        if part:IsA("BasePart") then
            local partPos2D = Vector2.new(part.Position.X, part.Position.Z)
            local distToOrigin = (partPos2D - origin2D).Magnitude

            local effectFactor = 1
            if distToOrigin > MaxEffectiveDistance then
                effectFactor = MinEffectFactor
            elseif distToOrigin > IntermediateThreshold then
                local t = (distToOrigin - IntermediateThreshold) / (MaxEffectiveDistance - IntermediateThreshold)
                effectFactor = 1 - (1 - MinEffectFactor) * t
            end

            local halfSize = part.Size / 2
            local sampleGridSize = 3

            local samplePoints = {}
            for ix = 0, sampleGridSize - 1 do
                for iz = 0, sampleGridSize - 1 do
                    local xOffset = -halfSize.X + (ix / (sampleGridSize - 1)) * part.Size.X
                    local zOffset = -halfSize.Z + (iz / (sampleGridSize - 1)) * part.Size.Z
                    table.insert(samplePoints, Vector3.new(xOffset, 0, zOffset))
                end
            end
#

Part 3:

            local wavePositions = {}
            for _, localOffset in ipairs(samplePoints) do
                local worldPos = part.CFrame:PointToWorldSpace(localOffset)
                local localToMesh = meshPart.CFrame:PointToObjectSpace(worldPos)
                local waveY = GetWaveHeightAtPos(localToMesh.X, localToMesh.Z, Vector2.new(0, 0), currentTime) * 0.7 * effectFactor
                table.insert(wavePositions, Vector3.new(worldPos.X, meshPart.Position.Y + waveY, worldPos.Z))
            end
            local avgPos = Vector3.new(0,0,0)
            for _, pos in ipairs(wavePositions) do
                avgPos = avgPos + pos
            end
            avgPos = avgPos / #wavePositions

            local normal = CalculateNormal(wavePositions[1], wavePositions[sampleGridSize], wavePositions[#wavePositions])

            local forward = part.CFrame.LookVector
            local right = normal:Cross(forward).Unit
            forward = right:Cross(normal).Unit

            local targetCFrame = CFrame.fromMatrix(avgPos, right, normal, forward)

            local prevCFrame = previousCFrames[part]
            if prevCFrame then
                local lerpPos = prevCFrame.Position:Lerp(targetCFrame.Position, math.clamp(LerpSpeed * dt, 0, 1))
                local lerpRot = prevCFrame:ToObjectSpace(targetCFrame)
                local newCFrame = CFrame.new(lerpPos) * targetCFrame - targetCFrame.Position
                part.CFrame = newCFrame
                previousCFrames[part] = newCFrame
            else
                part.CFrame = targetCFrame
                previousCFrames[part] = targetCFrame
            end
        end
    end
end)
#

Local Script in SPS:

local meshPart = workspace:WaitForChild("OceanMesh")
local bones = {}
local RunService = game:GetService("RunService")

for _, obj in pairs(meshPart:GetDescendants()) do
    if obj:IsA("Bone") then
        table.insert(bones, obj)
    end
end

local origin = Vector2.new(0, 0)
local WaveLength = 200
local Gravity = 9.81
local Steepness = 0.25
local TimeModifier = 20
local ShallowThreshold = 100
local IntermediateThreshold = 250
local waveDirX = 1
local waveDirZ = 0.5

local function GetWaveHeightAtPos(x, z, time)
    local pos2D = Vector2.new(x, z)
    local distance = (pos2D - origin).Magnitude

    local k = (2 * math.pi) / WaveLength
    local speed = math.sqrt(Gravity / k)
    local steepness = Steepness

    if distance < ShallowThreshold then
        steepness = steepness * 0.4
        speed = speed * 0.5
    elseif distance < IntermediateThreshold then
        steepness = steepness * 0.7
        speed = speed * 0.75
    end

    local a = steepness / k
    local phase = k * (waveDirX * x + waveDirZ * z) - speed * time
    local y = a * math.sin(phase)
    return y
end

RunService.RenderStepped:Connect(function()
    local time = workspace:GetServerTimeNow() / TimeModifier
    for _, bone in pairs(bones) do
        local localPos = bone.Position
        local worldPos = meshPart.CFrame:PointToWorldSpace(localPos)
        local y = GetWaveHeightAtPos(worldPos.X, worldPos.Z, time)
        local localY = localPos.Y
        bone.Transform = CFrame.new(0, y - localY, 0)
    end
end)
#

Sorry for splitting it up this much it's limiting messages so I cant post it all in one message.

fast arrow