You can achieve this by overriding LocalToWorld
component at the right time, for example:
scene hierarchy:
results is this (very much expected):
but, if you add a ConstantRotationCompoent
to this B and rotate it a bit:
it will keep that rotation as constant:
If you need them to “look at the camera” (camera-aligned variant) add the LookAtCameraComponent
to B (child) gameObject.
ConstantRotationComponent.cs:
using UnityEngine;
using Unity.Mathematics;
using Unity.Entities;
using Unity.Transforms;
namespace ConstantRotationSystem
{
public class ConstantRotationComponent : MonoBehaviour, IConvertGameObjectToEntity
{
void IConvertGameObjectToEntity.Convert ( Entity entity , EntityManager dstManager , GameObjectConversionSystem conversionSystem )
{
dstManager.AddComponent<ConstantRotation>( entity );
dstManager.SetComponentData( entity , new ConstantRotation{ Value = transform.rotation } );
}
}
public struct ConstantRotation : IComponentData
{
public quaternion Value;
}
[UpdateInGroup( typeof(TransformSystemGroup) )]
[UpdateAfter( typeof(EndFrameLocalToParentSystem) )]
public class ConstantRotationSystem : SystemBase
{
protected override void OnUpdate ()
{
Entities
.WithName("constant_rotation_job")
.ForEach(
( ref LocalToWorld transform , in ConstantRotation constantRotation ) =>
{
float3 scale = new float3{ x=math.length(transform.Value.c0) , y=math.length(transform.Value.c1) , z=math.length(transform.Value.c2) };
transform.Value = float4x4.TRS( transform.Position , constantRotation.Value , scale );
} )
.ScheduleParallel();
}
}
}
LookAtCameraComponent.cs
using UnityEngine;
using Unity.Mathematics;
using Unity.Entities;
using Unity.Transforms;
namespace LookAtCameraComponent
{
public class LookAtCameraComponent : MonoBehaviour, IConvertGameObjectToEntity
{
void IConvertGameObjectToEntity.Convert ( Entity entity , EntityManager dstManager , GameObjectConversionSystem conversionSystem )
=> dstManager.AddComponent<LookAtCamera>( entity );
}
public struct LookAtCamera : IComponentData {}
[UpdateInGroup( typeof(TransformSystemGroup) )]
[UpdateAfter( typeof(EndFrameLocalToParentSystem) )]
public class LookAtCameraSystem : SystemBase
{
protected override void OnUpdate ()
{
var camera = Camera.main;
if( camera==null ) return;
quaternion rotation = Quaternion.LookRotation( forward:-camera.transform.forward , upwards:-camera.transform.up );
Entities
.WithName("loot_at_camera_job")
.WithAll<LookAtCamera>()
.ForEach(
( ref LocalToWorld transform ) =>
{
float3 scale = new float3{ x=math.length(transform.Value.c0) , y=math.length(transform.Value.c1) , z=math.length(transform.Value.c2) };
transform.Value = float4x4.TRS( transform.Position , rotation , scale );
} )
.ScheduleParallel();
}
}
}
AnimateMeComponent.cs (just a test system to help with testing):
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
namespace AnimateMeSystem
{
public class AnimateMeComponent : MonoBehaviour, IConvertGameObjectToEntity
{
void IConvertGameObjectToEntity.Convert ( Entity entity , EntityManager dstManager , GameObjectConversionSystem conversionSystem )
=> dstManager.AddComponent<AnimateMe>( entity );
}
public struct AnimateMe : IComponentData {}
public class AnimateMeSystem : SystemBase
{
protected override void OnUpdate ()
{
float time = (float) Time.ElapsedTime;
Entities
.WithName("animation_job")
.WithAll<AnimateMe>()
.ForEach(
( ref LocalToWorld transform ) =>
{
float2 noiseScale = new float2{ x=100 , y=100 };
float2 noiseScaleHalved = noiseScale * 0.5f;
float ex = noise.pnoise( new float2(time,time+noiseScaleHalved.y) , noiseScale ) * math.PI;
float ey = noise.pnoise( new float2(time+noiseScaleHalved.x,time) , noiseScale ) * math.PI;
float ez = noise.pnoise( new float2(time,time)+noiseScaleHalved , noiseScale ) * math.PI;
transform.Value = float4x4.TRS( transform.Position , quaternion.Euler( ex , ey , ez ) , 1 );
} )
.ScheduleParallel();
}
}
}