Is Workspace:Raycast() broken with CFrame?

So, i am triyng to make a raycaster with roblox’s new Workspace:Raycast() method instead of the deprecated ray.new() method, but there is an issue.

There is this weird issue or bug. I am not sure why, but it appears roblox’s raycast system is a bit broken when using CFrame.

You can clearly see the ray is not casting straight.

I doubt there is anything wrong with my code, but you can take a look anyways.


raycast bug.rbxl (27.2 KB)


local CameraPart = workspace:WaitForChild("CameraPart")
local LevelWorkspace = workspace:WaitForChild("LevelWorkspace")

local DebugLaser = Instance.new("Part") -- Useful for visualizing the rays
DebugLaser.Anchored = true
DebugLaser.Name = "DebugLaser"
DebugLaser.Parent = workspace

while true do
	wait()
	
	local ViewRayOrigin = CameraPart.CFrame.Position

	local RenderDistance = 100

	local Params = RaycastParams.new()
	Params.FilterType = Enum.RaycastFilterType.Whitelist
	Params.FilterDescendantsInstances = LevelWorkspace:GetChildren()

	local ViewRayDirection = CameraPart.CFrame * CFrame.new(0, 0, -RenderDistance).Position

	local ViewRay = workspace:Raycast(ViewRayOrigin, ViewRayDirection, Params)
	
	if ViewRay and ViewRay.Instance and ViewRay.Instance:IsA("BasePart") then
		local HitPart = ViewRay.Instance

		local Distance = (ViewRayOrigin - ViewRay.Position).Magnitude
		DebugLaser.Size = Vector3.new(0.2, 0.2, Distance)
		DebugLaser.CFrame = CFrame.new(ViewRayOrigin, ViewRay.Position) * CFrame.new(0, 0, -Distance/2)
	end
end

No - you’re calculating ViewRayDirection incorrectly as a position relative to the world origin instead of relative to the camera part. You can tell it’s not a bug with the raycasting API because simply printing ViewRayDirection will show you that your calculation is wrong.

Fix:

local ViewRayDirection = CameraPart.CFrame.LookVector * RenderDistance
2 Likes

Oh. I jinxed myself.

Also how do I multiply CFrames by other CFrames in local space?

This one seems to be half world space too:

local ViewRayDirection = (CameraPart.CFrame * CFrame.new((Count * FieldOfView) / Resolution, 0, -RenderDistance)).Position

I think there is a fundamental misunderstanding of CFrames vs direction vectors here.

The second parameter in WorldRoot:Raycast is a direction vector, so for example <0, 1, 0> means: go directly up by one stud from the origin of the ray.

Your calculations are treating it more like a position in the world to aim at, which is not how it works. You multiplied the CFrame of the CameraPart (which contains position and rotation, relative to the world origin) by some other CFrame, and then took the .Position of the result. That yields the position that you want your ray to point towards, not the direction.

A simple way to fix this is to calculate the position you want to point towards, and then from there, calculate the direction vector by subtracting the ray origin from it:

local vec = Vector3.new(count * fieldOfView / resolution, 0, -renderDistance)
local pos = cameraPart.CFrame * vec
local dir = pos - cameraPart.Position

An alternative way of doing this would be:

local vec = Vector3.new(count * fieldOfView / resolution, 0, -renderDistance)
local dir = cameraPart.CFrame:VectorToWorldSpace(vec)

To understand why that works, you need to read up on CFrames and the Raycast API you’re using. At the moment, you’re going to have a hard time making progress with this.


NB: I’m not sure what you’re doing with count, fieldOfView, and resolution here, but it looks a bit suspect. This won’t generate a viewport shape like you want.

1 Like

Ah, i see. Thank you! Also that code is for a 2D Raycast Renderer.

But it has been changed to use angles instead of offsets.