How would i automatically rotate a part to be flat on a surface

So, i’m attempting to make a drawing system using parts, and i need parts to automatically rotate themselves to be flat on the canvas.
I have no clue how to do this, so any help would be nice.

Here is my code, which half works, but not really.

local RayParams = RaycastParams.new()
RayParams.FilterDescendantsInstances = {Character, workspace:WaitForChild('Paint')}
RayParams.FilterType = Enum.RaycastFilterType.Blacklist
local RayOrigin = Camera.CFrame.Position

local RayDirection = Mouse.Hit.Position * PaintRange

local Result = workspace:Raycast(RayOrigin, RayDirection, RayParams)

if Result and Result.Normal and (Result.Position - LastPaintPosition).Magnitude >= PaintSize then		
	local NewPart = script:WaitForChild('Paint'):Clone()
	NewPart.Color = Currect_Color.Value
	NewPart.Size = Vector3.new(PaintSize, PaintSize, 0.001)
	-- Both position and rotation are wrong
	NewPart.CFrame = CFrame.new(Result.Position) * Mouse.Hit.Rotation
	NewPart.Parent = workspace.Paint	
end

This is the part i am attempting to rotate, and i want it to appear flat on any rotated surface.
Screenshot 2022-10-01 211308

1 Like

To make this more understandable (with videos)
This is what i want to achieve:


(I modified the scripts here to make the rotation match that specific wall, not every wall)

And this is what i have:

Try to change the part Orientation to the part Orientation that the mouse is pointing to.

(Sorry if you don’t know what I meant, I am not the best at English.)

That wouldnt exactly work if i add unions as surfaces you can paint on though, plus it would be a pain to make sure that all surfaces that can be painted on are facing the correct way.

Update: I did get it to rotate correctly, but the position is offset by a lot.
new code:

if Painting then
		local RayParams = RaycastParams.new()
		RayParams.FilterDescendantsInstances = RayBlacklist()
		RayParams.FilterType = Enum.RaycastFilterType.Blacklist
		local RayOrigin = Camera.CFrame.Position
		
		local RayDirection = (Character.HumanoidRootPart.Position - Mouse.Hit.Position).Unit * -50
		
		local Result = workspace:Raycast(RayOrigin, RayDirection, RayParams)
		
		if Result and Result.Normal and (Result.Position - LastPaintPosition).Magnitude >= PaintSize/3 and Result.Instance and Result.Instance.Name == 'Paint_Surface' then
			
			LastPaintPosition = Result.Position
			local NewPart = script:WaitForChild('Paint'):Clone()
			NewPart.Color = Currect_Color.Value
			NewPart.Size = Vector3.new(PaintSize, PaintSize, 0.001)
			local EndFrame = CFrame.new(Result.Position, (CFrame.new(Result.Position) * CFrame.new(Result.Normal.X, Result.Normal.Y, Result.Normal.Z)).Position)
			NewPart.CFrame = EndFrame * CFrame.new(0, 0, NewPart.Size.Z/2)
			NewPart.CFrame = NewPart.CFrame + NewPart.CFrame.LookVector * (0.001 * Layer)
			NewPart.Parent = workspace.Paint
		end
	end

You can use Result.Normal. not sure why you aren’t, since you are checking for it.

NewPart.CFrame = CFrame.new(Result.Position, Result.Position+Result.Normal) -- * CFrame.Angles to rotate if needed
1 Like

Thanks, i did know that the Normal was probably needed, so i had the check there for it.
The painting position is still offset from the mouse a lot, but at least rotation works now.

Edit: Changed origin from root part to camera and it fixed the offset

1 Like

How would i do this but by ONLY changing the rotation and not doing anything related to the position?