You mean one single mesh makes up the geometry and length of the entire trail?
Yes, I think that may work well for you. I’m trying it out right now.
I’m having a difficult time understanding this new feature. lol, I have not done much with standalone meshes as it is.
Its currently in beta with very little proper documentation. When I’m done testing things out I will send my code with comments, hopefully it helps. Because EditableMeshes follow the standard convention of meshes you can look at external sources on how they work.
Alright sounds good, I’ll keep messing around with them in the meantime, thanks!
Still a WIP but its working right now. I’ll probably continue working on it tomorrow
It is a module script
Planning on adding the ability to remove markers, and allow fading them out over time and maybe some other stuff
Also fixing the math so that when you look along the beam from one end the triangles dont distort
also will add comments in the final version whenever I make that
local replicated_storage = game:GetService("ReplicatedStorage")
local Trail = {}
Trail.__index = Trail
local TrailsFacingCamera = {}
game:GetService("RunService").RenderStepped:Connect(function(dt)
local CameraLook = workspace.CurrentCamera.CFrame.LookVector
for _,Trail in TrailsFacingCamera do
for i,Marker in Trail.Markers do
local Mesh:EditableMesh = Trail.EditableMesh
local OriginalMesh:MeshPart = Trail.Mesh
local offset
if i == #Trail.Markers then
offset = CameraLook:Cross(Marker.Direction).Unit * Trail.Width
else
offset = CameraLook:Cross((Marker.Direction+Trail.Markers[i+1].Direction)/2).Unit * Trail.Width
end
Mesh:SetPosition(Marker.Associated_Vertices[1],OriginalMesh.CFrame:PointToObjectSpace(Marker.Position+offset))
Mesh:SetPosition(Marker.Associated_Vertices[2],OriginalMesh.CFrame:PointToObjectSpace(Marker.Position-offset))
end
end
end)
function Trail.new(Width:number,FaceCamera:boolean, StartingPoint:Vector3)
local T = setmetatable({}, Trail)
T.Width = Width
T.FaceCamera = FaceCamera
T.Mesh = Instance.new("MeshPart")
T.Mesh.Anchored = true
T.Mesh.CanCollide = false
T.Mesh.CanTouch = false
T.Mesh.CanQuery = false
--T.Mesh.Material = Enum.Material.Neon
T.Mesh.Size = Vector3.one
T.Mesh.Parent = workspace:WaitForChild("Trail_Folder")
T.EditableMesh = Instance.new("EditableMesh",T.Mesh) -- setting parent in constructor is usually bad practice, but here its fine because no properties are being modified after initialization and before parenting
T.Markers = {}
if StartingPoint then
T:AddMarker(StartingPoint)
end
if FaceCamera then
table.insert(TrailsFacingCamera,T)
end
return T
end
function Trail:AddMarker(point:Vector3)
local Marker = {}
local Mesh = self.EditableMesh
local OriginalMesh = self.Mesh
local offset = Vector3.new(0,1,0)*self.Width
Marker.Position = point
Marker.Associated_Vertices = {Mesh:AddVertex(OriginalMesh.CFrame:PointToObjectSpace(point+offset)),Mesh:AddVertex(OriginalMesh.CFrame:PointToObjectSpace(point-offset))} -- add two vertices for each marker
if #self.Markers ~= 0 then
local LastMarker = self.Markers[#self.Markers]
Marker.Direction = (LastMarker.Position - Marker.Position)
Mesh:AddTriangle(
Marker.Associated_Vertices[1],
Marker.Associated_Vertices[2],
LastMarker.Associated_Vertices[1]
)
Mesh:AddTriangle(
LastMarker.Associated_Vertices[1],
LastMarker.Associated_Vertices[2],
Marker.Associated_Vertices[2]
)
Mesh:AddTriangle(
LastMarker.Associated_Vertices[1],
Marker.Associated_Vertices[2],
Marker.Associated_Vertices[1]
)
Mesh:AddTriangle(
Marker.Associated_Vertices[2],
LastMarker.Associated_Vertices[2],
LastMarker.Associated_Vertices[1]
)
end
if #self.Markers == 1 then
self.Markers[1].Direction = Marker.Direction
end
table.insert(self.Markers,Marker)
--print(self.Property)
end
return Trail
In a local script somewhere
local one = workspace:WaitForChild("1")
local two = workspace:WaitForChild("2")
local three = workspace:WaitForChild("3")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Trail = require(ReplicatedStorage:WaitForChild("Trail"))
local trail1 = Trail.new(2,true,one.Position)
trail1:AddMarker(two.Position)
trail1:AddMarker(three.Position)
I appreciate you taking the time to do all of this, this should set a pretty good example at what I need to do, you don’t need to finish it or send me a final product if you don’t want to unless you deem it necessary for major things that I should know about, but I’ll mess around with what you made and all, thank you
So it’s been some time, and a few days ago I put in place what you designed. I also added a trail length based on distance from the part moving so the trail dissipates. This isn’t so bad at first, but after 30 to 45 seconds depending on how many trails, it begins to lag, but I don’t know why it would if it’s perfectly fine in the first 30 seconds and the trails are at their full length.
Are you sure the trails are the issue, and that there isn’t anything else that could be causing the lag? Sorry for the delay I haven’t been too active on the dev forum, my discord user is redevan if you want to shoot me a dm there, ill be able to reply much more quickly.
Sent a friend request, we can continue discussion there then if it’s more convenient.
For anyone seeing this after the fact, this is the module we came up with. The documentation is sparse but its pretty simple, if anyone has any questions/issues just dm me and ill see what I can do.
local RunService = game:GetService("RunService")
local Trail = {}
Trail.__index = Trail
function Trail.new(Width:number,FaceCamera:boolean,MaxLength:number) -- added MaxLength argument
local T = setmetatable({}, Trail)
T.Width = Width
T.FaceCamera = FaceCamera
--T.ThinOverTime = ThinOverTime
T.Mesh = Instance.new("MeshPart")
T.Mesh.Anchored = true
T.Mesh.CanCollide = false
T.Mesh.CanTouch = false
T.Mesh.CanQuery = false
T.Mesh.Size = Vector3.one
T.MaxLength = MaxLength
T.Mesh.Parent = workspace:WaitForChild("Trail_Folder")
T.EditableMesh = Instance.new("EditableMesh",T.Mesh) -- setting parent in constructor is usually bad practice, but here its fine because no properties are being modified after initialization and before parenting
T.EditableMesh:AddTriangle(T.EditableMesh:AddVertex(Vector3.zero),T.EditableMesh:AddVertex(Vector3.zero),T.EditableMesh:AddVertex(Vector3.zero)) -- triangle bug workaround
T.Markers = {}
T.StepConnection = RunService.Stepped:Connect(function(_,dt)
local CameraCF = workspace.CurrentCamera.CFrame
T.Mesh.Position = CameraCF.Position + CameraCF.LookVector*5
local MarkersToRemove = {}
for i,Marker in T.Markers do
if T.MaxLength ~= 0 then
if Marker.TotalLength >= T.MaxLength then -- if length is greater than max length
MarkersToRemove[i] = Marker -- add marker to the removal buffer
continue -- end this iteration early because marker does not exist anymore
end
end
if T.FaceCamera then -- if trail has face camera enabled
local offset -- get offset
if i == #T.Markers then
offset = (Marker.Position - CameraCF.Position).Unit:Cross(Marker.Direction).Unit * T.Width -- (1-math.clamp(Marker.Age/T.MaxAge,0,1)) -- gives 1 if age is 0 and 0 if age is at MaxAge
else
offset = (Marker.Position - CameraCF.Position).Unit:Cross((Marker.Direction+T.Markers[i+1].Direction)/2).Unit * T.Width --* (1-math.clamp(Marker.Age/T.MaxAge,0,1))
end
T.EditableMesh:SetPosition(Marker.Associated_Vertices[1],T.Mesh.CFrame:PointToObjectSpace((Marker.Position+offset)/T.Mesh.Size))
T.EditableMesh:SetPosition(Marker.Associated_Vertices[2],T.Mesh.CFrame:PointToObjectSpace((Marker.Position-offset)/T.Mesh.Size))
end
end
for _,v in MarkersToRemove do -- remove all markers inside the removal buffer
T:RemoveMarker(v)
end
end)
return T
end
function Trail:AddMarker(point:Vector3)
local Marker = {}
local Mesh = self.EditableMesh
local OriginalMesh = self.Mesh
local offset = Vector3.yAxis*self.Width
Marker.OriginalPosition = point
Marker.Position = point
Marker.Length = 0
Marker.TotalLength = 0
Marker.StoredAngle = 0
Marker.Associated_Vertices = {-- add two vertices for each marker
Mesh:AddVertex(OriginalMesh.CFrame:PointToObjectSpace(point+offset)),
Mesh:AddVertex(OriginalMesh.CFrame:PointToObjectSpace(point-offset))
}
for i,v in Marker.Associated_Vertices do
Mesh:SetVertexColorAlpha(v,1)
end
if #self.Markers ~= 0 then
local LastMarker = self.Markers[#self.Markers]
local DistanceVector = (LastMarker.Position - Marker.Position)
Marker.Direction = DistanceVector.Unit
LastMarker.Length = DistanceVector.Magnitude
for _,M in self.Markers do
M.TotalLength += DistanceVector.Magnitude
end
Marker.Associated_Triangles = { -- triangles are saved into table now
Mesh:AddTriangle(
LastMarker.Associated_Vertices[1],
Marker.Associated_Vertices[2],
Marker.Associated_Vertices[1]
),
Mesh:AddTriangle(
LastMarker.Associated_Vertices[1],
LastMarker.Associated_Vertices[2],
Marker.Associated_Vertices[2]
),
}
else
Marker.Direction = Vector3.xAxis
end
if #self.Markers == 1 then
self.Markers[1].Direction = Marker.Direction
end
table.insert(self.Markers,Marker)
return Marker
end
function Trail:MoveMarker(Marker,Position)
Marker.Position = Position
local MarkerIndex = table.find(self.Markers,Marker)
if MarkerIndex ~= 1 then
local LastMarker = self.Markers[MarkerIndex-1]
local DistanceVector = (LastMarker.Position - Marker.Position)
Marker.Direction = DistanceVector.Unit
for i,M in self.Markers do
if i ~= MarkerIndex then
M.TotalLength -= LastMarker.Length
M.TotalLength += DistanceVector.Magnitude
end
end
LastMarker.Length = DistanceVector.Magnitude
end
if MarkerIndex ~= #self.Markers then
local NextMarker = self.Markers[MarkerIndex+1]
local DistanceVector = (Marker.Position - NextMarker.Position)
NextMarker.Direction = DistanceVector.Unit
Marker.TotalLength += DistanceVector.Magnitude - Marker.Length
Marker.Length = DistanceVector.Magnitude
end
end
function Trail:RemoveMarker(Marker) -- Remove Marker Function
local Mesh:EditableMesh = self.EditableMesh
local MarkerIndex = table.find(self.Markers,Marker)
if MarkerIndex ~= #self.Markers then--the last marker does not have any triangles associated with it
for _,TriangleId in self.Markers[MarkerIndex+1].Associated_Triangles do -- loop through every triangle connected to our two vertices
Mesh:RemoveTriangle(TriangleId) -- remove them
end
end
for _,VertexId in Marker.Associated_Vertices do -- loop through our two associated vertices
Mesh:RemoveVertex(VertexId) -- remove them
end
table.clear(Marker) -- clear the marker table, may be unnecessary, if it causes issues you should remove this line
table.remove(self.Markers,MarkerIndex) -- find the index of the marker in the markers table, and then remove it
end
function Trail:Destroy()
self.StepConnection:Disconnect()
while self.Markers[1] do -- cant iterate over table with loop because the table is being shifted as markers are removed
self:RemoveMarker(self.Markers[1])
end
self.Mesh:Destroy()
table.clear(self)
end
return Trail
For anyone looking to have simple trails that last longer than 20 seconds, I encourage you use this module. Very helpful and impressive module. It was made with performance in mind, so if used properly, it should work just fine.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.