Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

Is there a way to detect all the bricks that are obscuring the camera's view of an object? [FIXED]

Asked by 9 years ago

Basically what I'm trying to achieve is a custom version of "Invisicam" mode as the CameraOcclusionMode property of the player. What it does is that instead of not allowing the camera to go past a part if that part is blocking the camera, the camera will go past the part and make whatever parts that are obstructing the camera's view of the player transparent. Essentially I'm trying to make a similar version of this, but I can't think of any way to do this efficiently and accuratly.

Any help would be appreciated, I'm not looking for a script, just suggestions or a walkthrough.

Thanks.

EDIT

I figured it out by using the Player CameraScript and using the Invisicam module that was a child of the script, I'll post the code below in the answers

1 answer

Log in to vote
0
Answered by 9 years ago

Here's the solution for anyone else who had my same question:

-- Invisicam Version 2.5 (Occlusion Series)
-- For the latest standalone version see id=183837794
-- OnlyTwentyCharacters

local Invisicam = {}

---------------
-- Constants --
---------------

local FADE_TARGET = 0.75
local FADE_RATE = 0.1

local MODE = {
    CUSTOM = 1, -- Whatever you want!
    LIMBS = 2, -- Track limbs
    MOVEMENT = 3, -- Track movement
    CORNERS = 4, -- Char model corners
    CIRCLE1 = 5, -- Circle of casts around character
    CIRCLE2 = 6, -- Circle of casts around character, camera relative
    LIMBMOVE = 7, -- LIMBS mode + MOVEMENT mode
}
Invisicam.MODE = MODE

local STARTING_MODE = MODE.LIMBS

local LIMB_TRACKING_SET = {
    ['Head'] = true,
    ['Left Arm'] = true,
    ['Right Arm'] = true,
    ['Left Leg'] = true,
    ['Right Leg'] = true,
}
local CORNER_FACTORS = {
    Vector3.new(1, 1, -1),
    Vector3.new(1, -1, -1),
    Vector3.new(-1, -1, -1),
    Vector3.new(-1, 1, -1)
}
local CIRCLE_CASTS = 10
local MOVE_CASTS = 3

---------------
-- Variables --
---------------

local RunService = game:GetService('RunService')
local PlayersService = game:GetService('Players')
local Player = PlayersService.LocalPlayer

local Camera = nil
local Character = nil
local Torso = nil

local Mode = nil
local Behaviors = {} -- Map of modes to behavior fns
local SavedHits = {} -- Objects currently being faded in/out
local TrackedLimbs = {} -- Used in limb-tracking casting modes

---------------
--| Utility |--
---------------

local function AssertTypes(param, ...)
    local allowedTypes = {}
    local typeString = ''
    for _, typeName in pairs({...}) do
        allowedTypes[typeName] = true
        typeString = typeString .. (typeString == '' and '' or ' or ') .. typeName
    end
    local theType = type(param)
    assert(allowedTypes[theType], typeString .. " type expected, got: " .. theType)
end

local function CameraCast(worldPoint, ignoreList)
    local cameraPoint = Camera.CoordinateFrame.p
    local vector = worldPoint - cameraPoint
    local ray = Ray.new(cameraPoint, vector.Unit * math.min(vector.Magnitude, 999))
    return workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
end

-----------------------
--| Local Functions |--
-----------------------

local function LimbBehavior(castPoints)
    for _, limb in pairs(TrackedLimbs) do
        if limb.Parent then
            table.insert(castPoints, limb.Position)
        end
    end
end

local function MoveBehavior(castPoints)
    for i = 1, MOVE_CASTS do
        local position, velocity = Torso.Position, Torso.Velocity
        local horizontalSpeed = Vector3.new(velocity.X, 0, velocity.Z).Magnitude / 2
        local offsetVector = (i - 1) * Torso.CFrame.lookVector * horizontalSpeed
        table.insert(castPoints, position + offsetVector)
    end
end

local function CornerBehavior(castPoints)
    local cframe = Torso.CFrame
    local centerPoint = cframe.p
    local rotation = cframe - centerPoint
    local halfSize = Character:GetExtentsSize() / 2 --NOTE: Doesn't update w/ limb animations
    table.insert(castPoints, centerPoint)
    for _, factor in pairs(CORNER_FACTORS) do
        table.insert(castPoints, centerPoint + (rotation * (halfSize * factor)))
    end
end

local function CircleBehavior(castPoints)
    local cframe = nil
    if Mode == MODE.CIRCLE1 then
        cframe = Torso.CFrame
    else
        local camCFrame = Camera.CoordinateFrame
        cframe = camCFrame - camCFrame.p + Torso.Position
    end
    table.insert(castPoints, cframe.p)
    for i = 0, CIRCLE_CASTS - 1 do
        local angle = (2 * math.pi / CIRCLE_CASTS) * i
        local offset = 3 * Vector3.new(math.cos(angle), math.sin(angle), 0)
        table.insert(castPoints, cframe * offset)
    end
end

local function LimbMoveBehavior(castPoints)
    LimbBehavior(castPoints)
    MoveBehavior(castPoints)
end

local function OnCharacterAdded(character)
    Character = character
    Torso = Character:WaitForChild('Torso')

    TrackedLimbs = {}
    for _, child in pairs(Character:GetChildren()) do
        if child:IsA('BasePart') and LIMB_TRACKING_SET[child.Name] then
            table.insert(TrackedLimbs, child)
        end
    end
end

local function OnWorkspaceChanged(property)
    if property == 'CurrentCamera' then
        local newCamera = workspace.CurrentCamera
        if newCamera then
            Camera = newCamera
        end
    end
end

-----------------------
-- Exposed Functions --
-----------------------

-- Update. Called every frame after the camera movement step
function Invisicam:Update()
    -- Make a list of world points to raycast to
    local castPoints = {}
    Behaviors[Mode](castPoints)

    -- Cast to get a list of objects between the camera and the cast points
    local currentHits = {}
    local ignoreList = {Character}
    local function add(hit)
        currentHits[hit] = true
        if not SavedHits[hit] then
            SavedHits[hit] = hit.LocalTransparencyModifier
        end
    end
    for _, worldPoint in pairs(castPoints) do
        repeat
            local hitPart = CameraCast(worldPoint, ignoreList)
            if hitPart then
                add(hitPart)
                for _, child in pairs(hitPart:GetChildren()) do
                    if child:IsA('Decal') or child:IsA('Texture') then
                        add(child)
                    end
                end
                table.insert(ignoreList, hitPart) -- Next ray will go through this part
            end
        until not hitPart
    end

    -- Fade out objects that are in the way, restore those that aren't anymore
    for hit, originalFade in pairs(SavedHits) do
        local currentFade = hit.LocalTransparencyModifier
        if currentHits[hit] then -- Fade
            if currentFade < FADE_TARGET then
                hit.LocalTransparencyModifier = math.min(currentFade + FADE_RATE, FADE_TARGET)
            end
        else -- Restore
            if currentFade > originalFade then
                hit.LocalTransparencyModifier = math.max(originalFade, currentFade - FADE_RATE)
            else
                SavedHits[hit] = nil
            end
        end
    end
end

function Invisicam:SetMode(newMode)
    AssertTypes(newMode, 'number')
    for modeName, modeNum in pairs(MODE) do
        if modeNum == newMode then
            Mode = newMode
            return
        end
    end
    error("Invalid mode number")
end

function Invisicam:SetCustomBehavior(func)
    AssertTypes(func, 'function')
    Behaviors[MODE.CUSTOM] = func
end

-- Want to turn off Invisicam? Be sure to call this after.
function Invisicam:Cleanup()
    for hit, originalFade in pairs(SavedHits) do
        hit.LocalTransparencyModifier = originalFade
    end
end

---------------------
--| Running Logic |--
---------------------

-- Connect to the current and all future cameras
workspace.Changed:connect(OnWorkspaceChanged)
OnWorkspaceChanged('CurrentCamera')

Player.CharacterAdded:connect(OnCharacterAdded)
if Player.Character then
    OnCharacterAdded(Player.Character)
end

Invisicam:SetMode(STARTING_MODE)

Behaviors[MODE.CUSTOM] = function() end -- (Does nothing until SetCustomBehavior)
Behaviors[MODE.LIMBS] = LimbBehavior
Behaviors[MODE.MOVEMENT] = MoveBehavior
Behaviors[MODE.CORNERS] = CornerBehavior
Behaviors[MODE.CIRCLE1] = CircleBehavior
Behaviors[MODE.CIRCLE2] = CircleBehavior
Behaviors[MODE.LIMBMOVE] = LimbMoveBehavior

return Invisicam

That's from the Invisicam module in the CameraScript that's a Player script. Hope this helped anybody.

0
I've been looking for something that would directly cast a ray from one point to another and return all the parts that the ray passed through, and this will probably help me with that. Thanks! xolbStudios 127 — 9y
Ad

Answer this question