I’m having a problem when the Normal returned causes an unwanted rotation on models. The reason I want to use the Normal vector is because I want the model to rotate along floor/walls/roof. So basically, the ‘Bottom’ surface of the model should ALWAYS be the side touching the surface (floor/walls/roof)
Worth noting, I actually did find a ‘fix’ for this, however, I then get other issues. The fix basically adds a CFrame.Angles to setting the CFrame, with -90 on the X and that causes the weird rotation to go away. But because the Y of the CFrame.Angles() is 0, it means the models rotation always gets reset back to 0.
Model:SetPrimaryPartCFrame(
CFrame.new(NewPos, NewPos + NewRay.Normal) * -- Set position
CFrame.Angles(-math.rad(90), 0, 0) * -- Fix the models rotation caused by NewRay.Normal
CFrame.new(0, Model.PrimaryPart.Size.Y / 2, 0) -- Offset the model so its not halfway through the floor
)
Mouse.Move:Connect(function()
if not IsMoving then return end
-- Check for seats
for _, v in pairs(Model:GetDescendants()) do
if v:IsA('Seat') then
local Occupant = v.Occupant
if Occupant then
-- Make the player sitting down stand up
Occupant.Sit = false
end
end
end
-- Do checks to make sure it's being placed within their base
local FloorCheck = workspace:Raycast(Character.HumanoidRootPart.Position, Vector3.new(0, -50, 0))
-- Not players floor/returned nil for some reason
if not FloorCheck.Instance then return end
-- Set models parts to not collideable
for i, v in pairs(Model:GetDescendants()) do
if v:IsA('BasePart') or v:IsA('UnionOperation') or v:IsA('MeshPart') then
v.CanCollide = false
end
end
local RaycastFilter = RaycastParams.new()
RaycastFilter.FilterType = Enum.RaycastFilterType.Blacklist
RaycastFilter.FilterDescendantsInstances = {Model, Player.Character, workspace.Plots.Interiors[Player.Name].Build.Door}
local UnitRay = Camera:ScreenPointToRay(Mouse.X, Mouse.Y, 1)
local NewRay = workspace:Raycast(UnitRay.Origin, UnitRay.Direction * 1000, RaycastFilter)
if not NewRay.Instance then return end
local PosX = math.floor((NewRay.Position.X / 0.5) + 0.5) * 0.5
local PosY = math.floor((NewRay.Position.Y / 0.5) + 0.5) * 0.5
local PosZ = math.floor((NewRay.Position.Z / 0.5) + 0.5) * 0.5
local NewPos = Vector3.new(PosX, PosY, PosZ)
Model:SetPrimaryPartCFrame(
CFrame.new(NewPos, NewPos + NewRay.Normal) * -- Set position
CFrame.new(0, Model.PrimaryPart.Size.Y / 2, 0) -- Offset the model so its not halfway through the floor
)
end)
I believe you are making the CFrame look up away from the floor it’s being placed on, I suggest using CFrame.fromMatrix instead where you can manually set the UpVector and right vector of the model to what you need.
Instead of this which sets position and orientation such that the model CFrame is at NewPos and is looking at a point above NewPos (if normal is the floor with vector (0,1,0))
CFrame.new(NewPos, NewPos + NewRay.Normal) * -- Set position
Do this which sets the CFrame such that the new vector of the model has to be the floor Normal and the right vector is an arbitrary one that we obtain through the cross product. If you want to change it further you would need to find a way to add rotation or find a new right vector.
local arbritaryLookVector = Vector3.new(0, 0, -1)
-- Remember the right-hand rule
local rightVector = NewRay.Normal:Cross(arbritaryLookVector)
Model:SetPrimaryPartCFrame(
CFrame.fromMatrix(NewPos, rightVector,NewRay.Normal)
)
Video is not working but it’s probably due to this:
This offset only moves the furniture “up” along the y axis, you would need to find a new way to offset a part relative to where it’s being placed wether on the floor or on the wall. Perhaps you will need to use:
Model.PrimaryPart.Size.X/2
in order to move it right from the way.
I suggest reading up on the CFrame articles and experimenting on your own in order to gain more tools to work with CFrames on.
Also, I advise using an external video hosting site like imgur to embed videos onto the devforumns and a screen recording software like ShareX(Windows) or Kap (Mac).
Have you tried debugging the vectors that are being obtained in order to get the RightVector and the UpVector of the model?
I advise debugging your furniture system by creating a part that represents the UpVector, RightVector, and LookVector.
This is what it should look like although it’s quite odd that the blue vector is facing towards the part in the image just image it’s reversed and it represents the floor normal as the new relative Y Axis.
Once you do, you will be able to easily visualize what is wrong with your CFrame methods and answer most CFrame problems you come across:
Would I need to rotate the furniture around the Y axis 90 degrees?
Is the position of the CFrame incorrect? Do I need to add an offset relative to the floor normal?
What exactly does this piece of code do to give me the RightVector? Is the right vector giving incorrect? Do I need to rotate it somehow to make it correct? Why did I choose (0, 0, -1) as vector.
local arbritaryLookVector = Vector3.new(0, 0, -1)
-- Remember the right-hand rule
local rightVector = NewRay.Normal:Cross(arbritaryLookVector)
Once you are able to visualize the CFrame you will be able to do some really cool stuff like this using new CFrame methods like CFrame.fromAxis()
Also, look at this tutorial furniture placement it’s where I got the image from and is basically what I’m trying to do with the example code I gave of finding a CFrame on the surface using the cross product properties.