简易的“虚拟头盔”实现

头盔原理很简单,大致就是使用两个透镜,缩短眼睛的焦距,将两个眼睛看到的东西合二为一从而产生双屏3D效果。

于是开始设想:既然有了3D效果,为了达到更加沉浸的体验,为何不将头部的运动也映射到虚拟世界中去呢?抱着这个想法,我们做了如下尝试:

把头部数据(如旋转角、俯仰角等等)用陀螺仪接收传回电脑,为了简单起见快速出效果,直接手机,然后在手机端写了个app,负责使用wifi发送陀螺仪数据到pc,pc接收到数据之后,我写了个dll,共享内存的,不断更新那一块内存,宿主程序使用的时候,只需要call那块数据即可,方法非常简单。

安卓客户端我不懂,所以是我同学写的。我只说c++ dll的代码,为了方便起见我是用了一个简单sender来模拟陀螺仪发回的数据。

//sender
#include <iostream>
#include <Windows.h>
#include <tchar.h>
#include <ctime>
using namespace std;

struct DataStruct
{
    float x;
    float y;
    float z;
};

#define BUF_SIZE 1024
TCHAR szName[]=TEXT("Global\\MyFileMappingObject"); 

int main()
{
    HANDLE hMapFile;
    float* pBuf;

    hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE,  
        NULL,                 
        PAGE_READWRITE,         
        0,                     
        BUF_SIZE,            
        szName);                

    if (hMapFile == NULL)
    {
        _tprintf(TEXT("Could not create file mapping object (%d).\n"),
            GetLastError());
        return 1;
    }
    pBuf = (float*) MapViewOfFile(hMapFile, 
        FILE_MAP_ALL_ACCESS, 
        0,
        0,
        BUF_SIZE);

    if (pBuf == NULL)
    {
        _tprintf(TEXT("Could not map view of file (%d).\n"),
            GetLastError());

        CloseHandle(hMapFile);

        return 1;
    }
    while(1)
    {
        float s[3] = {1.0f,33.2f,12.3f};
        size_t a = sizeof(s);
        srand(clock());
        *s = rand() / (double)(3.2);
        *(s+1) = rand() / (double)(3.2);
        *(s+2) = rand() / (double)(3.2);
        cout<<s[0]<<" "<<s[1]<<" "<<s[2]<<endl;
        memcpy((PVOID)pBuf, (void*)s, sizeof(s));
    }
}

接收dll代码

#include <windows.h>
#include <string.h>
#include <string>
#include <iostream>
#include <tchar.h>
#include "recevedate.h"
using namespace std;



#define BUF_SIZE 1024
TCHAR szName[]=TEXT("Global\\MyFileMappingObject"); 
HANDLE hMapFile;
float* pBuf;

int dll_data_init()
{
        hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE,    // use paging file
        NULL,                    // default security
        PAGE_READWRITE,          // read/write access
        0,                       // maximum object size (high-order DWORD)
        BUF_SIZE,                // maximum object size (low-order DWORD)
        szName);                 // name of mapping object

    if (hMapFile == NULL)
    {
        _tprintf(TEXT("Could not create file mapping object (%d).\n"),
            GetLastError());
        return -1;
    }
    pBuf = (float*) MapViewOfFile(hMapFile,   // handle to map object
        FILE_MAP_ALL_ACCESS, // read/write permission
        0,
        0,
        BUF_SIZE);

    if (pBuf == NULL)
    {
        _tprintf(TEXT("Could not map view of file (%d).\n"),
            GetLastError());

        CloseHandle(hMapFile);

        return -1;
    }
    return 0;
}

float get_x()
{
    return pBuf[0];
}

float get_y()
{
    return pBuf[1];
}

float get_z()
{
    return pBuf[2];
}

float get_dx()
{
    return pBuf[3];
}

float get_dy()
{
    return pBuf[4];
}

float get_dz()
{
    return pBuf[5];
}

void dll_data_ter()
{
    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);
}

初始化调用int dll_data_init()函数,退出时调用void dll_data_ter(),中间直接获取指定的数据即可。

using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices; 

public class dll : MonoBehaviour {
    [DllImport("daterecive.dll")]
    public static extern int dll_data_init();
    [DllImport("daterecive.dll")]
    public static extern void dll_data_ter ();
    [DllImport("daterecive.dll")]
    public static extern float get_x ();
    [DllImport("daterecive.dll")]
    public static extern float get_y ();
    [DllImport("daterecive.dll")]
    public static extern float get_z ();
    // Use this for initialization
    void Start () {
        dll_data_init ();
    }
    
    // Update is called once per frame
    void Update () {

        //getdata ();
    }



    void OnApplicationQuit()
    {
        dll_data_ter ();
    }
}

初始化后这些函数都是可以调用的,修改一下摄像机代码或者其他代码即可。

在unity中处理了一个场景,做了一下实验:

左上角就是传回的数据,由于是模拟数据,所以不是很真实。

有了这个dll,这个系统可以轻松的拓展到很多游戏引擎中去,我在UE4中也做了相似的尝试。

至于显示,只要场景是双屏即可:

最后,整个装置就成型了:

比较简陋不要在意那些细节,看上去效果还是很不错的,但是不知道怎么展示……

posted @ 2015-03-09 07:21  wubugui  阅读(598)  评论(0编辑  收藏  举报