You do it by figuring out where the mouse hits the specific plane you’re interested in, by doing ray-plane collision detection. The code for this is available on one of my favorite sites: https://geomalgorithms.com/code.html Specifically we want the function intersect3D_SegmentPlane() - find the 3D intersection of a segment and a plane
.
Here's the license, make sure you read and comply with it
// Copyright 2001, 2012, 2021 Dan Sunday
// This code may be freely used and modified for any purpose
// providing that this copyright notice is included with it.
// There is no warranty for this code, and the author of it cannot
// be held liable for any real or imagined damage from its use.
// Users of this code must verify correctness for their application.
If you want to see the original C++ source, it’s in the file C05_Line_Plane_Intersection.cpp
.
Here's the ported Lua code, ready to plop into any roblox game:
--[[
// Copyright 2001, 2012, 2021 Dan Sunday
// This code may be freely used and modified for any purpose
// providing that this copyright notice is included with it.
// There is no warranty for this code, and the author of it cannot
// be held liable for any real or imagined damage from its use.
// Users of this code must verify correctness for their application.
]]
-- intersect3D_SegmentPlane(): find the 3D intersection of a segment and a plane
-- Input:
-- segment = a segment = {Vector3 P1, Vector3 P2}, and
-- plane = a plane = {Vector3 P, Vector N}
-- Output: *I0 = the intersect point (when it exists)
-- Return:
-- nil, 0 = disjoint (no intersection)
-- Vector3 point, 1 = intersection in the unique point point
-- nil, 2 = the segment lies in the plane (counted as no intersectio)
local SMALL_NUM = 10e-5
function intersect3D_SegmentPlane(segment, plane)
local u = segment.P2 - segment.P1
local w = segment.P1 - plane.P
local D = plane.N:Dot(u)
local N = -plane.N:Dot(w)
if math.abs(D) < SMALL_NUM then -- segment is parallel to plane
if N == 0 then -- segment lies in plane
return nil, 2
else -- no intersection
return nil, 0
end
end
-- they are not parallel
-- compute intersect param
local sI = N/D
if sI < 0 or sI > 1 then -- no intersection
return nil, 0
end
local intersection = segment.P1 + sI * u -- compute segment intersect point
return intersection, 1
end
And here’s a test place showing how it can be used to get the intersection of the mouse ray with an any plane, in this case defined by a part.
RayPlaneIntersectTest.rbxl (28.9 KB)
And here's the code for the usage example
function getMouseRaySegment()
return {
P1 = mouse.UnitRay.Origin,
P2 = mouse.UnitRay.Origin + mouse.UnitRay.Direction * 1000
}
end
function getPartFrontPlane(part)
return { -- A plane, represented as a point P in the plane and the normal N of the plane
P = part.CFrame:PointToWorldSpace(Vector3.new(0, 0, -part.Size.Z/2)),
N = part.CFrame.LookVector
}
end
while wait() do
local s = getMouseRaySegment()
local p = getPartFrontPlane(game.Workspace.Plane)
local i, err = intersect3D_SegmentPlane(s, p)
if i then
game.Workspace.Cursor.CFrame = CFrame.new() + i
else
print(err) --either s is in the plane so there is no UNIQUE intersect, or they don't interesect at all
end
end
Let me know if you need help adapting it to your specific situation