vr四棱锥视频文件通过opengl在手机端播放全景视频

输入是一个正方形vr四棱锥变换后的视频,目的是手机上反映射播放全景视频。

app的demo基于native-media进行改动,因为大部分都是针对opengl ES的改动,所以主要修改文件为MyGLSurfaceView.java。

其他改动都是些界面或者按钮的改动,这里不赘述了。这里主要讲解一下opengl这部分的流程。


对应opengl函数请参考网上的文档

https://www.khronos.org/opengles/sdk/docs/man3/


1. 建立两个shader,vertexShader和fragmentShader,并创建program。

    每个shader都需要设定shader,编译shader,最后绑定到新建的program上。
    两个shader的输入是类C语言。具体参见另一篇文章,《Shader语言的一些简单解释和备注》

2. Shader如何作图。主要依赖两个数组:mVerticesValue[],mPositionValue[]。前者为目的投影点坐标,为三维坐标x,y,z。范围没有限制,只要保证比例就可以了。后者为原始图像上的点UV二维坐标,范围均为0~1。按比例对其进行选择。画图一般按三角形进行画图。

3. 建立一个texture(在显存中)

        int[] textures = new int[1];
        GLES30.glGenTextures(1, textures, 0);
        mTextureID = textures[0];

4. 绑定texture。因为是YUV数据所以绑定GL_TEXTURE_EXTERNAL_OES

  The GL_TEXTURE_EXTERNAL_OES texture target isusually in a YUV color space

GLES30.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);

5. 设置参数,用于texture缩放时如何处理

        // Can't do mipmapping with camera source
        GLES30.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_MIN_FILTER,
                //GLES30.GL_NEAREST);
				GLES30.GL_LINEAR);
        GLES30.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_MAG_FILTER,
                //GLES30.GL_NEAREST);
                GLES30.GL_LINEAR);
        // Clamp to edge is the only option
        GLES30.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_WRAP_S,<pre name="code" class="java">        mVerticesV.position(0);
        GLES30.glVertexAttribPointer(maPositionHandle, 3, GLES30.GL_FLOAT, false, 3 * FLOAT_SIZE_BYTES, mVerticesV);
        GLES30.glEnableVertexAttribArray(maPositionHandle);
        mPositionV.position(0);
        GLES30.glVertexAttribPointer(maTextureHandle, 2, GLES30.GL_FLOAT, false, 2 * FLOAT_SIZE_BYTES, mPositionV);
        GLES30.glEnableVertexAttribArray(maTextureHandle);

GLES30.GL_CLAMP_TO_EDGE); GLES30.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);

 

6. 创建一个surface(用于内存),用于给这个texture(显存中)送数据。绑定监听

        mSurface = new SurfaceTexture(mTextureID);
        mSurface.setOnFrameAvailableListener(this);

7. 准备画一幅图时,会来到onDrawFrame()。首先activate texture0,绑定当前创建的texture到GL_TEXTURE_EXTERNAL_OES上。

<pre name="code" class="java"><pre name="code" class="java">        GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT);
        GLES30.glUseProgram(mProgram);
        checkGlError("glUseProgram");

        GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
        GLES30.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);

 
 

8. 把需要画的顶点数组和纹理位置数组绑定,一个三维的用于重建,一个二维的是输入图像坐标

        mVerticesV.position(0);
        GLES30.glVertexAttribPointer(maPositionHandle, 3, GLES30.GL_FLOAT, false, 3 * FLOAT_SIZE_BYTES, mVerticesV);
        GLES30.glEnableVertexAttribArray(maPositionHandle);
        mPositionV.position(0);
        GLES30.glVertexAttribPointer(maTextureHandle, 2, GLES30.GL_FLOAT, false, 2 * FLOAT_SIZE_BYTES, mPositionV);
        GLES30.glEnableVertexAttribArray(maTextureHandle);

9. 设置观察点位置和方向。第二行三个坐标表示观察点坐标,例子中是原点。第二组3个坐标表示看的方向向量,可以变化。第三组大概意思是摄像机怎么摆放,可以理解为摄像师人头的坐标,(0,1,0)表示站在xz平面上,头在y正方向。 可以参考文章:http://blog.csdn.net/a7178077/article/details/38014373

        Matrix.setLookAtM(mVMatrix, 0, 
                                    0f, 0f, 0f, 
                                    lookX, lookY, lookZ, 
                                    0f, 1f, 0.0f);

10. 不太好解释frustum这个方法,怕误导,照搬一个解释放这:View frustum is justa visual representation of perspective projection that is used to convert 3Dpoint in the world coordinate space to the 2D point on the screen.

void glFrustum(GLdouble left, GLdouble Right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
创建一个透视型的视景体。其操作是创建一个透视投影的矩阵,并且用这个矩阵乘以当前矩阵。这个函数的参数只定义近裁剪平面的左下角点和右上角点的三维空间坐标,即(left,bottom,-near)和(right,top,-near);最后一个参数far是远裁剪平面的离视点的距离值,其左下角点和右上角点空间坐标由函数根据透视投影原理自动生成。near和far表示离视点的远近,它们总为正值(near/far 必须>0)。


final float ratio = 0.7f;

        Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -ratio, ratio, 1f, 10f);

11.  一些对数组的操作以及使能(具体没太深究,也没有修改这部分),最后调用GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 18) 画图。第一个参数表示按三角形画图,第二个参数表示输入一共有18个顶点,也就是6个三角形。

        Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);

        GLES30.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
        GLES30.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0);
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 18);

下面是我的顶点和纹理坐标数组,涉及到转四棱锥时的扩充参数以及反变换去缝的操作,也和四个三角形中心点取值位置有关,仅供参考。

// size 18
private final float[] mVerticesValue = {
    // X, Y, Z,
    0.f,  0.f, -3.16987f,	// O
    -5.f,  0.f, 1.830127f,	// A
    0.f, -5.f, 1.830127f,	// D
    
    0.f,  0.f, -3.16987f,	// O
    0.f, -5.f, 1.830127f,	// D
    5.f,  0.f, 1.830127f,	// C
    
    0.f,  0.f, -3.16987f,	// O
    5.f,  0.f, 1.830127f,	// C
    0.f,  5.f, 1.830127f,	// B
    
    0.f,  0.f, -3.16987f,	// O
    0.f,  5.f, 1.830127f,	// B
    -5.f,  0.f, 1.830127f,	// A
    
    // square
    0.f,  5.f, 1.830127f,	// B
    -5.f,  0.f, 1.830127f,	// A
    0.f, -5.f, 1.830127f,	// D
    
    0.f,  5.f, 1.830127f,	// B
    0.f, -5.f, 1.830127f,	// D
    5.f,  0.f, 1.830127f,	// C
};

private final float[] mPositionValue = {
    // U, V   1.1					
    0.005769f,	0.005769f,	// O(OAD
    0.005769f,	0.486538f,	// A	
    0.486538f,	0.005769f,	// D	
    
    0.994231f,	0.005769f, // O(ODC 
    0.513462f,	0.005769f, // D 	
    0.994231f,	0.486538f, // C 	
    
    0.994231f,	0.994231f,	// O(OCB
    0.994231f,	0.513462f,	// C	
    0.513462f,	0.994231f,	// B	
    
    0.005769f,	0.994231f,	// O(OBA
    0.486538f,	0.994231f,	// B	
    0.005769f,	0.513462f,	// A	
    
    // square						
    0.5f,		0.980769f,	// B	
    0.019231f,	0.5f,  // A 		
    0.5f,		0.019231f,	// D	
    
    0.5f,		0.980769f,	// B	
    0.5f,		0.019231f,	// D	
    0.980769f,	0.5f,  // C 		
};	

最后输出一下结果图。原始vr视频的截图如下:


四棱锥变换后的视频如下:


手机上通过opengl ES渲染为全景视频效果,角度正面偏左,可随意变换角度(无缝):



 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要实现这个效果,您可以按照以下步骤进行操作: 1. 创建一个棱锥的模型,并将其导入到场景中。 2. 为每个面创建一个不同的材质,并将其分配给棱锥的各个面。 3. 对于每个面,使用顶点着色的方法将颜色渐变效果应用到每个顶点。这可以通过在每个顶点处指定不同的颜色值来实现。 4. 保存您的场景并查看效果。 下面是一个示例代码片段,可以帮助您实现此效果: ```javascript // 创建棱锥的模型 var geometry = new THREE.ConeGeometry( 5, 10, 4 ); // 创建个不同的材质 var material1 = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); var material2 = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); var material3 = new THREE.MeshBasicMaterial( { color: 0x0000ff } ); var material4 = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); // 将材质分配给棱锥的各个面 var materials = [ material1, material2, material3, material4 ]; var mesh = new THREE.Mesh( geometry, materials ); // 对于每个面,使用顶点着色的方法将颜色渐变效果应用到每个顶点 for ( var i = 0; i < mesh.geometry.vertices.length; i ++ ) { var vertex = mesh.geometry.vertices[ i ]; var color = new THREE.Color( 0xffffff ); color.setRGB( vertex.x / 10 + 0.5, vertex.y / 10 + 0.5, vertex.z / 10 + 0.5 ); mesh.geometry.colors[ i ] = color; } // 启用顶点颜色 mesh.geometry.colorsNeedUpdate = true; // 将棱锥添加到场景中 scene.add( mesh ); ``` 请注意,此示例代码仅用于说明目的,您可能需要进行适当的修改才能使其适用于您的场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值