主要基于开源代码:https://github.com/ValveSoftware/openvr/tree/master/samples/hellovr_opengl
进行修改,开发工具:VS2015。
首先你得有四棱锥全景图,如下:xxx.png xxx.jpg 分辨率必须是4的倍数 宽高相同
bool CMainApplication::SetupTexturemaps()
{// 初始化 读取图片
rgbImg = imread("C:/.../xxx.jpg");
if (rgbImg.cols != rgbImg.rows | rgbImg.rows % 4 != 0 | rgbImg.cols % 4 != 0) {
cout << "分辨率有问题!" << endl;
getchar();
return false;
}
glGenTextures(1, &m_iTexture);
glBindTexture(GL_TEXTURE_2D, m_iTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rgbImg.cols, rgbImg.rows, 0, GL_BGR, GL_UNSIGNED_BYTE, rgbImg.data);//贴图
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLfloat fLargest;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
glBindTexture(GL_TEXTURE_2D, 0);
return (m_iTexture != 0);
}
然后修改void CMainApplication::AddCubeToScene( Matrix4 mat, std::vector
记得在class CMainApplication中添加声明:
void AddPyramidToScene( std::vector &vertdata);
void CMainApplication::AddPyramidToScene(std::vector &vertdata)
{ //绘制的三维图形和二维图片坐标绑定
//x右边 y上面 z后面 u右 v下 triangles instead of quads
//这里直接用AddCubeVertex()来添加三维坐标和二维坐标绑定 不要被函数名误导
AddCubeVertex(0.f, 0.f, 3.16987f, 0.0f, 1.0f, vertdata);//O
AddCubeVertex(-5.f, 0.f, -1.830127f, 0.0f, 0.5f, vertdata);//A
AddCubeVertex(0.f, -5.f, -1.830127f, 0.5f, 1.0f, vertdata);//D
AddCubeVertex(0.f, 0.f, 3.16987f, 1.0f, 1.0f, vertdata);//O
AddCubeVertex(0.f, -5.f, -1.830127f, 0.5f, 1.0f, vertdata);//D
AddCubeVertex(5.f, 0.f, -1.830127f, 1.0f, 0.5f, vertdata);//C
AddCubeVertex(0.f, 0.f, 3.16987f, 1.0f, 0.0f, vertdata);//O
AddCubeVertex(5.f, 0.f, -1.830127f, 1.0f, 0.5f, vertdata);//C
AddCubeVertex(0.f, 5.f, -1.830127f, 0.5f, 0.0f, vertdata);//B
AddCubeVertex(0.f, 0.f, 3.16987f, 0.0f, 0.0f, vertdata);//O
AddCubeVertex(0.f, 5.f, -1.830127f, 0.5f, 0.0f, vertdata);//B
AddCubeVertex(-5.f, 0.f, -1.830127f, 0.0f, 0.5f, vertdata);//A
AddCubeVertex(0.f, 5.f, -1.830127f, 0.5f, 0.0f, vertdata);//B
AddCubeVertex(-5.f, 0.f, -1.830127f, 0.0f, 0.5f, vertdata);//A
AddCubeVertex(0.f, -5.f, -1.830127f, 0.5f, 1.0f, vertdata);//D
AddCubeVertex(0.f, 5.f, -1.830127f, 0.5f, 0.0f, vertdata);//B
AddCubeVertex(0.f, -5.f, -1.830127f, 0.5f, 1.0f, vertdata);//D
AddCubeVertex(5.f, 0.f, -1.830127f, 1.0f, 0.5f, vertdata);//C
}
//这个是源文件里绘制立方体的函数
void CMainApplication::AddCubeToScene(Matrix4 mat, std::vector &vertdata)
{
//x右边 y上面 z后面 u右 v下 triangles instead of quads
// Matrix4 mat( outermat.data() );
Vector4 A = mat * Vector4(0, 0, 0, 1);
Vector4 B = mat * Vector4(1, 0, 0, 1);
Vector4 C = mat * Vector4(1, 1, 0, 1);
Vector4 D = mat * Vector4(0, 1, 0, 1);
Vector4 E = mat * Vector4(0, 0, 1, 1);
Vector4 F = mat * Vector4(1, 0, 1, 1);
Vector4 G = mat * Vector4(1, 1, 1, 1);
Vector4 H = mat * Vector4(0, 1, 1, 1);
//
AddCubeVertex(E.x, E.y, E.z, 0, 1, vertdata); //Front
AddCubeVertex(F.x, F.y, F.z, 1, 1, vertdata);
AddCubeVertex(G.x, G.y, G.z, 1, 0, vertdata);
AddCubeVertex(G.x, G.y, G.z, 1, 0, vertdata);
AddCubeVertex(H.x, H.y, H.z, 0, 0, vertdata);
AddCubeVertex(E.x, E.y, E.z, 0, 1, vertdata);
AddCubeVertex(B.x, B.y, B.z, 0, 1, vertdata); //Back
AddCubeVertex(A.x, A.y, A.z, 1, 1, vertdata);
AddCubeVertex(D.x, D.y, D.z, 1, 0, vertdata);
AddCubeVertex(D.x, D.y, D.z, 1, 0, vertdata);
AddCubeVertex(C.x, C.y, C.z, 0, 0, vertdata);
AddCubeVertex(B.x, B.y, B.z, 0, 1, vertdata);
AddCubeVertex(H.x, H.y, H.z, 0, 1, vertdata); //Top
AddCubeVertex(G.x, G.y, G.z, 1, 1, vertdata);
AddCubeVertex(C.x, C.y, C.z, 1, 0, vertdata);
AddCubeVertex(C.x, C.y, C.z, 1, 0, vertdata);
AddCubeVertex(D.x, D.y, D.z, 0, 0, vertdata);
AddCubeVertex(H.x, H.y, H.z, 0, 1, vertdata);
AddCubeVertex(A.x, A.y, A.z, 0, 1, vertdata); //Bottom
AddCubeVertex(B.x, B.y, B.z, 1, 1, vertdata);
AddCubeVertex(F.x, F.y, F.z, 1, 0, vertdata);
AddCubeVertex(F.x, F.y, F.z, 1, 0, vertdata);
AddCubeVertex(E.x, E.y, E.z, 0, 0, vertdata);
AddCubeVertex(A.x, A.y, A.z, 0, 1, vertdata);
AddCubeVertex(A.x, A.y, A.z, 0, 1, vertdata); //Left
AddCubeVertex(E.x, E.y, E.z, 1, 1, vertdata);
AddCubeVertex(H.x, H.y, H.z, 1, 0, vertdata);
AddCubeVertex(H.x, H.y, H.z, 1, 0, vertdata);
AddCubeVertex(D.x, D.y, D.z, 0, 0, vertdata);
AddCubeVertex(A.x, A.y, A.z, 0, 1, vertdata);
AddCubeVertex(F.x, F.y, F.z, 0, 1, vertdata); //Right
AddCubeVertex(B.x, B.y, B.z, 1, 1, vertdata);
AddCubeVertex(C.x, C.y, C.z, 1, 0, vertdata);
AddCubeVertex(C.x, C.y, C.z, 1, 0, vertdata);
AddCubeVertex(G.x, G.y, G.z, 0, 0, vertdata);
AddCubeVertex(F.x, F.y, F.z, 0, 1, vertdata);
}
三维图形(四棱锥)顶点坐标和二位图片(纹理)坐标对应关系如下:
m_iSceneVolumeInit(1)// 绘制贴图显示数量^3
里面数值假设为x,则最终会绘制x^3个四棱锥,我们只需要一个,所以初始化置1。
for (int z = 0; z< m_iSceneVolumeDepth; z++)
{
for (int y = 0; y< m_iSceneVolumeHeight; y++)
{
for (int x = 0; x< m_iSceneVolumeWidth; x++)
{
AddPyramidToScene(vertdataarray);//调用绘制函数 绘制的三维图形和二维图片贴图绑定
//AddCubeToScene(mat, vertdataarray);
mat = mat * Matrix4().translate(m_fScaleSpacing, 0, 0);
}
mat = mat * Matrix4().translate(-((float)m_iSceneVolumeWidth) * m_fScaleSpacing, m_fScaleSpacing, 0);
}
mat = mat * Matrix4().translate(0, -((float)m_iSceneVolumeHeight) * m_fScaleSpacing, m_fScaleSpacing);
}
到这里基本就可以观看四棱锥贴图的VR全景图。
float eyex=0., eyey=0., eyez=0.;//视点
Matrix4 LookAt(1., 0., 0., -eyex,
0., 1., 0., -eyey,
0., 0., 1., -eyez,
0., 0., 0., 1);
void CMainApplication::UpdateHMDMatrixPose()
{// 每帧更新坐标矩阵
if (!m_pHMD)
return;
vr::VRCompositor()->WaitGetPoses(m_rTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, NULL, 0);
m_iValidPoseCount = 0;
m_strPoseClasses = "";
for (int nDevice = 0; nDevice < vr::k_unMaxTrackedDeviceCount; ++nDevice)
{
if (m_rTrackedDevicePose[nDevice].bPoseIsValid)
{
m_iValidPoseCount++;
m_rmat4DevicePose[nDevice] = ConvertSteamVRMatrixToMatrix4(m_rTrackedDevicePose[nDevice].mDeviceToAbsoluteTracking);
if (m_rDevClassChar[nDevice] == 0)
{
switch (m_pHMD->GetTrackedDeviceClass(nDevice))
{
case vr::TrackedDeviceClass_Controller: m_rDevClassChar[nDevice] = 'C'; break;
case vr::TrackedDeviceClass_HMD: m_rDevClassChar[nDevice] = 'H'; break;
case vr::TrackedDeviceClass_Invalid: m_rDevClassChar[nDevice] = 'I'; break;
case vr::TrackedDeviceClass_GenericTracker: m_rDevClassChar[nDevice] = 'G'; break;
case vr::TrackedDeviceClass_TrackingReference: m_rDevClassChar[nDevice] = 'T'; break;
default: m_rDevClassChar[nDevice] = '?'; break;
}
}
m_strPoseClasses += m_rDevClassChar[nDevice];
}
}
if (m_rTrackedDevicePose[vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid)
{
m_mat4HMDPose = m_rmat4DevicePose[vr::k_unTrackedDeviceIndex_Hmd];
m_mat4HMDPose.setColumn(3, Vector4(0, 0, 0, 1));//只旋转 没有近大远小效果(会导致图片扭曲严重) 去掉该行则恢复该效果 视图矩阵=旋转矩阵*平移矩阵 平移矩阵置E
m_mat4HMDPose *= LookAt;//设置视点 默认视点在原点
m_mat4HMDPose.invert();
}
}
后续我会继续介绍一下我对源代码的一些理解。
后续要播放全景视频,只要在每帧渲染函数里添加贴图函数glTexImage2D即可。