"Volumetric Fog" V1

This is a way of creating volumetric fog in Roblox using beams. This simple yet effective system simulates light being influenced by fog, bringing a touch of realism and atmosphere to your game.

How?
The system uses beams positioned in front of the camera to simulate light scattering caused by fog… These beams adjust dynamically based on the camera’s field of view and resolution size. This setup is lightweight and customizable.

-- Services
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

-- Constants
local SETTINGS = {
    LIGHT = {
        PART_NAME = "LightRaySource",
        EMISSION = 1,
        INFLUENCE = 1,
        COLOR = Color3.fromRGB(255, 255, 255),
        CAMERA_OFFSET = 2
    },
    RAYS = {
        COUNT = 100,
        SPACING = 0.7,
        TRANSPARENCY = {
            MIN = 0.9855,
            MAX = 1
        }
    }
}

-- Variables
local Camera = workspace.CurrentCamera
local raySourcePart = nil
local lightBeams = {}

-- Helper Functions
local function createPart()
    local part = Instance.new("Part")
    part.Name = SETTINGS.LIGHT.PART_NAME
    part.Size = Vector3.new(1, 1, 1)
    part.Anchored = true
    part.CanCollide = false
    part.Transparency = 1
    part.Parent = Camera
    return part
end

local function calculateBeamProperties()
    local viewportSize = Camera.ViewportSize
    local halfFOV = math.rad(Camera.FieldOfView / 2)
    local beamWidth = (math.tan(halfFOV) * 2 * viewportSize.X / viewportSize.Y) * 150
    return beamWidth
end

local function createBeamAttachments(parent, index, beamWidth)
    local zOffset = -index * SETTINGS.RAYS.SPACING - (index == 0 and SETTINGS.LIGHT.CAMERA_OFFSET or 0)
    
    local topAttachment = Instance.new("Attachment")
    local bottomAttachment = Instance.new("Attachment")
    
    topAttachment.CFrame = CFrame.new(0, beamWidth / 2, zOffset)
    bottomAttachment.CFrame = CFrame.new(0, -beamWidth / 2, zOffset)
    
    topAttachment.Parent = parent
    bottomAttachment.Parent = parent
    
    return {
        top = topAttachment,
        bottom = bottomAttachment
    }
end

local function createBeam(parent, index, attachments, beamWidth)
    local transparency = SETTINGS.RAYS.TRANSPARENCY.MIN +
        (index / (SETTINGS.RAYS.COUNT - 1)) *
        (SETTINGS.RAYS.TRANSPARENCY.MAX - SETTINGS.RAYS.TRANSPARENCY.MIN)
    
    local beam = Instance.new("Beam")
    beam.LightEmission = SETTINGS.LIGHT.EMISSION
    beam.LightInfluence = SETTINGS.LIGHT.INFLUENCE
    beam.Color = ColorSequence.new(SETTINGS.LIGHT.COLOR)
    beam.FaceCamera = true
    beam.Transparency = NumberSequence.new(transparency)
    beam.Width0 = beamWidth
    beam.Width1 = beamWidth
    beam.Attachment0 = attachments.top
    beam.Attachment1 = attachments.bottom
    beam.Parent = parent
    
    return beam
end

-- Core Functions
local function initializeSystem()
    if #lightBeams > 0 then return end
    
    raySourcePart = raySourcePart or createPart()
    local beamWidth = calculateBeamProperties()
    
    for i = 0, SETTINGS.RAYS.COUNT - 1 do
        local attachments = createBeamAttachments(raySourcePart, i, beamWidth)
        local beam = createBeam(raySourcePart, i, attachments, beamWidth)
        table.insert(lightBeams, beam)
    end
end

local function updateSystem()
    if not raySourcePart then return end
    
    raySourcePart.CFrame = Camera.CFrame
    local beamWidth = calculateBeamProperties()
    
    for _, beam in ipairs(lightBeams) do
        beam.Width0 = beamWidth
        beam.Width1 = beamWidth
    end
end

-- Initialize
initializeSystem()
RunService:BindToRenderStep(
    "UpdateLightRays",
    Enum.RenderPriority.Camera.Value,
    updateSystem
)

Now, if you find anything you want to let me know about the script that is bad, I will change it or fix it. I am not a great scripter but I wanted to show my method for fog.

note
I have made a demo place for you to try here, Custom "Lighting Engine" Demo - Roblox , RBLX file aswell. One final thing is if you are interested in how I made probes to show light bouncing I have used this awsome tool. LampLight - Global Illumination For Roblox (New v1.2). One final note, this is great for dark scenes with light sources, limited light sources may ruin the scene.
FogGame.rbxl (88.4 KB)

License
This script is completely open-source and free to use in any project. Feel free to modify and improve it as needed. If you enhance the script or use it in a game, I’d love to see what you create! just dont sell it and lable it as yours, unless modified heavily heavily,

7 Likes

I actually could use this, perfect timing. Does the behaviour of this get changed in any kind of way if you change the shadow map to future for example or does it not really matter?

2 Likes

I just chose voxel for a better look, it makes the fog look like cubes almost. But you still can run other lighting technologies without the effect being changed. Its really just whatever fits your boat. :ok_hand:Thanks for checking this out! :100:

1 Like

Hey so I just peeked through the source and noticed you are using VOLUMIKA, which is paid-access. Was this intended? I don’t believe Elttob allowed redistribution.

major oops, im so sorry. I was using it just too see how it looked and fergot it was in the place file. I will fix.

1 Like