Post List

2017/11/29

Unreal4__7_2_몬스터상태에 따른 효과적용하기(Fresnel)

이번에는 프레넬이라는 라이팅 기법을 적용해 보았습니다. 이 라이팅 기법은 실루엣을 더욱 강조시키는 방법으로 림/에지 라이팅이라고도 합니다. 

게임에서 종종 오브젝트를 강조할때 보여지는 효과이기도 하며, 저는 몬스터가 데미지를 입었을 때 순간적으로 몬스터를 강조해주기 위해 위 사진과 같이 적용을 해보았습니다.

에디터에서 해당 몬스터의 머티리얼을 찾아 열어줍니다!

머티리얼을 열면 베이스컬러/노말/스페큘러 등 각 텍스쳐에 대한 처리 노드들이 연결되어 있습니다. 새로 만들게 될 경우에는 아무것도 없는 빈 창이겠지요!

저는 기존에 있던 머티리얼에 프레넬 효과를 추가하는 상황이기 때문에 빈 공간에 프레넬 효과를 적용해보겠습니다.

프레넬 효과를 적용하기 위해 Fresnel 이라는 노드를 사용하게 되는데 먼저 이 노드에서 사용되는 프로퍼티에 대해 알아보겠습니다.
ExponentIn :  프레넬 이펙트 감쇠를 제어합니다. 값이 커질수록 프레넬 이펙트가 가장가리에 가까워 집니다.
BaseReflectFractionIn :  표면을 봤을 때의 스펙큘러 리플렉션의 굴절율. 이 값을 1로 설정하면 사실상 프레넬이 꺼집니다.
Normal :  

Exp값을 1로 지정하고, Base값을 0으로 설정해주었습니다. 그리고 노출할 컬러와 Multiply 노드로 곱해주고, Scalar 노드를 하나 추가해 C++에서 프레넬의 노출 강도를 컨트롤할 수 있도록 곱해줍니다.

그리고 나온 최종값을 M_Char_Robo노드의 이미시브 컬러에 적용시켜줍니다. 


여기서 이미시브컬러 다른 표면을 실제로 밝혀 주진 않더라도, 머티리얼이 마치 라이트라도 되듯이 얼마만큼의 빛을 내뿜는지를 나타내줍니다.
이미시브는 라이트처럼 작용하기에 다른 라이트나 그림자에는 영향을 받지 않습니다. 

각 컬러에 대한 설명은 아래 링크를 참고하시면 되겠습니다.


이제 에디터상에서의 작업은 끝났습니다. 몬스터가 데미지를 입었을 때 C++ 코드로 프레넬효과를 적용시켜 보겠습니다.
JMonster.h를 열어 에티터에서 작업한 머티리얼에 접근할 수 있도록 변수를 추가해줍니다.

1
2
3
4
// JMonster.h
private:
 class UMaterialInstanceDynamic*    pMatInst;
 class UMaterial*   
cs

해당 값 수정을 위해 머리티얼 인스턴스 다이나믹 클래스가 필요합니다.
처음에 JMonster의 생성자에서 머티리얼과 머티리얼 인스턴스를 생성하다보니 에디터가 종료되는 현상이 발생했습니다.

1
2
3
4
5
6
7
8
// JMonster.cpp
AJMonster::AJMonster()
{
    ConstructorHelpers::FObjectFinder<UMaterial> mat(TEXT("Material'Game/Model/Monster/CharM_Robo/Materials/M_Char_Robo.M_Char_Robo'"));
    if(mat.Object != nullptr)
    {
        pMat = Cast<UMaterial*>(mat.Object);
    }
cs
여기서 처음 AJMonster() 생성자 안에서 Umaterial 객체와 UMaterialInstanceDynamin 객체를 생성하려다 보니
에러가 발생하였습니다..  정확한 이유는 아직 알지 못하지만

1
2
3
4
5
void AJMonster::BeginPlay()
{
    pMatInst = UMaterialInstanceDynamic::Create(pMat, this);
cs
생성자가 호출된 상태에서 UMaterialInstanceDynamic에 인자로 넘겨받는 this에 문제가 아닐까 하는 나의 생각.. 아무튼 메터리얼 인스턴스 다이나믹은 BeginPlay()함수에서 생성하도록 수정을 하였습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void AJMonster::Tick(float DeltaTime)
{
    if(bDamageEffect)
    {
        fCurrentDamage += DeltaTime + fSpeed;
        if(fCurrentDamage > fMaxDamage)
        {
            fCurrentDamage = fMaxDamage;
            bDamageEffect = false;
        }
        
    }
    else
    {
        fCurrentDamage -= (DeltaTime * fSpeed);
        if(fCurrentDamage < 0.0f)
            fCurrentDamage = 0.0f;
    }
    
    pMatInst->SetScalarParameterValue("Emissive_strength", fCurrentDamage);
  
cs
 매 프레임마다 호출되는 Tick 함수에서 에디터에서 보았던 Emissive_stength 노드의 값을 코드에서 수정을 해주는 코드입니다.
시간에 따라 효과가 나타났다 다시 사라지는 코드입니다.
여기서 핵심은 pMatInst->SetScalarParameterValue('NodeName', 'Value') 이지요. 머티리얼에 추가한 scalar 노드에 값을 증감소시켜 순간적으로 발광되었다 사라지게 됩니다. 

첫번째 인자는 노드의 이름이고, 두번째 인자는 수치입니다. 수치값이 증가될수록 프레넬 효과는 더욱 강하게 나타나게됩니다.