Update: Ran more tests as detailed in the posts below. Seems to be an issue when using large meshes. My test mesh reports 233145 vertices, which gives incorrect results with its index format set to 32bit, but work at 16bit(unity breaks up the mesh at 16bit though). In the mesh’s import settings, I had “Normals” set to “Import”, changing that to “Calculate” lowers my vertex count to 54082(though the number of indices stays the same), and everything starts working again. Issue does not happen when mesh has less than 65536 vertices, regardless of the selected index format.
Hi, I have a project which I started using DOTS 0.51, am upgrading it to 1.0 and I’m pretty sure that CastRay is broken(or I’m somehow doing something wrong, in which case I’m open to suggestions!). My project does a raycast through a mesh with a physics shape, and needs to determine every contact point. When calling CastRay with DOTS 0.51 using a native list, it acts as expected, a hit is detected wherever the ray enters and exits the mesh. But using the same function in DOTS 1.0, it reports many extra, incorrect collisions, and sometimes NONE of the collisions are correct.
I set up test projects using Unity 2021.3.16f1(initial version I was using), 2022.2.9, and 2022.2.11. The only differences in what I’m doing is how the collision world is accessed
This is my test script
using System.Collections.Generic;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;
using UnityEngine;
using UnityEngine.InputSystem;
using ECSWorld = Unity.Entities.World;
using Material = UnityEngine.Material;
using RaycastHit = Unity.Physics.RaycastHit;
public class raycast : MonoBehaviour {
private Mouse mouse;
private Camera _camera;
private List<List<GameObject>> dbgCubes;
public Material dbgMat;
public float dbgLength = 20f;
// Start is called before the first frame update
void Start() {
dbgCubes = new List<List<GameObject>>();
mouse = Mouse.current;
_camera = Camera.main;
}
// Update is called once per frame
void Update() {
GetWorldPos(mouse.position.value);
}
NativeList<RaycastHit> cast(float3 RayFrom, float3 RayTo) {
EntityQueryBuilder builder = new EntityQueryBuilder(Allocator.Temp).WithAll<PhysicsWorldSingleton>();
EntityQuery singletonQuery = ECSWorld.DefaultGameObjectInjectionWorld.EntityManager.CreateEntityQuery(builder);
var collisionWorld = singletonQuery.GetSingleton<PhysicsWorldSingleton>().CollisionWorld;
singletonQuery.Dispose();
RaycastInput input = new RaycastInput() {
Start = RayFrom,
End = RayTo,
Filter = new CollisionFilter() {
BelongsTo = ~0u,
CollidesWith = ~0u,
GroupIndex = 0
}};
var hitList = new NativeList<RaycastHit>(Allocator.Temp);
bool haveHit = collisionWorld.CastRay(input, ref hitList);
Debug.DrawLine(RayFrom, RayTo, haveHit ? Color.green : Color.red, dbgLength);
if(haveHit) {
hitList.Sort(new HitSort());
var dbgs = new List<GameObject>();
var grp = new GameObject("group "+dbgCubes.Count+": length "+hitList.Length);
Destroy(grp, dbgLength);
foreach (var raycastHit in hitList) {
var nm = "dbg " + dbgs.Count;
var dbg = GameObject.CreatePrimitive(hitList.Length > 1 ? PrimitiveType.Sphere: PrimitiveType.Cube);
dbg.transform.parent = grp.transform;
dbg.name = nm;
dbg.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
var mr = dbg.GetComponent<MeshRenderer>();
mr.material = dbgMat ? dbgMat : Resources.Load<Material>("debug cube");
dbgs.Add(dbg);
dbg.transform.position = raycastHit.Position;
}
dbgCubes.Add(dbgs);
}
return hitList;
}
public NativeList<RaycastHit> GetWorldPos(Vector2 mousePos2 = new Vector2(), bool dbg = false) {
Vector3 mousePos3 = mousePos2;
mousePos3.z = _camera.nearClipPlane;
var ray = _camera.ScreenPointToRay(mousePos3);
var dest = ray.GetPoint(10000);
var hits = cast(ray.origin, dest);
return hits;
}
struct HitSort : IComparer<RaycastHit> {
public int Compare(RaycastHit a, RaycastHit b) {
if (a.Fraction > b.Fraction) return 1;
if (a.Fraction < b.Fraction) return -1;
return 0;
}
}
}
I use the exact same code for both 0.51 and 1.0, other than how the CollisionWorld is accessed
0.51
var physicsWorldSystem = ECSWorld.DefaultGameObjectInjectionWorld
.GetExistingSystem<Unity.Physics.Systems.BuildPhysicsWorld>();
var collisionWorld = physicsWorldSystem.PhysicsWorld.CollisionWorld;
1.0
EntityQueryBuilder builder = new EntityQueryBuilder(Allocator.Temp).WithAll<PhysicsWorldSingleton>();
EntityQuery singletonQuery = ECSWorld.DefaultGameObjectInjectionWorld.EntityManager.CreateEntityQuery(builder);
var collisionWorld = singletonQuery.GetSingleton<PhysicsWorldSingleton>().CollisionWorld;
singletonQuery.Dispose();
I’ve included 2 packages for testing, can test using a unity project in one of the above mentioned editor versions, with the following packages installed
- Entities
- Entities Graphics/Hybrid Renderer
- Unity Physics
- Input System
- HDRP
OR you can download the full projects from here
https://drive.google.com/drive/folders/11gcwa-ey8KDtFkMv3Cc6k6pyRXp0i0Eg?usp=sharing
To use them, have the scene view and game view open at the same time, and run the project. A ray will cast from the camera to where the mouse is. As there are successful hits, GO’s will be added to the hierarchy. You’ll see groups with a number next to them representing the number of hits for a particular ray, and cubes(for single hits) or spheres(for multi-hits) as children of the group GO placed where the hit happened. The raycast script attached to the camera will let you change how long the debug rays and GO’s stay in the scene.
Looking forward to a response, kinda hoping I’m just screwing something up ^_^U
Here’s a screenshot showing expected results
And one with the results from DOTS 1.0
Note that in the second screenshot, both “hits” in group 2 are below the mesh, the hits in group 3 are litterally in the exact same position, and group 4 has both doubled up hits, and hits below the mesh.
8918399–1221629–raycast test dots 0-51.unitypackage (3.21 MB)
8918399–1221632–raycast test dots 1.unitypackage (3.2 MB)



