Raycast Limiting and Layers

I have a scene with several objects called panels. A raycast from the camera determines if the camera is ‘looking’ at a panel or not. There may be, at times, objects between the camera and the panels. So I have a raycast filter for only the ‘Panels’. There is a plane between the camera and the panels which is in layer ‘Ground’ (9), all of the panels are in layer ‘Panels’ (10).

If I remove the plane, the code executes perfectly. If the plane is present between the camera and the panels, the raycast suddenly doesn’t hit or doesn’t register hitting the panels. A debug draw line goes through both the panels and the plane.

What do I need to do to get the raycast to ignore the plane, but register the panel objects?

public LayerMask blockLayers;

void Awake() {
        blockLayers = LayerMask.GetMask("Panels");
}

void Update() {
        Camera camera;
        camera = oCam.GetComponent<Camera>();
        RaycastHit hit;
        Ray ray = camera.ScreenPointToRay(new Vector3((camera.pixelWidth / 2), (camera.pixelHeight / 2), 0));
        Debug.DrawRay(ray.origin, ray.direction * 10, Color.red);
        if (Physics.Raycast(ray, out hit, blockLayers))
        {
            if (hit.collider != null && hit.collider.gameObject.layer == 10)
            {
                hPanel(hit.collider.gameObject);
            }
        }
    }

Hi there.

I think your ray cast filtering is correct - you’ve used the layer mask system exactly how you should, so presuming you’re correct about what is in what layer, most of the code is correct. However on Line 15, you’re simply checking the layer index - that seems a bit suspicious to me, and you should never be referencing layers purely by integer, as it can change depending on scene and stuff. Instead try this:

if (hit.collider != null && hit.collider.gameObject.layer == LayerMask.NameToLayer("Panels"))

If that doesn’t work, try using Debug.Log to print out what is actually being found. i.e. inside the if statement:

Debug.Log(out.hit.collider.name)

-Chris

if (Physics.Raycast(ray, out hit, blockLayers))

blockLayers is interpreted as float (because the implicit casting from int to float) for maximum range.
for a layermask 1 << 10, your ray will return the first object hit in a 1024 distance, with the default layermask. So you’ll hit the first object which is the plane.

You got the method signature wrong.
Use either:
Raycast(Ray, out hit, float range, int layermask)

or

Raycast(Ray, float range, int layermask)

As @Soraphis points out, the method I had of utilizing physics.raycast was incorrect. blockLayers was being interpreted as an int for the distance of the raycast and not the layermask. I have re-written the line as follows using identifying practices provided by @wibble82, and it appears to work as needed:

        if (Physics.Raycast(ray, out hit, 10f, blockLayers))
        {
            Debug.Log(hit.collider.name + " was hit.");
            if (hit.collider != null && hit.collider.gameObject.layer == LayerMask.NameToLayer("Panels"))
            {
                
                hPanel(hit.collider.gameObject);
            }
        }

Moral of the story: Verify method overloads