第十七篇:Unity/UE4如何实现Cave空间(一)

首先什么叫CAVE空间, CAVE是围绕着观察者具有多个图像画面的虚拟现实系统,多个投影面组成一个虚拟空间。理论上CAVE是基于计算机图形学把高分辨率的立体投影技术和三维计算机图形技术、音响技术、传感器技术等综合在一起,产生一个供多人使用的完全沉浸的虚拟环境。
通常CAVE会有上下左右前五块屏幕组成一个沉浸式的空间,如下图

那么Unity和UE4如何实现Cave空间呢,这里我以UE4为例,Unity实现的原理类似。当然UE4中有一个叫nDisplay的插件,它也可以实现Cave空间,感兴趣的可以去新建一个nDisPlay的工程去研究一下,或者去官网看这个文档: https://docs.unrealengine.com/zh-CN/Engine/Rendering/nDisplay/index.html

第十七篇:Unity/UE4如何实现Cave空间(一)_第1张图片
今天我要讲的是另一个方案,他的基本思想是用五个相机分辨渲染出一个画面然后,拼成一个Cave空间。

1、首先新建一个C++工程,新建一个相机类继承pawn,往场景中添加五个相机类,保持类的location和rotation一直,修改相机类下面的camera的角度互成90度(Unity中建一个空物体作为父物体,在父物体下添加一个camera),至于为什么这么做,后面再介绍,如图:
第十七篇:Unity/UE4如何实现Cave空间(一)_第2张图片
第十七篇:Unity/UE4如何实现Cave空间(一)_第3张图片如果每个相机获取到的画面是一个正方形,那么肯定能拼成一个立方体的Cave空间。如图:
第十七篇:Unity/UE4如何实现Cave空间(一)_第4张图片
但是很多时候屏幕并不是一个正方形,可能是长方形,所以我们需要修改三个参数在,分辨是:分辨率、FOV、程序窗口位于屏幕左上角的位置(屏幕左上角为(0,0)点)。

2、设置分辨率和FOV
第十七篇:Unity/UE4如何实现Cave空间(一)_第5张图片
命令r.setRes 1920x1080w 是设置窗口分辨率的,w代表是窗口化,如果是f代表全屏

3、设置窗口距离屏幕原点(左上角)的位置
新建一个C++类继承Actor,cpp文件代码如下

void ASetWinLoc::SetLocation(int32 xposition, int32 yposition)
{

HWND hq = FindWindowW(NULL, L"nDisplay2  ");
//HWND hq = GetActiveWindow();

//得到程序窗口大小
RECT rect;
GetWindowRect(hq, &rect);
int w = rect.right - rect.left;
int h = rect.bottom - rect.top;


//移动窗口位置
MoveWindow(hq, xposition ,yposition,w,h,true);
//SetWindowPos(hq, HWND_TOP, xposition, yposition, w, h, SWP_SHOWWINDOW);

}

.h文件代码如下

public:
	UFUNCTION(BlueprintCallable)
	void SetLocation(int32 xposition,int32 yposition);

xpisition,yposition代表窗口距离原点的X轴和Y轴的坐标,
获取窗口句柄有两种方法:
1、FindWindow(In_opt LPCWSTR lpClassName,
In_opt LPCWSTR lpWindowName),第一个参数是窗口的类,第二个参数是窗口的句柄名字,如果你获取不到句柄,可能是你的参数名称填的不对,一开始我也是老是获取不到,没想到是因为在EXE名字的后面还有两个空格,要想准确获取窗口的句柄名称,可以用Spy++这个工具来获取,下载链接:
https://download.csdn.net/download/sxx930923/11958849
使用方法:
打开exe,点击放大镜图标,长按圆形图标拖动至目标窗口
第十七篇:Unity/UE4如何实现Cave空间(一)_第6张图片
2、GetActiveWindow(),这个方法是获取当前窗口的句柄,不需要任何参数。
移动窗口也有两种方法:
1、MoveWindow(
In HWND hWnd, //目标窗口句柄
In int X, //X轴坐标
In int Y, //Y轴坐标
In int nWidth, //窗口宽度
In int nHeight, //窗口高度
In BOOL bRepaint); //是否重绘窗口

2、 SetWindowPos(
In HWND hWnd, //目标窗口句柄
In_opt HWND hWndInsertAfter,
In int X, //X轴坐标
In int Y, //Y轴坐标
In int cx, //窗口宽度
In int cy, //窗口高度
In UINT uFlags);

有人会问,为什么不直接在这两个方法里设置窗口的分辨率,这是因为这里设置的分辨率在UE4打包出来之后是无效的,他无法改变窗口的分辨率,这可能跟UE4的机制有关。

4、超出屏幕分辨率的窗口
这么做之后我发现一个问题,当设置的窗口分辨率大于屏幕分辨率时,无法移动窗口的位置,我试想是不是因为屏幕不够大,所以在上面代码的基础上又把桌面屏幕放大了一倍,修改后代码如下:

void ASetWinLoc::SetLocation(int32 xposition, int32 yposition)
{
	HWND hq = FindWindowW(NULL, L"nDisplay2  ");
	//HWND hq = GetActiveWindow();
	
	//得到程序窗口大小
	RECT rect;
	GetWindowRect(hq, &rect);
	int w = rect.right - rect.left;
	int h = rect.bottom - rect.top;

	//得到桌面窗口
	RECT rect2;
	HWND hd = GetDesktopWindow();
	GetWindowRect(hd, &rect2);
	int w2 = (rect2.right - rect2.left)*2;
	int h2 = (rect2.bottom - rect2.top)*2;

	//移动窗口位置
	//SetWindowPos(hd, HWND_TOP,rect2.left , rect2.top, w2, h2, SWP_NOZORDER);
	MoveWindow(hd, rect2.left, rect2.top, w2, h2, true);
	//移动窗口位置
	MoveWindow(hq, xposition ,yposition,w,h,true);
	//SetWindowPos(hq, HWND_TOP, xposition, yposition, w, h, SWP_SHOWWINDOW);
}

编译代码,然后在关卡蓝图中调用方法
第十七篇:Unity/UE4如何实现Cave空间(一)_第7张图片

你可能感兴趣的:(第十七篇:Unity/UE4如何实现Cave空间(一))