Unity/Barracuda & Sentis

[Unity Sentis] 유니티 센티스를 활용하여 새로운 URP 샘플에 StyleTransfer (AdaIN) 적용기

pnltoen 2023. 11. 17.
반응형

Unity Sentis

Unity Technologies


 

 

서론

 

지금까지 센티스와 관련해서 2가지 포스팅을 제작하였습니다. 첫번째로, Barracuda로 작성한 코드를 Sentis로 migration 하였습니다. 두번째로 동일 기기 GPU에서 사용하였을 때 유니티 프로파일러에서 성능을 비교하였습니다.

 

[Unity Sentis 튜토리얼] Unity Sentis 소개 및 설치 + AdaIN 샘플 소개

Barrcuda → Sentis Unity Technologies 서론 기존에 2가지 포스팅을 진행하면서, Barracuda 패키지의 설치 방법을 알아보았습니다. [Unity Barracuda] 유니티 바라쿠다 튜토리얼 (StyleTransfer-AdaIN) Barracuda Unity Technol

pnltoen.tistory.com

 

[Unity Sentis] 유니티 센티스 성능 비교 + (Feat, 성능 프로파일링과 최적화 리뷰)

Unity Sentis Profiling Unity Technologies 서론 이전 Unity Sentis 소개 및 설치 + AdaIN 샘플 소개 글을 작성하고 나서... 바라쿠다와의 성능 비교를 같이 진행하고자 하였다. 하지만 무슨 일인지... 도저히 성능

pnltoen.tistory.com

 

문득, 유니티에서 새로 제작한 URP 샘플에 모델을 적용해보면 어떨까? 하는 생각을 하게 되었고 본 포스팅은 해당 내용을 진행하면서 겪었던 시행착오와 관련해서 기록하고자 합니다.

 

유니티로 들어가기에 앞서 기본적으로 생각한 단계는 다음과 같습니다.

 

 

  1. 카메라로 렌더되는 화면을 렌더 텍스쳐로 가져옵니다.
  2. 카메라로 부터 가져온 렌더 텍스처를 인풋 (Content)로 사용합니다. 기존 예제에서는 또 다른 2D Texture를 Input으로 사용하였습니다.
  3. 모델을 실행합니다.
  4. 실행한 모델로 얻은 Output (RenderTexture 타입)을 스크린에 렌더합니다.

위와 같이 진행하였고 그 시행착오 및 결과는 본문에 기재하였습니다.

 

본론

Camera 렌더링을 렌더 텍스쳐로 변환

 

간단하게 다음과 같은 Test 씬을 만들어보았습니다. 해당 Test Scene에 있는 검은색 quad는 카메라의 렌더 결과물을 받아올 quad입니다. 2가지 방법이 있는데 모두 테스트 해보았습니다.

 

Camera - Target Texture (인스펙터 활용)

 

렌더링 결과물을 받아올 카메라의 Output Texture에 정보를 받아오기 위해 생성한 Render Texture를 선택합니다.

카메라 설정의 경우 SRP, URP, HDRP 즉 그래픽 파이프라인에 따라 다를 수 있습니다. 본 포스팅에서는 URP를 사용하였습니다. 

 

이 후 메테리얼을 하나 생성해주고 다음과 같이 Base Map에 메테리얼을 할당합니다.

 

 

저의 경우에는 이미 한번 실행을 해본 상태라 렌더 결과물이 표시되지만 처음 진행하는 경우 검은색으로 출력되는 것이 일반적입니다.

 

 

다음과 같이 카메라의 이동에 따라 뒤의 렌더 텍스처가 카메라의 렌더 결과물을 받아오는 것을 확인할 수 있습니다.

하지만 저는 인스펙터를 이용하는 것이 추 후 문제를 발생할 수도 있다고 생각해서 다음과 같이 진행하였습니다.

 

Camera - Target Texture (코드)

    public Camera _cam;
    void Start()
    {
        _cam = GetComponent<Camera>();
    }
    
    void Update()
    {
            _cam.targetTexture = _content;
    }

 

위의 코드에서 카메라를 인스펙터에 할당하고 실행할 경우 동일한 결과를 확인하실 수 있습니다.

 

RenderTexture를 Input으로 사용하기 & Execute

 

이전 센티스 샘플과는 다르게 Input을 Texture2D에서 RenderTexture로 사용함으로 몇몇 내용을 수정해야 합니다.

 

    void Exctue_Sents()
    {
        _cam.targetTexture = _content;
        //Reset
        InputTensors = new Dictionary<string, Tensor>();
        //Resize
        t_content = TextureConverter.ToTensor(_content);
        t_style = TextureConverter.ToTensor(_style, 512, 512, 3); 
        //Add
        InputTensors.Add("style", t_style);
        InputTensors.Add("content", t_content);
        //Output
        t_output = m_Engine.Execute(InputTensors).PeekOutput() as TensorFloat;
        TextureConverter.RenderToTexture(t_output, _result);

        // Copy the rescaled tensor to the screen as a texture
        TextureConverter.RenderToScreen(t_output);

        t_content.Dispose();
        t_style.Dispose();
        t_output.Dispose();
    }

 

이 외의 내용의 경우 모두 정상적으로 작동함으로 별도로 수정할 필요가 없습니다.

 

Output 렌더 텍스처를 스크린으로 복사하기

 

이 부분을 하는 방법을 떠오르지 않아서 ChatGPT에 물어보았지만... 시간만 몇시간 날렸습니다 (잘못된 정보만 알려줌)

 

처음에는 Graphics.Blit를 이용하여 Render Texture를 복사하고 OnRenderImage에서 PP전 바꿔주려고 하였습니다. 하지만 OnRenderImage의 경우 SRP 에서만 활용이 되고 UIRP 에서는 별도의 Pass를 이용해야 합니다. 

 

Unity - Scripting API: Graphics.Blit

Success! Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable. Close

docs.unity3d.com

 

포스트 프로세싱 효과 작성 - Unity 매뉴얼

포스트 프로세싱은 Unity에서 렌더링된 이미지에 효과를 적용하는 방법입니다.

docs.unity.cn

 

관련해서 자료 조사를 하다가 우연히 센티스에서 실행한 Output을 스크린으로 옮겨주는 함수를 발견하였습니다. 센티스 문서의 Copy to the Screen 함수를 확인해보면, Output 결과를 스크린으로 복사할 수 있다는 내용 및 Output 벨류를 255로 나눠서 색상를 remap 할 수 있다는 내용을 포함하고 있습니다.

 

Use output data | Sentis | 1.0.0-exp.6

Use output data After you get the output from a model as a tensor, you can postprocess the data to use it in your project. You can also use WorkerFactory.CreateOps to do calculations on tensor outputs. Convert to a flattened 1D array Use ToReadOnlyArray to

docs.unity3d.com

 

해당 함수를 이용해서 코드를 수정해줍니다.

 

    void Exctue_Sents()
    {
        //transform.eulerAngles = new Vector3(0, 0, 180);
        _cam.targetTexture = _content;
        //Reset
        InputTensors = new Dictionary<string, Tensor>();
        //Resize
        t_content = TextureConverter.ToTensor(_content);
        t_style = TextureConverter.ToTensor(_style, 512, 512, 3);
        //Add
        InputTensors.Add("style", t_style);
        InputTensors.Add("content", t_content);
        //Output
        t_output = m_Engine.Execute(InputTensors).PeekOutput() as TensorFloat;
        TextureConverter.RenderToTexture(t_output, _result);

        // Create a tensor operation to divide the output values by 255, to remap to the (0-1) color range
        Ops ops = WorkerFactory.CreateOps(BackendType.GPUCompute, new TensorCachingAllocator());
        TensorFloat divideAmount = new TensorFloat(255f);
        TensorFloat tensorScaled = ops.Div(t_output, divideAmount);

        // Copy the rescaled tensor to the screen as a texture
        TextureConverter.RenderToScreen(t_output);

        t_content.Dispose();
        t_style.Dispose();
        t_output.Dispose();
    }

 

수정된 코드는 다음과 같습니다. RenderToScreen의 경우 Update() 함수가 아닌 OnEndFrameRendering에서 실행하였습니다. 자세한 내용은 Github Repo를 참고해보시길 바랍니다.

 

이를 실행해보면 정상적으로 출력되는 것을 확인할 수 있습니다.

 

 

en_campo_girls 스타일을 적용한 화면입니다. 개인적으로 좋아하는 스타일인데 보기가 어려워서 명암비가 뚜렷한 antimonocromatismo 스타일을 적용한 화면을 아래에 추가하였습니다.

 

 

카메라 반전 문제

 

명암비가 뚜렷한 스타일로 바꾸니 무언가 이상한 점이 보입니다. 네... 카메라가 반전되어 있습니다. 

 

 

그냥 카메라 X축으로 회전시켰습니다... 왜냐하면...! 그 분께서 문제가 아니라고 하셨거든요.

 

 

transform.eulerAngles = new Vector3(0, 0, 180);

 

한 줄 추가해서 해결해도 됩니다.

 

URP3DSampleScene에 적용

 

자 이제 센티스를 활용하여 카메라에 StyleTransfer를 적용하였으니 유니티의 새로운 URP 샘플에 적용해보겠습니다.

새로운 URP Sample은 Github에서 clone 할 수 있습니다. 저는 이 중 Garden 씬이 동양풍에 마음에 들어서 해당씬에 적용해보았습니다.

 

GitHub - Unity-Technologies/URP3DSampleScenes: The beta release of the new URP Sample Scene

The beta release of the new URP Sample Scene. Contribute to Unity-Technologies/URP3DSampleScenes development by creating an account on GitHub.

github.com

 

(좌측 상단)  antimonocromatismo (우측 상단) trial (좌측 하단) sketch (우측 하단) lamuse

 

눈치 채신 분들도 계시겠지만 해상도 이슈가 있습니다.  이는 기존 AdaIN.onnx 모델이 output이 512x512이기 때문입니다.

 

 

이를 수정하기 위해 다음과 같이 1920x1080 출력의 onnx 파일을 만들었지만... 크게 간과한 것이 있었습니다.

 

 

바로 1920x1080이 아닌 위와 같이 1080x1920 파일을 만들어야 한다는 점입니다. 왜냐면 파이토치에서는 일반적으로 CWH이 아닌 CHW이기 때문... 이를 위해 permute를 사용하였고 그 결과 아래의 사진 처럼 디버깅 단계에서 가로와 세로가 회전 (반전) 되는 불상사가 발생하였고...

 

 

 

해당 이슈를 해결 후 유니티에서 input을 WH => HW로 반전해서 넣고 output을 HW => WH로 반전해서 빼고자 하였습니다. 하지만 정상적으로 동작을 하지 않았고 센티스 문서에서 TensorShape을 직접적으로 수정은 불가능하고 데이터를 ShallowReshape로 Reshape 해야 한다고 해서 진행한 결과...

 

Create and modify tensors | Sentis | 1.2.0-exp.2

Create and modify tensors Tensor methods in Sentis are similar to methods in frameworks like numpy, TensorFlow, and PyTorch. Create a basic tensor Create a basic tensor using the methods in the TensorFloat or TensorInt APIs. For example use TensorFloat.Zer

docs.unity3d.com

 

 

망했어요... 이 부분은 추 후 센티스를 활용한 유니티 Segmentation과 Object Detection 튜토리얼을 작성하게 되면 추가적으로 다뤄보도록하겠습니다. 

 

결론

 

위의 결과물은 Github의 pnltoen/Unity_Sentis_AdaIN에서 확인하실 수 있습니다. 새로운 URP 샘플의 리소스의 용량이 큰 관계로 별도로 추가하지 않았습니다. 

 

GitHub - pnltoen/Unity_Sentis_AdaIN

Contribute to pnltoen/Unity_Sentis_AdaIN development by creating an account on GitHub.

github.com

 

대신에 기존 구버전 URP Sample을 아래와 같이 추가하였습니다.

 

반응형

댓글