Werid problem with Raycasting

Ive run into a very weird problem when raycasting, when my object has no rotation everything is ok and all the point connect correctly as expected -
8886384--1214943--A.png

However as soon as i rotate the object nothing connects…

8886384--1214946--B.png

this is the code for my raycasts, when checking the SqrMagitude changes on the rotated object and i have no idea how to fix…

                RaycastHit[] Hits = Physics.RaycastAll(Pos + new Vector3(0, 500, 0), -Vector3.up, 1000);
                Hits = Hits.OrderBy(item => item.point.y).ToArray();

To be honest, it is absolutely unclear what is going on in the picture and what the shown code has to do with it.

1 Like

Yea sorry, am making grid all nodes are spaced equally and placed in dictionary with the Vector3 Position as its key, then connected up by lookup

            Vector3 NP = new Vector3(Node.Position.x, Node.Position.y, Node.Position.z);
            Vector3 Additional = new Vector3(1, 0, 0);
            if (Nodes.ContainsKey(NP + Additional))
            {
                Node.Neighbours.Add(Nodes[NP + Additional]);
            }

so on and so forth, it all works perfectly fine if the object that being raycast isnt rotated but as soon as it is even though the node positions havent changed it wont connect the nodes up.

Use Debug.DrawRay/DrawLine to debug where the raycasts are going. That will probably lead you to what’s going wrong.

Only saying this as it’s still really hard to tell what’s going with the tiny snippets of our of context code.

Should point out the game object casting the rays is not the same object being hit

    void CreateGrid()
    {
        for (int x = -(GridSize / 2); x < (GridSize / 2); x++)
        {
            for (int z = -(GridSize / 2); z < (GridSize / 2); z++)
            {
                Vector3 Pos = new Vector3(x, 0, z);
                RaycastHit[] Hits = Physics.RaycastAll(Pos + new Vector3(0, 500, 0), -Vector3.up, 1000);
                //Hits = Hits.OrderBy(item => item.point.y).ToArray();
                for (int i = 0; i < Hits.Length; i++)
                {
                    float hx = Hits[i].point.x;
                    float hy = Mathf.Round(Hits[i].point.y * 10) / 10;
                    float hz = Hits[i].point.z;

                    Vector3 HitPos = new Vector3(hx,hy,hz);
                
                    //if (Physics.SphereCastAll(HitPos, EdgeDetection, Vector3.up, EdgeDetection).Length != 1)
                    //{
                    //    continue;
                    //}

                    if (Hits.Length == 1)
                    {
                        Nodes.Add(HitPos, new PF_Node(HitPos));
                    }
                    else
                    {
                        try
                        {
                            if ((Mathf.Round(Hits[i + 1].point.y * 10) / 10) - HitPos.y >= ImpassThreshold)
                            {
                                Nodes.Add(HitPos, new PF_Node(HitPos));
                            }
                        }
                        catch (System.Exception)
                        {
                            //Assume Nothing above it.
                            Nodes.Add(HitPos, new PF_Node(HitPos));
                        }
                    }
                }
            }
        }


        foreach (var Node in Nodes.Values)
        {
            Vector3 NP = new Vector3(Node.Position.x, Node.Position.y, Node.Position.z);
            Vector3 Additional = new Vector3(1, 0, 0);
            if (Nodes.ContainsKey(NP + Additional))
            {
                Node.Neighbours.Add(Nodes[NP + Additional]);
            }
            Additional = new Vector3(-1, 0, 0);
            if (Nodes.ContainsKey(NP + Additional))
            {
                Node.Neighbours.Add(Nodes[NP + Additional]);
            }
            Additional = new Vector3(0, 0, 1);
            if (Nodes.ContainsKey(NP + Additional))
            {
                Node.Neighbours.Add(Nodes[NP + Additional]);
            }
            Additional = new Vector3(0, 0, -1);
            if (Nodes.ContainsKey(NP + Additional))
            {
                Node.Neighbours.Add(Nodes[NP + Additional]);
            }

            Additional = new Vector3(-1, 0, 1);
            if (Nodes.ContainsKey(NP + Additional))
            {
                Node.Neighbours.Add(Nodes[NP + Additional]);
            }
            Additional = new Vector3(-1, 0, -1);
            if (Nodes.ContainsKey(NP + Additional))
            {
                Node.Neighbours.Add(Nodes[NP + Additional]);
            }
            Additional = new Vector3(1, 0, 1);
            if (Nodes.ContainsKey(NP + Additional))
            {
                Node.Neighbours.Add(Nodes[NP + Additional]);
            }
            Additional = new Vector3(1, 0, -1);
            if (Nodes.ContainsKey(NP + Additional))
            {
                Node.Neighbours.Add(Nodes[NP + Additional]);
            }

            float MaxHeightDist = GetMaxAngleHeight();
            for (float i = -MaxHeightDist; i < MaxHeightDist; i+=0.1f)
            {
                i = Mathf.Round(i * 10) / 10;
            
                Additional = new Vector3(1, i, 0);
                if (Nodes.ContainsKey(NP + Additional))
                {
                    Node.Neighbours.Add(Nodes[NP + Additional]);
                }
                Additional = new Vector3(-1, i, 0);
                if (Nodes.ContainsKey(NP + Additional))
                {
                    Node.Neighbours.Add(Nodes[NP + Additional]);
                }
                Additional = new Vector3(0, i, 1);
                if (Nodes.ContainsKey(NP + Additional))
                {
                    Node.Neighbours.Add(Nodes[NP + Additional]);
                }
                Additional = new Vector3(0, i, -1);
                if (Nodes.ContainsKey(NP + Additional))
                {
                    Node.Neighbours.Add(Nodes[NP + Additional]);
                }

                Additional = new Vector3(-1, i, 1);
                if (Nodes.ContainsKey(NP + Additional))
                {
                    Node.Neighbours.Add(Nodes[NP + Additional]);
                }
                Additional = new Vector3(-1, i, -1);
                if (Nodes.ContainsKey(NP + Additional))
                {
                    Node.Neighbours.Add(Nodes[NP + Additional]);
                }
                Additional = new Vector3(1, i, 1);
                if (Nodes.ContainsKey(NP + Additional))
                {
                    Node.Neighbours.Add(Nodes[NP + Additional]);
                }
                Additional = new Vector3(1, i, -1);
                if (Nodes.ContainsKey(NP + Additional))
                {
                    Node.Neighbours.Add(Nodes[NP + Additional]);
                }
            }
        }
    }

Also doing some breakpoint checks seems to show an inexpected result…

NP + Additional (While object is rotated -10 on Y)
“(0.00, 0.50, -2.00)”
magnitude: 2.061553
normalized: “(0.00, 0.24, -0.97)”
sqrMagnitude: 4.250002
x: -2.384186E-07
y: 0.5
z: -2

NP + Additional (While object is not rotated)
“(0.00, 0.50, -2.00)”
magnitude: 2.061553
normalized: “(0.00, 0.24, -0.97)”
sqrMagnitude: 4.25
x: 0
y: 0.5
z: -2

The sqrMagnitude and x pos are different - even though the positions are exactly the same

Not really. The differences are microscopic. Not enough to worry about.

Fixed it, Not sure why or how changing the hx,hy,hz to the below fixed it, at a guess it was a floating point issue.

                    float hx = Mathf.Round((Hits[i].point.x * 10) / 10);
                    float hy = Mathf.Round(Hits[i].point.y * 10) / 10;
                    float hz = Mathf.Round((Hits[i].point.z * 10) / 10);

I spotted the floating point issue as soon as you said…

The rule of thumb in programming is to never depend on floating point equality when evaluating conditions. And that’s exactly what happens in your Dictionary when you look something up by a Vector3 key - it has to check if a bunch of stored floats match a bunch of input floats.

Basically, the issue with this approach is that (5 * 2) is not guaranteed to come up with the same floating point representation of the answer as (2.5 * 4) or (10 * 1) or (11 * (10/11)) or whatever. And that’s not even getting into madness such as (3.333… * 3.333…). Your current calculation happens to end up with answers which have a matching floating point representation in current use cases, but there’s no way I’d trust that to hold true generally.

Personally, depending on what you’re trying to do overall, I’d do one of the following:

  • Use Vector3Int as my key.
  • If this is a grid which is always fully populated, use a 3-dimensional array.
    Either way, I’d also have a function which takes a Vector3 position and returns a Vector3Int index, or equivalent.
1 Like

Ew. I did’nt catch that! angrypenguin is right. Using floats as a dictionary key is a ruinously bad idea and will never work reliably (as you’ve already discovered).:hushed: