고급 베이킹, 베이킹 시스템 도입.
ECS Component들은 렌더링에 사용되는 Shader에 대한 입력을 제어할 수 있습니다.
Shader Graph를 통해 자체 Shader를 생성하고 사용자 지정 ECS Component를 해당 입력에 매핑하는 것은 이 Tutorial의 범위를 벗어나지만 URPMaterialPropertyBaseColor라는 Component를 사용합니다.
이름에서 알 수 있듯이 Standard URP Material의 기본 색상을 제어할 수 있습니다.
우리의 탱크는 3개의 요소(탱크, 포탑, 대포)로 구성되며 각 Entity에는 URPMaterialPropertyBaseColor Component가 추가되어야 합니다.
이렇게 하려면 탱크 프리팹을 열고 계층 구조에서 세 가지 요소(탱크, 포탑, 대포)를 모두 선택하지만 SpawnPoint 변환은 선택하지 않습니다. Renderer가 없기 때문에 색상이 필요하지 않습니다.
세 개의 요소(탱크, 포탑, 대포)를 선택한 상태에서 Insfector의 "Add Component" 버튼을 사용하여 URPMaterialPropertyBaseColorAuthoring Component 추가합니다.
1. 플레이 모드로 들어가 탱크가 이제 완전히 검은색임을 확인합니다(방금 추가한 Authoring Component의 기본 값인 0,0,0,0).
2. 재생 모드를 종료합니다.
Note:
아래 시스템에서 사용하는 EntityCommandBuffer에는 SetComponentForLinkedEntityGroup이 대상으로 지정해야 하는 Entity를 지정하는 쿼리가 필요합니다.Entity 쿼리의 핵심은 Component Type 집합으로 구성되며 쿼리는 해당 집합과 일치하는 Entity만 필터링된 보기를 제공합니다.
Entity 쿼리에 대한 자세한 내용은 Package Documentation를 참조하세요.
3. "Scripts/Systems" 폴더에 있는 "TankSpawningSystem.cs" 파일의 내용을 아래와 같이 수정합니다
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Rendering;
[BurstCompile]
partial struct TankSpawningSystem : ISystem
{
+ // 쿼리는 OnUpdate에서 즉석에서 생성되지 않아야 하므로 필드에 캐시합니다.
+ EntityQuery m_BaseColorQuery;
[BurstCompile]
public void OnCreate(ref SystemState state)
{
+ // Config 싱글톤이 로드되기 전에는 이 시스템을 실행하면 안 됩니다.
+ state.RequireForUpdate<Config>();
+ m_BaseColorQuery = state.GetEntityQuery(ComponentType.ReadOnly<URPMaterialPropertyBaseColor>());
}
[BurstCompile]
public void OnDestroy(ref SystemState state)
{
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var config = SystemAPI.GetSingleton<Config>();
+ // 이 시스템은 한 번만 실행되므로 임의 시드를 하드 코딩할 수 있습니다.
+ // 임의의 상수 시드를 사용하면 시드에 따라 동작이 결정적입니다.
+ var random = Random.CreateFromIndex(1234);
+ var hue = random.NextFloat();
+ // 가능한 한 서로 구별되는 색상을 생성하는 도우미.
+ // 이 접근 방식의 논리는 다음 주소에 자세히 설명되어 있습니다.
+ // https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
+ URPMaterialPropertyBaseColor RandomColor()
+ {
+ // Note: 이 개념에 익숙하지 않은 경우 이것은 "지역 함수"입니다.
+ // 자세한 내용은 인터넷에서 해당 용어를 검색할 수 있습니다.
+ // 0.618034005f == 2 / (math.sqrt(5) + 1) == 황금비의 역수
+ hue = (hue + 0.618034005f) % 1;
+ var color = UnityEngine.Color.HSVToRGB(hue, 1.0f, 1.0f);
+ return new URPMaterialPropertyBaseColor { Value = (UnityEngine.Vector4)color };
+ }
var ecbSingleton = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
var ecb = ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged);
var vehicles = CollectionHelper.CreateNativeArray<Entity>(config.TankCount, Allocator.Temp);
ecb.Instantiate(config.TankPrefab, vehicles);
+ // EntityQueryMask는 특정 Entity가 EntityQuery에 의해 선택되는지 여부에 대한 효율적인 테스트를 제공합니다.
+ var queryMask = m_BaseColorQuery.GetEntityQueryMask();
+ foreach (var vehicle in vehicles)
+ {
+ // 모든 Prefab 루트에는 모든 Entity 목록인 LinkedEntityGroup이 포함되어 있습니다.
+ ecb.SetComponentForLinkedEntityGroup(vehicle, queryMask, RandomColor());
+ }
state.Enabled = false;
}
}
4. 플레이 모드로 들어가면 이제 탱크의 색상이 무작위로 표시됩니다.
5. 플레이 모드를 종료합니다.
6. "Scripts/Authoring" 폴더에 있는 "CannonBallAuthoring.cs" 파일의 내용을 아래와 같이 수정합니다.
using Unity.Entities;
using Unity.Rendering;
class CannonBallAuthoring : UnityEngine.MonoBehaviour
{
class CannonBallBaker : Baker<CannonBallAuthoring>
{
public override void Bake(CannonBallAuthoring authoring)
{
AddComponent<CannonBall>();
+ AddComponent<URPMaterialPropertyBaseColor>();
}
}
}
struct CannonBall : IComponentData
{
public float3 Speed;
}
7. "Scripts/Aspects" 폴더에 있는 "TurretAspect.cs" 파일의 내용을 아래와 같이 수정합니다.
using Unity.Entities;
using Unity.Mathematics;
using Unity.Rendering;
readonly partial struct TurretAspect : IAspect
{
readonly RefRO<Turret> m_Turret;
+ readonly RefRO<URPMaterialPropertyBaseColor> m_BaseColor;
public Entity CannonBallSpawn => m_Turret.ValueRO.CannonBallSpawn;
public Entity CannonBallPrefab => m_Turret.ValueRO.CannonBallPrefab;
+ public float4 Color => m_BaseColor.ValueRO.Value;
}
8. "Scripts/Systems" 폴더에 있는 "TurretShootingSystem.cs" 파일의 내용을 아래와 같이 수정합니다.
[BurstCompile]
partial struct TurretShoot : IJobEntity
{
[ReadOnly] public ComponentLookup<LocalToWorldTransform> LocalToWorldTransformFromEntity;
public EntityCommandBuffer ECB;
void Execute(in TurretAspect turret)
{
var instance = ECB.Instantiate(turret.CannonBallPrefab);
var spawnLocalToWorld = LocalToWorldTransformFromEntity[turret.CannonBallSpawn];
var cannonBallTransform = UniformScaleTransform.FromPosition(spawnLocalToWorld.Value.Position);
cannonBallTransform.Scale = LocalToWorldTransformFromEntity[turret.CannonBallPrefab].Value.Scale;
ECB.SetComponent(instance, new LocalToWorldTransform
{
Value = cannonBallTransform
});
ECB.SetComponent(instance, new CannonBall
{
Speed = spawnLocalToWorld.Value.Forward() * 20.0f
});
+ // 아래 코드는 포탑에서 대포알로 색상을 전파합니다.
+ ECB.SetComponent(instance, new URPMaterialPropertyBaseColor { Value = turret.Color });
}
}
9. 플레이 모드로 들어가 포탄이 생성된 탱크와 동일한 색상을 갖게 되었는지 확인합니다.
10. 재생 모드를 종료합니다.
'Unity Entities Tutorial' 카테고리의 다른 글
Unity Entities 1.0.0 Tutorial - Step 9. Camera follow (0) | 2023.01.29 |
---|---|
Unity Entities 1.0.0 Tutorial - Step 8. Safe zone (0) | 2023.01.29 |
Unity Entities 1.0.0 Tutorial - Step 6. Spawning many tanks (0) | 2023.01.29 |
Unity Entities 1.0.0 Tutorial - Step 5. Cannon ball movement (0) | 2023.01.29 |
Unity Entities 1.0.0 Tutorial - Step 4. Cannon Balls (1) | 2023.01.28 |