Can you make this simulation 3d with particles in roblox studio? Code: --!native
local N = 100 -- Size of the grid
local gridSize = 1 -- Size of each part in the grid
local dt = 0.1 -- Time step
local iter = 8 -- Number of solver iterations
local diff = 0.0 -- Diffusion rate
local visc = 0.0 -- Viscosity
local moveSpeed = 25 -- Speed of the object movement
local stormSize = 5 -- Size of the fluid emission area
local dispersionRate=0
local fluidSpeed= 5
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local function createGrid(n)
local grid = {}
for i = 1, n do
grid[i] = {}
for j = 1, n do
grid[i][j] = 0
end
end
return grid
end

local function setBoundary(b, x)
for i = 2, N - 1 do
x[1][i] = (b == 1 and -x[2][i] or x[2][i])
x[N][i] = (b == 1 and -x[N-1][i] or x[N-1][i])
x[i][1] = (b == 2 and -x[i][2] or x[i][2])
x[i][N] = (b == 2 and -x[i][N-1] or x[i][N-1])
end
x[1][1] = 0.5 * (x[2][1] + x[1][2])
x[1][N] = 0.5 * (x[2][N] + x[1][N-1])
x[N][1] = 0.5 * (x[N-1][1] + x[N][2])
x[N][N] = 0.5 * (x[N-1][N] + x[N][N-1])
end

local function linSolve(b, x, x0, a, c)
local cRecip = 1.0 / c
for k = 1, iter do
for i = 2, N - 1 do
for j = 2, N - 1 do
x[i][j] = (x0[i][j] + a * (x[i+1][j] + x[i-1][j] + x[i][j+1] + x[i][j-1])) * cRecip
end
end
setBoundary(b, x)
end
end

local function diffuse(b, x, x0, diff, dt, dissipationRate)
local a = dt * diff * (N - 2) * (N - 2)
local cRecip = 1.0 / (1 + 4 * a + dissipationRate * dt)
for k = 1, iter do
for i = 2, N - 1 do
for j = 2, N - 1 do
x[i][j] = (x0[i][j] + a * (x[i+1][j] + x[i-1][j] + x[i][j+1] + x[i][j-1])) * cRecip
end
end
setBoundary(b, x)
end
end

local function advect(b, d, d0, u, v, dt, parts, wall)
local dt0 = dt * (N - 2)
for i = 2, N - 1 do
for j = 2, N - 1 do
local x = i - dt0 * u[i][j]
local y = j - dt0 * v[i][j]
if x < 1.5 then x = 1.5 end
if x > N - 0.5 then x = N - 0.5 end
local i0 = math.floor(x)
local i1 = i0 + 1
if y < 1.5 then y = 1.5 end
if y > N - 0.5 then y = N - 0.5 end
local j0 = math.floor(y)
local j1 = j0 + 1
local s1 = x - i0
local s0 = 1 - s1
local t1 = y - j0
local t0 = 1 - t1
local i00 = i0
local i10 = i1
local j00 = j0
local j10 = j1
if parts[i0][j0] == wall then
i00 = i1
j00 = j0
u[i][j] = 0
v[i][j] = 0
elseif parts[i1][j0] == wall then
i10 = i0
j10 = j0
u[i][j] = 0
v[i][j] = 0
elseif parts[i0][j1] == wall then
i00 = i0
j00 = j1
u[i][j] = 0
v[i][j] = 0
elseif parts[i1][j1] == wall then
i10 = i0
j10 = j1
u[i][j] = 0
v[i][j] = 0
end
d[i][j] = s0 * (t0 * d0[i00][j00] + t1 * d0[i00][j10]) + s1 * (t0 * d0[i10][j00] + t1 * d0[i10][j10])
end
end
setBoundary(b, d)
end

local function project(u, v, p, div)
local h = 1.0 / (N - 2)
for i = 2, N - 1 do
for j = 2, N - 1 do
div[i][j] = -0.5 * h * (u[i+1][j] - u[i-1][j] + v[i][j+1] - v[i][j-1])
p[i][j] = 0
end
end
setBoundary(0, div)
setBoundary(0, p)
linSolve(0, p, div, 1, 4)
for i = 2, N - 1 do
for j = 2, N - 1 do
u[i][j] = u[i][j] - 0.5 * (p[i+1][j] - p[i-1][j]) / h
v[i][j] = v[i][j] - 0.5 * (p[i][j+1] - p[i][j-1]) / h
end
end
setBoundary(1, u)
setBoundary(2, v)
end

local function addSource(x, s, dt)
for i = 1, N do
for j = 1, N do
x[i][j] = x[i][j] + dt * s[i][j]
end
end
end

local function fluidStep(u, v, uPrev, vPrev, dens, densPrev, parts, wall, dissipationRate)
addSource(u, uPrev, dt)
addSource(v, vPrev, dt)
addSource(dens, densPrev, dt)


    uPrev, u = u, uPrev
    vPrev, v = v, vPrev
    diffuse(1, u, uPrev, visc, dt, dissipationRate)
    diffuse(2, v, vPrev, visc, dt, dissipationRate)
    project(u, v, uPrev, vPrev)

    uPrev, u = u, uPrev
    vPrev, v = v, vPrev
    advect(1, u, uPrev, uPrev, vPrev, dt, parts, wall)
    advect(2, v, vPrev, uPrev, vPrev, dt, parts, wall)
    project(u, v, uPrev, vPrev)

    densPrev, dens = dens, densPrev
    diffuse(0, dens, densPrev, diff, dt, dissipationRate)
    densPrev, dens = dens, densPrev
    advect(0, dens, densPrev, u, v, dt, parts, wall)

    -- Apply wall boundary conditions
    for i = 1, N do
            for j = 1, N do
                    if parts[i][j] == wall then
                            u[i][j] = -u[i][j]
                            v[i][j] = -v[i][j]
                    end
            end
    end

    -- Move pushable objects
    for i = 1, N do
            for j = 1, N do
                    if parts[i][j] ~= wall then
                            local forceX = u[i][j] * moveSpeed
                            local forceY = v[i][j] * moveSpeed
                            parts[i][j].Velocity = Vector3.new(forceX, 0, forceY)
                    end
            end
    end
end
local function createParts()
local parts = {}
for i = 1, N do
parts[i] = {}
for j = 1, N do
local part = Instance.new("Part")
part.Size = Vector3.new(gridSize, 1, gridSize)
part.Anchored = true
part.Position = Vector3.new((i - 1) * gridSize, 0, (j - 1) * gridSize)
part.Color = Color3.fromRGB(255, 255, 255)
part.Parent = workspace
parts[i][j] = part
end
end
return parts
end

local function updateParts(parts, dens, u, v, wall, pushableObject)
for i = 1, N do
for j = 1, N do
local part = parts[i][j]
local density = dens[i][j]
if part == wall then
part.Color = Color3.fromRGB(255, 0, 0)
else
local color = Color3.fromHSV((1 - density) * 0.7, 1, 1) -- Rainbow shading
part.Color = color
end
end
end


    -- Update the pushable object's position based on the fluid forces
    local pushableObjectPosition = pushableObject.Position
    local x = math.floor(pushableObjectPosition.X / gridSize) + 1
    local y = math.floor(pushableObjectPosition.Z / gridSize) + 1

    if x >= 1 and x <= N and y >= 1 and y <= N then
            local forceX
            local forceY
            if u[x] and u[x][y] then
                    forceX = u[x][y]
            else
                    forceX = 0
            end

            if v[x] and v[x][y] then
                    forceY = v[x][y]
            else
                    forceY = 0
            end

            pushableObject.Velocity = Vector3.new(forceX * moveSpeed, 0, forceY * moveSpeed)
    end
end

local UserInputService = game:GetService("UserInputService")

local angle = 0

local angle = 0

local function applyMouseForce(uPrev, vPrev, densPrev, centerX, centerY, angle, force, size)
local radius = size // 2
for i = -radius, radius do
for j = -radius, radius do
local xi = centerX + i
local yj = centerY + j
if xi >= 1 and xi <= N and yj >= 1 and yj <= N then
local fx = force * math.cos(angle)
local fy = force * math.sin(angle)
uPrev[xi][yj] = uPrev[xi][yj] + fx
vPrev[xi][yj] = vPrev[xi][yj] + fy
densPrev[xi][yj] = densPrev[xi][yj] + 1
end
end
end
end

UserInputService.InputBegan:Connect(function(input)
if input.KeyCode == Enum.KeyCode.Left then
angle = angle - 0.1
elseif input.KeyCode == Enum.KeyCode.Right then
angle = angle + 0.1
end
end)

local function main()
local u = createGrid(N)
local v = createGrid(N)
local uPrev = createGrid(N)
local vPrev = createGrid(N)
local dens = createGrid(N)
local densPrev = createGrid(N)


    local parts = createParts()

    -- Create wall
    local wall = Instance.new("Part")
    wall.Size = Vector3.new(gridSize, 1, gridSize)
    wall.Anchored = true
    wall.Position = Vector3.new(50 * gridSize, 0, 50 * gridSize)
    wall.Color = Color3.fromRGB(255, 0, 0)
    wall.Parent = workspace

    parts[32][51] = wall
    parts[32][52] = wall
    parts[32][53] = wall
    parts[32][54] = wall
    parts[32][55] = wall
    parts[32][56] = wall
    parts[32][57] = wall
    parts[32][58] = wall

    parts[33][51] = wall
    parts[33][52] = wall
    parts[33][53] = wall
    parts[33][54] = wall
    parts[33][55] = wall
    parts[33][56] = wall
    parts[33][57] = wall
    parts[33][58] = wall

    parts[34][51] = wall
    parts[34][52] = wall
    parts[34][53] = wall
    parts[34][54] = wall
    parts[34][55] = wall
    parts[34][56] = wall
    parts[34][57] = wall
    parts[34][58] = wall

    -- Create invisible colliders above the walls
    for i = 1, N do
            for j = 1, N do
                    if parts[i][j] == wall then
                            local collider = Instance.new("Part")
                            collider.Size = Vector3.new(gridSize, 20, gridSize)
                            collider.Position = Vector3.new((i - 1) * gridSize, 10, (j - 1) * gridSize)
                            collider.Anchored = true
                            collider.CanCollide = true
                            collider.Transparency = 1
                            collider.CollisionGroup = "WallCollider"
                            collider.Parent = workspace
                    end
            end
    end

    -- Create pushable object
    local pushableObject = Instance.new("Part")
    pushableObject.Size = Vector3.new(gridSize, 1, gridSize)
    pushableObject.Anchored = false
    pushableObject.Position = Vector3.new(30 * gridSize, 0, 30 * gridSize)
    pushableObject.Color = Color3.fromRGB(0, 255, 0)
    pushableObject.Parent = workspace

    --local parts = createParts()

    -- Set initial position for fluid emission
    local centerX = math.floor(N / 2)
    local centerY = math.floor(N / 2)
    local fluidForce = 5 -- Force applied when fluid is emitted
    local fluidSize = stormSize -- The size of the fluid emission area



    -- Main simulation loop
    RunService.Heartbeat:Connect(function()
            -- Clear previous velocity and density
            uPrev = createGrid(N)
            vPrev = createGrid(N)
            densPrev = createGrid(N)

            -- Apply force from the center following the current angle
            applyMouseForce(uPrev, vPrev, densPrev, centerX, centerY, angle, fluidForce, fluidSize)

            -- Perform fluid simulation step
            fluidStep(u, v, uPrev, vPrev, dens, densPrev, parts, wall, 0.01)

            -- Update the parts to visually reflect the fluid simulation
            updateParts(parts, dens, u, v, wall, pushableObject)
    end)
end

main()