스킬트리랩 이득우님이 정리해주신 내용을 퍼옴
개요>
언리얼 엔진에 파노라마 VR영상을 찍을 수 있는 Stereo Panoramic Movie Capture플러그인이 있다. 이의 소스코드를 조금 수정하면 Up-Down 방식의 스틸 샷과 이미지를 얻을 수 있고, 이를 유튜브나 페이스북에 업로드하여 공유하는 것이 가능하다.
아래는 해당 작업에 대해 기술한 언리얼 공식 홈페이지 블로그 링크다.
https://www.unrealengine.com/ko/blog/capturing-stereoscopic-360-screenshots-videos-movies-unreal-engine-4
소스 코드를 수정해서 다시 빌드한 엔진은 아래 링크를 통해 다운로드 받을 수 있다.
링크: https://1drv.ms/u/s!AlN8ibroa1gjhWGGqpwyzPAyIw1N
캡쳐 환경설정
위의 블로그에서 캡쳐를 위해 설정한 환경은 아래와 같다.
SP.HorizontalAngularIncrement 2
SP.VerticalAngularIncrement 30
SP.CaptureHorizontalFOV 30
SP.ConcurrentCaptures 6
SP.CaptureSlicePixelWidth 720
SP.ShouldOverrideInitialYaw 0
SP.StepCaptureWidth 4096
이를 콘솔 코맨드를 사용해서 직접 입력하면 되나, 블루프린트의 Execute Console 명령을 사용해 만들어두면놓으면 편하게 쓸 수 있다. 명령어는 문서의 마지막에 있는 캡쳐 세팅 코드를 긁어서 레벨 블루프린트등에 붙여넣기를 해주면 된다.
캡쳐
아래 콘솔 명령으로 캡쳐할 폴더를 지정하고
SP.OutputDir D:/Work
SP.PanoramicScreenshot
명령을 주면 화면이 멈추면서 자동으로 스크린샷이 날자와 시간이름의 폴더에 저장된다.
캡쳐를 하면 영상을 자동으로 만들어주지는 않고 한 프레임당 이미지를 만들어주게 되는데, 이를 위해 캡쳐를 진행할 프레임 수를 함께 입력해주면 된다.
아래 명령은 총 240 프레임 이미지를 생성하는 명령이다.
SP.PanoramicMovie 0 239
여기서 주의할 점은 프레임 캡쳐에는 시간이 오래 소요되기 때문에 엔진에게 고정 시간마다 프레임을 진행해달라고 요청해야 한다. 따라서 엔진 실행시 아래 파라미터를 붙여서 실행해야 한다. 에디터 실행 시 아래처럼 배치 파일을 만들어 놓고 에디터를 실행하면 편하게 사용할 수 있다. ( 압축 파일에 포함되어 있음 )
@echo off
start Engine\Binaries\Win64\UE4Editor.exe -usefixedtimestep -fps=60 -notexturestreaming
exit
영상 제작
만들어진 이미지 시퀀스는 ffmpeg을 사용해 영상으로 제작이 가능하다.
FFMpeg 윈도우 버젼 다운로드 링크 : https://ffmpeg.zeranoe.com/builds/
영상 제작을 위한 커맨드는 다음과 같다.
"{프로그램설치경로}ffmpeg.exe" -framerate 60 -i {이미지폴더경로}/Frame_%5d.jpg -c:v libx264 -profile:v high -level 4.2 -r 60 -pix_fmt yuv420p -crf 18 -preset slower {영상이름}.mp4
이도 마찬가지로 배치 파일을 만들어놓으면 편리하다.
위에서 캡쳐를 60프레임을 기준으로 진행하기 때문에 -framerate를 30으로 설정하면 시간이 두 배 늘어난 영상으로 제작될 것이다.
참고로 스틸이미지로 영상을 만들려면 아래와 같은 커맨드를 사용하면 된다.
{프로그램설치경로}ffmpeg -loop 1 -i {이미지폴더경로}/{이미지이름}.jpg -c:v libx264 -t 10 -profile:v high -level 4.2 -pix_fmt yuv420p -crf 18 -preset slower {영상이름}.mp4
이렇게 만들어진 영상은 그대로 올리면 안되고, 상하 분리된 영상이라는 메타데이터를 영상 파일에 넣어줘야 페이스북에나 유툽에 제대로 반영된다.
이를 위해 구글이 Metadata 인젝터 프로그램을 공개했다.
https://github.com/google/spatial-media/releases
파이썬 2 다운로드 링크 : https://www.python.org/downloads/
소스코드 : https://github.com/google/spatial-media/archive/v2.0.zip
여기서 최신 버젼을 받은 후, Open 버튼을 눌러 생성된 영상을 불러온 후 첫 번째 옵션을 체크하고 Inject Meta 데이터 버튼을 눌러 저장하면 영상이 최종 완성된다.
캡쳐 세팅 코드
[코드 시작]
Begin Object Class=K2Node_CallFunction Name="K2Node_CallFunction_102"
Begin Object Class=EdGraphPin Name="EdGraphPin_162"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_163"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_164"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_165"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_166"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_167"
End Object
Begin Object Name="EdGraphPin_162"
PinName="execute"
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_101.EdGraphPin_157'
End Object
Begin Object Name="EdGraphPin_163"
PinName="then"
Direction=EGPD_Output
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_103.EdGraphPin_168'
End Object
Begin Object Name="EdGraphPin_164"
PinName="self"
PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target")
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.KismetSystemLibrary')
DefaultObject=Default__KismetSystemLibrary
bHidden=True
End Object
Begin Object Name="EdGraphPin_165"
PinName="WorldContextObject"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/CoreUObject.Object')
bHidden=True
End Object
Begin Object Name="EdGraphPin_166"
PinName="Command"
PinType=(PinCategory="string")
DefaultValue="SP.HorizontalAngularIncrement 2"
End Object
Begin Object Name="EdGraphPin_167"
PinName="SpecificPlayer"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.PlayerController')
End Object
FunctionReference=(MemberParent=Class'/Script/Engine.KismetSystemLibrary',MemberName="ExecuteConsoleCommand")
Pins(0)=EdGraphPin'EdGraphPin_162'
Pins(1)=EdGraphPin'EdGraphPin_163'
Pins(2)=EdGraphPin'EdGraphPin_164'
Pins(3)=EdGraphPin'EdGraphPin_165'
Pins(4)=EdGraphPin'EdGraphPin_166'
Pins(5)=EdGraphPin'EdGraphPin_167'
NodePosX=480
NodePosY=-352
NodeGuid=22CF9E0E499AE6A3ECE8DE9F778FDEF5
End Object
Begin Object Class=K2Node_CallFunction Name="K2Node_CallFunction_103"
Begin Object Class=EdGraphPin Name="EdGraphPin_168"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_169"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_170"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_171"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_172"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_173"
End Object
Begin Object Name="EdGraphPin_168"
PinName="execute"
PinToolTip="\n실행"
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_102.EdGraphPin_163'
End Object
Begin Object Name="EdGraphPin_169"
PinName="then"
PinToolTip="\n실행"
Direction=EGPD_Output
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_104.EdGraphPin_174'
End Object
Begin Object Name="EdGraphPin_170"
PinName="self"
PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target")
PinToolTip="타겟\nKismet System Library 레퍼런스"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.KismetSystemLibrary')
DefaultObject=Default__KismetSystemLibrary
bHidden=True
End Object
Begin Object Name="EdGraphPin_171"
PinName="WorldContextObject"
PinToolTip="World Context Object\nObject 레퍼런스"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/CoreUObject.Object')
bHidden=True
End Object
Begin Object Name="EdGraphPin_172"
PinName="Command"
PinToolTip="Command\n스트링\n\nCommand to send to the console"
PinType=(PinCategory="string")
DefaultValue="SP.VerticalAngularIncrement 30"
End Object
Begin Object Name="EdGraphPin_173"
PinName="SpecificPlayer"
PinToolTip="Specific Player\nPlayer Controller 레퍼런스\n\nIf specified, the console command will be routed through the specified player"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.PlayerController')
End Object
FunctionReference=(MemberParent=Class'/Script/Engine.KismetSystemLibrary',MemberName="ExecuteConsoleCommand")
Pins(0)=EdGraphPin'EdGraphPin_168'
Pins(1)=EdGraphPin'EdGraphPin_169'
Pins(2)=EdGraphPin'EdGraphPin_170'
Pins(3)=EdGraphPin'EdGraphPin_171'
Pins(4)=EdGraphPin'EdGraphPin_172'
Pins(5)=EdGraphPin'EdGraphPin_173'
NodePosX=848
NodePosY=-352
NodeGuid=E1466AEE4E402FD09BF3E8BC723EEAD6
End Object
Begin Object Class=K2Node_CallFunction Name="K2Node_CallFunction_104"
Begin Object Class=EdGraphPin Name="EdGraphPin_174"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_175"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_176"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_177"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_178"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_179"
End Object
Begin Object Name="EdGraphPin_174"
PinName="execute"
PinToolTip="\n실행"
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_103.EdGraphPin_169'
End Object
Begin Object Name="EdGraphPin_175"
PinName="then"
PinToolTip="\n실행"
Direction=EGPD_Output
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_105.EdGraphPin_180'
End Object
Begin Object Name="EdGraphPin_176"
PinName="self"
PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target")
PinToolTip="타겟\nKismet System Library 레퍼런스"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.KismetSystemLibrary')
DefaultObject=Default__KismetSystemLibrary
bHidden=True
End Object
Begin Object Name="EdGraphPin_177"
PinName="WorldContextObject"
PinToolTip="World Context Object\nObject 레퍼런스"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/CoreUObject.Object')
bHidden=True
End Object
Begin Object Name="EdGraphPin_178"
PinName="Command"
PinToolTip="Command\n스트링\n\nCommand to send to the console"
PinType=(PinCategory="string")
DefaultValue="SP.CaptureHorizontalFOV 30"
End Object
Begin Object Name="EdGraphPin_179"
PinName="SpecificPlayer"
PinToolTip="Specific Player\nPlayer Controller 레퍼런스\n\nIf specified, the console command will be routed through the specified player"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.PlayerController')
End Object
FunctionReference=(MemberParent=Class'/Script/Engine.KismetSystemLibrary',MemberName="ExecuteConsoleCommand")
Pins(0)=EdGraphPin'EdGraphPin_174'
Pins(1)=EdGraphPin'EdGraphPin_175'
Pins(2)=EdGraphPin'EdGraphPin_176'
Pins(3)=EdGraphPin'EdGraphPin_177'
Pins(4)=EdGraphPin'EdGraphPin_178'
Pins(5)=EdGraphPin'EdGraphPin_179'
NodePosX=1168
NodePosY=-352
NodeGuid=14C663A6467273FEE00F4FA590E7F3F2
End Object
Begin Object Class=K2Node_CallFunction Name="K2Node_CallFunction_105"
Begin Object Class=EdGraphPin Name="EdGraphPin_180"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_181"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_182"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_183"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_184"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_185"
End Object
Begin Object Name="EdGraphPin_180"
PinName="execute"
PinToolTip="\n실행"
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_104.EdGraphPin_175'
End Object
Begin Object Name="EdGraphPin_181"
PinName="then"
PinToolTip="\n실행"
Direction=EGPD_Output
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_109.EdGraphPin_186'
End Object
Begin Object Name="EdGraphPin_182"
PinName="self"
PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target")
PinToolTip="타겟\nKismet System Library 레퍼런스"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.KismetSystemLibrary')
DefaultObject=Default__KismetSystemLibrary
bHidden=True
End Object
Begin Object Name="EdGraphPin_183"
PinName="WorldContextObject"
PinToolTip="World Context Object\nObject 레퍼런스"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/CoreUObject.Object')
bHidden=True
End Object
Begin Object Name="EdGraphPin_184"
PinName="Command"
PinToolTip="Command\n스트링\n\nCommand to send to the console"
PinType=(PinCategory="string")
DefaultValue="SP.ConcurrentCaptures 6"
End Object
Begin Object Name="EdGraphPin_185"
PinName="SpecificPlayer"
PinToolTip="Specific Player\nPlayer Controller 레퍼런스\n\nIf specified, the console command will be routed through the specified player"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.PlayerController')
End Object
FunctionReference=(MemberParent=Class'/Script/Engine.KismetSystemLibrary',MemberName="ExecuteConsoleCommand")
Pins(0)=EdGraphPin'EdGraphPin_180'
Pins(1)=EdGraphPin'EdGraphPin_181'
Pins(2)=EdGraphPin'EdGraphPin_182'
Pins(3)=EdGraphPin'EdGraphPin_183'
Pins(4)=EdGraphPin'EdGraphPin_184'
Pins(5)=EdGraphPin'EdGraphPin_185'
NodePosX=1504
NodePosY=-352
NodeGuid=4A66728D486E238A98F616B3159D01BE
End Object
Begin Object Class=K2Node_CallFunction Name="K2Node_CallFunction_109"
Begin Object Class=EdGraphPin Name="EdGraphPin_186"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_187"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_188"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_189"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_190"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_191"
End Object
Begin Object Name="EdGraphPin_186"
PinName="execute"
PinToolTip="\n실행"
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_105.EdGraphPin_181'
End Object
Begin Object Name="EdGraphPin_187"
PinName="then"
PinToolTip="\n실행"
Direction=EGPD_Output
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_107.EdGraphPin_192'
End Object
Begin Object Name="EdGraphPin_188"
PinName="self"
PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target")
PinToolTip="타겟\nKismet System Library 레퍼런스"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.KismetSystemLibrary')
DefaultObject=Default__KismetSystemLibrary
bHidden=True
End Object
Begin Object Name="EdGraphPin_189"
PinName="WorldContextObject"
PinToolTip="World Context Object\nObject 레퍼런스"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/CoreUObject.Object')
bHidden=True
End Object
Begin Object Name="EdGraphPin_190"
PinName="Command"
PinToolTip="Command\n스트링\n\nCommand to send to the console"
PinType=(PinCategory="string")
DefaultValue="SP.CaptureSlicePixelWidth 720"
End Object
Begin Object Name="EdGraphPin_191"
PinName="SpecificPlayer"
PinToolTip="Specific Player\nPlayer Controller 레퍼런스\n\nIf specified, the console command will be routed through the specified player"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.PlayerController')
End Object
FunctionReference=(MemberParent=Class'/Script/Engine.KismetSystemLibrary',MemberName="ExecuteConsoleCommand")
Pins(0)=EdGraphPin'EdGraphPin_186'
Pins(1)=EdGraphPin'EdGraphPin_187'
Pins(2)=EdGraphPin'EdGraphPin_188'
Pins(3)=EdGraphPin'EdGraphPin_189'
Pins(4)=EdGraphPin'EdGraphPin_190'
Pins(5)=EdGraphPin'EdGraphPin_191'
NodePosX=1808
NodePosY=-352
NodeGuid=FED599384145D9D459B8078088C68767
End Object
Begin Object Class=K2Node_CallFunction Name="K2Node_CallFunction_107"
Begin Object Class=EdGraphPin Name="EdGraphPin_192"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_193"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_194"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_195"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_196"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_197"
End Object
Begin Object Name="EdGraphPin_192"
PinName="execute"
PinToolTip="\n실행"
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_109.EdGraphPin_187'
End Object
Begin Object Name="EdGraphPin_193"
PinName="then"
PinToolTip="\n실행"
Direction=EGPD_Output
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_100.EdGraphPin_198'
End Object
Begin Object Name="EdGraphPin_194"
PinName="self"
PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target")
PinToolTip="타겟\nKismet System Library 레퍼런스"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.KismetSystemLibrary')
DefaultObject=Default__KismetSystemLibrary
bHidden=True
End Object
Begin Object Name="EdGraphPin_195"
PinName="WorldContextObject"
PinToolTip="World Context Object\nObject 레퍼런스"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/CoreUObject.Object')
bHidden=True
End Object
Begin Object Name="EdGraphPin_196"
PinName="Command"
PinToolTip="Command\n스트링\n\nCommand to send to the console"
PinType=(PinCategory="string")
DefaultValue="SP.ShouldOverrideInitialYaw 0"
End Object
Begin Object Name="EdGraphPin_197"
PinName="SpecificPlayer"
PinToolTip="Specific Player\nPlayer Controller 레퍼런스\n\nIf specified, the console command will be routed through the specified player"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.PlayerController')
End Object
FunctionReference=(MemberParent=Class'/Script/Engine.KismetSystemLibrary',MemberName="ExecuteConsoleCommand")
Pins(0)=EdGraphPin'EdGraphPin_192'
Pins(1)=EdGraphPin'EdGraphPin_193'
Pins(2)=EdGraphPin'EdGraphPin_194'
Pins(3)=EdGraphPin'EdGraphPin_195'
Pins(4)=EdGraphPin'EdGraphPin_196'
Pins(5)=EdGraphPin'EdGraphPin_197'
NodePosX=2176
NodePosY=-352
NodeGuid=CD39F3B649EDC762CA76AF86EDBC21CC
End Object
Begin Object Class=K2Node_CallFunction Name="K2Node_CallFunction_100"
Begin Object Class=EdGraphPin Name="EdGraphPin_198"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_199"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_200"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_201"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_202"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_203"
End Object
Begin Object Name="EdGraphPin_198"
PinName="execute"
PinType=(PinCategory="exec")
LinkedTo(0)=EdGraphPin'K2Node_CallFunction_107.EdGraphPin_193'
End Object
Begin Object Name="EdGraphPin_199"
PinName="then"
Direction=EGPD_Output
PinType=(PinCategory="exec")
End Object
Begin Object Name="EdGraphPin_200"
PinName="self"
PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target")
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.KismetSystemLibrary')
DefaultObject=Default__KismetSystemLibrary
bHidden=True
End Object
Begin Object Name="EdGraphPin_201"
PinName="WorldContextObject"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/CoreUObject.Object')
bHidden=True
End Object
Begin Object Name="EdGraphPin_202"
PinName="Command"
PinType=(PinCategory="string")
DefaultValue="SP.StepCaptureWidth 4096"
End Object
Begin Object Name="EdGraphPin_203"
PinName="SpecificPlayer"
PinType=(PinCategory="object",PinSubCategoryObject=Class'/Script/Engine.PlayerController')
End Object
FunctionReference=(MemberParent=Class'/Script/Engine.KismetSystemLibrary',MemberName="ExecuteConsoleCommand")
Pins(0)=EdGraphPin'EdGraphPin_198'
Pins(1)=EdGraphPin'EdGraphPin_199'
Pins(2)=EdGraphPin'EdGraphPin_200'
Pins(3)=EdGraphPin'EdGraphPin_201'
Pins(4)=EdGraphPin'EdGraphPin_202'
Pins(5)=EdGraphPin'EdGraphPin_203'
NodePosX=2528
NodePosY=-368
NodeGuid=4385CB574222F8CE62F7CCBE0199C751
End Object
[코드 끝]