"Raycast.Normal" not returning expected orientation

I did my Projectile System using Raycast, and it’s working fine, but, i wanted to change the orientation of the object bases where the Ray hit.

I tried to use Raycast.Normal but isn’t working at the way that I wanted to work.
Here’s a visual representation: vv

What is should be doing:

What is actually doing:


Some kind of orientation is being setted -1.322, -137.297, -0.002 but not the right one.

The module script:

local RunService = game:GetService("RunService")
local Debris = game:GetService("Debris")

local Projectile = {}
local Trowable

function Projectile.new(Gravity, Whitelist, Wind, Visualize, Object)
	local newProjectile = {}

	newProjectile.Gravity = Gravity
	newProjectile.Whitelist = Whitelist
	newProjectile.Wind = Wind
	newProjectile.Visualize = Visualize
	newProjectile.Object = Object
	newProjectile.Params = RaycastParams.new()

	newProjectile.Params.FilterType = Enum.RaycastFilterType.Whitelist
	newProjectile.Params.FilterDescendantsInstances = Whitelist

	function newProjectile:Cast(start, dest, force)
		local conversion = 100/9.8
		local vForce = (dest - start).Unit * force * conversion

		local Acceleration = Vector3.new(self.Wind.X, self.Wind.Y - self.Gravity * 9.8, self.Wind.Z) * conversion
		local Time = 0
		local StartPos = start
		local RayResult = nil
		local found = false

		if self.Object then
			Trowable = self.Object:Clone()
			Trowable.Anchored = true
			Trowable.CanCollide = false
			Trowable.Parent = workspace

			for _, Motor6D in pairs(Trowable:GetDescendants()) do
				if Motor6D:IsA("Motor6D") then
					Motor6D:Destroy()
				end
			end
		end

		local Connection = RunService.Heartbeat:Connect(function(DeltaTime)
			if not found then
				Time += DeltaTime

				local ProjPos = Vector3.new(
					start.X + vForce.X * Time + 0.5 * Acceleration.X * Time * Time, -- equação maluca q determina a posição
					start.Y + vForce.Y * Time + 0.5 * Acceleration.Y * Time * Time,
					start.Z + vForce.Z * Time + 0.5 * Acceleration.Z * Time * Time
				)

				RayResult = workspace:Raycast(StartPos, ProjPos - StartPos, self.Params)
				StartPos = ProjPos

				if self.Visualize == true then -- Se não houver parte, ele vai criar uma linha do raycast
					local Part = Instance.new("Part")
					Part.Size = Vector3.new(.5,.5,.5)
					Part.Position = ProjPos
					Part.Anchored = true
					Part.CanCollide = false
					Part.Material = Enum.Material.Neon
					Part.Color = Color3.fromRGB(0, 255, 0)
					Part.Shape = "Ball"
					Part.Parent = workspace

					Debris:AddItem(Part, .5)
				end

				Trowable.Position = ProjPos

				if RayResult then 
					found = true
					
					Trowable.CFrame = CFrame.new(RayResult.Position, RayResult.Normal)
					
					
					if self.Visualize == true then  -- debug²
						local Part = Instance.new("Part")
						Part.Size = Vector3.new(3,3,3)
						Part.Position = RayResult.Position
						Part.Anchored = true
						Part.CanCollide = false
						Part.Material = Enum.Material.Neon
						Part.Color = Color3.fromRGB(255, 0, 4)
						Part.Shape = "Ball"
						Part.Parent = workspace

						Debris:AddItem(Part, .5)
					end
				end
			end
		end)

		while not found do
			wait()
		end

		Connection:Disconnect()

		if RayResult then
			print("foi tlg, detectado")
		end
	end

	return newProjectile
end

return Projectile

To make the projectile correctly land on the surface you can multiply the projectile cframe by another rotated cframe like this

Trowable.CFrame = CFrame.new(RayResult.Position, RayResult.Normal) * CFrame.fromOrientation(math.rad(-90), 0, 0)
1 Like

Unlike rays, CFrames are constructed with position and target rather than position and direction. Add the normal to the position to give it a target position

CFrame.new(position, position+normal)

1 Like

Something is happening, it’s changing his orientation to the desired object surface, but there’s a way to rotate it a little to make it upwards?

Trowable.CFrame = CFrame.new(RayResult.Position, RayResult.Position + RayResult.Normal)

Looking good! Looks like it’s off by 90 degrees? After you calculate that CFrame, just add on a bit of rotation like what @denkodin was doing.

Trowable.CFrame = CFrame.new(RayResult.Position, RayResult.Position + RayResult.Normal) * CFrame.Angles(math.rad(90), 0, 0)

math.rad turns degrees into radians. You may need to make this -90 degrees and/or move it to the Y or Z axis depending on which direction they need to rotate.

3 Likes

Since this is already my solution, I marked it already.
Thank you so much, orientation is being setted correctly!

Trowable.CFrame = CFrame.new(RayResult.Position, RayResult.Position + RayResult.Normal) * CFrame.Angles(math.rad(-90), 0, 0)

Just as an addicional, since ~m a t h - i s - m y - p a s s i o n~, I need a little help setting the final position of the Throwable. As you can see at the photo, the position of the object is getting a little inside of the part… is there a simple way to resolve that?

1 Like

Heck yeah, love math. There are two easy ways to do this. The first is to throw another CFrame offset onto it.
[everything else] * CFrame.new(offsetX, offsetY, offsetZ)
This is conveniently in local space, so if the top of the banana is positive Y and you want to move it up by 0.75 studs, you can do * CFrame.new(0, 0.75, 0)

However, this invokes matrix multiplication which is a lot slower than regular addition. You won’t notice the difference since you only calculate once per throw, but it’s worth mentioning that there’s a more efficient way. Since we already have the Normal, which points conveniently in the direction we need to move it, we can just add that to the CFrame. Again I’m assuming we need to move it 0.75 studs for the sake of example.
[everything else] + RayResult.Normal * 0.75

Feel free to send me a direct message if you want more help with this; I love CFrames and I’d be happy to talk about them whenever I have free time.


Edit to add, there is one more way. I think it’s probably the best method there is. You could take the CFrame.Angles and the CFrame.new method and multiply those together manually before the script runs.

print(
    CFrame.Angles(math.rad(-90), 0, 0)
    * CFrame.new(0, 0.75, 0)
)
--> 0, -3.27835394e-08, -0.75, 1, 0, 0, 0, -4.37113883e-08, 1, 0, -1, -4.37113883e-08
-- (e-08 is basically 0, probably just rounding errors)

So we can simplify the entire thing down to this.

Trowable.CFrame = CFrame.new(RayResult.Position, RayResult.Position + RayResult.Normal) * CFrame.new(0, 0, -0.75, 1, 0, 0, 0, 0, 1, 0, -1, 0)

If that’s the wrong axis, you can just mess around with the first three numbers until you get the right axis and the right offset. There are ways to find the desired axis without trial-and-error, but it’s not really worth the effort to remember or draw the frames of reference when you can just swap some numbers.

Working really well now! Thank you, you’re my savior!

there’s a little error in the offset but I already going to solve this, because it’s just a value that Is a little wrong

Trowable.CFrame = CFrame.new(RayResult.Position, RayResult.Position + RayResult.Normal) * CFrame.Angles(math.rad(-90), 0, 0) * CFrame.new(0, 1.4, 0)

I used this, since it’s the one that more fit my situation, since the other one made a mess with the rotations, but this one didn’t. Probably not the most efficient, but effective.

But anyways, again, thank you so much! c:

1 Like

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