OpenGL ES實(shí)踐教程(六)全景視頻獲取焦點(diǎn)

教程

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

前言

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

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

說說可能的方案:

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

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

核心思路

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

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

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

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

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

效果展示

具體細(xì)節(jié)

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

1、添加表示按鈕的色塊

  • 在頂點(diǎn)著色器添加varying lowp vec3 varyOtherPostion變量,傳遞頂點(diǎn)數(shù)據(jù)到像素著色器;
  • 新建變量leftBottom、rightTop、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中獲取對(duì)應(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)聽手指移動(dòng)并判斷聚焦

  • 添加初始點(diǎn)position,我們假設(shè)是(0, 0, -1, 1);
GLKVector4 position = GLKVector4Make(0, 0, -1, 1);
  • 計(jì)算變化矩陣,求出變換后的點(diǎn)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);
  • 判斷是否聚焦成功;(點(diǎn)(0.2, -0.05, -1.0)是根據(jù)初始點(diǎn)算出來的聚焦中心位置,如果初始點(diǎn)變化,這個(gè)點(diǎn)也要跟著變化)
  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é)

本文存在各種不嚴(yán)謹(jǐn)?shù)牡胤?,僅供參考。
中間在手動(dòng)計(jì)算空間直線方程的時(shí)候,還計(jì)算錯(cuò)誤,通過空間直線方程得到糾正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容