How to account for the orientation of a part when finding the relative position of the mouse?

I’m currently trying to make it so when you click a part, it’ll create an attachment at that position. This is my code and it works find when the part is not rotated.

    local Attachment = Instance.new("Attachment", Mouse.Target)
    local RelativePosition = Mouse.Hit.p - Mouse.Target.Position
    Attachment.Position = RelativePosition
    Attachment.Visible = true

Here’s a gif that shows the problem, the first part has the default orientation while the second part has a random one.

So how would I account for the rotation?

EDIT(the attachment on the second part is hard to see as it blends in with the ground, but it is there)

The solution is RelativePosition = Mouse.Target.CFrame:inverse() * Mouse.Hit.p, where the mouse position is being translated into the relative coordinate space of the target’s CFrame.

3 Likes

Thank you so much!

Note that there is a CFrame method that makes it easier to remember:

CFrame:pointToObjectSpace

That seems handy! I’ll change it to that.

Though one problem I’ve just come up with is that I also need the Attachment to rotate so that it’s facing where the mouse clicked. Not sure how I’d go about this

Attachments have CFrame values too! I am fairly certain you can rotate an Attachment the same way you would rotate a BasePart.

Try

attachment.CFrame = CFrame.new(attachment.Position, mouse.Hit.p)

That is not how they work. Attachment CFrames are local/relative to their parent so that

worldcf  = parentcf*attcf

and

attcf = parentcf:toObjectSpace(worldcf)
1 Like

I was thinking that I could do that but I wasn’t quite sure.

I just tried that, it doesn’t error and when I go into the properties the orientation has changed, but it hasn’t actually in the world.

https://gyazo.com/8c857e7c04efddbf7b8621de5f74f97c

That is also not how mouse CFrame works. You need to cast your own ray to find the surface normals. Mouse hit CFrame is oriented the same way that the camera is. Essentially, after you have casted the ray, the CFrame would need to be

attachmentcf = parentcf:toObjectSpace(CFrame.new(rayhitpos,rayhitpos+raysurfacenormal))

What does the mouse cframe have to do with it? Surely it should rotate the attachment to face the mouses position?

That does not make any sense, rotation is not the same thing as position (you gave no base). Also if you were to base it off of object center, the particle orientation would be incredibly inaccurate on objects that are not perfect spheres.

I’ve already sorted setting the position of the attachments, but I came up with another problem where I needed the attachment to also face where I click.

Shouldnt it be facing away from the surface you clicked?

aka in direction of the surface normal

my example would (after casting the appropriate ray) put the attachment at where you clicked, facing away from the surface, and relative to the part so it is correctly positioned.

Sorry, I had such a brain-fart and get what you meant now.

UnitRay might be helpful in getting origin and direction so you can cast your own N-length ray that ignores or whitelists any specific objects if need be.

Just to double check, parentcf is the parts position?

yes, as i have explained before:

Hi! As I was reading this, I noticed the solution is a bit complex, especially for those who may stumble on this in the future.

If you want something which will place an attachment where you click on a part, you can use mouse.Hit, mouse.Target, and attachment.WorldCFrame.

Example:

local function inputBegan(input, textBoxFocused)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		local mouse = game:GetService("Players").LocalPlayer:GetMouse()
		local target, hit = mouse.Target, mouse.Hit
		if target then
			local New_Attachment = Instance.new("Attachment", target)
			New_Attachment.WorldCFrame = hit
			New_Attachment.Visible = true
		end
	end
end
game:GetService("UserInputService").InputBegan:Connect(inputBegan)
1 Like