UDN
Search public documentation:

PhysicalMaterialSystemKR
English Translation
日本語訳
中国翻译

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

피지컬 머티리얼 시스템

문서 요약: 피지컬 머티리얼 시스템에 대한 자세한 내용 및 (임팩트 효과, 발자국 소리 등의) 머티리얼 기반 효과를 내는 법에 대한 예제 서론입니다.

문서 변경: 서론 작성.

개요

이 페이지는 다음의 네 부분으로 나뉘어 있습니다:

-피지컬 머티리얼 시스템 개요
-피지컬 머티리얼의 계층구조를 만드는 자세한 방법
-머티리얼 기반 효과에 그 계층구조를 사용하는 방법
-머티리얼 기반 발자국 소리를 내는 예제 코드

피지컬 머티리얼 시스템 개요

UE3에서는 피지컬 머티리얼을 머티리얼이나 머티리얼 인스턴스 불변에다가 부착할 수 있습니다. 머티리얼에 부가 속성을 갖게 하는 것과는 달리, 부착을 통해서는 다수의 머티리얼에 피지컬 머티리얼 시스템을 재사용할 수 있습니다.

간단한 예제는 다음과 같습니다:

게임의 자갈길에 적용한 gravelRoad 머티리얼이 있습니다. 그 gravelRoad 머티리얼에는 gravel 이라는 피지컬 머티리얼이 있습니다.

그 gravel 피지컬 머티리얼에다 발자국 소리를 내는 PawnType 에 따라 다양한 발자국 소리를 재생하도록 설정해 뒀습니다.

PawnTypeOne 이 걸을 때, 사운드큐 A에서 소리를 재생합니다.

PawnTypeTwo 가 걸을 때, 사운드큐 B에서 소리를 재생합니다.

**이제 하나의 머티리얼에다 피지컬 머티리얼을 동시에 둘 적용할 수 있게 되었습니다. 충돌이 발생하면 선 검사 코드가 적중한 트라이앵글을 찾아내고, 적중 위치의 텍스처 UV를 구한 다음 마스크 텍스처와 대조해서 적중 픽셀이 검정인지 하양인지를 결정합니다. 적절한 피지컬 머티리얼이 반환되게 되는 겁니다.

프로그래머용 세부사항

세부사항:

PhysicalMaterial.uc 참고

특히:

var(PhysicalProperties) export editinline PhysicalMaterialPropertyBase PhysicalMaterialProperty;

PhysicalMaterialPropertyBase.uc에 읽어 두면 좋은 주석이 달려 있습니다!

상황에 따른 발자국 소리를 내고, 다른 깔끔한 피지컬 머티리얼 기반 효과를 내기 위한 얼개(framework)를 만들려면 클래스를 만들어야 합니다:

class MyGamePhysicalMaterialProperty extends PhysicalMaterialPropertyBase
collapsecategories
editinlinenew
hidecategories(Object);


var(FootSteps) editinline MyGamePhysicalMaterialFootSteps MyGamePhysicalMaterialFootSteps;

그리고 MyGamePhysicalMaterialFootSteps 클래스에:

var() SoundCue ProtagonistFootSteps;

var() SoundCue NPCTypeOneFootSteps;

var() SoundCue NPCTypeTwoFootSteps;
등이 생깁니다.

이제 폰이 (AnimNotify_Footstep 또는 기타 메쏘드를 통해) 걸을 때 eventPlayFoorStepSound 를 호출할 수 있으며, 바로 이벤트가 올바른 폰에 전송됩니다. 이제 폰이 종류와 피지컬 머티리얼에 따라 어떤 소리를 재생할 지 결정할 수 있는 겁니다!

예로 NPC 오우거가 자갈길을 따라 걷고 있습니다. 걸을 때마다 eventPlayFootStepSound 가 호출되고선 추적(trace)을 합니다. 피지컬 머티리얼을 찾아내고, 폰 종류에 따라 사운드큐를 구한 다음 재생하는 겁니다.

주: 현재 피지컬 머티리얼을 구하려면 추적 작업을 해야 합니다. C++ 영역에서 바로 추적하는 것이 훨씬 효율적일테고, 대부분의 라이선시가 게임에서 원할 기능이 이런 것이기에 아마도 곧 eventPlayFootStepSound 가 피지컬 머티리얼을 전달할 수 있도록 업데이트될 겁니다. 상황에 따른 발자국 소리는 멋지거든요!

분명 위에서처럼 피지컬 머티리얼 시스템과 속성 얼개를 통해, (임팩트 소리라든가 적중 효과, 데칼, 발자국 소리 등) 정말 죽이는 상황에 따른 기능성을 뭐든지 쉽게 만들어 낼 수 있습니다.

피지컬 머티리얼의 계층구조

프로그래밍 직원이 위와 같은 게임 클래스를 만들어 내면, 콘텐츠 팀이 피지컬 머티리얼의 계층구조 만들기를 시작하면서 게임 디자인상 필요한 효과를 채워넣을 수 있습니다.

콘텐츠 제작자용 세부사항

피지컬 머티리얼에는 var(Parent)PhysicalMaterial Parent 가 있습니다. 이를 통해 피지컬 머티리얼의 계층구조를 만들 수 있으며, 거기서 (우리 예제의 경우) 발자국 소리의 계층구조도 만들 수 있는 겁니다.

즉 이런 식으로 가능한 거죠:

기본값
^
|
흙
^
|
진흙

이제 콘텐츠 팀이 게임 월드에 둔 피지컬 머티리얼에 대해 제대로 구체적인 작업이 가능합니다. 진흙 밟는 소리를 내고 싶으면 그럴 수 있는거죠. 진흙 밟는 소리가 없으면 계층구조를 뒤져 찾아보던가, 없으면 기본값으로 지정된 발자국 소리를 쓰던가 하면 됩니다.

계층구조 사용하기

이제 코드 지원도 있고 파라미터화된 피지컬 머티리얼 계층구조도 생겼으니 피지컬 머티리얼을 머티리얼에 할당할 수 있습니다! 할당을 마치고 나면 게임에서 소리를 직접 들어볼 수 있을 겁니다.

콘텐츠 제안

(예제를 이어가기 위해) 발자국 소리를 만들 때, 사운드팀이 사운드 원본과 피치 및 감쇠 부분 다에서 랜덤화된 발소리를 내는 사운드큐를 만들도록 해야 합니다. 그래야 좀 더 그럴듯한 발자국 소리가 나게 됩니다. 부가적으로 피지컬 머티리얼 시스템으로의 올바른 추상화도 가능해지게 됩니다.

예제 코드

/**
*  발자국 소리를 재생하라는 C++ 영역에서의 이벤트
**/
event PlayFootStepSound(int FootDown)
{
   local vector PawnLoc;
   local float CurrHeight;

   local Actor TraceActor;

   local vector out_HitLocation;
   local vector out_HitNormal;
   local vector TraceDest;
   local vector TraceStart;
   local vector TraceExtent;
   local TraceHitInfo HitInfo;

   // 자자 여기서 바닥까지 추적을 해줘야 겠습니다! (kk here we need to do a tracez0r down down into the ground baby!)
   // 주: 이건 결국 C++ 영역으로 넘어갈 겁니다.
   PawnLoc = self.Location;
   CurrHeight = self.GetCollisionHeight();

   TraceStart = PawnLoc;
   TraceDest = PawnLoc - ( Vect(0, 0, 1 ) * CurrHeight ) - Vect(0, 0, 15 );

   // 추적해 내려가서 뭘 밟고 서 있는지 봅니다.
   TraceActor = Trace( out_HitLocation, out_HitNormal, TraceDest, TraceStart, false, TraceExtent, HitInfo, true );

   //DrawPersistentDebugLine( TraceStart, TraceDest, 255, 0, 0 );

   if( TraceActor != none )
   {
      // 이제 실제 소리를 재생합니다.
      ActuallyPlayFootStepSound( FootDown, HitInfo );
      MakeNoise( 0.1f, 'NOISETYPE_FootStep' );
   }
   // 아니면 아무것도 맞지 않은 공중에 있는 겁니다.
   else
   {
   //   Log( " 공중에 있다구!" );
   }

}

/**
* 이를 통해 밟고 서 있는 머티리얼이 뭔지 알아내고
* 올바른 발자국 소리를 재생합니다.
* 스폰하기에 적절한 효과를 찾을 때까지 피지컬 머티리얼 트리를 찾아봅니다.
* 찾지 못하면 해당 무기에 대해 .uc 파일에 코딩된 효과를
* 기본으로 삼습니다.
**/
function ActuallyPlayFootStepSound( int FootDown, TraceHitInfo HitInfo )
{
   local PhysicalMaterial ParentPhysMaterial;
   local SoundCue SC;
   local SoundCue FootStepSound;

   // XO5 HAX0R
   // 비속에 있으면 물발자국 소리를 냅니다.
   // 주: 현재 터레인은 추적용 머티리얼을 반환하지 않으니 직접 해 주는 수밖에요.
   //if( IsTimerActive( 'DropRainDropsOnToPawn' ) == TRUE )
   if( bShouldPlayWetFootSteps == TRUE )
   {
      Self.PlaySound( SoundCue'FootSteps.SoundCues.Footsteps_Marcus_Water', FALSE, TRUE );
      return;
   }


   // 피지컬 머티리얼이 없으면
   if( HitInfo.PhysMaterial != none )
   {
      FootStepSound = GetFootStepSound( HitInfo.PhysMaterial, FootDown );
   }
   else
   {
      // 머티리얼이 있는지 검사해 봅니다.
      // 머티리얼이 없으면 기본 PS_DefaultImpactEffect 를 사용해야 겠습니다.
      if( HitInfo.Material != none )
      {
         FootStepSound = GetFootStepSound( HitInfo.Material.PhysMaterial, FootDown );
      }
      else
      {
         // 항상 흙 발자국 소리인 "기본 발자국 소리"를 재생합니다.
         Self.PlaySound( SoundCue'FootSteps.SoundCues.Footsteps_Marcus_Dirt', FALSE, TRUE );
         return;
      }
   }


   // 이제 여기서, 원하는 특성에 없는 경우 "계층구조"를 찾아봐야 겠습니다.
   // 콘텐츠님께서 우리의 주린 배를 데이터로 채워주지 못하시는 경우,
   // 기본값을 재생시키는 예비 코드를 둬야 겠습니다.

   // 핒 머티리얼에 없는 경우,
   if( HitInfo.PhysMaterial != none )
   {
      ParentPhysMaterial = HitInfo.PhysMaterial.Parent;
   }
   // 부모 핒 머티리얼을 여기다 설정.
   else
   {
      // 머티리얼에 핒 머티리얼이 있는지 검사.
      if( HitInfo.Material.PhysMaterial != none )
      {
         ParentPhysMaterial = HitInfo.Material.PhysMaterial.Parent;
      }
      else
      {
         ParentPhysMaterial = none;
      }
   }


   // 부모가 null이거나 발자국 소리를 찾아서 (기본적으로 exception 케이스인)
   // break out(빠져나오기) 전까지는 트리를 순회하게 됩니다.
   // 근데 .uc 영역에는 exception이 없습니다.
   while( ( FootStepSound != none )
      && ( ParentPhysMaterial != none )
      )
   {
      // 부모의 데이터를 살펴봅니다.
      FootStepSound = GetFootStepSound( ParentPhysMaterial, FootDown );
      ParentPhysMaterial = ParentPhysMaterial.Parent;
   }


   // 머티리얼 기반 효과를 사용합니다.
   if( FootStepSound != none )
   {
      //Log( " 사운드 재생중: " $ FootStepSound );
      SC = FootStepSound;
   }
   // 기본 동작 수행
   else
   {
      //Log( " 기본 사운드 재생중" );
      SC = SoundCue'FootSteps.SoundCues.Footsteps_Marcus_Dirt';
   }

   Self.PlaySound( SC, FALSE, TRUE );
}


/**
* 현재 피지컬 머티리얼의 사운드가 사용가능한지 살펴봅니다.
**/
function SoundCue GetFootStepSound( PhysicalMaterial PMaterial, int FootDown )
{
   local SoundCue Retval;

   Retval = none;

   // 이제 Specific 속성이 존재하니
   // specificProperty 를 끄집어 내기 위한 함수를 호출해야 합니다.
   if( ( none != PMaterial )
      && ( none != PMaterial.PhysicalMaterialProperty )
      && ( none != WarPhysicalMaterialProperty(PMaterial.PhysicalMaterialProperty) )
      && ( none != WarPhysicalMaterialProperty(PMaterial.PhysicalMaterialProperty).WarPhysicalMaterialFootSteps )
      )
   {
      Retval = GetSpecificFootStepSound( WarPhysicalMaterialProperty(PMaterial.PhysicalMaterialProperty).WarPhysicalMaterialFootSteps, FootDown );
   }
   else
   {
      Retval = none;
   }

   return Retval;
}


/**
* 각 오브젝트가 이를 덮어쓰게 되며 전달된 오브젝트를 기반으로 한 데이터를
* 반환합니다. (예로 마커스에서 호출된 GetSpecificFootStepSound 는 마커스
* 발자국 소리를 찾아보며, 로커스트에서 호출되면 로커스트 소리를 찾아봅니다.)
**/
function SoundCue GetSpecificFootStepSound( WarPhysicalMaterialFootSteps FootStepSounds, int FootDown )
{
   local SoundCue Retval;

   // 가능한 연산 등을 수행합니다.
   Retval = None;

   return Retval;
}


예를 들어 BigOgre 클래스에서


function SoundCue GetSpecificFootStepSound( MyGamePhysicalMaterialFootSteps FootStepSounds, int FootDown )
{
   local SoundCue Retval;

   // 가능한 연산 등을 수행합니다.
   Retval = SoundCue'FootSteps.SoundCues.Footsteps_Player_Dirt';  // or make this a config and store the value in an .ini for editing by non programmers

   return Retval;
}