Decal Surface Displacement Plugin

Wow! This is really cool! Thank you for making this amazing plugin! This will help me a lot in buildings

2 Likes

I didn’t even imagine that this would be possible let alone even consider using skinned meshes for something like this, incredible work!

3 Likes

This is absolute gold. I’m definitely going to use this on my terrain heavy games.

Thanks a lot!

2 Likes

Good job, really helpful plugin.

1 Like

For those interested, I made a very simple script to improve the performance of the decals. Here’s how it looks in-game:

And here is the file for that. It’s a local script so you have to insert it inside a player.
DecalRenderingHandler.rbxm (4.2 KB)

And here is the code if you want to have a look at it here.

local RunService = game:GetService("RunService")

local LastTick = tick()

local RenderDistance = 150

local Unloaded = Instance.new("Folder")
Unloaded.Name = "Unloaded"
Unloaded.Parent = game:GetService("ReplicatedStorage")

local PlanePreset = script.LowFidelityPlane
local Planes = {}

function CheckForValidation(Plane)
	if 
		Plane:IsA("MeshPart") and
		Plane:GetAttribute("Valid") ~= true and
		Plane:GetAttribute("Bake") ~= nil and 
		Plane:GetAttribute("Offset") ~= nil and 
		Plane:GetAttribute("RayRange") ~= nil then
		
		Plane:SetAttribute("Valid",true)
		
		local PlaneTable = {
			Plane = Plane,
			Parent = Plane.Parent,
			LowFidelityModel = PlanePreset:Clone()
		}
		
		PlaneTable.LowFidelityModel.Name = Plane.Name
		PlaneTable.LowFidelityModel.Transparency = Plane.Transparency
		PlaneTable.LowFidelityModel.Parent = Unloaded
		PlaneTable.LowFidelityModel.CFrame = Plane.CFrame
		PlaneTable.LowFidelityModel.Size = Plane.Size
		PlaneTable.LowFidelityModel.Color = Plane.Color
		PlaneTable.LowFidelityModel.Material = Plane.Material
		PlaneTable.LowFidelityModel.Reflectance = Plane.Reflectance
		
		for _,v in pairs(Plane:GetChildren()) do
			if v:IsA("SurfaceAppearance") or v:IsA("Texture") or v:IsA("Decal") then
				v:Clone().Parent = PlaneTable.LowFidelityModel
			end
		end
		
		table.insert(Planes,PlaneTable)
		
	end
end

for _,Plane in pairs(workspace:GetDescendants()) do
	CheckForValidation(Plane)
end

workspace.DescendantAdded:Connect(function(Descendant)
	CheckForValidation(Descendant)
end)

RunService.Heartbeat:Connect(function()
	if tick()-LastTick >= 1 then
		LastTick = tick()
		for _,PlaneTable in pairs(Planes) do
			local Distance = (workspace.CurrentCamera.CFrame.Position-PlaneTable.Plane.Position).Magnitude
			if Distance > RenderDistance then
				PlaneTable.Plane.Parent = Unloaded
				PlaneTable.LowFidelityModel.Parent = PlaneTable.Parent
			else
				PlaneTable.Plane.Parent = PlaneTable.Parent
				PlaneTable.LowFidelityModel.Parent = Unloaded
			end
		end
	end
end)

I put this together fairly quickly so it probably has some flaws here and there. But for the most part it should help you gain better performance on larger scale levels. Feel free to modify the code as you see fit.

12 Likes

Kinda reminds me of this feature request.
This is some seriously impressive stuff. :+1:

1 Like

This is revolutionary! I’ll be getting to using this plugin right away. Thank you very much :slight_smile:

3 Likes

This is fantastic! Exactly the solution I was looking for. Totally forgot you can exploit MeshDeformation.

Stop. I can’t take this anymore. This is just too great. I don’t care if it’s laggy or not, it’s still crazy cool.

WHY
WHYHWYYW
:frowning:

1 Like

I noticed this bug earlier today as well. I’ll have a look at it. Thanks for the notice : )

1 Like

Not sure what the bug would be, but if it’s the decal not being deformed correctly, then I’m having the same issue.
It’s weird as it worked perfectly fine at one point, Then I restarted studio and it broke :stuck_out_tongue:

1 Like

I think I found a fix. The cage deformer beta feature broke it for me. I recommend disabling for the time being if if you plan on using the plugin.

1 Like

Thank you! Also I already said this in another comment but I found a way to fix it for myself at least. The cage deformation beta seems to break it so disabling that and restarting studio should do the trick.

2 Likes

Do You have a tutorial for this

-Also Really Cool

it sadly just didnt work for me idk if i’m just stupid but rip

Make sure you don’t have the cage mesh deformer beta enabled.

For some reason it breaks this plugin.

2 Likes

Amazing plugin!
I was wondering: is there a way to implement this in a script? I’d like to use this “technology” to creare AoE vfx for when a player casts a skill, however if I try to move the plane where the player is, it won’t deform to match the terrain’s shape.

1 Like

You can use this function directly from the plugin:

function UpdatePlane(Plane)
	local Success = {}
	local Failure = {}
	
	for _,Point in pairs(Plane:GetChildren()) do
		if Point:IsA("Bone") then
			
			if Point:GetAttribute("OriginalPosition") == nil then
				Point:SetAttribute("OriginalPosition",Point.Position/Plane.Size)
			end
			
			Point.Position = Point:GetAttribute("OriginalPosition")*Plane.Size
			
			local RayResults = workspace:Raycast(Point.WorldPosition,Plane.CFrame.UpVector*-Plane:GetAttribute("RayRange"),RayParams)
			if RayResults then
				table.insert(Success,Point)
				Point.WorldPosition = RayResults.Position+RayResults.Normal*Plane:GetAttribute("Offset")
			else
				table.insert(Failure,Point)
			end
		end
	end

	if #Success > 0 then
		for _,Point in pairs(Failure) do

			local Nearest = nil
			local NearestDist = math.huge
			for _,Point2 in pairs(Success) do
				local Dist = (Point:GetAttribute("OriginalPosition")*Plane.Size-Point2:GetAttribute("OriginalPosition")*Plane.Size).Magnitude
				if Dist < NearestDist then
					NearestDist = Dist
					Nearest = Point2
				end
			end

			Point.WorldPosition = Nearest.WorldPosition
		end
	end
end

This is what is used to place the plane onto surfaces. Let me know if you run into any issues with it!

4 Likes

Thank you SO much!! I appreciate it, you are so nice. I will let you know!

1 Like