How do I make realistic bullet holes?

I am making a gun system using raycasting.

How do I make bullet holes like this guy did?

This is my script:

script.Parent.Fire.OnServerEvent:Connect(function(player, MuzzlePos, MousePos, Handle, MouseTarget)

	local RayCast =, (MousePos-MuzzlePos).unit * 1000)
	local Part, Position, Normal = game.Workspace:FindPartOnRay(RayCast, player.Character, false, true)

	if RayCast then
		if Part then
			local hum = Part.Parent:FindFirstChild("Humanoid")
			if hum then


		--Add/Create attachments
		local AttachmentA ="Attachment", MouseTarget)
		AttachmentA.WorldPosition = MousePos
		AttachmentA.Name = "AttachmentA"

		local AttachmentB ="Attachment", MouseTarget)
		AttachmentB.WorldPosition = MuzzlePos
		AttachmentB.Name = "AttachmentB"

		--Create beam
		local beam ="Beam", workspace)
		beam.Attachment0 = AttachmentA
		beam.Attachment1 = AttachmentB
		--Beam properties
		beam.Width0 = 0.15
		beam.Width1 = 0.15
		beam.TextureSpeed = 10
		beam.TextureMode = Enum.TextureMode.Wrap
		beam.Color =, 255, 183), Color3.fromRGB(242, 255, 183))
		beam.Transparency ={, 0.9),, 0.9)
		beam.TextureLength = 50
		beam.LightEmission = 1
		beam.LightInfluence = 1
		--Remove the bullet
		game.Debris:AddItem(beam, 0.1)
		game.Debris:AddItem(AttachmentA, 0.1)
		game.Debris:AddItem(AttachmentB, 0.1)

Well, you could probably use Surface GUIs. Using your already sent rays, you would detect which part was hit and the exact position.


How do I figure out which face it is?

1 Like

Using Workspace:FindPartOnRay is not advisable anymore:

A very good alternative is using Workspace:Raycast, just like in the tutorial on Roblox Developer Hub.

Below you can see the return:

local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)

From returned result, you can get the the part that was hit (and check if it is player’s part) as well as the exact position. Now you can create a new Surface GUI (perhaps clone it) on that spot and use for example Debris to remove it after some time.

he scaled the image label based on how far the player was, pretty simple; really

1 Like

Here you go:

local bulletHoleImageIdsBasedOnMaterial = {
    [Enum.Material.Wood] = "rbxassetid//:123412312"; -- put Ids here
    [Enum.Material.Plastic] = "rbxassetid//:1234123132";
    [Enum.Material.Metal] = "rbxassetid//:1234123152";
    -- put rest of materials here with their corresponding ID

local rayResult = workspace:Raycast() -- ray here
if rayResult then
    local bulletPart ="Part")
    bulletPart.Transparency = 1
    bulletPart.Anchored = true
    bulletPart.CanCollide = false
    bulletPart.Size =, 0.35, 0.05) -- you might have to change the axis, i didnt test this
    bulletPart.CFrame = CFrame.lookAt(rayResult.Position, rayResult.Position + rayResult.Normal)

    local bulletImage ="Decal")
    bulletImage.Texture = bulletHoleImageIdsBasedOnMaterial[rayResult.Instance.Material] or ""
    bulletImage.Parent = bulletPart
    bulletImage.Face = Enum.NormalId.Front

    bulletPart.Parent = workspace -- best if you add it to a folder you use for debris

Even though this should all work, you might need to adjust which face it is since I did not test any of this :sunglasses:


Sorry for the late response. So I use the “Raycast.Normal” to figure out which face it is?

No, I think RaycastResult.Position is to be used here (because it stores location of the point where intersection occured).

So when you have the CFrame stored, you can for example clone the “bullet hole” from the ReplicatedStorage and parent it to the hit part, which is also detected when hit by a ray and is thus stored in RaycastResult too. The last step is positioning the hole according to the CFrame.
You have a least two options when creating bullet holes. You can either use surface GUIs or parts with applied texture using decals.

use my module, you can check my profile for it.
The module allows you to create images in a 3d pocision