Part not correctly aligning to surfaces while Raycasting

My part that I am raycasting seems to not be aligning with surfaces.

Screenshot_20230124_061858

Screenshot_20230124_061850

Screenshot_20230124_061838

How can I fix this?

Right now you’re pivoting a part that is at raycastResult.Position but is looking at the raycast result position + normal, so the origin may be either sunken in or floating above and likely rotated wrongly.

What is your expected result? Do you want the part to snap to the side the cursor is hovering over, or do you want it to snap to the top? Or to the orientation of the face?

I want it to basically snap to the top (Aligning the part at the normal) and also, I am raycasting at the HumanoidRootPart.

I see, how do you want the part to be oriented? Should it be vertical or just horizontal?

I want it to face vertically. (Basically, the correct way like a bullethole)

I see ok,

So I’m not sure how you are casting the ray so I’ll start there. First you’d probably want to ray cast from the root part’s -upvector (would be the orientation of the bottom face or “downvector” if you will)

local ray = workspace:Raycast(rootPart.Position, -rootPart.CFrame.UpVector * 50, raycastParams)

Now you would need to use the ray.Instance’s CFrame to get a position relative to the part, it’s likely you won’t get the expected result if your ray result part is oriented in a direction other than 0, 0, 0 if you don’t take into account the its CFrame.

local ray = workspace:Raycast(rootPart.Position, -rootPart.CFrame.UpVector * 50, raycastParams)

local goalPart = ray.Instance
local goalPartCFrame = goalPart.CFrame
-- now we need to get the CFrame of the result part's normal that is intersected by the ray. it's easier than it seems, you really only need to do the following:
local normalCFrame = goalPart.CFrame * CFrame.new(ray.Normal * goalPart.Size / 2)
-- ^ note we have to divide the size by 2 because the part's CFrame is at the part's centre. so if we didn't divide it by 2, it would be offset by the entire size of the part (too far)

-- now that we have the normal of the part, we now need to translate the hit position to the normal's object space
local hitPosRelativeToNormal = normalCFrame:PointToObjectSpace(ray.Position)

-- finally to get the (possibly) final CFrame in world coordinates, we use this hit position relative to the normal to construct a new cframe that, from this relative position, faces the same direction as the normal
local goalCFrameRelative = CFrame.lookAt(hitPosRelativeToNormal, hitPosRelativeToNormal + ray.Normal)

-- you could set the CFrame here like so:
part.CFrame = normalCFrame:ToWorldSpace(goalCFrameRelative)

-- but you will notice that the bullethole is still sunken into the ground. to fix, we just take the goalCFrameRelative and apply an offset of 0, 0, -bullethole.Size.Z / 2
-- so let's go back a step and apply this offset:
local goalCFrameRelative = CFrame.lookAt(hitPosRelativeToNormal, hitPosRelativeToNormal + ray.Normal) * CFrame.new(0, 0, -part.Size.Z / 2)
part.CFrame = normalCFrame:ToWorldSpace(goalCFrameRelative)

Now it’s pretty hard to test whether or not this will work with any normal because the root part is basically always vertical unless the character’s ragdolled but I’ll adapt it to work with the mouse for proof of concept:

Anyway, that’s how you’d do it. Let me know if you need any more help or need clarification on anything

1 Like

Making the code you gave right now. (Also, I’m making the part sort of follow the player by raycasting the HumanoidRootPart position and such so I want it to slope on a ramp, etc.) hope this works!

2 Likes

There are a couple of problems with this code would it be possible to solve these?

Green line represents the result I want.

Screenshot 2023-01-24 192637

I want the square to be flat on the ground not standing upright.

Screenshot 2023-01-24 192730

I want the square to be where the green line is facing basically opposite direction.

I see, if you want to do that, you’d want to change the offset when you call CFrame.lookAt. Something like this should work:

local goalCFrameRelative = CFrame.lookAt(hitPosRelativeToNormal, hitPosRelativeToNormal + ray.Normal) 
    * CFrame.Angles(math.pi / 2, 0, 0)  -- can do math.rad(90) if you want an easier translation between degrees and radians.
    * CFrame.new(0, part.Size.Y / 2, part.Size.Z / 2) -- Note we need to divide y by 2 so it isn't stuck inside the part

Depending on what your goal is you will probably need to mess with the numbers, but the logic’s all there

Another approach to remove the call to CFrame.Angles would be this:

local goalCFrameRelative = CFrame.lookAt(hitPosRelativeToNormal, hitPosRelativeToNormal + CFrame.identity.LookVector) -- you may have to change LookVector to another vector such as RightVector or -LookVector
    * CFrame.new(0, part.Size.Y / 2, part.Size.Z / 2)
1 Like

I went with the math.pi situation and it worked perfectly since it doesn’t get stuck in the ground!

I can now FINALLY create Realistic Reflections thank you!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.