Raycast not finding collider when instantiated from code

tl;dr Using the same methods, I am not able to get raycast to find one of two objects. If I manually drag the ‘missing’ object into the scene from a prefab, it works no problem.

Setup:
I have two objects, a mesh I use for terrain, and a hill. Both created in blender, exported as FBX with the same settings. Both show the mesh normals as expected.

For both objects I created a prefab with the following process:

  • create 3d empty in scene
  • add imported FBX as child object
  • add a mesh collider to FBX child (which auto-assigns the mesh)
  • set layer to custom ‘Ground’ layer (not yet used anywhere)
  • drag into assets to create prefab

From there I use the following code to instantiate the prefabs (the hill mesh bounds rise above the bounds of the terrain mesh):


    GameObject terrain = Instantiate(terrainGameObject);
    terrain.transform.position = new Vector3(0f, 0f, 0f);
    terrain.transform.parent = terrainParent.transform;
    
    GameObject hill = Instantiate(hillGameObject);
    hill.transform.position = new Vector3(40f, 1f, 12f);
    hill.transform.parent = terrainParent.transform;
    
    // Check for the hill placed
    RaycastHit terrainRayCast;
    if(Physics.Raycast(new Vector3(40f, 10f, 12f), Vector3.down, out terrainRayCast, 11f)){
        Debug.DrawRay(terrainRayCast.point + new Vector3(0f, 11f, 0f), Vector3.down * 11f, Color.red, 0.5f);
        Debug.Log(string.Format("Hit point: {0} at {1} on {2}",
                LayerMask.LayerToName(terrainRayCast.transform.gameObject.layer),
                terrainRayCast.point,
                terrainRayCast.transform.gameObject.name));
    }

...where the game objects indicated are prefabs pulled into a field in the inspector. Both objects show up as expected, with all components and I've verified they're all enabled at execution. The mesh colliders are intact. But, the resulting output shows 
 

`Hit point: Default at (40.0, 0.1, 10.0) on terrain_flat_01`
 

To further test, I have manually brought in via the editor the hill prefab 25 units over, adjusted a second raycast and gotten the desired results:

`Hit point: Ground at (40.0, 2.5, -15.0) on terrain_hill_03`

I manually placed the terrain prefab via editor as well and the raycast works to find the terrain mesh no problem. I've also tested in editor and at runtime, to the same effect. Here is a visualization of the issue, with the code-instantiated hill on the left:
![alt text][1]

Since it works when manually placed I know it's not the mesh. Since the terrain mesh works both via code and manually, I know it's not my setup process. Since the raycast always hits the terrain no matter what and also hits the manual hill, it's not the raycast code. Also, in runtime the player collides with both meshes without issue, as expected (able to walk on it).

The only difference I see is that the code-instantiated object isn't linked to a prefab, which is expected, but doesn't affect the terrain. I've also tested the order of the prefab instantiation, the method (e.g., using `PrefabUtility.Instantiate` instead), re-assigning the mesh at execution, but I can't figure it out.

Any idea what could be the issue? 

  [1]: https://i.imgur.com/fp3f3Si.png
1 Like

After doing more testing, this appeared to be a timing issue. If I make two buttons in the editor inspector, one to do the placement/instantiation with an immediate raycast, and one to do the raycasting separately, the former maintains the issue while the latter works without issue. Adding in a system sleep for half a second doesn’t appear to work, which told me it wasn’t the order or timing of my code as much as what happens AFTER my code completes, e.g., in a frame update.

So, after some additional digging into what happens after the code returns and before any other code is called, I came upon this Stack Overflow post which detailed how to simulate a physics step to recalculate the collider mesh:

Physics.autoSimulation = false;
Physics.Simulate(Time.fixedDeltaTime);  
Physics.autoSimulation = true;

Calling this prior to the raycast resolved this issue.