반응형
UFUNCTION()

이전 UPROPERTY()는 C++의 변수를 블루프린트와 연동하는 내용이였으면 이번엔 함수에 대해 포스팅을 합니다.

Category나 Meta키워드는 UPROPERTY와 중복되는 내용이니 이전 포스팅을 참고해 주시길 바랍니다.

 

 


BlueprintCallable

가장 기본적으로 C++에서 작성한 함수를 블루프린트에서 사용할 수 있게 하는 BlueprintCallable키워드 입니다,

간단한 기능이라서 블루프린트 내에서 따로 재정의 할 수 없습니다.

 

 


BlueprintPure

매우 간단하게 값 하나 반환하는 형태에 사용하는 BlueprintPure키워드입니다.

 

인자값을 추가로 넣는 것도 가능합니다.

 

 

UPARAM 메크로 - 레퍼런스를 인자로 받고 싶을때

인자값으로 레퍼런스 주소를 입력하고 싶어서 위 처럼 코드를 작성했으나 우측 처럼 레퍼런스 변수가 반환값으로 설정 되어 있습니다.

정확한 원인은 모르겠으나 UPARAM메크로를 사용해야 해결이 가능합니다.

 

레퍼런스 인자값 앞에 UPARAM(ref) 메크로를 붙임으로서 의도한대로 블루프린트에서 인자값을 받을 수 있게 되었습니다.

UPARAM의 정확한 기능은 모르겠지만 또 다른 사용 용도가 있습니다.

 

인자값에 DisplayName기능을 사용 할 수 있습니다.

 

 

 


BlueprintImplementableEvent

이전에 BlueprintCallable은 블루프린트가 C++ 함수를 호출하는 형태면 BlueprintImplementableEvent 는 C++이 블루프린트 함수를 호출하는 형태 입니다, 다만 C++에서 블루프린트에서 사용할 함수 원형을 작성해야 합니다.

위 처럼 코드를 작성하면 블루프린트에서 해당 함수를 사용 할 수 있으며

 

 

블루프린트에서 위 처럼 함수의 기능을 작성하고 

 

C++코드에서 해당 함수를 호출하면 위 처럼 동작을 하게 됩니다.

 

 

블루프린트 Custom 함수 호출하기

BlueprintImplementableEvent 는 C++에서 함수 원형을 만들어서 호출하는 방식이 였고 이번엔 블루프린트에서 자체적으로 만든 Custom Event 함수를 C++에서 호출해 보겠습니다.

 

 

결과가 잘 나옵니다.

 

인자값을 넣고 싶으면 위와 같이 FString::Printf함수를 이용해 "함수 이름 %d" 형식으로 구현할 수 있습니다.

 

 

 


BlueprintNativeEvent

BlueprintImplementableEvent 와 비슷하게 C++에서 함수 원형을 만드는 것은 동일하지만 BlueprintNativeEvent는 C++에서 가상함수를 만드는 개념입니다.

 

그래서 "void CallNativeFuction"이라는 함수를 만들고 C++에서 가상함수로 "void CallNativeFuction_Implementation()"함수를 추가로 만들었습니다.

 

부모 함수 호출하는 방법은 이벤트 노드에 우측마우스 클릭해서 위 메뉴로 생성할 수 있습니다.

 

 

 

ref : https://darkcatgame.tistory.com/64

반응형
반응형

언리얼 엔진 4 는 다수의 멀티플레이어 함수성이 내장되어 있어, 네트워크를 통해 플레이 가능한 기본적인 블루프린트 게임을 쉽게 구성할 수 있습니다. 간단히 뛰어들어 멀티플레이어 게임 플레이를 시작해 볼 수 있습니다. 기본적인 멀티플레이어 기능이 지원되는 로직 대부분은 Character 클래스 및 삼인칭 템플릿에서 사용하는 CharacterMovementComponent 에 내장된 네트워킹 기능 지원 덕입니다.

게임플레이 프레임워크 검토

게임에 멀티플레이어 함수성을 추가하려면, 엔진에 제공되는 주요 게임플레이 클래스의 역할과 서로, 특히나 멀티플레이어 컨텍스트에서 어떻게 작동하는지를 이해하는 것이 중요합니다:

  • GameInstance 게임 인스턴스
  • GameMode 게임 모드
  • GameState 게임 스테이트
  • Pawn (및 거기서 상속되는 Character), 폰과 캐릭터
  • PlayerController 플레이어 컨트롤러
  • PlayerState 플레이어 스테이트

자세한 정보는 게임플레이 프레임워크 문서를 참고하시고, 멀티플레이어 게임을 디자인할 때는 최소한 다음의 팁 정도는 유념해 주시기 바랍니다:

  • GameInstance 는 엔진 세션 도중에만 존재합니다. 즉 엔진 시작 시 생성되며, 종료될 때까지 소멸 또는 대체되지 않습니다. 서버와 각 클라이언트마다 별도의 GameInstance 가 존재하며, 이 인스턴스는 서로 통신하지 않습니다. GameInstance 는 게임 세션 외부에 존재하므로, 특정 유형의 지속성 데이터를 저장하기에 좋은 곳입니다. 이를테면 플레이어 전반적인 통계 (지금까지 이긴 게임 횟수), 계정 정보 (특수 아이템 잠김/해제 상태), 언리얼 토너먼트같은 경쟁형 게임에서 돌아가며 플레이할 맵 목록 등을 말합니다.
  • GameMode 오브젝트는 서버에서만 존재합니다. 일반적으로 클라이언트가 명시적으로 알 필요가 없는 게임 관련 정보를 저장합니다. 예를 들어 "로켓 런처만" 나오는 특수 규칙 게임에서, 클라이언트는 이 정보를 알 필요가 없지만, 맵에 무기를 무작위로 스폰할 때 서버는 "로켓 런처" 카테고리에서만 선택해야한다 알아야 할 것입니다.
  • GameState 는 서버와 클라이언트에 존재하며, 서버는 GameState 상의 리플리케이티드 변수를 사용하여 모든 클라이언트에서 게임에 대한 데이터를 최신 상태로 유지할 수 있습니다. 예로, 야구 게임에서 GameState 를 통해 각 팀의 점수와 현재 이닝을 리플리케이트할 수 있습니다.
  • 각 클라이언트에는 그 머신의 플레이어마다 하나의 PlayerController 가 존재합니다. 이는 서버와 연결된 클라이언트 사이에 리플리케이트되지만, 다른 클라이언트에는 리플리케이트되지 않으므로, 서버는 모든 플레이어에 대한 PlayerController 를 갖고 있고, 로컬 클라이언트는 로컬 플레이어에 대한 PlayerController 만 갖습니다. 클라이언트가 접속되어 있는 도중에는 PlayerController 가 존재하여 Pawn 에 할당되지만, Pawn 과는 달리 소멸되거나 리스폰되지는 않습니다. 특정 플레이어에게만 감지된 게임 이벤트에 반응하여 미니맵에 핑을 찍도록 서버가 클라이언트에게 알리는 등의 작업처럼, 다른 클라이언트에 리플리케이트할 필요 없는 클라이언트와 서버 사이 통신에 적합합니다.
  • PlayerState 는 게임에 접속된 모든 플레이어에 대해 서버와 클라이언트 양쪽에 존재합니다. 이 클래스는 소유중인 클라이언트만이 아닌 모든 클라이언트가 알아야 하는, 이를테면 프리-포-올 게임에서 각 플레이어의 현재 점수와 같은 리플리케이티드 프로퍼티에 사용할 수 있습니다. PlayerController 처럼 개별 Pawn 에 할당되지만, Pawn 과는 달리 소멸 및 리스폰되지 않습니다.
  • Pawn (및 Character 포함) 역시 서버와 모든 클라이언트에 존재하며, 리플리케이티드 변수 및 이벤트를 갖고 있습니다. 특정 변수나 이벤트에 대해 PlayeyController 를 쓸 것이냐, PlayerState 를 쓸 것이냐, Pawn 을 쓸 것이냐 하는 것은 상황에 따라 다르지만, 주로 고려할 것은 PlayerController 와 PlayerState 는 플레이어가 접속된 시간동안 그리고 게임이 새 레벨을 로드하지 않는 한 내도록 유지되는 반면, Pawn 은 그렇지 않을 수 있습니다. 예를 들어 Pawn 이 게임플레이 도중 죽는 경우, 보통 소멸되고 새로운 Pawn 으로 대체되는 반면, PlayerController 와 PlayerState 는 계속해서 존재하며 새로운 Pawn 의 스폰이 끝나면 거기에 할당됩니다. Pawn 의 생명력은 그래서 Pawn 자체에 저장되는데, 실제 그 Pawn 인스턴스에만 해당되며, 새로운 Pawn 으로 대체되면 리셋시켜야 하기 때문됩니다.

액터 리플리케이션

UE4 의 네트워킹 기술의 핵심은 액터 리플리케이션입니다. "Replicates" (리플리케이트) 옵션이 True 로 설정된 액터는 서버에서 그 서버에 연결된 클라이언트로 자동 동기화됩니다. 꼭 이해해야 할 점은, 액터는 서버에서 클라이언트로만 리플리케이트되지, 클라이언트에서 서버로 액터를 리플리케이트시키는 것은 불가능하다는 점입니다. 물론, 클라이언트에서 서버로 데이터를 전송하는 것이 가능은 하며, 리플리케이트되는 "Run on server" 이벤트를 통해 이루어집니다.

블루프린트에서 액터 리플리케이트 에서 구체적인 예제를 확인해 보시고, 액터 리플리케이션 도 참고해 보시기 바랍니다.

오소리티

월드의 모든 액터에 대해서, 접속된 플레이어 중 하나는 해당 액터에 대해 오소리티가 있는 것으로 간주됩니다. 서버에 존재하는 모든 액터에 대해서, 서버는 모든 리플리케이티드 액터를 포함해서 해당 액터에 대해 오소리티를 갖습니다. 결과적으로 클라이언트에서 Has Authority 함수가 실행되고, 타깃이 그에게 리플리케이트된 액터인 경우, False 를 반환하게 됩니다. 또한 Switch Has Authority 편의 매크로를 사용하여 리플리케이트되는 액터에서 서버와 클라이언트에 따라 다른 동작을 하도록 하는 분기를 빠르게 만들 수도 있습니다.

변수

액터상의 변수에 대한 디테일 패널에 보면 리플리케이션 드롭다운이 있어 변수 리플리케이션 방법을 조정할 수 있습니다.

옵션설명

None 없음 - 새 변수의 기본값으로, 이 값을 네트워크를 통해 클라이언트에 전송하지 않는다는 뜻입니다.
Replicated 리플리케이트됨 - 서버가 이 액터를 리플리케이트하면, 이 변수를 클라이언트에 전송합니다. 받는 클라이언트의 변수 값은 자동으로 업데이트되어, 다음 번 접근할 때 서버상에 있던 값을 반영합니다. 물론 실시간 네트워크를 통해 플레이할 때는, 네트워크 지연시간만큼 업데이트에 걸리는 시간이 지연됩니다. 기억할 것은 리플리케이티드 변수는 한 방향, 즉 서버에서 클라이언트로만 갑니다! 클라이언트에서 서버로 데이터를 전송하는 방법은 "이벤트" 부분을 확인하세요.
RepNotify 리플 알림 - Replicated 옵션처럼 변수 리플리케이션은 하지만, 추가로 블루프린트에 OnRep_<변수명> 함수가 생성됩니다. 이 함수는 이 변수의 값이 변할 때마다 서버와 클라이언트에서 엔진에 의해 자동 호출됩니다. 이 함수는 게임의 필요에 따라 원하는 대로 자유롭게 구현해도 됩니다. 

엔진의 내장 클래스 내 변수 다수에는 이미 리플리케이션이 켜져 있어서, 여러가지 기능이 멀티플레이어 상황에서도 자동으로 작동합니다.

블루프린트에서 변수 리플리케이트 에서 변수 리플리케이션 관련 구체적인 예제 안내 및 프로퍼티 리플리케이션 문서도 참고해 보시기 바랍니다.

스폰 및 소멸

리플리케이트되는 액터가 서버에 스폰되면, 클라이언트에 통신하여 거기서도 자동으로 그 액터 사본을 스폰합니다. 하지만 일반적으로 리플리케이션은 클라이언트에서 서버로 이루어지지 않기에, 리플리케이트되는 액터가 클라이언트에 스폰되는 경우 그 액터는 해당 클라이언트에만 존재하게 됩니다. 서버도 다른 클라이언트도 그 액터 사본을 받지 않습니다. 하지만 스폰하는 클라이언트는 그 액터에 대한 오소리티를 갖게 됩니다. 게임플레이에 영향을 끼치지 않는 장식성 액터같은 것에는 유용할 수 있지만, 게임플레이에 영향을 끼치고 리플리케이트시켜야 하는 액터의 경우 서버에서 스폰되도록 하는 것이 가장 좋습니다.

리플리케이트되는 액터를 소멸(destroy)시키는 상황도 비슷합니다: 서버가 하나를 소멸시키면, 모든 클라이언트에서도 각자의 사본을 소멸시킵니다. 클라이언트는 오소리티를 가진, 즉 직접 스폰시킨 액터를 자유롭게 소멸시킬 수 있는데, 다른 플레이어에 리플리케이트되지도 않았고 영향을 끼치지도 않을 것이기 때문입니다. 클라이언트가 오소리티를 갖지 않은 액터를 소멸 시도하는 경우, 그 소멸 요청은 무시됩니다. 여기서의 핵심 요점은 액터 스폰에도 마찬가지입니다: 리플리케이트되는 액터를 소멸시켜야 하는 경우, 서버에서 소멸시켜 주세요.

이벤트 리플리케이션

블루프린트에서 액터와 그 변수 리플리케이트에 추가로, 클라이언트와 서버 너머로 이벤트를 실행시킬 수도 있습니다.

블루프린트에서 함수 리플리케이트 에서 구체적인 예제에 대한 안내 및 RPC 문서도 참고해 보시기 바랍니다.

RPC (Remote Procedure Call) 이라는 용어가 보이는데, 블루프린트에서 리플리케이트되는 이벤트는 본질적으로 엔진 내에서 RPC 로 (보통 C++ 에서는 그렇게 불립니다) 컴파일된다는 점만 알아두시면 됩니다.

오너십

멀티플레이어 작업시 이해해야 할 중요한 개념, 특히나 리플리케이트되는 이벤트 관련해서는, 어떤 접속을 특정 액터 또는 컴포넌트의 오너로 간주할 것인지 입니다. 우리 용도상 "Run on server" 이벤트는 클라이언트가 소유하는 액터 (또는 그 컴포넌트)에서만 호출 가능하다는 것을 압니다. 이게 무슨 뜻이냐면, 다음 액터 또는 그 액터 중 하나의 컴포넌트에서 "Run on server" 이벤트를 전송할 수만 있다는 뜻입니다:

  • 클라이언트의 PlayerController 자체,
  • 클라이언트의 PlayerController 가 빙의된 Pawn, 또는
  • 클라이언트의 PlayerState.

마찬가지로 "Run on owning client" 이벤트를 전송하는 서버의 경우, 그 이벤트 역시 이 액터 중 하나에서 호출되어야 합니다. 그렇지 않으면 서버는 이벤트를 전송할 클라이언트를 알지 못하게 되어, 서버에서만 실행될 것입니다!

이벤트

커스텀 이벤트의 디테일 패널에서, 이벤트 리플리케이션 방식을 설정할 수 있습니다.

옵션설명

Not Replicated 리플리케이트 안됨 - 기본값으로, 이 이벤트에 대한 리플리케이션이 없다는 뜻입니다. 클라이언트에서 호출되는 경우 해당 클라이언트에서만 실행되고, 서버에서 호출되는 경우 서버에서만 실행됩니다.
Multicast 멀티캐스트 - 서버에서 멀티캐스트 이벤트가 호출되면, 타깃 오브젝트를 어느 접속에서 소유했는지와 무관하게 접속된 모든 클라이언트에 리플리케이트됩니다. 클라이언트가 멀티캐스트 이벤트를 호출하는 경우, 리플리케이트되지 않은 것으로 간주, 호출한 클라이언트에서만 실행합니다.
Run on Server 서버에서 실행 - 이 이벤트가 서버에서 실행된 경우, 서버에서만 실행됩니다. 클라이언트에서 클라이언트가 소유한 타깃으로 실행된 경우, 서버에 리플리케이트되어 실행됩니다. "Run on Server" 이벤트는 클라이언트가 서버에 데이터를 전송하기 위한 주요 메서드입니다.
Run on Owning Client 소유 클라이언트에서 실행 - 서버에서 호출된 경우, 이 이벤트는 타깃 액터를 소유한 클라이언트에서 실행됩니다. 서버는 액터 자체를 소유할 수 있으므로, "Run on Owning Client" 이벤트는 그 이름과 무관하게 서버에서 실행 가능합니다. 클라이언트에서 호출된 경우, 이벤트는 리플리케이트되지 않은 것으로 간주, 호출한 클라이언트에서만 실행됩니다.

다음 표는 이벤트 호출 방법에 따라 여러가지 리플리케이션 모드가 이벤트 실행 위치에 어떠한 영향을 끼치는지 나타냅니다.

서버에서 이벤트가 호출된 경우, 타깃이 왼쪽 열이라 한다면, 실행되는 곳은...

리플리케이트 안됨멀티캐스트서버에서 실행소유 클라이언트에서 실행

클라이언트 소유 타깃 서버 서버와 모든 클라이언트 서버 타깃의 소유 클라이언트
서버 소유 타깃 서버 서버와 모든 클라이언트 서버 서버
미소유 타깃 서버 서버와 모든 클라이언트 서버 서버

이벤트가 클라이언트에서 호출된 경우, 타깃이 왼쪽 열이라 한다면, 실행되는 곳은...

리플리케이트 안됨멀티캐스트서버에서 실행소유 클라이언트에서 실행

호출 클라이언트에 소유된 타깃 호출 클라이언트 호출 클라이언트 서버 호출 클라이언트
다른 클라이언트에 소유된 타깃 호출 클라이언트 호출 클라이언트 버림 호출 클라이언트
서버 소유 타깃 호출 클라이언트 호출 클라이언트 버림 호출 클라이언트
미소유 타깃 호출 클라이언트 호출 클라이언트 버림 호출 클라이언트

위 표에서 볼 수 있듯이, 클라이언트에서 호출되면서 서버에서 실행 설정되지 않은 이벤트는 리플리케이트되지 않는 것으로 간주됩니다.

 

클라이언트에서 서버로 리플리케이트되는 이벤트를 전송하는 유일한 방법은 클라이언트에서 서버로 정보를 통신하는 방법뿐인데, 일반적인 액터 리플리케이션은 서버에서 클라이언트로만 이루어지도록 디자인되었기 때문입니다.

 

또한 멀티캐스트 이벤트는 서버에서만 전송 가능하다는 점도 눈여겨 봅시다. 언리얼의 클라리언트-서버 모델로 인해, 클라이언트는 다른 클라이언트와 직접 접속되지 않으며, 서버에만 접속됩니다. 그러므로 클라이언트에서 다른 클라이언트로 멀티캐스트 이벤트를 직접 전송하는 것은 불가능하고, 서버와의 통신이 반드시 있어야만 합니다.

 

리플리케이트되는 이벤트를 서버에서 실행 이벤트 하나, 멀티캐스트 이벤트 하나, 총 두 개를 사용하여 이러한 작동방식을 흉내낼 수는 있습니다. 서버에서 실행 이벤트의 구현은 필요하다면 인증을 거친 후 멀티캐스트 이벤트를 호출합니다.

그러면 멀티캐스트 이벤트 구현은 접속된 모든 플레이어에게 실행시키고자 하는 로직을 수행합니다.

인증을 전혀 하지 않는 예제의 경우, 다음 그림을 참고하세요:

 

 

소유중인 클라에서 서버로 ForwardMulticast 를 콜하고 서버에선 전체 클라로 Server Multicast 를 보내는 예제이다

 

 

 

참가중 고려사항

게임 상태 변화 통신시 리플리케이티드 이벤트 사용시 염두에 둬야 할 점 한 가지는, 참가중 상태를 지원하는 게임을 어떻게 처리할 것인지 입니다. 플레이어가 진행중인 게임에 참가할 때, 참가 전에 일어난 리플리케이트되는 이벤트는 새 플레이어에게 실행되지 않을 것입니다. 여기서 한 가지 중요한 점은, 게임이 참가중 상태 처리를 제대로 하도록 하기 위해서는, 리플리케이트되는 변수를 통해 중요 게임플레이 데이터를 동기화시키는 것이 최선이라는 점입니다. 꽤 자주 겪게 되는 패턴은 클라이언트가 월드에서 어떤 동작을 하고, 서버는 "서버에서 실행" 이벤트를 통해 그 동작을 알린 뒤, 그 이벤트의 구현에서 서버는 그 동작에 따른 몇 가지 리플리케이트되는 변수를 업데이트합니다. 그러면 그 동작을 수행하지 않은 다른 클라이언트에서도 리플리케이트되는 변수를 통해 동작의 결과를 확인할 수 있게 됩니다. 추가로 동작이 벌어진 이후 참가중 상태였던 클라이언트도 월드 상태를 제대로 확인할 수 있게 되는데, 서버에서 리플리케이트되는 변수의 가장 최신 값을 받게 되기 때문입니다. 서버가 이벤트 전송만 했다면, 참가중 상태의 플레이어는 그런 동작이 있었는지 알지 못할 것입니다!

신뢰성

리플리케이트되는 이벤트에 대해 Reliable (신뢰성)인지 Unreliable (비신뢰성)인지 선택할 수 있습니다.

신뢰성 이벤트는 (위의 오너십 규칙을 따른다는 가정하에) 목적지에 반드시 도달한다는 보장이 있습니다만, 그로 인해 보다 많은 대역폭을 필요로 하고, 지연시간이 길어질 수 있습니다. 신뢰성 이벤트를 너무 자주, 이를테면 매 틱마다 전송하지 않도록 하세요. 신뢰성 이벤트에 대한 엔진의 내부 버퍼가 넘칠(overflow) 수가 있으며, 그러한 현상이 발생하면 관련된 플레이어는 접속이 끊어질 것입니다!

비신뢰성 이벤트는 이름이 암시하는 바대로 목적지에 도달하지 못할 수 있는데, 예를 들면 네트워크에서의 패킷 손실이라든가 엔진에서 우선권이 높은 부분을 먼저 전송하기 위해 트래픽을 차지하기로 결정한 경우입니다. 그에 따라 비신뢰성 이벤트는 신뢰성보다 대역폭을 적게 차지하며, 자주 호출해도 보다 안전합니다.

 

 

 

ref : https://docs.unrealengine.com/4.27/ko/InteractiveExperiences/Networking/Blueprints/

반응형

'게임엔진(GameEngine) > Unreal4' 카테고리의 다른 글

UE4 Get IP Adress C++  (0) 2022.07.22
UFUNCTION BlueprintCallable, BlueprintImplementableEvent, ..  (0) 2022.07.19
UE5 특징  (0) 2022.06.16
lambda with timers  (1) 2022.04.24
비히클 셋업  (0) 2022.03.16
반응형

루멘 글로벌 일루미네이션 및 리플렉션

루멘은 씬과 라이트 변화에 즉각적으로 반응하는 완전 다이내믹 글로벌 일루미네이션 및 리플렉션 솔루션입니다. 아티스트와 디자이너는 루멘을 활용하여 더욱 다이내믹한 씬을 제작할 수 있습니다. 태양의 각도를 바꾸거나, 손전등을 켜거나, 외부의 문을 열거나, 벽에 구멍을 내면 상황에 따라 간접광과 리플렉션이 적용됩니다.

이 시스템은 밀리미터 단위의 디테일한 환경에서 킬로미터 단위의 광활한 환경까지 무한한 바운스와 간접 스펙큘러 리플렉션으로 디퓨즈 인터리플렉션을 렌더링합니다.

 

이제 아티스트와 디자이너는 사전 연산된 라이팅이 텍스처에 베이크되어 있는 스태틱 씬에 얽매이지 않습니다. 개별 스태틱 메시에 대한 라이트 맵 UV를 구성하거나 라이팅을 다시 빌드할 필요 없이 에디터 내에서 변화를 바로 확인할 수 있어 시간이 크게 절약됩니다.

 

루멘은 효율적인 소프트웨어 레이 트레이싱을 구현하여 글로벌 일루미네이션 및 리플렉션이 다양한 그래픽 카드에서 실행되도록 지원하는 동시에 고급 비주얼을 위한 하드웨어 레이 트레이싱도 지원합니다.

 

 

 

나나이트 가상화 지오메트리

나나이트의 가상화된 마이크로폴리곤 지오메트리 시스템을 사용하면 방대한 양의 지오메트릭 디테일이 포함된 게임을 만들 수 있습니다. ZBrush 스컬프트에서 사진측량 스캔까지 수백만 개의 폴리곤으로 구성된 영화 수준의 소스 아트를 바로 임포트하고, 리얼타임 프레임 레이트를 유지한 채로 눈에 띄는 퀄리티 손실 없이 수백만 번 배치할 수 있습니다.

나나이트는 인식 가능한 디테일만 스마트하게 스트리밍 및 처리하여 트라이앵글 수와 드로 콜의 제약을 크게 줄입니다. 노멀 맵에 디테일을 굽거나 디테일 레벨을 직접 작성하는 등 시간이 걸리는 작업을 제거하여 창작에만 집중할 수 있습니다.

 

 

 

 

언리얼 엔진 5 얼리 액세스 출시 이후로 나나이트에서 향상된 사항은 다음과 같습니다.

  • 디스크에서 나나이트 메시의 크기를 줄이는 최적화 컨트롤
    • 가장 중요도가 낮은 데이터를 제거함으로써 손실 압축에 가깝게 만들어 개발 과정에서 메시를 최적화할 수 있습니다. 예를 들어 테크 데모 ‘나나이트 세계의 루멘'에서는 조각상 중 하나의 가슴 부분에서 눈에 띄는 차이 없이 트라이앵글의 88%(및 디스크 크기)를 줄일 수 있었습니다.
  • 압축 기능을 향상해 동일한 퀄리티의 나나이트 메시를 사용할 때 차지하는 공간을 20%까지 줄일 수 있었습니다.
  • UE4에서 UE5로 프로젝트 변환 시 나나이트 검사 툴(Nanite Auditing Tool) 이 나나이트를 활용할 수 있도록 기존 콘텐츠의 대량 이동을 보조하고, 지원되지 않는 기능이 활성화되는 것 처럼 개발 과정에서 깨지게 되는 나나이트 콘텐츠를 진단합니다.

 

 

 

버추얼 섀도 맵(베타)

버추얼 섀도 맵은 언리얼 엔진 5의 나나이트, 월드 파티션 기능을 활용해 차세대 다이내믹 섀도잉을 실시간으로 제공합니다. 영화 수준의 에셋과 대규모 오픈 월드를 지원하는 데 필요한 높은 퀄리티의 섀도를 일관되게 제공합니다.

기존 다이내믹 섀도잉 기법은 소규모 또는 중간 규모의 월드로 제한되는 경우가 많고 디자이너와 아티스트가 퍼포먼스를 위해 퀄리티를 희생해야 했습니다. 반면 버추얼 섀도 맵은 가장 필요한 곳의 퀄리티를 자동으로 높여 주는 단일 통합 섀도잉 메서드를 제공합니다. 이제 사실적이고 부드러운 반그림자 및 컨택트 하드닝을 통해 먼 거리에 걸쳐 작은 오브젝트 및 큰 오브젝트에 일관된 퀄리티의 섀도를 적용할 수 있습니다.

 

 

 

템포럴 슈퍼 해상도

나나이트 마이크로폴리곤 지오메트리와 차세대 게임의 퀄리티에 대한 기대로 화면에 표시할 수 있는 디테일이 그 어느 때보다 높아졌습니다. 이 기대감을 충족시키기 위해, 언리얼 엔진 4의 하이엔드 플랫폼용 템포럴 안티 에일리어싱(Temporal Anti-Aliasing, TAA)의 대안으로 템포럴 슈퍼 해상도 알고리즘을 새로 개발했습니다.

템포럴 슈퍼 해상도는 언리얼 엔진에 기본 내장되어 높은 퀄리티의 업샘플링을 제공하고 폭넓은 하드웨어를 지원합니다. 템포럴 슈퍼 해상도는 디폴트 안티 에일리어싱 메서드이며 모든 프로젝트에서 활성화되어 있습니다.

 

 

 

DirectX 12

이제 언리얼 엔진 5의 기능을 사용해 Windows PC의 RHI를 구현할 때는 Microsoft의 DirectX 12(DX12)를 권장합니다. 에픽에서는 엔진에서 DX12 지원을 강화하는 동안 메모리 관리, 기능 무결성, 안전성을 최우선으로 고려할 예정입니다. 언리얼 엔진 5에서 새로 생성한 프로젝트는 기본적으로 DX12를 사용합니다.

 

 

Vulkan

언리얼 엔진 5의 Vulkan RHI는 여러 번의 안정성 및 기능 업데이트를 통해 데스크톱 및 모바일에서의 효율이 향상되었습니다. Linux에 나나이트, 루멘(소프트웨어 레이 트레이싱 전용) 등 언리얼 엔진 5 기능이 지원됩니다.

사양에 대한 자세한 정보는 하드웨어 및 소프트웨어 사양 문서를 참조하세요.

 

 

 

액터당 한 개의 파일

새로운 액터당 한 개의 파일(One File Per Actor) 시스템은 월드 파티션과 함께 작동하여 대규모 월드에서 공동 편집을 더욱 쉽게 만들어 줍니다. 레벨 에디터는 개별 액터를 단일 모놀리식 레벨 파일로 그룹화하지 않고 자체적인 파일로 저장합니다. 즉, 전체 레벨이 아닌 소스 컨트롤에서 필요한 액터만 체크아웃하면 됩니다.

이 기능은 월드 파티션을 사용할 때 기본적으로 활성화되어 있습니다.

자세한 정보는 액터당 한 개의 파일 문서를 참조하세요.

 

 

 

대규모 월드 좌표

이제 대규모 월드 좌표(Large World Coordinates, LWC)가 언리얼 엔진 5에서 더블 정밀도 데이터 베리언트 타입을 지원합니다. 부동 소수점 정밀도를 향상하기 위해 UE5의 모든 엔진 시스템 전반에서 커다란 변화가 이루어졌습니다. 새로운 엔진 시스템에는 건축 시각화, 시뮬레이션, 렌더링 (나이아가라 및 HLSL 코드), 대규모 월드 스케일 프로젝트 등이 있습니다. 대규모 월드 좌표를 UE의 모든 곳에서 실행하고 노출하도록 많은 개발 작업을 진행했지만, 원래 지점에서 멀리 떨어진 일부 시스템의 경우 아직 해결하지 않은 정밀도 문제 때문에 몇 가지 제한이 존재합니다.

라이선스 이용자는 코드를 바로 이 신규 데이터 타입으로 옮기기 시작할 수 있으나, 엔진의 전 시스템이 대규모에서도 지금처럼 효율적으로 작동하는지 확인한 후, 5.1 버전에서 대규모 월드에 대한 생성 및 배치를 정식으로 지원할 예정입니다. 이후 최대 월드 크기의 디폴트 값을 매우 큰 수치로 설정할 것입니다.

언리얼 엔진 4에서는 32비트 플로트 정밀도 타입으로 인해 월드의 크기가 제한되었습니다. LWC는 코어 데이터 타입으로 64비트 더블을 제공하여 프로젝트 크기를 크게 향상시킵니다. 이 변화로 대규모 월드를 구축할 수 있게 되었으며, 액터 배치 정확도 및 오리엔테이션 정밀도가 크게 향상되었습니다. 대규모 월드 좌표는 더블 타입을 사용하기 때문에, PhysX 피직스 시스템 은 UE5와 호환되지 않습니다.

대규모 월드 실험에 관련된 자세한 정보는 대규모 월드 좌표 문서를 참조하세요.

 

 

 

 

PhysX 및 카오스 피직스 시스템

UE5는 피직스 시뮬레이션에 대해 카오스 피직스 엔진을 사용하며, 기본값인 PhysX 를 대체합니다. PhysX가 여전히 UE5에 있지만 향후 버전에서 제거될 예정입니다. 카오스 피직스의 피직스 시뮬레이션은 PhysX와 다르게 작동하며, 일관적인 물리 동작을 위해선 개발자의 조정이 필요합니다.

피직스 틱 속도는 기본적으로 새로 생성된 프로젝트에 따라 변경됩니다. 틱 속도 변화는 프로젝트 세팅(메뉴: 수정(Edit) > 프로젝트 세팅(Project Settings) ) 내에 있는 틱 비동기 피직스에서 액세스할 수 있습니다. 이 신기능은 게임 스레드 대신 자체 스레드에서 피직스를 시뮬레이션합니다.

 

PhysX는 UE5에서 제거될 예정이나, 필요한 경우 PhysX가 활성화된 소스에서 컴파일할 수 있습니다.

 

 

 

 

게임플레이 프레임워크

제거

블루프린트 네이티브화(Blueprint Nativization) 는 UE5에 없습니다. 이 기능을 활용한 프로젝트에는 변경사항이 없습니다. 성능에 영향을 미칠 수 있으나 적절하게 작동하려면 수정이 필요합니다. 이 경우 개발자는 다른 최적화 접근 방식을 수행해야 합니다.

네트워킹

지원 중단

AES, RSA, RSA 키 AES 암호화 핸들러(AES, RSA, and RSA Key AES Encryption Handler) 는 UE5 5.0에서 지원 중단되고, UE5의 향후 버전에서 제거될 예정입니다. 현재는 DTLS만 사용됩니다.

  • AES GCM은 UE5 5.0 이전에는 사용되지만 UE5의 후속 릴리스에서는 제거됩니다. 사용자는 이 변경사항으로 인해 프로젝트를 수정할 필요가 없습니다.

코어

제거

젠 로더(Zen Loader)  이벤트 중심 로더(Event-Driven Loader) 를 대체합니다. 대부분의 사용자는 이벤트 주도형 로더와 직접 접속하지 않으므로 이 변경사항에 따라 프로젝트 마이그레이션 도중 작업을 수행할 필요가 없습니다.

지원 중단

언리얼 인사이트(Unreal Insights) 시스템은 UE5 5.0 정식 출시 이후 통계 시스템(Stats System) 을 대체합니다. 통계 시스템은 UE5 5.0에 계속 존재하지만 언리얼 인사이트를 위해 제거될 예정입니다.

반응형

'게임엔진(GameEngine) > Unreal4' 카테고리의 다른 글

UFUNCTION BlueprintCallable, BlueprintImplementableEvent, ..  (0) 2022.07.19
블루프린트에서의 멀티플레이어  (0) 2022.07.13
lambda with timers  (1) 2022.04.24
비히클 셋업  (0) 2022.03.16
check(표현식);  (0) 2022.03.03
반응형
  1. yourLayerMask |= (1 << LayerMask.NameToLayer("Default"));
  2. yourLayerMask |= (1 << LayerMask.NameToLayer("AnotherLayer"));
  3. yourLayerMask |= (1 << LayerMask.NameToLayer("Water"));

 

ref : https://answers.unity.com/questions/1103210/how-to-add-layer-to-layer-mask.html

반응형
반응형

 

유니티에 dll 을 추가하는 방법

 

  1. A 프로젝트를 dll 로 만든다
  2. unityengine.dll 을 사용하고자 하는 곳(A)에 reference 로 추가한다
  3. 빌드를 통해 나온 A.dll 을 사용하고자 하는 프로젝트(유니티에 드래그엔 드랍으로 끌어다 놓으면 해당 dll  내용을 사용 할 수 있다

 

 

 

 


 

Dynamically Linked Library

우리말로 바꾸면 동적으로 링크된 라이브러리 정도가 되는 DLL은 어떤 기능을 하는 클래스 등을

다른 프로그램에서도 사용할 수 있게 재활용 목적을 가지기도 하고,

적은 리소스를 사용하기 위함, 손쉬운 배포와 설치, 관리의 이점, 모듈식 아키텍처 등을 위해 사용한다.

Dll은 정적 링크인 라이브러리(.lib) 파일과는 달리 필요할 때 불러오기 때문에

메모리 관리라는 관점에서 봐서 이점이 있다.

이론은 이 정도면 충분하고 바로 DLL을 만들어보자

먼저 비주얼 스튜디오를 실행하고, 새 프로젝트 만들기를 통해

C# 클래스 라이브러리 .NET(닷넷에서 돌리기 때문)을 만들자.

이름은 DLL의 이름이니 원하는 이름을 적어 넣도록 하자.

유니티에서 사용할 DLL이기 때문에 유니티의 기능을 쓰려고 하는데 오류가 난다.

유니티를 이용하는 사람이라면 바로 어떤 문제인지 바로 알아차렸을 것이다

바로 using에서 UnityEngine을 추가시켜주기 않았기 때문이다.

??? 추가를 해줬는데도 오류가 생겼다.

보통 유니티로 코딩을 배운 사람들은 여기서 더 이상 해결하지 못하고 전전긍긍하고 있을 것이다.

저기서 오류가 나는 이유는 간단한 이유에서인데 바로 UnityEngine이라는 Dll을 추가시켜주지 않아서이다.

솔루션 탐색기에서 참조 추가를 누르면

이런 창이 뜬다.

위 사진에서는 바로 유니티엔진dll이 보이지만 내가 최근에 사용해서 보이는 것이고 처음 빌드 한다면

바로 보이지 않을 것이다.

그러므로 아래의 찾아보기 버튼을 눌러서 직접 추가해주자.

윈도우의 경우 허브를 설치했다면 위와 같은 경로에서 찾을 수 있을 것이다.

(맥의 경우 이 글의 제일 처음 부분의 유니티 공식 가이드 링크에서 확인하면 된다.)

그리고 추가를 눌러주자.

그러면 이렇게 우리가 추가하려는 Dll이 나올 것이다.

체크를 하고 확인을 눌러 추가해주자.

추가된 유니티 엔진 dll을 확인할 수 있고,

오류가 사라진 것도 볼 수 있을 것이다.

근데 여기서 스크립트를 하나 더 추가하고 싶다면

솔루션 바로 아래의 우리가 만들고 있는 DLL에 우클릭 - 추가 - 새 항목을 눌러서

C# 클래스를 선택해주자

추가를 해주면

이렇게 C# 스크립트가 하나 더 추가된 것을 확인할 수 있다.

아무튼 이제 빌드를 해보자.

Debug에서 Release로 고쳐주고 바로 위에 있는 빌드 탭을 눌러

솔루션 빌드를 눌러주자.

빌드 된 경로와 함께 성공 메시지가 떴다.

빌드 된 경로를 복사하여 탐색기에 붙여 넣은 뒤 들어가 보자.

잘 만들어졌다.

이제 이걸 유니티에 넣어보자.

Plugins라는 폴더를 만들어주고,

(사실 지금 만든 기능은 아무 데나 넣어도 되는데 만약 내가 만든 것이

네이티브 기능들을 건드리는 경우에는 무조건 Plugins 안에 넣어야 하기 때문에 그냥 보여주는 것이다.

이 부분은 유니티 공식 가이드에서 더 자세히 확인 가능하다.)

폴더에 넣어주면 끝이다.

(옆에 BTAI는 신경 쓰지 말자.)

인스펙터를 봐서 이런 식으로 나온다면 정상적으로 들어간 것이다.

대충 아무 스크립트 하나 만들어서 기능이 정상적으로 작동하는지 확인해보자.

using에 아까 만든 DLL의 namespace를 적어주고

클래스를 생성해서 접근한다.

아무 오브젝트 하나 만들고 넣어준 다음 플레이하면,

이렇게 성공한 모습을 볼 수 있다!

 

 

 

ref : https://blog.naver.com/PostView.nhn?blogId=cdw0424&logNo=221634807872

반응형
반응형

I am tired of clicking through the hierarchy trying to find where X script is so I can look at it's public variables when testing things out. Especially from scene to scene when placement might be different. How do you stay organized? Find in scene wasn't that useful. Guess I might have to look into editing the inspector. I hope it's easy enough to do. Maybe an asset could help?

 

 

 

Answer by Neamtzu · 

As somebody already stated, you can right click on a script in the project tab, click on "Find References in Scene". Depending on the size of the project, this may take a bit and Unity may seem unresponsive until the search is completed. An alternative to this is to search the type you need in Hierarchy search tab with by typing t:TheTypeYou'reLookingFor. The results, if any, appear instantly and you can search for Unity classes too (t:camera - will return all camera scripts in the scene).

An useful tool for hierarchy management is QHierarchy.

반응형
반응형

유니티 안드로이드 로그캣으로 디버깅 하기 - Unity Android Logcat Debugging.

유니티 에디터에서는 문제가 없이 잘 돌아 가는데 

꼭 핸드폰에 올리면 죽거나 퍼즈 되는 경우가 있다.

이럴 땐 안드로이드 logcat를 이용 하여

출력된 디버깅 정보를 확인 하고 에러를 해결 할 수 있다. 

 

기존 방법

 

1. 핸드폰을 개발자 모드로 활성화 하고 USB 디버깅 모드 사용으로 설정.

( 설정->휴대전화정보 -> 소프트웨어 정보->빌드번호

-> 빌드번호 창을 7회 클릭 -> 설정으로 이동

-> 개발자 옵션 생김 -> USB 디버깅 사용으로 전환 )

 

2. 안드로이드 SDK 설치 된 경로에서 명령창을 열어 다음 명령으로 로그 출력

( 기본 C:\Users\[유저이름]\AppData\Local\Android\Sdk\platform-tools\adb.exe )

  adb logcat -s Unity

 

adb logcat : 전체 로그 출력

adb logcat -s Unity : 유니티 태그로 발생 되는 로그 출력

 

유니티 패키시 이용 방법

 

 위에서 2번의 adb.exe 이용 방법 외에

지금은 유니티에서

Android Logcat 

이라는 패키지를 설치 하여 로그캣을 gui로 유니티 에디터에서 볼 수 있다. 

설치: 유니티 -> Window -> Package Manager -> Android Logcat 검색 -> 설치 

 

Android logcat

 

확인: Window->Analysis -> Android Logcat를 클릭 하면 창을 볼 수 있음.

android logcat

 

유니티 앱에서 발생 되는 로그만 보기 원한다면 

상단의 Tag 항목을 클릭 -> Unity를 선택 하면 된다. 

 

 

ref : https://dragontory.tistory.com/410

반응형
반응형

 

It just that i have to write a long line and then declare a function in the header and implement it in the cpp file only to make a simple delay.
In javascript for example you can do something like that:

setTimeout(function()
{
...
},300);

But when i tried to use lambda within the timer function it says it couldn’t convert what he needs to lambda.
Is it really have to be such a mess only to make a simple delay ?

 

 

 

FTimerDelegate TimerCallback;
TimerCallback.BindLambda([]
{
	// callback;
});

FTimerHandle Handle;
GetWorld()->GetTimerManager().SetTimer(Handle, TimerCallback, 5.0f, false);

 

Inrate 에 대한 설명  == /** Time between set and fire, or repeat frequency if looping. */

 

 

 

Is this what you’re looking for?

 

 

 

 

If you want an inline callback, you can do the following:

GetWorld()->GetTimerManager().SetTimer(Handle, FTimerDelegate::CreateLambda([] { /* callback; */ }), 5.0f, false);

 

 

 

ref : https://forums.unrealengine.com/t/can-i-use-lambda-with-timers/30620

 

Can i use lambda with timers?

It just that i have to write a long line and then declare a function in the header and implement it in the cpp file only to make a simple delay. In javascript for example you can do something like that: setTimeout(function() { ... },300); But when i tried

forums.unrealengine.com

 

 

33님 댓글 

GetWorldTimerManager().SetTimer(FTimerhandle,[this]{ bla bla bal },InRate,Loop);



반응형

'게임엔진(GameEngine) > Unreal4' 카테고리의 다른 글

블루프린트에서의 멀티플레이어  (0) 2022.07.13
UE5 특징  (0) 2022.06.16
비히클 셋업  (0) 2022.03.16
check(표현식);  (0) 2022.03.03
문자 변환  (0) 2022.02.10
반응형

유니티는 C# 6.0을 지원한다. 2018 버전부터는 7.0도 지원한다고 알고있다. async, await 키워드는 C# 5.0부터 추가된 기능이므로 유니티에서 사용 가능하다.

굉장히 오버헤드가 큰 작업을 해야하는데 실시간성을 확보하고 싶을때가 있다. 맵을 로딩하는 동안 로딩 아이콘이 끊김 없이 뱅글뱅글 돌게 하고 싶은 경우가 좋은 예시. 보통 이럴 땐 일회용 스레드를 생성하고 그 안에서 작업을 수행한다. 이런 작업을 위해서 있는 편의 기능이 Task인데 aysnc와 await는 이 Task와 함께 사용하는 키워드이다.

async, await의 사용법을 모를 때는 유니티에서 일회용 스레드를 만들고 싶으면 아래와 같이 쓰곤 했었다.

using UnityEngine;
using System.Collections;
using System.Threading;

public class AsyncTest_Coroutine : MonoBehaviour
{
	void Start()
	{
		StartCoroutine(Run(10));
	}

	IEnumerator Run(int count)
	{
		int result = 0;
		bool isDone = false;

		// 이렇게 하면 변수 스코프를 공유할 수 있는 장점이 있다.
		// 스레드 내에서 result와 isDone 변수에 접근할 수 있다.
		(new Thread(() =>
		{
			for (int i = 0; i < count; ++i)
			{
				Debug.Log(i);
				result += i;
				Thread.Sleep(1000);
			}

			// 작업이 끝났음을 알린다.
			isDone = true;
		}))
		.Start();

		// isDone == true 가 될 때까지 대기한다.
		while (!isDone) yield return null;

		Debug.Log("Result : " + result);
	}
}

프로그램을 block 시키지 않고 10초간 비동기 작업이 실행되는 코드이다.

이렇게 스레드 객체를 만들고 람다식으로 함수를 정의하면 나름 보기 좋은 코드가 나온다. 새로운 스레드를 팠지만 그냥 위에서 아래로 순차적으로 읽으면 동작을 이해할 수 있어서 개인적으로 굉장히 좋은 코드라고 생각한다. 하지만 매번 코루틴을 사용해야 하는 단점이 있고 그마저도 유니티이기 때문에 가능한 것이었다.

그런데 async, await 키워드를 이용하면 더 간단하고 유니티 코루틴의 도움 없이도 동일한 동작을 하는 코드를 작성할 수 있다. 다음은 async, await를 사용하는 예제이다.

using System.Threading.Tasks;
using System.Threading;
using UnityEngine;

public class AsyncTest : MonoBehaviour
{
	void Start()
	{
		Debug.Log("Run() invoked in Start()");
		Run(10);
		Debug.Log("Run() returns");
	}

	void Update()
	{
		Debug.Log("Update()");
	}

	async void Run(int count)
	{
		// 새로 만들어진 태스크 스레드에서 CountAsync()를 실행한다.
		var task = Task.Run(() => CountAsync(10));

		// 함수를 리턴하고 태스크가 종료될 때까지 기다린다.
		// 따라서 바로 "Run() returns" 로그가 출력된다.
		// 태스크가 끝나면 result 에는 CountAsync() 함수의 리턴값이 저장된다.
		int result = await task;

		// 태스크가 끝나면 await 바로 다음 줄로 돌아와서 나머지가 실행되고 함수가 종료된다.
		Debug.Log("Result : " + result);
	}

	int CountAsync(int count)
	{
		int result = 0;

		for (int i = 0; i < count; ++i)
		{
			Debug.Log(i);
			result += i;
			Thread.Sleep(1000);
		}

		return result;
	}
}

await 키워드가 들어있는 메소드는 반드시 async 키워드를 붙여야 한다. Task 객체 앞에 await를 붙이면 해당 태스크가 종료될 때까지 기다리게 된다. await를 만나면 즉시 함수를 리턴하고 해당 스레드는 다음 작업을 계속 수행할 수 있다. 태스크가 종료되면 다시 await가 있던 곳으로 돌아와 나머지가 실행된다. 물론 함수가 호출됐던 동일한 스레드에서 실행된다.

이제 람다식을 사용해서 첫 번째 예제처럼 수정하면 다음과 같다.

using System.Threading.Tasks;
using System.Threading;
using UnityEngine;

public class AsyncTest_Lambda : MonoBehaviour
{
	void Start()
	{
		Debug.Log("Run() invoked in Start()");
		Run(10);
		Debug.Log("Run() returns");
	}

	void Update()
	{
		Debug.Log("Update()");
	}

	async void Run(int count)
	{
		int result = 0;

		await Task.Run(() =>
		{
			for (int i = 0; i < count; ++i)
			{
				Debug.Log(i);
				result += i;
				Thread.Sleep(1000);
			}
		});

		Debug.Log("Result : " + result);
	}
}

 

ref : https://velog.io/@anzsoup/%EC%9C%A0%EB%8B%88%ED%8B%B0%EC%97%90%EC%84%9C-async-await-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

반응형
반응형

자동차 바퀴는 Kinematic 으로 설정하고 콜리전 같은 효과를 주기위해서 대신 Ray cast 를 사용하여 월드와 상호작용하도록 처리한다

 

 

 

 

비히클용으로 아주 기본적인 최소한의 아트 셋업은, 스켈레탈 메시 입니다. 비히클 유형에 따라 얼마나 복잡한 아트 셋업이 필요할 것인지가 결정되며, 서스펜션에 특별한 관심을 쏟아야 할 수 있습니다. 탱크라면 서스펜션이 거의 항상 보이지 않을 테니 별달리 신경쓸 필요가 없겠지만, 비히클 게임 에서 볼 수 있는 것과 같은 모래언덕용 소형차라면 노출된 부품이 좀 더 그럴싸하게 움직이도록 하기 위해서는 조인트가 추가로 필요할 것입니다.

기본

비히클 메시는 양수 X 를 아래로 향하고 있어야 합니다.

언리얼 엔진 4 에서 사용할 휠의 반경은 센티미터 단위로 측정해야 합니다.

위 그림에서는 Maya의 Distance Measurement (거리 측정) 툴을 사용하여 휠 서로 반대편의 두 버텍스 사이의 거리에 따라 휠의 지름을 측정합니다. 휠의 반경은 이 값의 절반이 됩니다.

3DsMax 의 경우 Helpers 섹션에도 비슷한 툴이 있습니다.

조인트

4륜 비히클에 필요한 최소한의 조인트 갯수는 루트에 하나, 휠마다 하나씩 총 5 개입니다. 휠과 루트 조인트는 X 가 앞쪽, Z 가 위쪽으로 맞춰져 있어야 합니다:

그래야 Y 축 중심으로 회전하면서 Z 축으로 스티어링됩니다.

다른 모든 조인트는 원하는 대로 배치 가능하지만, 애니메이션 블루프린트  Look At 노드같은 것들은 X 가 앞쪽이라 가정한다는 점 참고하시기 바랍니다.

시각적으로 어색해 보이는 것을 방지하기 위해, 휠의 조인트는 중앙을 정확히 맞춰야 합니다. 콜리전 감지에 시각적인 메시가 사용되지는 않을 것이지만, 휠 메시가 중앙을 벗어난 경우 휠이 망가진 것처럼 보일 것이기에, 모션 블러로 인해 정말 눈에 띨 것입니다.

바인딩

Maya의 경우 표준 스무드 바인드고, 3DS Max 의 경우 스킨 모디파이어 입니다. 휠은 하나의 조인트에만 웨이팅이 있어야 이상한 변형 없이 자유로운 스핀이 가능합니다. 쇼크 앱소버와 스트럿 서스펜션의 경우 복잡한 스키닝으로 해도 가능하지만, 언리얼 에디터 측에서는 좀 더 생각을 많이 해야 할 것입니다.

익스포트

비히클은 단순히 스켈레탈 메시 로 익스포트되며, 별달리 고려할 것은 없습니다.

임포트

스켈레탈 메시에 대한 표준 FBX 임포트입니다. 임포터가 피직스 애셋 을 생성하도록 하는 것이 좋을 것입니다.

피직스 애셋

피직스 애셋 은 비히클에 엄청나게 중요하므로, 간과하거나 생략할 수 없습니다. 처음 언리얼 엔진 4 로 피직스 애셋 을 생성할 때, 아마도 거의 이와 같아 보일 것입니다:

그 이유는 피직스 애셋 툴 (PhAT) 이 조인트에 스키닝된 버텍스를 가능한 만큼 래핑 시도하기 때문입니다. 그리고 솔직히, 그 전부 지우고 다시 만들게 될 것입니다. 왜냐구요? 모든 피직스 바디를 결합시킬 컨스트레인트 재생성을 제대로 처리할 수 있는 방법이, 현재 PhAT 에는 없기 때문입니다. 즉 중간 피직스 바디를 삭제하면 상위 계층구조에 새로운 컨스트레인트를 만들지 않습니다. 그러나 모든 피직스 바디를 삭제하고 루트 조인트부터 쌓아가기 시작하면 모든 컨스트레인트가 제대로 생성될 것입니다.

계층구조 패널에서 모든 것을 Shift 선택한 다음 Delete 키를 누릅니다. 그러면 애셋에서 모든 피직스 바디가 제거됩니다.

이제 루트 조인트부터 시작해서 비히클 조인트에 피직스 바디를 만들기 시작합니다. 염두에 둘 것은, 물리 시뮬레이션을 하거나 비히클의 바운드에 영향을 끼칠 필요가 있는 조인트에만 피직스 바디가 필요하다는 것입니다.

여기 우리 버기의 경우, 루트에 대한 박스나 휠에 대한 구체가 시작하기 딱 좋을 것이며, 원하는 동작을 내기 위해서는 여러가지 다른 피직스 바디가 필요할 것입니다.

바디 콜리전 생성

비히클 루트에 대한 박스를 생성하려면:

  1. 계층구조 패널에서 루트 조인트에 우클릭합니다.
  2. 바디 추가 를 선택합니다.
  3. 콜리전 지오메트리  박스 로 설정합니다.
  4. "OK" 를 클릭합니다.
  5. 그 후 새로운 피직스 바디 를 이동, 회전, 스케일 조절하여 비히클의 모양을 더욱 잘 추정해 낼 수 있습니다.

휠 콜리전 생성

휠에 쓸 구체를 생성하려면:

  1. 계층구조 패널에서 휠 조인트에 우클릭합니다.
  2. 바디 추가 를 선택합니다.
  3. 콜리전 지오메트리  구체 로 설정합니다.
  4. "OK" 를 클릭합니다.
  5. 디테일 패널에서 Physics Type 프로퍼티를 찾아 Kinematic 으로 설정해 줍니다.비히클의 바운드에 영향을 끼치려는 휠에는 필수인데, 그림자와 컬링이 정상 작동하도록, 또 게임이 시작되면 비히클에서 휠이 떨어져 나오지 않도록 하기 위해서입니다.
  6.  피직스 바디 는 절대 실제 콜리전에 사용되지 않습니다.
    현재 휠은 레이 캐스트를 사용하여 월드와의 상호작용을 처리합니다.

더 나아가서

간단한 셋업은 이렇습니다. '비히클 게임' 내 '비히클' 의 '피직스 애셋' 을 살펴보면 이렇습니다:

휠 외에 모든 콜리전 바디는 비히클의 루트 조인트상에 존재합니다. 휠이 특정 게임 요소에 걸리지 않도록 하고, 휠의 메시가 벽이나 철책에 잘리지 않도록 하기도 합니다.

 

ref : https://docs.unrealengine.com/4.27/ko/InteractiveExperiences/Vehicles/VehicleContentCreation/

반응형

'게임엔진(GameEngine) > Unreal4' 카테고리의 다른 글

UE5 특징  (0) 2022.06.16
lambda with timers  (1) 2022.04.24
check(표현식);  (0) 2022.03.03
문자 변환  (0) 2022.02.10
언리얼4 Android용 Visual Studio 디버깅 가능해지다!!  (0) 2021.08.20
반응형

 

 

You should be using either

LayerMask.GetMask("A", "B")

or

(1 << LayerMask.NameToLayer("A")) | (1<< LayerMask.NameToLayer("B"))

or if you wanna make life easy, just add a public LayerMask field and set in in the inspector

public LayerMask layerMask
반응형
반응형

이 매크로는 표현식을 실행한 뒤, 어서트 결과가 false 이면 실행을 중지시킵니다. 표면식은 매크로가 빌드에 컴파일되는 경우에만 실행됩니다 (DO_CHECK=1). 가장 간단한 형태의 check() 매크로입니다.

예:

check(Mesh != nullptr);
check(bWasInitialized && "Did you forget to call Init()?");

 

checkf(표현식, ...);

checkf() 매크로는 표현식이 true 가 아니면 디버깅에 도움이 되는 추가 정보를 출력하는 것이 가능합니다. 컴파일 면에 있어서는 check() 와 똑같습니다.

예:

checkf(WasDestroyed, TEXT( "Failed to destroy Actor %s (%s)"), *Actor->GetClass()->GetName(), *Actor->GetActorLabel());
checkf( TCString<ANSICHAR>::Strlen( Key ) >= KEYLENGTH( AES_KEYBITS ), TEXT( "AES_KEY needs to be at least %d characters" ), KEYLENGTH( AES_KEYBITS ) );

 

 

 

ref : https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/ProgrammingWithCPP/Assertions/

반응형

'게임엔진(GameEngine) > Unreal4' 카테고리의 다른 글

lambda with timers  (1) 2022.04.24
비히클 셋업  (0) 2022.03.16
문자 변환  (0) 2022.02.10
언리얼4 Android용 Visual Studio 디버깅 가능해지다!!  (0) 2021.08.20
모바일 Joystick 을 PC 에서도 입력되도록  (0) 2021.06.28
반응형

 

OhPontonInstantiate
    Start
        같은 Gameobjecdt 들의 Start 호출
    OnPhotonSerializeView
    순으로 호출됨
    이후에 SerializeView 는 계속 호출된다


    OnPhotonSerializeView 는 photonview 에서 Observed Components 로 연결되어 있어야 호출 된다

반응형
반응형

FName

콘텐츠 브라우저에서 새 애셋 이름을 지을 때, 다이내믹 머티리얼 인스턴스의 파라미터를 변경할 때, 스켈레탈 메시에서 본에 접근할 때, 모두 FName 을 사용합니다. FName 은 문자열 사용에 있어서 초경량 시스템을 제공하는데, 주어진 문자열이 재사용된다 해도 데이터 테이블에 한 번만 저장되는 것입니다. FName 은 대소문자를 구분하지 않습니다. 변경도 불가능하여, 조작할 수 없습니다. 이처럼 FName 의 정적인 속성과 저장 시스템 덕에 찾기나 키로 FName 에 접근하는 속도가 빠릅니다. FName 서브시스템의 또다른 특징은 스트링에서 FName 변환이 해시 테이블을 사용해서 빠르다는 점입니다.

FText

In Unreal Engine 4 (UE4) the primary component for text localization is the FText class. All user-facing text should use this class, as it supports text localization by providing the following features:

FText also features the AsCultureInvariant function (or the INVTEXT macro), which creates non-localized, or "culture invariant" text. This is useful for things like converting a player name from an external API into something you can display in your user interface.

You can create a blank FText using either FText::GetEmpty(), or by using just FText().

FString

FName 이나 FText 와는 달리, FString 은 조작이 가능한 유일한 스트링 클래스입니다. 대소문자 변환, 부분문자열 발췌, 역순 등 사용가능한 메서드는 많습니다. FString 은 검색, 변경에 다른 스트링과의 비교도 가능합니다. 그러나 바로 그것이 FString 이 다른 불변의 스트링 클래스보다 비싸지는 이유입니다.

변환

에서로예제

FName FString TestHUDString = TestHUDName.ToString();
FName FText TestHUDText = FText::FromName(TestHUDName);
FName -> FText 는 가능한 경우도 있지만, FName 의 내용이 FText 의 "자동 현지화" 혜택을 받지 못할 수 있음에 유념해 주시기 바랍니다.

FString FName TestHUDName = FName(*TestHUDString);
FString -> FName 은 손실성 변환이라 위험합니다. FName 은 대소문자를 구분하지 않기 때문입니다.

FString FText TestHUDText = FText::FromString(TestHUDString);
FString -> FText 은 가능한 경우도 있지만, FString 의 내용이 FText 의 "자동 현지화" 혜택을 받지 못할 수 있음에 유념해 주시기 바랍니다.

FText FString TestHUDString = TestHUDText.ToString();
FText -> FString 은 안전하지 않습니다. 일부 언어에서는 변환시 손실될 위험이 있습니다.

FText FName FText 에서 FName 으로의 직접 변환은 없습니다. 대신, FString 을 거친 다음 FName 으로 변환하는 방법이 있습니다.
FText -> FString -> FName 은 손실성 변환이라 위험합니다. FName 은 대소문자를 구분하지 않기 때문입니다.

인코딩

일반적으로 스트링 변수 리터럴 설정시에는 TEXT() 매크로를 사용해야 합니다. TEXT() 매크로를 지정하지 않으면, 리터럴은 ANSI 를 사용해서 인코딩되기에, 지원되는 글자가 크게 제한됩니다. FString 에 전달되는 ANSI 리터럴은 TCHAR (네이티브 유니코드 인코딩)으로의 변환을 겪어야 하기에, TEXT() 를 사용하는 편이 보다 효율적입니다.

인코딩 관련 상세 정보는 캐릭터 인코딩 문서를 참고해 주시기 바랍니다.

 

ref : https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/StringHandling/

반응형
반응형

Custom Instantiation Data

You can send some initial custom data when the instantiation call. Just make use of the last parameter in the PhotonNetwork.Instantiate* method.

This has two main advantages:

  • save traffic by avoiding extra messages: we don't have to use a separate RPC or RaiseEvent call for synchronizing this kind of information
  • timing: the data exchanged is available on the time of the prefab instantiation which could be useful to do some initialization

The instantiation data is an object array (object[]) of anything Photon can serialize.

Example:

Instantiate with custom data:

object[] myCustomInitData = GetInitData();
PhotonNetwork.Instantiate("MyPrefabName", new Vector3(0, 0, 0), Quaternion.identity, 0, myCustomInitData);

Receive custom data:

public void OnPhotonInstantiate(PhotonMessageInfo info)
{
    object[] instantiationData = info.photonView.InstantiationData;
    // ...
}

 

 

ref : https://doc.photonengine.com/en-us/pun/current/gameplay/instantiation

반응형
반응형

event, Action은 꽤 많이 사용하는 편인데

가끔씩 초기화 코드가 중복되면서 이벤트가 중복 호출되는 문제가 발생하기 쉽다. 

그런데 이런 휴먼에러가 발생하면 이벤트 쪽은 이원화되어 있기 떄문에 오류를 발견하기 어렵다..

 

 

1. 방법 1 : 명시적으로 제거하기

using System.Linq;

private EventHandler foo;
public event EventHandler Foo
{
    add
    {
        if (foo == null || !foo.GetInvocationList().Contains(value))
            foo += value;
    }
    remove
    {
        foo -= value;
    }
}

 

2. 방법 2 : 언제나 초기화 전에 제거하기

중요한 사실. -=은 발견되지 않아도 예외가 발생하지 않는다.

때문에 많은 개발자들이 체인을 걸기 전에 빼는 방식으로 구현한다고 함.

private void OnEnable()
{
    Value.onValueChanged -= OnValueCallback;
    Value.onValueChanged += OnValueCallback;
}

private void OnDisable()
{
    Value.onValueChanged -= OnValueCallback;
}

다음과 같이 이벤트 핸들러 내부에서 처리하는 방법도 존재한다!

private EventHandler _foo;
public event EventHandler Foo 
{
    add 
    {
        _foo -= value;
        _foo += value;
    }
    remove 
    {
        _foo -= value;
    }
}

 

3. 단일 이벤트라면 그냥 대입연산자 쓰기

- 다른 이벤트가 체인될게 아니라면 그냥 대입연산자를 써버리는 방법도 있다.

  연결되어있던 모든 이벤트들의 레퍼런스가 사라지며, 새로 대입한 레퍼런스로 바뀐다.

- 버튼은 일반적으로 한 개의 이벤트만 가지기 때문에, 주로 버튼에 이벤트 체인걸 때 사용하게 된다.

private void OnEnable()
{
    Value.onValueChanged = OnValueCallback;
}

private void OnDisable()
{
    Value.onValueChanged -= OnValueCallback;
}

 

 

마치며..

사실 이벤트 order를 가진 프로퍼티를 만들어볼까 하고 만지작거리고 있었는데,

이벤트는 이원화되어야하며, 순서를 가진다면 당신은 무언가 잘못 짠 것입니다.

라길래 순서 없는 버전까지만 하는걸로!

 

 

 

ref : https://mentum.tistory.com/602

반응형
반응형
private GameObject playerUiPrefab;
 GameObject _uiGo =  Instantiate(playerUiPrefab);
    _uiGo.SendMessage ("SetTarget", this, SendMessageOptions.RequireReceiver);

수신자가 필요하며 이 의미는 SetTarget이 응답할 컴포넌트를 찾지 못했을 때 경고를 받게 된다는 것 입니다. 

 

 인스턴스로 부터 PlayerUI 컴포넌트를 받기 위한 방식중의 하나는 SetTarget 을 직접 호출 하는 것 입니다. Component 들을 직접 사용하는 것이 일반적으로 권장 되지만 다양한 방식으로 동일한 사항을 할 수 있다는 것을 알아두는 것도 좋습니다.

SendMessageOptions.RequireReceiver

 

Description

SendMessage에 대한 수신자가 필요한 경우에 사용합니다.

수신자를 찾을 수 없는 경우에, 콘솔에 오류가 출력됩니다. (기본 설정값입니다.) See Also: GameObject.SendMessage

 

 

ref : https://docs.unity3d.com/kr/530/ScriptReference/SendMessageOptions.RequireReceiver.html

반응형
반응형

PlayerPrefs

 

 

PlayerPrefs 클래스는 유니티에서 제공해주는 데이터 관리 클래스이다.

해당 클래스는 int, float, string, bool 타입의 변수를 저장하고 로드하는 기능을 제공한다.

 

 

PlayerPrefs 은 (엑셀에서 두 개의 컬럼으로 구성되어 있는 것과 같이) key와 Value 의 쌍으로 묶여진 항목들의 리스트의 룩업 리스트 입니다. 

그리고 각 플랫폼별 알아서 저장해줍니다

Description

게임 세션(session)사이에 플레이어 preference를 저장하고, preference에 접근합니다.

 

Mac OS X 에서 PlayerPrefs는 ~/Library/Preferences 폴더에 unity.[company name].[product name].plist의 파일이름으로 저장되며,

On Mac OS X PlayerPrefs are stored in ~/Library/Preferences folder, in a file named unity.[company name].[product name].plist, where company and product names are the names set up in Project Settings. Windows 독립 플레이어에서 PlayerPrefs는 @@HKCU
Software
[company name]
[product name]@@ 키 아래의 레지스트리에 저장되며 standalone players.

웹 플레이어에서 PlayerPrefs는 Mac OS X에서 ~/Library/Preferences/Unity/WebPlayerPrefs아래에 HKCU\Software\[company name]\[product name] key, where company and product names are 웹 플레이어 URL 당, 한개의 preference 파일이 존재하며, 파일 크기는 1메가 바이트로 제한됩니다. 파일 크기가 이 제한 값을 초과하는 경우,

On Linux, PlayerPrefs can be found in ~/.config/unity3d/[CompanyName]/[ProductName] again using the company and product names specified in the Project Settings.

On Windows Store Apps, Player Prefs can be found in %userprofile%\AppData\Local\Packages\[ProductPackageId]>\LocalState\playerprefs.dat

On Windows Phone 8, Player Prefs can be found in application's local folder, See Also: Windows.Directory.localFolder

On Android data is stored (persisted) on the device. The data is saved in SharerPreferences. C#/JavaScript, Android Java and Native code can all access the PlayerPrefs data. The PlayerPrefs data is physically stored in /data/data/pkg-name/shared_prefs/pkg-name.xml.

WebPlayer

On Web players, PlayerPrefs are stored in binary files in the following locations:

Mac OS X: ~/Library/Preferences/Unity/WebPlayerPrefs

Windows: %APPDATA%\Unity\WebPlayerPrefs

웹 플레이어에서 PlayerPrefs는 Mac OS X에서 ~/Library/Preferences/Unity/WebPlayerPrefs아래에

There is one preference file per Web player URL and the file size is limited to 1 megabyte. If this limit is exceeded, SetInt, SetFloat and SetString will not store the value and throw a PlayerPrefsException.

Static Functions

DeleteAll preference에서 모든 key와 값들을 제거합니다. 사용 시 경고가 뜹니다.
DeleteKey 키와 대응하는 값을 삭제합니다.
GetFloat Preference 파일에 존재하는 /key/에 대응하는 값을 반환합니다.
GetInt Preference 파일에 존재하는 /key/에 대응하는 값을 반환합니다.
GetString Preference 파일에 존재하는 /key/에 대응하는 값을 반환합니다.
HasKey 키가 존재하는지 확인합니다.
Save 수정된 모든 preferences를 디스크에 씁니다.
SetFloat /key/로 식별된 Preference의 값을 설정합니다.
SetInt /key/로 식별된 Preference의 값을 설정합니다.
SetString /key/로 식별된 Preference의 값을 설정합니다.

 

ref : https://docs.unity3d.com/kr/530/ScriptReference/PlayerPrefs.html

 

반응형
반응형

thisisdivakars said: 
how to set manually
Go to Player Settings -> Select Android -> Other Settings -> For Target API select API 29 (As of now API 30 is recommended at the time of this response)

 

 

ref : https://forum.unity.com/threads/android-sdk-does-not-include-your-target-sdk-of-28.1002894/

반응형
반응형

ScriptableObject

ScriptableObject는 클래스 인스턴스와는 별도로 대량의 데이터를 저장하는 데 사용할 수 있는 데이터 컨테이너입니다. ScriptableObject의 주요 사용 사례 중 하나는 값의 사본이 생성되는 것을 방지하여 프로젝트의 메모리 사용을 줄이는 것입니다. 이는 연결된 MonoBehaviour 스크립트에 변경되지 않는 데이터를 저장하는 프리팹이 있는 프로젝트의 경우 유용합니다.

이러한 프리팹을 인스턴스화할 때마다 해당 데이터의 자체 사본이 생성됩니다. 이러한 방법을 사용하여 중복 데이터를 저장하는 대신 ScriptableObject를 이용하여 데이터를 저장한 후 모든 프리팹의 레퍼런스를 통해 액세스할 수 있습니다. 즉, 메모리에 데이터 사본을 하나만 저장합니다.

MonoBehaviour와 마찬가지로 ScriptableObject는 기본 Unity 오브젝트에서 파생되나, MonoBehaviour와는 달리 게임 오브젝트에 ScriptableObject를 연결할 수 없으며 대신 프로젝트의 에셋으로 저장해야 합니다.

에디터 사용 시, ScriptableObject에 데이터를 저장하는 작업은 편집할 때나 런타임에 가능합니다. 이는 ScriptableObject가 에디터 네임스페이스와 에디터 스크립팅을 사용하기 때문입니다. 배포된 빌드에서는 ScriptableObject를 사용하여 데이터를 저장할 수 없으나, 개발 시 설정한 ScriptableObject 에셋의 저장된 데이터를 사용할 수 있습니다.

에디터 툴에서 에셋 형태로 ScriptableObject에 저장한 데이터는 디스크에 작성되므로 세션 간에도 그대로 유지됩니다.

ScriptableObject 사용하기

ScriptableObject의 주요 사용 사례는 다음과 같습니다.

  • 에디터 세션 동안 데이터 저장 및 보관
  • 데이터를 프로젝트의 에셋으로 저장하여 런타임 시 사용

ScriptableObject를 사용하려면 애플리케이션의 Assets 폴더에 스크립트를 생성하고 ScriptableObject 클래스에서 상속하도록 해야 합니다. CreateAssetMenu 속성을 사용하면 더욱 간편하게 클래스를 이용하여 커스텀 에셋을 생성할 수 있습니다. 다음 예를 참조하십시오.

 

바로 메뉴에 보이는게 아니고 SpawnManagerScriptableObject

클래슬르 먼저 만들고 ScriptableObject 를 만들고 menuName 을 따라가보면 생성할수 있는 메뉴가 나온다

 

[사용예시 더보기 클릭]

 

더보기

생성방법

[CreateAssetMenu(fileName = "New HeroData", menuName = "Sword HeroData", order = 2)]

public class test : ScriptableObject

{

 

}

유니티에서 스크립트를 생성하면 Monobehaviour를 자동으로 상속 받게 되는데 지우고

ScriptableObject를 상속받아온다.

 

[CreateAssetMenu] : 없어도 되지만 있으면 편함

fileName : 새로 제작하게되면 임시로 생성된다. 

menuName : 유니티 메뉴에 표기되는 이름

order : 메뉴에서 보일 순서

Assets -> Create 보면 방금 생성한 HeroData가 보이게 된다.

 

SerializeField의 원본 데이터들은 수정되면 안되기 때문에 

데이터 값을 받을 게터를 public으로 추가해준다.

public class test : ScriptableObject

{

    [SerializeField]

    string heroName;

    [SerializeField]

    string description;

    [SerializeField]

    int goldCost;

 

    public string sName => heroName;

    public string sDesc => description;

    public int    nCoin => goldCost;

}

 

사용법

데이터 값 입력

ScriptableObject를 받을 코드 작성

public class Scene : MonoBehaviour

{

    public Text m_txtUI;

    public test m_Data;

    void Start()

    {

        m_txtUI.text = string.Format(m_Data.sName + " // " + m_Data.sDesc);

    }

}

Data 매칭 인스펙터 창에서 끌어다 놓는다

 

 

 

 

 

using UnityEngine;

[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/SpawnManagerScriptableObject", order = 1)]
public class SpawnManagerScriptableObject : ScriptableObject
{
    public string prefabName;

    public int numberOfPrefabsToCreate;
    public Vector3[] spawnPoints;
}

 

 

 

 

Assets 폴더의 상기 스크립트를 이용하여 Assets > Create > ScriptableObjects > SpawnManagerScriptableObject 로 이동하여 ScriptableObject의 인스턴스를 생성할 수 있습니다. 새 ScriptableObject 인스턴스에 알아볼 수 있는 이름을 지정하고 값을 변경합니다. 이러한 값을 사용하려면 ScriptableObject를 참조하는 새로운 스크립트를 만들어야 합니다(이 경우 SpawnManagerScriptableObject). 다음 예를 참조하십시오.

 

using UnityEngine;

public class Spawner : MonoBehaviour
{
    // The GameObject to instantiate.
    public GameObject entityToSpawn;

    // An instance of the ScriptableObject defined above.
    public SpawnManagerScriptableObject spawnManagerValues;

    // This will be appended to the name of the created entities and increment when each is created.
    int instanceNumber = 1;

    void Start()
    {
        SpawnEntities();
    }

    void SpawnEntities()
    {
        int currentSpawnPointIndex = 0;

        for (int i = 0; i < spawnManagerValues.numberOfPrefabsToCreate; i++)
        {
            // Creates an instance of the prefab at the current spawn point.
            GameObject currentEntity = Instantiate(entityToSpawn, spawnManagerValues.spawnPoints[currentSpawnPointIndex], Quaternion.identity);

            // Sets the name of the instantiated entity to be the string defined in the ScriptableObject and then appends it with a unique number. 
            currentEntity.name = spawnManagerValues.prefabName + instanceNumber;

            // Moves to the next spawn point index. If it goes out of range, it wraps back to the start.
            currentSpawnPointIndex = (currentSpawnPointIndex + 1) % spawnManagerValues.spawnPoints.Length;

            instanceNumber++;
        }
    }
}

 

위의 스크립트를 의 게임 오브젝트에 연결하십시오. 그런 다음 인스펙터에서 Spawn Manager Values 필드를 새로 설정한 SpawnManagerScriptableObject로 설정해야 합니다.

Entity To Spawn 필드를 Assets 폴더의 아무 프리팹으로 설정하고, 에디터의 Play 를 클릭하십시오. Spawner에서 참조한 프리팹이 SpawnManagerScriptableObject 인스턴스에서 설정된 값을 사용하여 인스턴스화됩니다.

인스펙터에서 ScriptableObject 레퍼런스로 작업할 때 레퍼런스 필드를 더블 클릭해서 ScriptableObject의 인스펙터를 열 수 있습니다. 또한 인스펙터가 나타내는 데이터의 관리에 도움이 되도록 모양을 정의해 커스텀 에디터를 만들 수도 있습니다.

 

 

 

ref : https://funfunhanblog.tistory.com/81

ref : https://docs.unity3d.com/kr/2019.4/Manual/class-ScriptableObject.html

반응형
반응형

아주 갱장한 소식입니다

이제 언리얼4 에서도 안드로이드 디버깅이 가능해졌다고 하네요!!

 

 

Android용 Visual Studio 디버깅

이제 Android 프로젝트에서도 Visual Studio 디버깅 워크플로를 사용할 수 있습니다. Google의 Visual Studio용 AGDE 플러그인을 설치하면, Android 프로젝트 생성 시 언리얼 엔진에서 해당 플러그인을 내부적으로 활성화합니다. 이를 통해 Visual Studio에서 직접 프로젝트를 디플로이 및 디버그할 수 있습니다.

 

 

 

 

https://docs.unrealengine.com/4.27/ko/WhatsNew/Builds/ReleaseNotes/4_27/

반응형
반응형

 

 

 

 

 

전반적인 강화 학습의 형태

강화 학습에는 Agent, Action , State ,Reward , Environment 가 존재한다

 

Agent 는 알고리즘 이라고 생각하면 되는데 

 

 

이와 같은것들이 있다

 

 

 

환경을 제작할 수 있는 엔진에는 유니티, 언리얼 등등이 있다

 

 

 

 

 

 

 

강화 학습에는 Agent, Action , State ,Reward 가 있으며 이것이 Environment에서 돈다

 

 

Agent 는 강화학습 딥러닝으로 많이들 한다

이때 딥러닝은 파이썬이나 TensorFlow 등등을 이용함

 

머신러닝과 가장 큰 차이점 딥러닝은 분류에 사용할 데이터를 스스로 학습할 수 있는 반면 

머신 러닝은 학습 데이터를 수동으로 제공해야한다는점이 딥러닝 머신러닝의 가장 큰 차이점입니다.

 

머신 러닝이란?
인공지능의 하위 집한 개념인 머신러닝은 정확한 결정을 내리기 위해 제공된 데이터를 통하여 스스로 학습할 수 있습니다. 처리될 정보에 대해 더 많이 배울 수 있도록 많은 양의 데이터를 제공해야 합니다.

즉, 빅데이터를 통한 학습 방법으로 머신러닝을 이용할 수 있습니다. 머신 러닝은 기본적으로 알고리즘을 이용해 데이터를 분석하고, 분석을 통해 학습하며, 학습한 내용을 기반으로 판단이나 예측을 합니다. 따라서 궁극적으로는 의사 결정 기준에 대한 구체적인 지침을 소프트웨어에 직접 코딩해 넣는 것이 아닌, 대량의 데이터와 알고리즘을 통해 컴퓨터 그 자체를 ‘학습’시켜 작업 수행 방법을 익히는 것을 목표로 한답니다.

 

 

환경은 내가 알아서 만듬(유니티, 언리얼 같은것으로)

 

 

Agent 와 환경은 둘이 다른 환경(프로그래밍 언어등)인데 이 둘 사이를 연결해주는것을 보고 유니티에서

 

ML-Agent 라하며 이것을 ToolKit 이라 볼 수 있다

 

#1

 

이 그림에서 보면 Learnig Enviroment 유 유니티 같은 환경에서 보상과 관측된 정보를 Python API 로 넘긴다

Python API  에서 넘어온 정보를 기반으로 강화학습 알고리즘을 만들어(Python Low-Level API) 알고리즘을 통하여 Action 을 다시 환경으로 넘겨주게 할 수 있다

그런데 강화학습 알고리즘을 직접 짜곳 싶지 않다면 유니티에서 제공하는 Python Trainer 를 갖고 학습을 시킨후

액션을 선택하여 환경에 넘겨줘 서로 통신할수 있게 할 수 있다

 

 

 

Trainers 를 통해서 할대는 학습이 완료된 .nn 이라는 파일을 유니티로 내장 후 이것을 그대로 사용 할 수 있다

 

 

 

ML-Agent 1.0 에선 다음과 같은것들이 있었음

 

 

 

 

Agents 스크립트는 

 

환경을 다 구성해 놓고 어떤 정보와 어떤 액션들어오는 지에 따라서 어떻게 행동 할지를 결정 할수 있는 스크립트

보상과 게임 종료 조건도 결정 할 수 있다

 

 

Behavior 스크립트(예전에는 Brain 이였다고함) ( 위 그림에서 Behavior Parameters 스크립트)

 

1.0 에서

예젠에는 Acamedy 가 있었는데(빌드된 화면의 환경크기, 몇프레임마다 화면 업데이트 할지등등)

지금은 Acamedy 가 사라지고 파이썬으로 옮겨갔음

 

 

 

 

 

Agent 하나당  하나의 Behavior 스크립트가 붙어야 하며 이 Behavior  는 Agents 에 대한 구체적인 설정을 하게된다

 

Vector Observation : x,y,z 위치, 속도 등 관측에 필요한 정보개수들 설정 

Stacked Vectors : 이전것 그 전전의 것 그 전전전의 것을 쌓아서 행동을 결정할때 쌓는정도를 말함

 

Space Type : 액션의 타입인데 연속적인 액션 또는 비연속적인 액션등으로 설정 할 수 있음

 

 

 

 

 

학습환경 내에 있는 Agent A1, Agent A2 가 사용하는 Behavior 가 같다면 Behavior 를 하나로 묶어줘도 된다

 

그다음 이렇게 묶인 것을 Communicator 를 통해서 Python API 와 통신하게 만든다 (#1)

 

 

 

여기서 오른쪽에 Behavior C 는 inference 와 견결 되어 있는데 inference  는 이미 학습된 강화 학습을 통한 결과를 통해 곧바로 행동 할수 있도록 하는것 

 

Behavior D 는 Heuristic 과 연결 되어 있는데 이것은 정해진 규칙에 의해서 움직이게 할 수 있다

사람이 제어하게 할수 있거나, 규칙에 따라 설정 해줄 수가 있다

 

 

 

 

유니티와 파이썬 사이에 직접적으로 연관 없는데이터를 교환하는 것이 가능하다

 

ex ) 자동차를 강화 학습 하는데 자기자신이 아닌 앞차나 뒷차의 정보가 앞차와 뒷차의 거리 등등이 궁금할때(log) Side Channel 을 통해 해볼 수 있다

 

 

 

 

위 처럼 하나를 

 

Agent 를 하나가 아닌 여러개로 구성하여 강화학습을 좀 더 빠르게 하는 방법들이 존재..

Distributed Agents : 

 

이것처럼 여러개로 만들어 좀 더 빠르고 정확한 결과를 볼 수도있음

 

 

Multi-agents : 양 한마리에 여러 사자들이 협력하여 양을 잡을 수 있게 할 수있음

 

 

1:1로 붙는 agents 학습을 말함 알파고 바둑 같은 경우를 말함 , 흑/백돌

둘이서 Self play 환경 (ai 끼리 대결하면서 하는 학습방식)

이때 학습 해놓은것에서 하나를 빼고 대신 사람이 플레이하게 해서 학습 할 수 도 있게 할수 있따

 

 

 

파란색이 주황색공을 피하게 한다

limitation Learning 은 사람이 하는 행동을 따라하는 것을 말함

우선 사람이 플레이를 한다음 그때의 행동이나 데이터를 기반으로해서 사람이 한것을 따라해보라고 학습을 시키는 것을 말한다

학습이 이상하면 플레이어의 문제 일 수도 있음

 

 

 

 

 

중간 사각형의 색상에 따라서 파란색 삭각형이 색상에 일치하는 문으로 가는  Agent 의 예시이다

 

 

이것 같은 경우에는 골기퍼들이 하나씩 있고 스트라이커들이 골을 넣는 환경으로 

각자의 Agents 의 역할이 다르다 행동들도 다르다, 즉 Multi Agent 이다 

 

 

 

 

강화 핛브에는 오른쪽 그림 처럼 Exploitation 이냐 Exploration 이냐에 따라서 학습 되는것이 다르다 

이것은 강화 학습에서 중요한 문제인데, 오른쪽 그림에서 로봇이 아래로만 가도 reward 를 1 을 얻기 때문에

계속 아래로만 갈 수 있다는것 위로가면 더 좋은 보상을 얻을 수 있지만 위로 가기전까진 모름으로

어떻게 에이전트가 다양한 경험을 하면서 학습할지가 성능등 중요한 문제 중 하나

 

* 학습과 탐험을 적절히 섞어 행동하도록 하는것이 중요

 

e : 엡실론 (랜덤하게 액션을 선택할 확률)

x 값이 1에 가까워지면 행동 하던대로만 행동하게 되고 0에 가까워지면 여러 탐색을 먼저 시도를 하게 된다

이것이 엡실론 그리디 방식임

 

그렇지만 목표에 도달하는데까지 상황이 복잡해질 수록 랜덤하게 탐험 하는것인 목표에 도달하는데 거의 불가능에 가까워진다, 보상획득이 어려워져 학습이 불가

 

 이런것은 랜덤 학습으로 키 까지 도달하는데 어려움(거의 불가)

 

 

그런데 호기심(curiosity) 탐험 방식이 있는데 

다음 상태를 예측하기 어려워서 내부 보상을 부여하여 새로운 경험을 선택하도록함

외부 보상은 일반적으로 게임에 보이는 보상

 

 

스태이트와 다음 스태이트가 있을 경우 이것을 동일한 Feature 라는 네트워크를 몇번 통과 시킨다

(상태에서 Feature 를 뽑아냄)

 

이렇게 뽑아진 Feature 를 Forward Model 이라는 곳에 넣어서 다음 스태이트를 예측해본다 (즉 예측한 다음 상태가 나옴)

 

 

 

현재 상태와 다음 상태를 뽑고

 

현재 상태에서 내부 보상을 통하여 다음 상태를예측한다음(Forward Model)

 

현제에서다음을 예측한것과 다음 상태간의 차이를 구한다 

 

즉 이 차이를 이용하여 내부 보상을 만든다

 

내부 보상이 큰경우 : 현재 상태의 액션을 갖고 다음 상태를 예측 했을때 다음 상태와의 차이가 큰경우를 말함

 

내부 보상이 작은경우 : 현재 상태의 액션을 갖고 다음 상태를 예측 했을때 다음 상태와의 차이가 작은경우를 말함

 

 

inverse Model : 

 현재 상태의 state 와 다음 상태의 state 를 둘다 넣고 액션을 해봤을 때 추정하는것으로 추정된 액션과 실제 액션으로 잘 추정하도록 만드는것을 말함 , 즉 이것이 잘 되야 현재에서 다음상태로의 유의미한 Feature 를 뽑아낼수 있는것

 

정리하자면 다음 상태를 잘 모르겠는 상태일때 내부 보상을 크게 줘서 원하는곳으로 가도록 유도하는것 

가본적이 많이 없으면 내부 보상이 작아진다

 

즉 다른곳으로 가게 하려면 내부 보상을 줄이면 된다(새로운 곳으로 가도록 유도함)

처음 가보는 곳은 내부 보상이 커지게 바꾼다

 

 

즉 랜덤하게 돌아다니면 경우의 수가 너무 많기 때문에 이런 식으로 다음 탐험에 대한 방향성을 좁힐 수 있다

 

 

 

 

 

imitation

 

사람의 플레이를 통해서 경험을 쌓는 방식

만약 사람이 플레이를이상하게 하면 agent 도 이상하게 행동을 하게 된다

 

 

 

이미테이션 러닝에서 레퍼런스가 되는 애니메이션이 있고 여기에서 목표하는 타겟을 때리는 것을 강화학습으로 애니시키면 그냥 강화학습으로 목표를 때리는것보다는 자연스럽게 처리 할 수 있다

 

 

 

 

유니티 ML-Agents 에서 제공 하는 학습 방법은?

 

Self-Play : Agent 끼리 서로 대결하면서 학습하는 방식

  • Symmetric  액션이랑 보상함수가 동일한형태로  Policy 를 공유할수 있음

    Agent 의 위치와 속도 , 공의 위치, 속도 등의 요소를 고려하여 학습 
    https://openai.com/blog/emergent-tool-use/  같은 사이트에서 제공하는 학습이 있다 
    빨강애가 못오게 파랑색이 문을 막는다
  •  

Curriculum Learning : 어려운 문제를 한단계씩 쉬운 난이도 부터 학습해서 조금식 어렵게 바꿔나가는 방식

 

파란색이 초록색 박스를 밀어서 녹색 플러스에 집어 넣어야 한다, 빨간색 플러스쪽으로 밀어 넣으면 안됨

제대로 밀어 넣었으면 좀 더 어려운 다음 스테이지에서도 밀어 넣을 수 있도록 난이도를 점점 높여간다

엡실론 (랜덤하게 액션을 선택할 확률) 값을 적당히 높여서 다음 난이도에서 학습하도록함

 

 

Environment parameter Randomization

 

 

사각형 얼굴이 왔다갔다하면서 위에 공을 떨어뜨리지 않도록 할때 Environment parameter 를 쓸 수 있다

공의 크기 또한 바꿀 수 있도로고 파라미터화를 할 수도 있다 (이런 랜덤한 값이 실행활에 있을수 있으니 그런 경우에 유용하다)

 

 

 

 

자동차가 여러개 가고있는데 그중 하나가 끝착선에서 다른 끝차선으로 차선 변경할대 Multi-Agent 를 사용 할수 있다

차선을 이동하는 차가 아닌 다른 차들도 협력을해야 하는 상황

 

빨간색 공이 있는 차가 빨간선 라인으로 차선 변경을 하기 위해서 다른 차들이 비키거나 속력을 내서 공간을 확보한 이후 차선 변경이 되도록함, 하지만 다른 차들의 속도저하는 최소한으로 처리하도록 함

 

 

 

알까기 : 당구와 비슷 

알을 까서 이동하는 동안 상대방은 치면 안됨

액션을 결정하는데 조건이 있음 즉 상대방이 친 돌이 이동하고 멈춰야 내 돌이이동 할 수 있음

이때 어떤 조건에서 알을 까도록 decision 을 설정할 수 있는데 이것을 만들어 주면 가능함

 

 

ML-Agent 설계 팁

  • Obervation : 최대한 실제적인 것을 사용 하는것이 중요하다, 처음엔 목표달성에 너무 쉬운 정보들을 줬다가 점점 빼는 형태로 가면 학습 속도를 빨리 할 수 있다
  • Action : 너무 많을 수록 학습이 잘 안된다, 액션의 조합을 다 합처서 많으면 너무 선택이 많음으로
  • Reward : 어떻게 움직이고 싶어하는 목표에 맞춰서 만든다

 

전체적으로 너무 많은 변수들과 액션 리워드를 세팅 하면 처음 학습 자체가안되거나 어디서 문제가 발생이 됐는지 알기 어려움으로 환경을 과 액션 reward 를 최대한 간단하게 만들고 여기서 학습이 되는 것을 확인한 다음에 차츰 어려운 환경을 만들어 나가는 것이 최종 만들어나가는데 빠른길이 될 수 있다

 

 

 

 

ref : https://wendys.tistory.com/136

ref : https://youtu.be/APMAHDRNv2I

반응형
반응형

아래 옵션들을 체크해주면 된다

반응형
반응형

 

캐릭터 BP 의 컴포넌트들 에서 CharacterMovement 가 아래 처럼 존재할 수있다

 

ABaseCharacter::ABaseCharacter(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer.SetDefaultSubobjectClass<UTDCharacterMovementComponent>(CharacterMovementComponentName))
{

 

 

ObjectInitializer 파라메터로 받는 생성자에서 상위클래스 초기화될 때 파라메터로 커스텀하게 만든 캐릭터 무브먼트 컴포넌트를 생성해주면됨.

다만 기본 Getter 인 GetCharacterMovement() 는 기본 클래스인 UCharacterMovementComponent를 리턴하므로 부를때마다 캐스팅을 하던지, 아니면 그냥 아래와 같은 래퍼를 하나 쓰는것도 간단해서 괜찮아보이긴 함.

 

FORCEINLINE UTDCharacterMovementComponent* GetTDCharacterMovement() { return Cast<UTDCharacterMovementComponent>(GetCharacterMovement()); }

 

 

 

ref : https://bbagwang.com/unreal-engine/character-movement-%EC%A0%81%EC%9A%A9-%EB%B0%A9%EB%B2%95/

반응형
반응형

https://www.unrealengine.com/ko/download?install=true 

 

언리얼 엔진 | 가장 강력한 리얼타임 3D 창작 플랫폼

언리얼 엔진은 게임, 시뮬레이션, 시각화의 디자인 및 개발에 사용되는 통합 크리에이터용 툴세트입니다.

www.unrealengine.com

 

 

 

You can now get the UE5 launcher

 

 

But it's still early access.

 

 

 

https://youtu.be/kXYLq1apcok

 

 

 

Run UE5 and ShaderCompile..

 

 

UE5 Editor

ㅇㅇ

언리얼 엔진 로열티, 게임 프로젝트당 총 수익 백만 달러까지 면제

언제나 그랬듯이, 지금 바로 언리얼 엔진 4를 다운로드하여 무료로 게임을 개발하실 수 있습니다. 새로운 점이라면, 이제 게임 프로젝트당 총 수익이 백만 달러가 될때까지는 로열티가 면제됩니다. 2020년 1월 1일부터 소급 적용되는 새로운 언리얼 엔진 라이선스 조건은 게임 개발자들에게 다른 엔진 라이선스 모델에 비해 전례 없는 혜택을 제공합니다. 더 자세한 정보는 자주 묻는 질문을 확인해 주세요.

 

 

언리얼 엔진 4 & 5 출시 일정

언리얼 엔진 4.25는 이미 Sony 및 Microsoft의 차세대 콘솔 플랫폼을 지원합니다. 에픽은 언리얼 엔진 4를 활용하여 차세대 게임을 개발하려는 콘솔 제조사 및 다수의 게임 개발사와 퍼블리셔들과 긴밀하게 협업하고 있습니다.

언리얼 엔진 5는 2021년 초 프리뷰 버전 출시가 예정되어 있으며, 차세대 콘솔, 최신 콘솔, PC, Mac, iOS 및 Android를 지원합니다.

저희는 상위호환을 염두에 두고 엔진을 설계하고 있으므로, 지금 UE4로 차세대 게임개발을 시작하는 개발사라면, UE5가 준비되었을 때 큰 어려움없이 엔진을 변경하실 수 있습니다.

에픽게임즈는 UE4로 개발한 포트나이트를 차세대 콘솔로도 출시할 예정이며, 업계 최고의 기능들을 직접 검증해 보이기 위한 노력의 일환으로, 저희의 자체 제작 게임인 포트나이트를 2021년 중순에 UE5로 엔진 변경할 예정입니다.

 

 

 

나나이트

는 가상화된 마이크로폴리곤 지오메트리로서, 아티스트들로 하여금 육안으로 식별할 수 있는 최대치의 섬세한 디테일을 구현할 수 있도록 해줍니다. 나나이트 가상화된 지오메트리라는 것은, 수억 개 또는 수십억 개의 폴리곤으로 구성된 영화 수준의 아트 소스를 언리얼 엔진으로 직접 임포트하고 작업할 수 있게 된다는 것을 의미합니다. Zbrush 스컬프팅부터 사진측량 스캔과 CAD 데이터 등 어떠한 데이터라도 그렇게 가능합니다.  나나이트 지오메트리는 실시간으로 스트리밍되고 확장되기 때문에, 이제부터 폴리곤 수, 폴리곤 메모리 또는 드로 콜 버짓으로부터 자유로워지고, 노멀맵에 디테일을 굽거나 LOD를 수동으로 제작할 필요가 없습니다. 퀄리티가 저하되지 않음은 물론입니다.

 

 

 

 

 

 

 

루멘

은 완전한 다이내믹 글로벌 일루미네이션 솔루션으로서 장면과 라이팅의 변화에 즉각적으로 반응하며 특별한 레이 트레이싱 하드웨어가 필요하지 않습니다. 이 시스템은 킬로미터에서 밀리미터까지의 거대하고 세밀한 환경 속에서 무한한 숫자의 빛 반사와 간접 스페큘러 리플렉션으로 디퓨즈 인터리플렉션을 만들어 냅니다. 아티스트들과 디자이너들은 루멘을 활용하여 보다 역동적인 장면을 제작할 수 있습니다. 예를 들어, 하루의 특정 시간에 맞춰 태양의 각도를 바꾸거나, 손전등을 켜거나, 천장에 구멍을 내면 그에 따라 간접광이 적용됩니다. 루멘을 통해 앞으로는 라이트맵의 베이킹을 완료하고, 라이트맵 UV를 제작할 때까지 기다릴 필요가 없습니다. 언리얼 에디터에서 최종 버전의 게임에서 돌아가는 모습과 똑같이 실시간으로 라이트를 움직이며 개발을 하게 되므로, 아티스트로서는 상당한 시간절약을 할 수 있게 됩니다

 

 

수많은 개발팀과 기술들이 모여 이러한 비약적인 퀄리티의 도약을 가능하게 했습니다. 개발팀은 나나이트 지오메트리 기술을 활용하여 매우 방대한 규모의 환경을 제작하기 위해 퀵셀 메가스캔 라이브러리를 집중적으로 활용했으며, 이는 최대 수억 개의 폴리곤으로 구성된 영화 수준의 오브젝트를 제공합니다. 이러한 방대한 규모의 환경을 구현하기 위해, Playstation 5는 이전 세대에 비해 크게 늘어난 스토리지 대역폭을 제공합니다.

이 데모에서는 카오스 피직스 및 디스트럭션, 나이아가라 VFX, 컨볼루션 리버브와 앰비소닉 렌더링 등 기존 엔진 시스템도 선보입니다.

 

 

ref : https://www.unrealengine.com/ko/blog/a-first-look-at-unreal-engine-5

반응형
반응형

 

나나이트 : 공수가 적어져 게임 창작에만 집중할 수 있는 렌더링을 말합니다

 

CTO 인 KIM LIBRERI 는 나나이트를 자유라고 표현합니다

 

 

그도 그럴 것이  초고해상도를 모델을 쉽게말해 그냥 UE5 에 올리면 됩니다 아래 처럼요

이 전의 작업 공수에 비하면 굉장히 비약적인 발전이라 볼 수 있을것입니다

 

 

 

 

제약 사항과 물론 시간차는 있겠지만 더이상 저해상도 노우폴이나 노멀을 따로 만들지 않아도 되는 시기가 다가왔습니다

 

EPIC 에서 이런 저런 시도를 많이 했었지만 나나이트 뿐만 아니라 관련된것들이 이 전과는 상당히 의미 있는 변화라고 볼 수가 있습니다

시간이 갈 수록 그 변화의 폭은 클것으로 예상 되됩니다

 

 

 

 

퀵셀 메가스캔 : epic 에서 만든 실사 모델 스캔ㅊ라이브러리

 

사실 이것은 놀랍다기 보단 epic 에서 훨씬 오래전부터 계속 작업을 해왔던 것입니다

 

 

실제 스캔 장비들을 다각도에서 스캔하여 실제 모델을 만듭니다

이런 스캐닝된 모델 형태들과 같은것을 epic 에서 이미 제공을 하고 있었지요

 

 

이제 점점 이것이 빛을 발하는 날이 다가오고 있는것 같네요

실시간으로 UE 에서 초하이폴을 끌어다 배치 하는 하는 모습인데

 

이제 커스터마이징(LOD 기타 최적화 등등, 조립되어 있는 모델) 할 필요도 없이 UE 에서 알아서 처리해줍니다

 

즉 그냥 붙여 넣기만 하면 되는 것이죠 

 

지형 오브젝트 회전 배치

 

 

이런 식으로배치된 지형이 이미 잘 알려진 바로 이것입니다

 

 

각 개별 에셋인데 어떤각 개별 에셋에는 수천만개의 폴리곤(트라이앵글)로 이루어져 있기도 합니다

 

그래서 전체 씬의 개수는 셀수가 없게 된다 또는 세는것이 의미 없게 됩니다

 

하지만 이것이 이제 거의 바로 앞으로 다가왔다는 것이죠

 

 

이제 임포트하기만 하면 디테일은 UE 가 알아서 해주게 됩니다

 

 

 

 

 

 

작업 후..

 

 

 

 

ref : https://www.youtube.com/watch?v=OkfLh-laEww

반응형
반응형

언리얼 도큐먼트에 보면 게임모드가 리플리케이트 되지 않는 다는 내용을 볼수 있긴 하지만

실행을 하다보면 게임모드가 클라에 있는 경우를 볼 수 가있는데 왜 그런것인지 한번 파악을 해보자

 

 

용어 정리

새 에디터 창(PIE) : 새로운 창에서 실행 화면을 띄움 (Client, Server 를 구분하면서 보기에 유용하다)

스탠드 얼론(Stand alone) : 독립형 게임을 말한다

리슨서버 : 서버와 클라 동시에 실행되는 서버를 말한다

데디케이트 서버 : 렌더링 관련기능 등이 언리얼에서 빠진 오직 서버 기능만이 있는 서버를 말한다

 

 

 

멀티 환경 설정

보다 정확한 멀티 플레이 세팅을 하려면 아래 단일 프로세스 하 실행 옵션을 해제해야한다

옵션이 체크되면 하나의 프로세스에서 실행 되다보니 값이 중복되는 등 제대로된 상태를 보기 어렵게 된다

 

 

 

테스크

 

월드에 큐브를 하나 배치하고 이 큐브에 대한 메터리얼 세팅하는 테스트를 하기위해 다음과 같이 세팅한다

 

큐브를 레벨에 올리고 다음과 같이 블루프린트를 만들어준다

 

 

큐브의 리플리케이션 설정은 다음과 같다

Net Load On Client : 클라이언트에 맵이 로드되면서 동시에 이 항목이 체크된 해당 액터도 맵과 함께 클라이언트에게 보여지게 된다

 

 

 

 

게임모드의 실행여부를 확인하기 위해 게임모드 클래스를 상속받는다

 

void ANSGameMode::BeginPlay()
{
Super::BeginPlay();

GEngine->AddOnScreenDebugMessage(-1, 100.f, FColor::Red, FString::Printf(TEXT("AGameMode::BeginPlay")));

 

 

 

 

Play Offiline 로 실행할경우 게임모드의 존재 여부를 살펴보면 

 

넷 모드를 Play Offline 으로 세팅하고 실행해보면

 

 

Play Offiline 으로 할 경우

 

Role 이 Autority 이고 게임모드의 BeginPlay 또한 호출 되는 것을 볼 수가 있다

이때에는 게임 모드가 클라이언트에서도 실행이 되며 존재한다(실행 자체가 클라임으로)

 

 

 

아래와 같이 클라이언트에서 실행 되었지만 게임모드는 클라에서 만들어졌기 때문에 Role 이 Authority 이며

게임모드 BeginPlay 또한 실행 된것을 볼 수 있으며 메터리얼 또한

노란색 무늬가 있는 메터리얼로 씌워진 것을 볼 수 있다

(멀티 플레이어 옵션에서 -> 플레이어 수 를 늘려도 마찬가지)

 

 

 

Play As Listen Server 로 플레이 하는 경우

 

 

 

 

서버에서는 GameMode 의 Role 가 Authority 이며 GameMode::BeginPlay 또한 호출 된것을 볼수 있으며 게임 모드가 존재 한다는 것을 알수 있다

 

 

 

하지만 클라이언트에서는 GameMode 의 Role 가 None 이며GameMode::BeginPlay 또한 호출 되지 않았다는 것을 알 수 있다(존재하지 않음으로) 

 

 

 

 

 

 

Play As Client 로 테스트를 하기 위해선 아래 과정들이 필요하다

 

 

 

먼저 서버를 위한 빌드를 하나 한다 

 

 

프로젝트 세팅에서 다음 처럼 세팅한다음 빌드를 한 후

 

 

아래 처럼 서버바로 가기를 세팅 한다

 

 

 ?Listen -Rex=500 -ReY=350 -WINDOWED

 

 

서버를 실행 .exe

서버(리슨서버)를 띄웠으니 당연히 Authority 에 큐브 또한 노란색 띄 메터리얼이 입혀졌다

게임모드의 BeginPlay 도 호출된것을 볼 수 있다

 

 

서버를 띄운 다음

 

또한 콘솔 명령으로 Open 1278.0.0.1 로 클라이언트에서 서버쪽으로 붙을 수가 있다

 

 

멀티 플레이 환경 세팅이 되었다는 가정 하에 게임 모드가 존재하는 상황이 있는데

 

서버 역할을 하는 경우와 

 

 

 ?Listen -Rex=500 -ReY=350 -WINDOWED

 

 

 

에디터에서 Play As Client 로 실행하면 

 

에디터에서 실행한 화면이 Server 가 아닌 Client 라는 것을 타이틀창에서 알수 있으며

게임모드의 Role 또한 None 이며 Beginplay 또한 호출되지 않은 즉 게임모드가 존재 하지 않는 다는 거을 알 수가 있다

 

 

 

추가로 붙은 클라이언트에서도 마찬가지인 상황을 알 수가 있다

 

 

 

 

 

게임 모드의 존재 유무 정리

 

Play as Offline 으로 실행 될때 게임 모드가 존재하며 Role 이 Authority 인것을 알수 있고

서버로 실행 되었을때에도 마찬가지로 Authority 이면서 BeginPlay 가 호출된것을 볼 수가 있다

 

 

멀티 환경에서 게임 모드는 서버에서 클라로  Replicated 되지 않고 서버에만 존재하지만

 

Play as Offline 인 클라이언트 단독으로만 실행 할 경우에는 게임모드가 클라이언트에서 생성 되고 삭제 되고 다른곳에 복제 시킬 일도 없음으로 클라이언트 자체가 GameMode 의 Authority 가 된다는 것을 알 수가 있다

 

 

Role_Authority 란 서버만을 얘기 하는 것이 아니라(보통은 서버) 해당 오브젝트가 생성되어 실질적으로 관리를 하고 있는 대상에 따라 Authority 가 된다

 

 

ex) 

1. 멀티 환경에서 서버에서 게임모드는 서버가 관리 함으로 서버에서 GameMode 는 Role_Authority 

하지만 클라에서는 존재자체를 하지 않음

 

2. Play As Offline 으로 서버 없이 실행할 경우 클라에 게임모드가 생성이 되며 이때 생성된 게임 모드는 Role 은 Role_Authority 가 된다, 여기서 관리 되고 삭제 됨으로

 

 

언리얼 도큐먼트 설명에 나와 있는 클라로 Replicated 하지 않는다,

즉 클라이언트중 게임모드가 존재하지 않는다는 것은

멀티 환경 구성이 갖추어 진상태에서 서버가 존재하지만 Play As Client 로 실행 하여 클라로 붙었을때 게임 모드가 존재하지 않는 것이다라는 것을 알 수 있다

반응형
반응형

EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());

이것을 호출 하면 instantiate 한 GameObject 가 에디터를 껐다 킨 이후에도 정상적으로 저장되어 있음

 

하단은 저장 관련한 내용들..

 

 

I am using Unity 2019.2.6f1

I have a single scene that I am using for the main field of play. All characters are prefabs. Each level is saved to a JSON file that controls which characters are to be loaded for the scene and where they are to be positioned.

I have an editor script (SaveLevel) that will create the JSON file based on how I have the scene configured in the editor. I have a second editor script (LoadLevel) that will read the JSON file and set up the scene for that level.

This is all done in the editor at design time. I can save and load levels fine. However, after I load a level, if I hit the play button, to test the level, the scene resets to an empty scene (how it was before I loaded the level).

How can I load my prefabs into my scene and save the scene so that I can test the level?

Here is my code for loading the level:

-- EDIT -- Based on the response by @Ron the fix is the code change in LoadLevel() below.

 

 

...

 

Are you saying that you run this code inside the editor, see the gameobjects created in the hierarchy and scene view, and when you hit play it resets to an empty scene? – Ron Nov 10 '19 at 20:48

  • Yes, except the scene's not completely empty. All of the gameobjects that are saved with the scene, before I run my script, are still there. Only the gameobjects added by my script are missing. – Don Shrout Nov 10 '19 at 22:22
  • C# != UnityScript (which is a Javascript derivative created for unity). – Llama Nov 11 '19 at 0:51
  • @John thanks for the clarification. I added the UnityScript tag because this is a question about code not just the editor. I didn't realize that UnityScript was the official title for Unity's version of JavaScript. I've only ever used C# with Unity. – Don Shrout Nov 11 '19 at 12:50
  • Can you try calling EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); before you call EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo(); – Ron Nov 13

 

 

 

stackoverflow.com/questions/58790108/load-prefabs-via-script-and-save-scene-in-unity-editor

반응형
반응형

아래 그림 처럼 부모가 Cube 자식이 비어 있는 Sphere 트리거 인 경우 

 

[상황 설정]

자식 오브젝트와 부모 오브젝트 각각에 BoxCollide (Trigger 가 켜진) 와 스크립트가 변로로 존재하고(OnTriggerEnter 가 각각 있는) 부모에만 Rigidbody 가 있다면

 

Sphere 에 충돌시 부모의 OnTriggerEnter 와 자식의 OnTriggerEnter 가 모두 불리는데 

이는 자식과 부모를 하나의 닫힌 Mesh 라고 판단하기 때문

 

그래서 각각 부모와 자식의 스크립트의 OnTriggerEnter 가 호출되게 하려면 

자식에도 Rigidbody 를 추가해줘야 한다

 

 

 

 

 

Trigger in child object calls OnTriggerEnter in parent object

The parent object is a small cube with a box collider trigger to fit and a kinematic rigidbody. the child of that object is an empty with a sphere collider trigger that is larger than the box collider.

different scripts are in both parent and child with OnTriggerEnter functions.

expected behavior: when the larger sphere collider (a component of the child) is triggered without triggering the parent, OnTriggerEnter is called in the child object's script.

observed behavior: when the larger sphere collider is triggered, OnTriggerEnter is called in both the parent and the child scripts.

 

 

 

 

Answer by hoy_smallfry · '13년 Mar월 04일 PM 09시 47분

Read the section labeled "Compound Colliders" on this page.

Long story short, collider shapes can't be concave and the only way to accomplish something concave is to treat all convex colliders in children under a parent as if they are one shape, if the parent is the only one with a rigidbody. So, your parent is treating it as if its a complex shape, hence OnTriggerEnter in your parent is getting called.

Try this: give the child a kinematic rigidbody. This will separate it from the parent collision, but still allow it to be moved by the parent's transform instead of physics.

However, be aware that if one touches or encompasses the other, now that they are seen as separate entities, a collision trigger will get registered between the two, even if it's just at the beginning of the scene. They won't bounce off each other since one is a trigger, but you may want to have each OnTriggerEnter function ignore the other Collider if it matches the tag of the other:

 

 

I hope that helps!

Add comment ·  Hide 11 · Share

buscommando · '13년 Mar월 05일 AM 02시 34분 1

 

I will experiment with this. Thank you much!

The parent's trigger matches the parent's mesh exactly, if something triggers it the parent dies.

The child's trigger is a spatial buffer - if something triggers the child's collider, the parent moves/runs away from the object that triggered it.

I had not considered giving both the parent and the child I$$anonymous$$ rigidbodies, currently only the parent has a rigidbody.

$$anonymous$$y solution in the interim was to remove the collider from the parent and add a second child with its own OnTriggerEnter script and a trigger collider identical to the parent's old collider. It worked but felt kludgey, your solution seems a bit more elegant.

kalibcrone  buscommando · '17년 Jul월 13일 PM 01시 06분 2

 

Just a friendly note, "I$$anonymous$$" stands for "Inverse $$anonymous$$inematics" and doesn't really mean the same thing in this context of a $$anonymous$$inematic RigidBody. The term I$$anonymous$$ is generally used when talking about rigging a model for animation.

pas0003 · '13년 Jun월 03일 AM 10시 27분 0

 

Thank you so much for that tip!! :D

filip_andry · '14년 Jul월 01일 AM 06시 58분 0

 

Thanks, It worked for me.

einzweidrei · '15년 Feb월 24일 AM 10시 42분 1

 

Yes, $$anonymous$$inematic Rigidbody did it exactly. Thanks, this made it work finally after long period of banging my head around. :-)

dgreedy · '15년 Apr월 29일 PM 11시 23분 0

 

Buscommando's solution of seperating the triggers and trigger scripts into separate children of the parent object worked well for me. Thanks.

 

 

ref : answers.unity.com/questions/410711/trigger-in-child-object-calls-ontriggerenter-in-pa.html

반응형
반응형

버텍스 애니메이션 툴

2D 텍스처나 메시의 UV 에 복잡한 애니메이션 데이터를 저장하면, 애니메이션 부하를 줄이면서도 애니메이션에 필요한 모양과 느낌을 유지시키는 데 좋습니다. 과거에는 그렇게 하기 위해 모프 타깃 을 사용했겠지만, 이 새로운 방법에는 전에 없던 장점이 몇 가지 있습니다. 그 중 하나는, 기존에 캐스케이드 파티클 에디터에서 모프 타깃을 활용하거나 하지 않으면 불가능했을 복잡한 시스템 내 애니메이션 데이터를 사용할 수 있다는 점입니다. 여기서는 이 스크립트를 사용해서 UE4 프로젝트에 쓸 콘텐츠를 생성하는 법에 대해 다루도록 하겠습니다.

 

스크립트 위치

이 스크립트는 언리얼 엔진 4 (UE4) 4.8 이상 버전에서만 사용가능합니다.

버텍스 애니메이션 스크립트의 이름은 VertexAnimationTools.ms 이고, 위치는 다음과 같습니다:

Engine\Extras\3dsMaxScripts\VertexAnimationTools.ms

3Ds Max 2014 이상 버전에서의 이미지 감마 처리 방식 보정을 위해 버텍스 애니메이션 스크립트 최신 버전이 업데이트되었습니다.

툴 주의사항

이 툴은 복잡한 애니메이션 데이터를 텍스처에 저장하여 애니메이션 부하를 줄이는 데 매우 좋지만, 툴 사용시 생기는 문제점이 몇 가지 있습니다. 무엇보다 이 툴은 하나의 2D 텍스처 내 최대 8192 버텍스 에만 영향을 끼칠 수 있습니다. 그 이유는, DirectX 11 에서 최대 텍스처 크기는 X 나 Y 어느 한 쪽이 8192 픽셀 이내여야 하기 때문입니다. 이 툴은 다음 공식을 사용하여 텍스처 내 데이터를 생성합니다.

최종 텍스처 해상도: X = 메시의 버텍스 수, Y = 캡처된 프레임 수.

이러한 한계로 인해 이 툴은 비주얼 이펙트나 배경 스태틱 메시처럼 애니메이션이 필요는 하지만 복잡한 애니메이션 리깅까지 쓰기에는 조금 무리인 경우에 최적입니다. 이 툴은 스켈레탈 메시 애니메이션과도 작동하지 않는데 본 트랜스폼은 머티리얼 에디터에서 사용할 수 없기 때문입니다. 즉 스켈레탈 메시의 버텍스에 비슷한 방식으로 영향을 끼치려면, 모프 타깃 을 사용해야 한다는 뜻입니다.

버텍스 애니메이션 툴 분석

버텍스 애니메이션 툴 안에는 스태틱 메시의 버텍스에 영향을 끼치는 완전히 다른 메서드가 둘 있습니다. 다음 부분에서는 이 두 메서드에 대해 그 차이점을 포함해서 다루도록 하겠습니다.

  • 버텍스 애니메이션 툴: 버텍스 애니메이션 툴 상단의 Vertex Animation Tools 부분은 모프 타깃 버텍스 위치와 노멀을 저장하는 2D 텍스처 생성용입니다.

    프로퍼티 이름설명

    Animation Options:

    애니메이션 옵션 - 3dx Max 의 타임라인을 사용해서 제작된 애니메이션을 사용하거나, 3Ds Max 나 Maya, Blender 같은 다른 3D 패키지에서 제작된 개별 키프레임을 사용하도록 선택한 다음, 그 패키지에서 프레임별로 익스포트하여 3Ds Max 에서 애니메이션을 재구성할 수 있도록 합니다.

    Process Animated Meshes:

    애니메이티드 메시 처리 - 이 버튼은 3Ds Max 씬에 있는 애니메이티드 메시를 처리하고, 필요한 텍스처를 생성한 뒤 익스포트합니다.

    Anim Start:

    애님 시작 - 애니메이션 시작 프레임을 지정하는 옵션입니다.

    Anim End:

    애님 끝 - 애니메이션 끝 프레임을 지정하는 옵션입니다.

    Frame Skip:

    프레임 스킵 - 프레임을 건너뛰어 텍스처 공간 절약을 시도해 볼 수 있는 옵션입니다.

    Process Selected Meshes:

    선택된 메시 처리 - 키 프레임 메시가 활성화된 경우에만 사용할 수 있는 옵션으로, 키 프레임 메시를 선택한 순서대로 처리합니다.

  • Sequence Painter: 시퀀스 페인터 - 버텍스 애니메이션 툴과 비슷하지만 한 가지 핵심적인 차이점이 있는데, 버텍스 위치 정보가 2D 텍스처가 아닌 메시의 UV 에 저장됩니다.

    프로퍼티 이름설명

    Paint Selection Sequence:

    선택 시퀀스 페인트 - 메시 버텍스에 대한 정보를 2D 텍스처가 아닌 메시 UV 안에 저장합니다.

3Ds Max 버전 & 스크립트 설치

이 툴은 3Ds Max 2015 에서만 테스트되었습니다. 다른 버전에서도 작동이 가능할 수는 있지만, 테스트를 거치진 않았으므로 다른 버전을 사용하는 경우 직접 위험을 감수하셔야 합니다. 스크립트 설치는 간단히 4.8\Engine\Extras\3dsMaxScripts 에서 3Ds Max 뷰포트에 끌어놓으면 스크립트가 저절로 실행됩니다.

이 스크립트를 자주 사용하시는 경우, 언제든 툴바나 쿼드 메뉴에 스크립트를 추가하실 수 있습니다. 자세한 방법은 Autodesk site 에 그 방법이 매우 자세히 소개되어 있습니다.

3Ds Max 유닛 설정

툴 사용 시작 전 3Ds Max 에서 사용하는 측정단위가 UE4 에서 사용하는 측정단위와 제대로 맞는지 확인해 줘야 합니다. 이런 식으로 툴이 3Ds Max 에서 익스포트하는 데이터가 UE4 에서도 동일한 방식으로 작동하도록 만들 수 있습니다. UE4 는 센티미터를 기본 측정단위로 사용하므로 3Ds Max 에서도 동일한 단위를 사용하는지 확인해 줘야 하며, 변경하는 방법은 다음과 같습니다.

  1. 먼저 3Ds Max 2015 를 열고 로드되면 메인 툴바에서 Customize > Unit Setup 을 선택합니다.

  2. 다음 System Unit Setup 을 클릭한 다음 Inches 에서 Centimeters 로 변경한 뒤 OK 버튼을 누릅니다.

  3. 마지막으로 Display Unit Scale  Generic Units 으로 변경한 다음 OK 버튼을 누릅니다.

이 단계는 매우 중요하므로 건너뛰시면 안됩니다. 이 단계를 건너뛰면 UE4 와 3Ds Max 의 단위가 달라 콘텐츠 임포트시 렌더링 오류가 생길 수 있습니다.

툴 선택

버텍스 애니메이션 3Ds Max 스크립트는 버텍스 애니메이션 데이터 저장을 위한 메서드를 두 가지 제공합니다. 하나는 버텍스 위치를 2D 텍스처에 저장하는 반면, 다른 하나는 메시의 UV 에 버텍스 위치 데이터를 저장합니다. 두 메서드 구성 및 사용법 링크는 아래에서 찾을 수 있습니다.

키 프레이밍 메서드 - 다른 3D 패키지에서 익스포트한 뒤 3Ds Max 로 임포트할 수 있는 개별 키 프레임을 사용하는 메서드입니다. 그 정보는 메시의 UV 에 저장됩니다.

애니메이션 타임라인 메서드 - 3Ds Max 애니메이션 타임라인을 사용하여 그 결과를 2D 텍스처에 인코딩하는 메서드입니다.

팁 & 정보

이 기법을 최대한 활용하기 위한 팁과 정보가 몇 가지 있는데, 아래와 같습니다.

애니메이션 재생 속도 높이기

애니메이션 재생 속도가 너무 느리다면, TimeWithSpeedVariable 머티리얼 함수를 사용하여 재생 속도를 높이면 됩니다. 그 방법은 TimeWithSpeedVariable 출력을 MS_SequencePainter_SequenceFlibook 머티리얼 함수를 사용하는 경우 0-1 Animation 입력에 연결하기만 하면 됩니다. MS_VertexAnimationTools_MorphTargets 머티리얼 함수를 사용한다면 TimeWithSpeedVariable 출력을 Morph Animations 입력에 연결하면 됩니다.

다중 애니메이티드 메시

한 번에 여러 개의 애니메이티드 메시를 선택하면 스크립트는 그 데이터 전부를 하나의 메시와 한 세트의 텍스처로 구워줍니다. 여러가지 파트로 이루어진 캐릭터 작업시 매우 유용한 기능인데요. 평소처럼 사용하고자 하는 파트를 선택한 다음 스크립트를 실행해 주기만 하면 됩니다. 그러면 스크립트가 선택한 조각들을 합쳐 필수 2D 텍스처와 함께 메시를 새로 생성해 줍니다.

프레임 스킵

스크립트의 Vertex Animation Tools 섹션 아래 Frame Skip 옵션을 사용하면 특정 프레임을 건너뛸 수 있습니다. 원본 애니메이션의 모양과 느낌을 유지하면서도 최종 텍스처 크기를 줄일 수 있는 매우 유용한 옵션입니다.

아래 비디오에서 프레임 스킵 옵션의 실전 적용 예제를 확인할 수 있습니다. Original 이라 적힌 처음 차주전자를 보면, 전체 프레임 범위의 애니메이션이 보입니다. 2 라고 적힌 다음 차주전자를 보면, 짝수 프레임을 건너뛴 애니메이션이 보입니다. 마지막 예제에서 볼 수 있듯이, 10 프레임을 건너뛴대도 모양과 느낌이 그대로 유지됩니다.

메시 이름 /번호텍스처 크기메모리 절약

Original

175 KB

N/A

2

59 KB

116 KB

5

30 KB

145 KB

10

21 KB

154 KB

기술적 정보

버텍스 애니메이션 스크립트 작동방식에 대한 기술적인 정보입니다. 참고로 이 부분은 스크립트를 변경하기 위해 그 작동 원리를 더욱 자세히 알고자 하는 분들을 위한 것입니다.

한계

버텍스 위치 모프 타깃 정보는 16 비트 부호화 부동 소수점 파일 포맷으로 저장됩니다. 32 비트 이미지면 정밀도가 조금 더 높겠지만, 대부분의 FX 작업에는 16 으로 충분할 것입니다. 말이 나온 김에, 오프셋 버텍스 위치는 원래 놓이는 위치에서 멀리 이동할 수록 정밀도가 떨어질 것입니다.

또 참고로 스크립트 텍스처는 가장 가까운 인접 메서드를 사용하여 샘플링해야 합니다.

메모리 사용량

버텍스당 각 프레임에 쓰이는 메모리 양은 다음과 같습니다:

  • 버텍스 오프셋 텍스처: 프레임당 버텍스마다 8 바이트 (각 픽셀)

  • 노멀 텍스처: 프레임당 버텍스마다 4 바이트 (각 픽셀)

 

 

 

 

반응형

+ Recent posts