教程
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ù)到像素著色器; - 新建變量
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中獲取對應(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ù)牡胤?,僅供參考。
中間在手動計算空間直線方程的時候,還計算錯誤,通過空間直線方程得到糾正。