Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved Terrain Authoring Problem

Discussion in 'Physics for ECS' started by Palom-Porom, Aug 12, 2023.

  1. Palom-Porom

    Palom-Porom

    Joined:
    Sep 21, 2022
    Posts:
    33
    Hello everyone. I am new to Unity DOTS and I need to learn how to create terrain. After I had seen that https://forum.unity.com/threads/using-unity-terrain-with-dots-workflow.755105/ thread, I tried to do the same thing as Avol done there (2 page). But I got some error which I poorly understand and do not know what to do with it
    Here is the full text of it:

    AssertionException: Assertion failure. Value was False
    Expected: True
    UnityEngine.Assertions.Assert.Fail (System.String message, System.String userMessage) (at <e97d84204f8d4aef92b538c5bab948f1>:0)
    UnityEngine.Assertions.Assert.IsTrue (System.Boolean condition, System.String message) (at <e97d84204f8d4aef92b538c5bab948f1>:0)
    UnityEngine.Assertions.Assert.IsTrue (System.Boolean condition) (at <e97d84204f8d4aef92b538c5bab948f1>:0)
    Unity.Physics.Math+ScaledMTransform..ctor (Unity.Mathematics.RigidTransform transform, System.Single uniformScale) (at ./Library/PackageCache/com.unity.physics@1.0.11/Unity.Physics/Base/Math/Physics_Transform.cs:109)
    Unity.Physics.RigidBody+RigidBodyUtil.CastRay[T] (Unity.Entities.BlobAssetReference`1[T] bodyCollider, Unity.Entities.Entity rbEntity, Unity.Physics.RaycastInput input, T& collector, Unity.Mathematics.RigidTransform worldFromBody, System.Single unifromScale) (at ./Library/PackageCache/com.unity.physics@1.0.11/Unity.Physics/Collision/RigidBody/RigidBody.cs:110)
    Unity.Physics.RigidBody.CastRay[T] (Unity.Physics.RaycastInput input, T& collector) (at ./Library/PackageCache/com.unity.physics@1.0.11/Unity.Physics/Collision/RigidBody/RigidBody.cs:92)
    Unity.Physics.Broadphase+BvhLeafProcessor.RayLeaf[T] (Unity.Physics.RaycastInput input, System.Int32 rigidBodyIndex, T& collector) (at ./Library/PackageCache/com.unity.physics@1.0.11/Unity.Physics/Collision/World/Broadphase.cs:624)
    Unity.Physics.BoundingVolumeHierarchy.Raycast[TProcessor,TCollector] (Unity.Physics.RaycastInput input, TProcessor& leafProcessor, TCollector& collector) (at ./Library/PackageCache/com.unity.physics@1.0.11/Unity.Physics/Collision/Geometry/BoundingVolumeHierarchy.cs:373)
    Unity.Physics.Broadphase.CastRay[T] (Unity.Physics.RaycastInput input, Unity.Collections.NativeArray`1[T] rigidBodies, T& collector) (at ./Library/PackageCache/com.unity.physics@1.0.11/Unity.Physics/Collision/World/Broadphase.cs:534)
    Unity.Physics.CollisionWorld.CastRay[T] (Unity.Physics.RaycastInput input, T& collector) (at ./Library/PackageCache/com.unity.physics@1.0.11/Unity.Physics/Collision/World/CollisionWorld.cs:338)
    Unity.Physics.QueryWrappers.RayCast[T] (T& target, Unity.Physics.RaycastInput input, Unity.Physics.RaycastHit& closestHit) (at ./Library/PackageCache/com.unity.physics@1.0.11/Unity.Physics/Collision/Queries/Collidable.cs:664)
    Unity.Physics.CollisionWorld.CastRay (Unity.Physics.RaycastInput input, Unity.Physics.RaycastHit& closestHit) (at ./Library/PackageCache/com.unity.physics@1.0.11/Unity.Physics/Collision/World/CollisionWorld.cs:318)
    MovementJob.Execute (Unity.Transforms.LocalTransform& transform, MovementComponent& movementComponent) (at Assets/Scripts/Player/MovementSystem.cs:72)
    MovementJob.Execute (Unity.Entities.ArchetypeChunk& chunk, System.Int32 chunkIndexInQuery, System.Boolean useEnabledMask, Unity.Burst.Intrinsics.v128& chunkEnabledMask) (at Unity.Entities.SourceGen.JobEntityGenerator/Unity.Entities.SourceGen.JobEntity.JobEntityGenerator/Temp/GeneratedCode/Assembly-CSharp/MovementSystem__JobEntity_4119310620.g.cs:34)
    MovementJob.Unity.Entities.IJobChunk.Execute (Unity.Entities.ArchetypeChunk& chunk, System.Int32 unfilteredChunkIndex, System.Boolean useEnabledMask, Unity.Burst.Intrinsics.v128& chunkEnabledMask) (at <caba33998ce645f1b26653a6699ee1cc>:0)
    Unity.Entities.JobChunkExtensions+JobChunkProducer`1[T].ExecuteInternal (Unity.Entities.JobChunkExtensions+JobChunkWrapper`1[T]& jobWrapper, System.IntPtr bufferRangePatchData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities/IJobChunk.cs:412)
    Unity.Entities.JobChunkExtensions+JobChunkProducer`1[T].Execute (Unity.Entities.JobChunkExtensions+JobChunkWrapper`1[T]& jobWrapper, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities/IJobChunk.cs:359)
    Unity.Jobs.JobHandle:ScheduleBatchedJobsAndComplete(JobHandle&)
    Unity.Jobs.JobHandle:Complete()
    MovementSystem:OnUpdate(SystemState&) (at Assets/Scripts/Player/MovementSystem.cs:34)
    MovementSystem:__codegen__OnUpdate(IntPtr, IntPtr)
    Unity.Entities.<>c__DisplayClass9_0:<SelectBurstFn>b__0(IntPtr, IntPtr) (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities/SystemBaseRegistry.cs:256)
    Unity.Entities.UnmanagedUpdate_0000158C$BurstDirectCall:wrapper_native_indirect_000001D9106A1AE0(IntPtr&, Void*)
    Unity.Entities.UnmanagedUpdate_0000158C$BurstDirectCall:Invoke(Void*)
    Unity.Entities.WorldUnmanagedImpl:UnmanagedUpdate(Void*) (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities/WorldUnmanaged.cs:828)
    Unity.Entities.WorldUnmanagedImpl:UpdateSystem(SystemHandle) (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities/WorldUnmanaged.cs:894)
    Unity.Entities.ComponentSystemGroup:UpdateAllSystems() (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities/ComponentSystemGroup.cs:729)
    Unity.Entities.ComponentSystemGroup:OnUpdate() (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities/ComponentSystemGroup.cs:693)
    Unity.Entities.SystemBase:Update() (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities/SystemBase.cs:418)
    Unity.Entities.DummyDelegateWrapper:TriggerUpdate() (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities/ScriptBehaviourUpdateOrder.cs:526)

    Here is the code where error refers if I double click it
    Code (CSharp):
    1. /// <summary>   Constructor. </summary>
    2. ///
    3. /// <param name="transform">    The transform. </param>
    4. /// <param name="uniformScale"> The uniform scale. </param>
    5. public ScaledMTransform(RigidTransform transform, float uniformScale)
    6. {
    7.     Transform = new MTransform(transform);
    8.     UnityEngine.Assertions.Assert.IsTrue(uniformScale != 0.0f);
    9.  
    10.     m_Scale = uniformScale;
    11. }

    And here are my own pretty simple code:

    Code (CSharp):
    1. public partial struct MovementSystem : ISystem
    2. {
    3.     public void OnCreate(ref SystemState state)
    4.     {
    5.         state.RequireForUpdate<MovementComponent>();
    6.     }
    7.  
    8.  
    9.     public void OnUpdate(ref SystemState state)
    10.     {
    11.         var moveJob = new MovementJob { time = SystemAPI.Time.DeltaTime, collisionWorld = SystemAPI.GetSingleton<PhysicsWorldSingleton>().CollisionWorld };
    12.         JobHandle a = moveJob.Schedule(state.Dependency);
    13.         a.Complete();
    14.     }
    15.  
    16.     public void OnDestroy(ref SystemState state)
    17.     {
    18.      
    19.     }
    20. }
    21.  
    22. public partial struct MovementJob : IJobEntity
    23. {
    24.     public float time;
    25.     public CollisionWorld collisionWorld;
    26.     public void Execute(ref LocalTransform transform, in MovementComponent movementComponent)
    27.     {
    28.         if (math.distancesq(movementComponent.target, transform.Position) < 1f)
    29.             return;
    30.         RaycastInput rayDown = new RaycastInput
    31.         {
    32.             Start = transform.Position,
    33.             End = transform.Position + math.mul(transform.Rotation, new float3(0f, -100f, 0f)),
    34.             Filter = new CollisionFilter
    35.             {
    36.                 BelongsTo = ~0u,
    37.                 CollidesWith = 1u << 7,
    38.                 GroupIndex = 0
    39.             }
    40.         };
    41.         if (collisionWorld.CastRay(rayDown, out Unity.Physics.RaycastHit closestHit))
    42.         {
    43.             transform.Position.y = closestHit.Position.y + 1;
    44.            //transform.Rotation = Quaternion.Euler(closestHit.SurfaceNormal);
    45.            //Debug.Log(closestHit.SurfaceNormal);
    46.         }
    47.         else
    48.         {
    49.             Debug.Log("ERROR: Terrain under unit is not found");
    50.         }
    51.         float3 tempDir = movementComponent.target - transform.Position;
    52.         tempDir.y = 0;
    53.         float3 dir = math.normalize(tempDir);
    54.         transform.Position += dir * time * movementComponent.speed;
    55.  
    56.  
    57.     }
    58. }
    Code (CSharp):
    1. public class TerrainAuthoring : MonoBehaviour
    2. {
    3.     [SerializeField] LayerMask belongsToLayers;
    4.     [SerializeField] LayerMask collidesWithLayers;
    5.     [SerializeField] int groupIndex;
    6.     private void Awake()
    7.     {
    8.         if (!TryGetComponent(out Terrain terrain))
    9.         {
    10.             Debug.Log("Terrain component was not found");
    11.             return;
    12.         }
    13.  
    14.         CollisionFilter filter = new CollisionFilter
    15.         {
    16.             BelongsTo = (uint)belongsToLayers.value,
    17.             CollidesWith = (uint)collidesWithLayers.value,
    18.             GroupIndex = groupIndex
    19.         };
    20.  
    21.         PhysicsCollider terrainCollider = CreateTerrainCollider(terrain.terrainData, filter);
    22.  
    23.  
    24.         EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
    25.         Entity terrainEntity = entityManager.CreateEntity();
    26.         Debug.Log("Created Entity");
    27.         entityManager.AddComponent<PhysicsCollider>(terrainEntity);
    28.         Debug.Log("Added PhysicsCollider");
    29.         entityManager.SetComponentData<PhysicsCollider>(terrainEntity, terrainCollider);
    30.         Debug.Log("Setted PhysicsCollider");
    31.         entityManager.AddComponent<LocalToWorld>(terrainEntity);
    32.         Debug.Log("Added LocalToWorld");
    33.         entityManager.AddComponent<LocalTransform>(terrainEntity);
    34.         Debug.Log("Added LocalTransform");
    35.         entityManager.AddComponent<PhysicsWorldIndex>(terrainEntity);
    36.         Debug.Log("Added PhysicsWorldIndex");
    37.     }
    38.  
    39.     private PhysicsCollider CreateTerrainCollider (TerrainData terrainData, CollisionFilter collisionFilter)
    40.     {
    41.         int resolution = terrainData.heightmapResolution;
    42.         int2 size = new int2(resolution, resolution);
    43.         Vector3 scale = terrainData.heightmapScale;
    44.         Debug.Log(scale);
    45.  
    46.         NativeArray<float> heights = new NativeArray<float>(resolution * resolution, Allocator.Temp);
    47.         float[,] temporaryHeightsMatrice = terrainData.GetHeights(0, 0, resolution, resolution);
    48.         for (int j = 0; j < size.y; j++)
    49.             for (int i = 0; i < size.x; i++)
    50.             {
    51.                 var h = temporaryHeightsMatrice[i, j];
    52.                 heights[j + i * size.x] = h;
    53.             }
    54.  
    55.         Debug.Log("Check");
    56.         PhysicsCollider collider = new PhysicsCollider
    57.         {
    58.             Value = Unity.Physics.TerrainCollider.Create(heights, size, scale, Unity.Physics.TerrainCollider.CollisionMethod.Triangles)
    59.         };
    60.         Debug.Log("Check2");
    61.         heights.Dispose();
    62.         Debug.Log("Check3");
    63.         return collider;
    64.     }
    65. }
    And here is the hierarchy, character components and terrain components (maybe my mistake is there, I don`t know :()
    upload_2023-8-12_22-12-49.png

    upload_2023-8-12_22-13-2.png

    upload_2023-8-12_22-13-12.png

    Because all debugs in TerrainAuthoring appear in Console, I suggest that terrain entity was at least created. But when MovingSystem is trying to Raycast it, some problem appears. But what is it and how to solve it?...
     
    Last edited: Aug 12, 2023
  2. mgi388

    mgi388

    Joined:
    Jun 3, 2023
    Posts:
    4
    I think I had a similar error when I set my scale to 0 so double check your scale values to see if that is it.
     
    Last edited: Aug 13, 2023
  3. Tigrian

    Tigrian

    Joined:
    Mar 21, 2021
    Posts:
    105
    Your terrain is out of subscene, because (i guess) your doing all the authoring in your TerrainAuthoring Awake and not in a baker. But in your terrain authoring Awake, you only add a localTransform and localToWorld, you don't set them. You might try to set the localTransform, see if it solves the problem. Check the entities hierarchy to see the localTransform and localToWorld actual values of your terrain.
     
    daniel-holz likes this.
  4. Palom-Porom

    Palom-Porom

    Joined:
    Sep 21, 2022
    Posts:
    33
    Thanks mgi388, really big thanks Tigrian (again :)). As you said the error was connected with not setting the Components` values (By default it thought that Scale equals 0f, which is not supposed to be so in any case).
    But unfortunately now it is another problem - RayCast on that terrain just doesn`t work :( (Again problems with RayCasting). To be more accurate, on the first update RayCast always find the surface (hit in the (0f,0f,0f) position), but from the second update it is no collision with the Ray. Firstly I thought that I messed up with Rotation value on the terrain, but as I understood - no, it is alright. So after a lot of different tries I am out of ideas what to do with it.

    Code (CSharp):
    1. public class TerrainAuthoring : MonoBehaviour
    2. {
    3.     [SerializeField] LayerMask belongsToLayers;
    4.     [SerializeField] LayerMask collidesWithLayers;
    5.     [SerializeField] int groupIndex;
    6.     private void Awake()
    7.     {
    8.         if (!TryGetComponent(out Terrain terrain))
    9.         {
    10.             Debug.Log("Terrain component was not found");
    11.             return;
    12.         }
    13.  
    14.         CollisionFilter filter = new CollisionFilter
    15.         {
    16.             BelongsTo = (uint)belongsToLayers.value,
    17.             CollidesWith = (uint)collidesWithLayers.value,
    18.             GroupIndex = groupIndex
    19.         };
    20.  
    21.         PhysicsCollider terrainCollider = CreateTerrainCollider(terrain.terrainData, filter);
    22.  
    23.  
    24.         EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
    25.         Entity terrainEntity = entityManager.CreateEntity();
    26.         entityManager.AddComponent<PhysicsCollider>(terrainEntity);
    27.         entityManager.SetComponentData<PhysicsCollider>(terrainEntity, terrainCollider);;
    28.         entityManager.AddComponent<LocalToWorld>(terrainEntity);
    29.         entityManager.SetComponentData(terrainEntity, new LocalToWorld());
    30.         entityManager.AddComponent<LocalTransform>(terrainEntity);
    31.         entityManager.SetComponentData(terrainEntity, new LocalTransform
    32.         {
    33.             Rotation = quaternion.Euler(0f, 1f, 0f),
    34.             Scale = 1f
    35.         });
    36.         entityManager.AddComponent<PhysicsWorldIndex>(terrainEntity);
    37.     }
    38.  
    39.     private PhysicsCollider CreateTerrainCollider (TerrainData terrainData, CollisionFilter collisionFilter)
    40.     {
    41.         int resolution = terrainData.heightmapResolution;
    42.         int2 size = new int2(resolution, resolution);
    43.         Vector3 scale = terrainData.heightmapScale;
    44.  
    45.         NativeArray<float> heights = new NativeArray<float>(resolution * resolution, Allocator.Temp);
    46.         float[,] temporaryHeightsMatrice = terrainData.GetHeights(0, 0, resolution, resolution);
    47.         for (int j = 0; j < size.y; j++)
    48.             for (int i = 0; i < size.x; i++)
    49.             {
    50.                 var h = temporaryHeightsMatrice[i, j];
    51.                 heights[j + i * size.x] = h;
    52.             }
    53.  
    54.         PhysicsCollider collider = new PhysicsCollider
    55.         {
    56.             Value = Unity.Physics.TerrainCollider.Create(heights, size, scale, Unity.Physics.TerrainCollider.CollisionMethod.Triangles)
    57.         };
    58.         heights.Dispose();
    59.         return collider;
    60.     }
    61. }
     
  5. Tigrian

    Tigrian

    Joined:
    Mar 21, 2021
    Posts:
    105
    For the rotation, you can use quaternion.identity, (except if rotating by 1 degrees on y axis is what you want). But that should not be the problem. Your code looks good, everything should work. I will try to reproduce it as soon as i get to my computer, see where it can fail.
     
  6. Tigrian

    Tigrian

    Joined:
    Mar 21, 2021
    Posts:
    105
    Alright, I think I found. I reproduced the same steps as you, and got the same result. When you create a terrain, its origin (placed at (0,0,0)) is at the bottom left corner of the terrain. One habit one can have then is to move the terrain to (-500,0, -500), to center its actual mesh center to the world center. Thus, as you set the target to x=-20, z=-8, your unit is going right in the direction where there was no terrain when it was not moved, and because the position field of the localTransform was not set to the transform of the terrain, the actual runtime spawned terrain is in (0,0,0) instead of (-500,0,-500). That is why the unit had one raycast that hit the corner of the terrain, and then it went off terrain.

    I noticed that the quaternion.Euler also bugged the terrain, I don't know why. So doing this should make it work
    Code (CSharp):
    1.         entityManager.SetComponentData(terrainEntity, new LocalTransform
    2.         {
    3.             Position = transform.position,
    4.             Rotation = quaternion.identity,
    5.             Scale = 1f
    6.         });
     
    daniel-holz and Palom-Porom like this.
  7. Palom-Porom

    Palom-Porom

    Joined:
    Sep 21, 2022
    Posts:
    33
    Omg, such a dumby mistake! I must have noticed it by myself.
    Anyway, thank you very much!