The HitRaycast function fires a ray and gets the verticies on the position given a radius. It also manipulates the position fo the verticies because this is actually a module for realistic gore
local Gore = {}
-- Services
local AssetService = game:GetService("AssetService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")
-- Modules
local Noise = require(ReplicatedStorage.Shared.Utility.Noise)
local AssetsDealer = require(ReplicatedStorage.Shared.AssetsDealer)
-- Constants
local RAYCAST_PARAMS = RaycastParams.new()
local function debugNode(position)
local node = AssetsDealer.GetMesh("Misc/Node")
node.Parent = workspace
if position then
node.Position = position
end
Debris:AddItem(node,5)
return node
end
local function debugAttachment(position)
local attachment = Instance.new("Attachment")
attachment.Parent = workspace.Terrain
if position then
attachment.WorldPosition = position
end
return attachment
end
local function getVerticiesPositions(editableMesh: EditableMesh,verts: {number})
local positions = {}
for _,vertexId in verts do
positions[vertexId] = editableMesh:GetPosition(vertexId)
end
return positions
end
local function mergeCloseVerticies(editableMesh: EditableMesh)
local vertsPositions = getVerticiesPositions(editableMesh, editableMesh:GetVertices())
for vertex_id,position in vertsPositions do
local closeVerticies = editableMesh:GetAdjacentVertices(vertex_id)
for _,closeVertexId in closeVerticies do
if closeVertexId ~= vertex_id then
local closeVertexPosition = vertsPositions[closeVertexId]
if (closeVertexPosition-position).Magnitude < 0.05 then
editableMesh:SetPosition(vertex_id,closeVertexPosition)
break
end
end
end
end
end
local function getBloodMesh(part: MeshPart)
local bloodMesh = part:FindFirstChild("BloodMesh")
if not bloodMesh then
bloodMesh = part:Clone()
bloodMesh.Name = "BloodMesh"
bloodMesh.Parent = part
bloodMesh.Color = Color3.new(.7,0,0)
bloodMesh.Size -= Vector3.one/5
end
return bloodMesh
end
local function raycast(origin,direction)
local raycast = workspace:Raycast(origin,direction,RAYCAST_PARAMS)
if raycast then
if raycast.Instance then
local mesh = raycast.Instance:FindFirstChild("Mesh")
if mesh and mesh:IsA("MeshPart") then
return raycast.Position,mesh,raycast.Normal
end
end
end
end
function Gore.GetEditableMesh(part: MeshPart)
assert(part:IsA("MeshPart"),`Part "{part.Name}" must be a meshpart to work with EditableMesh.`)
local editableMesh = part:FindFirstChildOfClass("EditableMesh") :: EditableMesh
-- If no editablemesh is found one will be created.
if not editableMesh then
editableMesh = AssetService:CreateEditableMeshAsync(part.MeshId)
editableMesh.Parent = part
end
return editableMesh
end
local function getLocalRadius(part,radius)
local size = part.Size
return math.max(size.X,size.Y,size.Z)*radius
end
function Gore.HitRaycast(origin: Vector3, direction: Vector3, radius: number)
radius = radius or 1
local localRadius = radius/2
assert(typeof(origin) == "Vector3",`Origin must be a Vector3`)
assert(typeof(direction) == "Vector3",`Direction must be a Vector3`)
assert(typeof(radius) == "number",`Radius must be a number`)
local position,part,normal = raycast(origin,direction)
if not position or not part or not normal then warn("Raycast failed.") return end
local editableMesh = Gore.GetEditableMesh(part)
local bloodMesh = getBloodMesh(part)
local bloodEditableMesh = Gore.GetEditableMesh(bloodMesh)
local localPosition = part.CFrame:PointToObjectSpace(position)
local localDirection = part.CFrame:VectorToObjectSpace(direction)
--local biggestAxis = math.max(part.Size.X,part.Size.Y,part.Size.Z)
--assert(localRadius > 0, `Local radius is zero`)
local attachment = debugAttachment()
attachment.Parent = part
attachment.CFrame = CFrame.lookAlong(localPosition,normal)
local localTarget = localDirection.Unit
--local node = debugNode(position)
--node.Size = Vector3.one*radius
--node.Color = Color3.new(0,0,1)
local verts = editableMesh:FindVerticesWithinSphere(localPosition,localRadius)
if #verts <= 0 then warn(`No vertices found in radius`) return end
local vertsPositions = getVerticiesPositions(editableMesh,verts)
--assert(#vertsPositions > 0, `Failed to get vertex positions.`)
print("hit")
for _, vertexId in verts do
local pos = vertsPositions[vertexId]
--local node = debugNode(part.CFrame:PointToWorldSpace(pos))
--node.Size = Vector3.one/5
local biggestNormalAxis = math.max(normal.X,normal.Y,normal.Z)
local normalX,normalY
if biggestNormalAxis == normal.X then
normalX = normal.Y; normalY = normal.Z
elseif biggestNormalAxis == normal.Y then
normalX = normal.X; normalY = normal.Z
else
normalX = normal.X; normalY = normal.Y
end
local distance = (pos-localPosition).Magnitude
if distance > localRadius then warn(distance) end
local distanceFactor = 1-math.clamp(distance/localRadius,0,1)
local noise = math.clamp(Noise.Get2D(normalX,normalY,.3),0,1)
local factor = math.clamp((distanceFactor*0.4)^0.9 - noise*0.3,0,0.7)
local newPos = pos:Lerp(localTarget,factor)
local newBloodPos = pos:Lerp(localTarget,math.clamp(factor-0.2,0,1))
--editableMesh:RemoveVertex(vertexId)
editableMesh:SetPosition(vertexId,newPos)
bloodEditableMesh:SetPosition(vertexId,newBloodPos)
end
mergeCloseVerticies(editableMesh,vertsPositions)
mergeCloseVerticies(bloodEditableMesh,vertsPositions)
end
return Gore