#Bullet Penetration Method

1 messages · Page 1 of 1 (latest)

earnest tendon
#

The variables that are accessible are the RaycastResult, The Direction and Origin of the Raycast (Vector3 obviously), The Instance properties and what im trying to get from this is the other surface end point in a Vector3 value (Penetration length can be obtained by subtracting origin Vector3, the calculated Vector3 Penetration point and index .Magnitude), I have tried doing the method where you perform a 2nd Raycast check with the 1st RaycastResult Instance excluded and then the 3rd Raycast is from the 2nd RaycastResult Position with the inverted direction and get the 3rd RaycastResult Position and subtract the 1st and 3rd Position and get the Penetration length, this leads to more bugs one of which that if an object is inside the part it will get inaccurate results.

Maybe is there a bunch of math formulas that can help only to calculate the Penetration position and its length ?

#

Here is the method I tried came up with

#
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local runService = game:GetService("RunService")

local function raycastAndPenetrate()
    local direction = mouse.UnitRay.Direction * 1000
    local currentOrigin = mouse.Origin.Position

    while runService.RenderStepped:Wait() do
        local params = RaycastParams.new()
        local firstHitResult = workspace:Raycast(currentOrigin, direction, params)
        if firstHitResult then
            if direction.Magnitude - (firstHitResult.Position - currentOrigin).Magnitude <= 0 then
                return firstHitResult
            else
                params.FilterType = Enum.RaycastFilterType.Exclude
                params:AddToFilter(firstHitResult.Instance)
                local secondHitResult = workspace:Raycast(firstHitResult.Position, direction, params)
                if secondHitResult then
                    local backDirection = (firstHitResult.Position - secondHitResult.Position).Unit * direction.Magnitude
                    params.FilterType = Enum.RaycastFilterType.Include
                    local backHitResult = workspace:Raycast(secondHitResult.Position, backDirection, params)
                    if backHitResult and backHitResult.Instance == firstHitResult.Instance then
                        local penetrationDepth = (firstHitResult.Position - backHitResult.Position).Magnitude
                        if penetrationDepth > 5 then -- getMaxPenDepth(penetrationDepth, firstHitResult.Material)
                            return firstHitResult
                        else
                            currentOrigin = backHitResult.Position
                        end
                    else
                        return firstHitResult
                    end
                else
                    return firstHitResult
                end
            end
        else
            return
        end

    end
end

mouse.Button1Down:Connect(raycastAndPenetrate)```
earnest tendon
twilit fractal
#

why is it so long

#

All you need to do is check if hit part is penetrable, if yes, raycast again from result position to goal and add the part into a blacklist

#

Oh I see you're trying to get the depth that needs to be shot through

earnest tendon
#

also since its penetration the first RaycastResult value is accessible for the penetration calculation (and the Origin and Direction)

grand goblet
#

You could look into RaycastResult.Normal

#

As far as I know, there is no way to work with part surfaces directly

#

Using the part size may be inconsistent with non blocks like spheres

#

A double raycast sounds like the best choice

#

You can filter it to only include the part that’s being checked for penetration

#

But I don’t know any way to check mathematically

earnest tendon
#

guess ill find out when I finish highschool

grand goblet
#

I had a similar issue with something else a while ago

#

Actually it’s a very similar issue 🤔

#

I was trying to do it without raycasting but in the end, I decided it wasn’t worth the trouble

twilit fractal
twilit fractal
#

Hmm, I dont think there is a way without assuming its a square

#

Actually even for a square you would still need more and sifferent data

#

Since you dont actually know much about the hit part

still prairie
#

@earnest tendon

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local runService = game:GetService("RunService")

local function performRaycast(origin, direction, filterInstance)
    local params = RaycastParams.new()
    if filterInstance then
        params.FilterDescendantsInstances = { filterInstance }
        params.FilterType = Enum.RaycastFilterType.Exclude
    end
    return workspace:Raycast(origin, direction, params)
end

local function calculatePenetration(firstHit, direction)
    local penetrationDir = direction.Unit * 1000
    local secondHit = performRaycast(firstHit.Position, penetrationDir, firstHit.Instance)
    
    if secondHit then
        local reverseDir = (firstHit.Position - secondHit.Position).Unit * direction.Magnitude
        local backHit = performRaycast(secondHit.Position, reverseDir)
        
        if backHit and backHit.Instance == firstHit.Instance then
            local penetrationDepth = (firstHit.Position - backHit.Position).Magnitude
            return penetrationDepth, backHit.Position
        end
    end
    return 0, firstHit.Position
end

local function raycastAndPenetrate()
    while runService.RenderStepped:Wait() do
        local direction = mouse.UnitRay.Direction * 1000
        local origin = mouse.Origin.Position
        local hitResult = performRaycast(origin, direction)
        
        if hitResult then
            local penetrationDepth, penetrationPoint = calculatePenetration(hitResult, direction)
            if penetrationDepth > 5 then
                return penetrationPoint
            else
                return hitResult.Position
            end
        else
            return
        end
    end
end

mouse.Button1Down:Connect(raycastAndPenetrate)
earnest tendon
earnest tendon
still prairie
maiden onyxBOT
#

studio** You are now Level 3! **studio

earnest tendon
twilit fractal
#

Hit position, size of the part is irrelevant because even if you knew how to get around it being oriented differently

#

if its hit at an angle it no longer applies

#

Normal wouldnt help at all either

#

So all you really know is the hit position and bullet direction

#

I don't think you can find much from this without another ray cast

#

I am still not sure where your third raycast comes in though

earnest tendon
twilit fractal
#

I highly doubt it

#

Only additional information you can get is length from entry point to corner

earnest tendon
#

btw what were you explaining

twilit fractal
#

?

earnest tendon
#

ee

twilit fractal
#

which you cant without knowing it

earnest tendon
#

the method to get the exit point from the entry point

#

I know how to get the depth/length if you didnt know

twilit fractal
#

Well it's not a method because it isn't possible imo

earnest tendon
twilit fractal
#

Oh well yeah

earnest tendon
#

both thing's are the entry/exit points

twilit fractal
#

But our issue is getting thing

earnest tendon
#

no

#

because

twilit fractal
#

All you know is entry

earnest tendon
#

The first RaycastResult

twilit fractal
#

without a second raycast

#

Yeah

#

That only gives us entry

earnest tendon
#

yes

twilit fractal
#

We can't do much with that

earnest tendon
#

Yeah but a Raycast result gives us the instance (the thing) and the point

twilit fractal
#

Yeah but you don't know which side is which

#

You don't even know which side you hit

#

You only know the normal of that face

#

There is no way, especially in any shape other than rectangle or square

#

But I'm a bit confused on where you use backhit and fronthit raycasts

earnest tendon
#

First raycast gets the first instance we want to penet, 2nd raycast excluded the instance and get a stopping point to raycast back, third raycast, goes reverse direction

#

so just subtracting the 1st raycast hit point and the 3rd one gets the penetration depth

#

is there a game that documents their game

#

which also happens to be a shooter

twilit fractal
#

There probably is

#

I don't know any though

earnest tendon
#

any questions

#

this is the method I came up with,

#

and theres no offsets between every raycast origin

#

same direction

#

2nd raycast Origin is from where the 1st raycast hit

#

3rd origin is from 2nd hit

#

but direction is inverted

twilit fractal
#

what if there is no second object

earnest tendon
#

probably I think it went off the sky

#

and returned the 1st raycast result

#

so yeh

twilit fractal
#

You are saving a raycast but this isn't much faster

earnest tendon
#

its innacurate

twilit fractal
#

It's slower in some instances too

#

Raycast length matters

#

It would be better just using the more obvious solution

earnest tendon
#

it doesnt have to hit anything if the 2nd fails

twilit fractal
#

Yeah but the length

#

The length of the second one

#

It needs to check far more

earnest tendon
#

oh Ill just override it with like

#

1024 studs

#

2048

twilit fractal
#

Thats still a lot more then just adding another raycast

#

thats going to be like 5 studs

earnest tendon
#

yeah but the purpose of the 2nd ray is to find a candidate for the 3rd raycast origin

maiden onyxBOT
#

studio** You are now Level 4! **studio

earnest tendon
#

far from the instance we want to penetrate

#

im bad english

twilit fractal
#

Yeah youre trying to skip one

earnest tendon
#

skip what?

twilit fractal
#

Here you have three raycasts

#

two of them can have varying lengths

#

depending on how far an object is

#

and one is max penetration length long

#

compared to the other solution

#

which has three x long raycasts

#

So if the second object is a 100 studs away

#

thats 95 more studs to check

#

Making a raycast isn't expensive

#

How much it checks is the important part

twilit fractal
#

Your solution saves a miniscule amount of ram at the cost of speed

#

which is far more important when you have a shooter game

earnest tendon
#

How do phantom forces

#

nvm

twilit fractal
#

I dont think thats public

earnest tendon
#

source code were leaked maybe I could learn

#

but

twilit fractal
earnest tendon
#

what if theres a part inside in the penet part, and the 2nd raycast takes it

twilit fractal
#

Good thinking

#

Easy fix though, just check

earnest tendon
#

I knew how to get the length from the 1st point and the 2nd one

#

how do I know its not inside

#

that kinda goes back to the mathematical method I wanted to find out

twilit fractal
#

Well that matters on how raycasts handle being inside of a part

earnest tendon
#

sorry brain

twilit fractal
#

which I don't actually know

#

If it ignores then we might have a slight issue

#

if it hits, then itll hit the exact same spot as entrance

#

meaning it exceeded max limit so dont penetrate

#

simplest solution is to not overcomplicate the system

#

and not worry about length at all

#

which is what phantom forces likely does

earnest tendon
#

ok imma look inside their 2016 save

twilit fractal
#

because no one will care or notice that since they hit is at a different angle they do 2% less damage

earnest tendon
#

im stupid asf 💔

still prairie
#

ReplicatedStorage/Config/Combat.lua

#

--!strict
-- Centralized, tunable values (no magic numbers in logic)

export type MaterialResistanceMap = {[Enum.Material]: number}

local Combat = {
    -- Shooting
    RateLimitSeconds = 0.06,
    MaxRange = 1000.0,
    BaseEnergy = 25.0,
    MaxPenetrations = 16,
    MinDirMagnitude = 1e-4,

    -- Damage
    HitDamage = 20.0,

    -- Penetration
    Epsilon = 1e-3,
    DefaultMaterialResistance = 2.0,
    PenMultiplierAttribute = "PenetrationMultiplier" :: string,
    MaterialResistance = {
        [Enum.Material.Air] = 0.0,
        [Enum.Material.Plastic] = 0.8,
        [Enum.Material.Wood] = 1.0,
        [Enum.Material.Glass] = 0.5,
        [Enum.Material.Concrete] = 3.0,
        [Enum.Material.Brick] = 2.2,
        [Enum.Material.Metal] = 5.0,
        [Enum.Material.DiamondPlate] = 6.0,
        [Enum.Material.Granite] = 4.0,
        [Enum.Material.Slate] = 3.5,
        [Enum.Material.Asphalt] = 2.6,
        [Enum.Material.Grass] = 0.3,
        [Enum.Material.Ice] = 0.6,
    } :: MaterialResistanceMap,

    -- Anti-exploit
    MaxOriginOffsetFromCharacter = 15.0, -- studs from HumanoidRootPart
}

return Combat
#

ReplicatedStorage/Modules/Penetration.lua

#

ServerScriptService/ServerShoot.server.lua