OpenGL ES實踐教程(六)全景視頻獲取焦點

教程

OpenGL ES實踐教程1-Demo01-AVPlayer
OpenGL ES實踐教程2-Demo02-攝像頭采集數(shù)據(jù)和渲染
OpenGL ES實踐教程3-Demo03-Mirror
OpenGL ES實踐教程4-Demo04-VR全景視頻播放
OpenGL ES實踐教程5-Demo05-多重紋理實現(xiàn)圖像混合
其他教程請移步OpenGL ES文集

前言

有開發(fā)者在群里問如何實現(xiàn):

觀看VR視頻的時候,眼神停在菜單上,稍后會觸發(fā)事件,比如暫停,重放功能

說說可能的方案:

  • 1、添加外設(shè):采集眼球運動和眨眼操作,并通過無線通訊傳給手機;
  • 2、離屏渲染:新建緩沖區(qū),把像素是否能操作編碼到顏色分量(RGBA均可),按照屏幕渲染的流程在新的緩沖區(qū)內(nèi)渲染,然后通過glReadPixel讀取對應(yīng)像素的操作;
  • 3、模擬計算:假設(shè)有一條直線從視點出發(fā),經(jīng)過焦點,最終與全景球面相交,通過計算交點是否在按鈕上確定是否聚焦成功;

方案1是理想的方案,但實際應(yīng)用開發(fā)成本,成本太高;
方案2需要離屏渲染,首先切換幀緩存導致GPU等待;其次,每次聚焦都要重繪(當用戶一直移動屏幕的時候,需要不斷重繪);最后,glReadPixel是同步操作,對性能有較大的影響;
方案3是較為合理的實現(xiàn)方案,僅需要CPU進行少量的浮點變化運算,不需要外設(shè)和離屏渲染;
本文在OpenGL ES實踐教程4-Demo04-VR全景視頻播放的基礎(chǔ)上,添加簡單的色塊,單焦點進入色塊時進行變色。

核心思路

通過計算全景球面上的點經(jīng)過旋轉(zhuǎn)投影后的位置,來確定當前焦點是否停留在按鈕上。

  • 實現(xiàn)1:從攝像機的視點O(0,0,0)到的焦點P(0.5,0.5,0.5)連接一條直線PO,求出直線與全景球面X2+Y2+Z^2=1上面的交點T。
    當攝像機旋轉(zhuǎn)的時候,焦點P不斷變化,對新的焦點P’,按照上述的方式求出點T’,判斷點T’是否在球面的按鈕區(qū)域;

可以通過手寫,我們知道直線OP的方程為2x-1=2y-1=2z-1
聯(lián)合方程,可以求出交點T(1/sqrt(3), 1/sqrt(3), 1/sqrt(3) )。
當攝像機旋轉(zhuǎn)的時候,再求出對應(yīng)的交點即可。

  • 實現(xiàn)2:假設(shè)點P是按鈕的中心,對點P進行旋轉(zhuǎn)、投影等變換后,求出點P在屏幕上的位置,如果點P在焦點范圍內(nèi),則認為聚焦;

demo采用的是實現(xiàn)2。

效果展示

具體細節(jié)

先把OpenGL ES實踐教程4-Demo04-VR全景視頻播放的工程拖過來。

1、添加表示按鈕的色塊

  • 在頂點著色器添加varying lowp vec3 varyOtherPostion變量,傳遞頂點數(shù)據(jù)到像素著色器;
  • 新建變量leftBottomrightTop、myTexture1表示按鈕的區(qū)域和按鈕的紋理;
varying lowp vec2 texCoordVarying;
varying lowp vec3 varyOtherPostion;
precision mediump float;
uniform sampler2D SamplerY;
uniform sampler2D SamplerUV;
uniform mat3 colorConversionMatrix;
uniform vec2 leftBottom;
uniform vec2 rightTop;
uniform sampler2D myTexture1;
void main()
{
    mediump vec3 yuv;
    lowp vec3 rgb;
    
    // Subtract constants to map the video range start at 0
    yuv.x = (texture2D(SamplerY, texCoordVarying).r);// - (16.0/255.0));
    yuv.yz = (texture2D(SamplerUV, texCoordVarying).ra - vec2(0.5, 0.5));
    
    rgb = colorConversionMatrix * yuv;
    
    if (varyOtherPostion.x >= leftBottom.x && varyOtherPostion.y >= leftBottom.y && varyOtherPostion.x <= rightTop.x && varyOtherPostion.y <= rightTop.y && varyOtherPostion.z > 0.0) {
        lowp vec2 test = vec2((varyOtherPostion.x - leftBottom.x) / (rightTop.x - leftBottom.x), 1.0 -  (varyOtherPostion.y - leftBottom.y) / (rightTop.y - leftBottom.y));
        lowp vec4 otherColor = texture2D(myTexture1, test);
        otherColor.a = 0.5;
        gl_FragColor = otherColor * otherColor.a + vec4(rgb, 1.0) * (1.0 - otherColor.a);
    }
    else {
        gl_FragColor = vec4(rgb, 1.0);
    }
}
  • 在中LYOpenGLView.m中獲取對應(yīng)的變量并賦值;
glUniform1i(uniforms[UNIFORM_TEXTURE1], 2);
glUniform2f(uniforms[UNIFORM_LEFT_BOTTOM], -0.25, -0.25);
glUniform2f(uniforms[UNIFORM_RIGHT_TOP], 0.25, 0.25);

2、監(jiān)聽手指移動并判斷聚焦

  • 添加初始點position,我們假設(shè)是(0, 0, -1, 1);
GLKVector4 position = GLKVector4Make(0, 0, -1, 1);
  • 計算變化矩陣,求出變換后的點targetPosition;
    GLKMatrix4 modelViewMatrix = GLKMatrix4Identity;
    modelViewMatrix = GLKMatrix4RotateX(modelViewMatrix, horizontalDegree);
    modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, verticalDegree);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(90, CGRectGetWidth(self.bounds) * 1.0 / CGRectGetHeight(self.bounds), 0.01, 10);
    GLKVector4 position = GLKVector4Make(0, 0, -1, 1);
    GLKVector4 targetPosition = GLKMatrix4MultiplyVector4(GLKMatrix4Multiply(projectionMatrix, modelViewMatrix), position);
  • 判斷是否聚焦成功;(點(0.2, -0.05, -1.0)是根據(jù)初始點算出來的聚焦中心位置,如果初始點變化,這個點也要跟著變化)
  float dif = 0.3;
  if (fabs(targetPosition.x - 0.2) <= dif &&
      fabs(targetPosition.y + 0.05) <= dif &&
      fabs(targetPosition.z + 1.00) <= dif &&
      1) {
      [self setupFirstTexture:@"select"];
  }
  else {
      [self setupFirstTexture:@"normal"];
  }

總結(jié)

本文存在各種不嚴謹?shù)牡胤?,僅供參考。
中間在手動計算空間直線方程的時候,還計算錯誤,通過空間直線方程得到糾正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容