Quick Reference
이름 기반 Unity API를 반복 호출할 때는 ID를 한 번 계산해 사용합니다. Animator.StringToHash는 Animator parameter 이름용이고, Shader.PropertyToID는 Material·MaterialPropertyBlock property 이름용입니다. 둘은 이름을 검증하거나 외부 데이터에 저장하는 ID가 아닙니다.
| 대상 | ID 생성 | 사용하는 API | 범위 |
|---|---|---|---|
Animator parameter "Speed" | Animator.StringToHash | SetFloat, SetBool, SetTrigger | Controller의 이름·타입과 일치해야 함 |
Shader property "_BaseColor" | Shader.PropertyToID | Material.SetColor, MaterialPropertyBlock.SetColor | 해당 shader에 그 property가 있어야 함 |
| 저장·네트워크 값 | 문자열/자체 enum·schema | 직접 검증 후 해석 | PropertyToID 숫자를 저장·전송하지 않음 |
private static readonly int SpeedId = Animator.StringToHash("Speed");
private static readonly int BaseColorId = Shader.PropertyToID("_BaseColor");Shader.PropertyToID 결과는 한 실행 안에서는 같은 property name에 대해 유지되지만, 게임을 다시 실행하거나 다른 machine에서는 같은 숫자라고 보장되지 않습니다. 디스크·네트워크·save data에는 property name이나 별도 versioned data를 사용합니다.
Animator parameter ID
Animator ID는 문자열 hash 비용을 반복 호출 경로에서 줄이고, 이름을 한 class에 모으는 데 도움이 됩니다. 그러나 hash ID가 parameter 존재·타입을 compile time에 검증하지는 않습니다. Controller에서 Speed를 MoveSpeed로 바꾸거나 Float를 Bool로 바꾸면 C# 상수도 함께 고쳐야 합니다.
private static readonly int SpeedId = Animator.StringToHash("Speed");
private static readonly int AttackId = Animator.StringToHash("Attack");
[SerializeField] private Animator animator;
private void Update()
{
animator.SetFloat(SpeedId, movementMagnitude);
if (attackPressed)
{
animator.SetTrigger(AttackId);
}
}SetFloat처럼 값이 매 frame 바뀌는 호출에는 ID cache가 자연스럽습니다. 초기화에서 한 번만 부르는 property라면 문자열 overload를 써도 의도가 더 읽기 쉬울 수 있습니다. 실제 병목은 Profiler로 확인하며, ID cache가 parameter 설계의 모호함까지 해결해 준다고 보지 않습니다.
Shader property ID와 Material 소유권
Shader property ID는 property name을 integer로 바꾸는 것뿐입니다. 다른 Renderer마다 한 property 값만 다르게 주려면 shared material asset을 바꾸는 대신 MaterialPropertyBlock을 우선 검토합니다. renderer.material은 shared material과 다른 instance material을 만들 수 있어, 많은 Renderer에서 호출하면 메모리·batching 결과가 달라질 수 있습니다.
private static readonly int BaseColorId = Shader.PropertyToID("_BaseColor");
[SerializeField] private Renderer targetRenderer;
private readonly MaterialPropertyBlock propertyBlock = new();
public void SetTint(Color color)
{
targetRenderer.GetPropertyBlock(propertyBlock);
propertyBlock.SetColor(BaseColorId, color);
targetRenderer.SetPropertyBlock(propertyBlock);
}MaterialPropertyBlock은 Renderer별 override를 전달하는 컨테이너입니다. 이 방식이 항상 batching에 유리하다고 단정하지 말고, 사용하는 render pipeline과 material instance 정책을 기준으로 Frame Debugger·Profiler에서 확인합니다. _BaseColor도 URP Lit의 property 예시일 뿐 모든 shader에 존재하지는 않습니다.
자주 틀리는 부분
| 증상 | 원인 | 수정 |
|---|---|---|
| ID가 있는데 Animator가 반응하지 않음 | Controller에 같은 이름·타입 parameter가 없음 | Controller Parameters와 hash 원문을 같이 확인 |
| property ID를 save에 넣었더니 다음 실행에서 못 읽음 | PropertyToID 정수의 실행 간 안정성을 가정 | 저장·network에는 문자열 또는 자체 schema 사용 |
| 한 Renderer 색을 바꿨더니 모든 캐릭터가 변함 | shared material asset을 수정 | per-renderer override에는 MaterialPropertyBlock 검토 |
renderer.material 호출 뒤 material 수가 늘어남 | instance material 생성 경로를 인지하지 못함 | shared/material/property block 중 소유 정책을 명시 |
| ID cache를 했는데 느림 | 병목이 문자열 hash가 아닌 rendering·animation 계산 | 측정 후 실제 hot path를 최적화 |
참고 링크
3 sources