Echo Location Visual Effect Tutorial

Hello, this is the very first tutorial I’ve ever created so I’m likely to screw something up. If you have any questions or suggestions go ahead and say something in the comments or message me.

If you have ever seen the game Lurking (there’s is a gameplay video by Markiplier if your curious they can hear you... | Lurking - YouTube), it has a really cool shader/visual effect that act like echos and after some experimenting, I was able to replicate it in Roblox studio. Ima just head into it and provide steps on how to do it and explain on the way, but note this isn’t just basic forcefield outlining a part, and making the exact visual effect can be extremely tedious/annoying.

I am currently making a game using this echolocation visual if you would like to check it out (it’s definitely not finished):

Step 1:
First, you start by making a part called “Echo”. This is simply a sphere that’s completely white, the material is ForceField, anchored is true, and CastShadow false. You can also just Instance.new() a part in but I find it easier to just clone from replicated storage, especially since we will be adding a child to the Echo object later. I suggest if your spawning the echo from the character you make the size of it (7.05, 7.05, 7.05) since having it too small will cause a slight camera obstruction.

Step 2:
Go ahead and put it in replicated storage when you’re done making the echo object. Depending on how you want to spawn the echo, you simply clone the Echo object from replicated storage into the workspace and give the position to where ever you want the echo to originate from. I’m just going to spawn an echo 5 studs above 0, 0, 0 every 5 seconds with a script called “SpawnEcho” in ServerScriptService. Side note: if your spawning from a character, I suggest spawning it -3.2 studs under the humanoidRootPart. This gives the echo the appearance that it’s coming from your feet, not your torso.

Code
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local echoObject = ReplicatedStorage.Echo

while wait(5) do
	local echoClone = echoObject:Clone()
	echoClone.Position = Vector3.new(0, 5, 0)
	echoClone.Parent = workspace
end

Then tween the cloned echo so it fades out while also increasing in size; I suggest a size of 50. As you might notice it looks like the cheap echo I was talking about earlier but we aren’t done yet.

Code
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")

local echoObject = ReplicatedStorage.Echo

local echoInfo = TweenInfo.new(
	3,
	Enum.EasingStyle.Quint,
	Enum.EasingDirection.Out,
	0,
	false,
	0
)

local echoGoals = {
	Size = Vector3.new(50, 50, 50);
	Transparency = 1;
}

while wait(5) do
	local echoClone = echoObject:Clone()
	echoClone.Position = Vector3.new(0, 5, 0)
	echoClone.Parent = workspace
	TweenService:Create(echoClone, echoInfo, echoGoals):Play()
end

The Echo should look like this:

Step 3: Understanding this step takes some knowledge of normals and how they render but you could probably just find a box with inverted normals in the toolbox and not worry about it; basically, if you have a box with normals inverted, the inside of the box will be the only thing you can see and the faces which normally faces the viewer appears to be invisible. Combining this with a normal box you can make a sort of outline. Once you make the outline effect make sure that the middle part is neon black and the outline (inverted box) is plastic white. This is your new annoying building tool if your game is based on this echo visual.

Step 4: I suggest making a sort of room or identifiable thing before continuing with this step. Let’s go back to the Echo object and add a PointLight as a child of the part. Go ahead and copy the properties into the light object: Brightness = 500, Color = (255, 255, 255), Range = 1, and Shadows are off. You can experiment with this a bit, but I found these settings to be the best. You could also mess with the Shadows setting as true so that you can’t see echos through walls but you would still have the forcefield going through walls. If you don’t understand why we are doing this right now, don’t worry, it will make sense in the next/last step.

Step 5: Go ahead and tween the range and brightness of the PointLight we just made so that it mimics the echo (fades out as it gets bigger).


You won’t see much difference till this last part. Go ahead and set these lighting settings in the script:

LightSettings

Lighting technology = Voxel

local Lighting = game:GetService("Lighting")

Lighting.Brightness = 0
Lighting.Ambient = Color3.new(0, 0, 0)
Lighting.ColorShift_Bottom = Color3.new(0, 0, 0)
Lighting.ColorShift_Top = Color3.new(0, 0, 0)
Lighting.EnvironmentDiffuseScale = 0
Lighting.EnvironmentSpecularScale = 0
Lighting.GlobalShadows = false
Lighting.OutdoorAmbient = Color3.new(0, 0, 0)
Lighting.ClockTime = 0
Lighting.ExposureCompensation = 1
Lighting.FogColor = Color3.new(0, 0, 0)
Lighting.FogEnd = 1000
Lighting.FogStart = 500

You can experiment with this as much as you want though I find these settings work best.

That’s it! if you did everything correct you should get something like this:

Finial Code
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Lighting = game:GetService("Lighting")

--Lighting Settings:
Lighting.Brightness = 0
Lighting.Ambient = Color3.new(0, 0, 0)
Lighting.ColorShift_Bottom = Color3.new(0, 0, 0)
Lighting.ColorShift_Top = Color3.new(0, 0, 0)
Lighting.EnvironmentDiffuseScale = 0
Lighting.EnvironmentSpecularScale = 0
Lighting.GlobalShadows = false
Lighting.OutdoorAmbient = Color3.new(0, 0, 0)
Lighting.ClockTime = 0
Lighting.ExposureCompensation = 1
Lighting.FogColor = Color3.new(0, 0, 0)
Lighting.FogEnd = 1000
Lighting.FogStart = 500
--End

local echoObject = ReplicatedStorage.Echo

local echoInfo = TweenInfo.new(
	3,
	Enum.EasingStyle.Quint,
	Enum.EasingDirection.Out,
	0,
	false,
	0
)

local echoGoals = {
	Size = Vector3.new(50, 50, 50);
	Transparency = 1;
}

local echoLightGoals = {
	Range = 18;
	Brightness = 0;
}

while wait(5) do
	local echoClone = echoObject:Clone()
	echoClone.Position = Vector3.new(0, 5, 0)
	echoClone.Parent = workspace
	TweenService:Create(echoClone, echoInfo, echoGoals):Play()
	TweenService:Create(echoClone.PointLight, echoInfo, echoLightGoals):Play()
end

If you have any questions, I will try to answer them as soon as I can.
P.S. The echo does look different when coming from your character.

I am currently making a game using this echolocation visual if you would like to check it out (it’s definitely not finished):

89 Likes

I love it. I am going to playtest your game now.

2 Likes

My gosh, looks incredible!
This is the sort of thing that I’ve wanted for ages without knowing it! This could be used for loads of things, like some horror games, or even showcases! Great job! :smile:

3 Likes

Btw for anyone whos still interested in doing this, I plan to reupload this tutorial making building with this visual effect a whole lot easier. I also made a few mistakes in this tutorial such as not tweeting the part locally for a smoother and much nicer transition.

10 Likes

I can see this cool effect being useful in horror games. Someone better make one with it!

2 Likes

Awesome! Can’t wait to see it!

2 Likes

It looks amazing. But how could I make the echo react to a Sound?

u need to use an attachment as the sound’s parent and then use the attachment’s position to determine where the sound is

1 Like

hello i know this is an old forum but if anyone is still here how do i do step 4 i dont understand can someone give me step by step

Hello, what exactly are you having trouble with?

In short, step 4 is adding a point light to the echo part with these properties: Brightness = 500, Color = (255, 255, 255), Range = 1, Shadows = false.

SO SORRY! i meant step 3 the parts inverted and normal one :pray:

Ah, no worries.

For the inverted mesh, I suggest grabbing an inverted cube from the toolbox. Here’s one I found that you can use: https://create.roblox.com/store/asset/13937987843/Inverted-Cube

If you’d like to make your own inverted meshes you’ll need a 3D modelling software like Blender.

Steps for creating an inverted mesh in blender:

To start, you’ll need a mesh to invert the normals of. I’ll be using the default cube that’s automatically loaded when blender opens a new file; however, you can export parts directly from roblox if you wish.

Simply right click the part you want to export > Save / Export > Export Selection…

Then in blender import the file by going to File > Import > Wavefront (.obj)


Now for inverting the mesh. Select the mesh in blenders viewport:

Press tab to switch to edit mode:

And lastly invert the mesh by going to Mesh > Normal > Flip:

You won’t see much of a difference because blender renders both sides of the face no matter which way the normal faces. You can verify if you did it correctly by going to the viewport overlays menu and checking face orientation to true:

If the mesh appears red, it’s inverted and correct. From here you can fatten the mesh or scale it up so it looks correct in Roblox.


Alright, we’ll need this mesh in Roblox Studio again. Select the meshes you want to move over. (You can exit edit mode by pressing tab again)

Export the mesh by going to File > Export > Wavefront (.obj)

Make sure to have these settings, especially the Selection Only setting set to true:

Import the mesh by going back to studio and opening up Asset Manager:

Then clicking the import button on the top right of the window:
image

Make sure “Reverse inward-pointing mesh normals” is false:

Then insert the asset into the workspace by right clicking it in the asset manager:
image

Once you have an inverted mesh in the viewport you can add a normal black neon part to the center and your done! (with step 3)

Let me know if you have any questions. : )

Thank u sooo much I made a decent map/build with your help :pray:t2::grin:

1 Like