openGL ES进阶教程(二)之全景图片
来源:互联网 发布:淘宝 店招 代码 编辑:程序博客网 时间:2024/05/18 01:14
全景又被称为3D实景,是一种新兴的富媒体技术,其与视频,声音,图片等传统的流媒体最大的区别是“可操作,可交互”。 全景分为虚拟现实和3D实景两种。虚拟现实是利用maya等软件,制作出来的模拟现实的场景,代表有虚拟紫禁城等;3D实景是利用单反相机或街景车拍摄实景照片,经过特殊的拼合,处理,让作者立于画境中,让最美的一面展现出来。
全景顾名思义就是给人以三维立体感觉的实景360度全方位图像~
此图像最大的三个特点是:
1、全:全方位,全面的展示了360度球型范围内的所有景致;可在例子中用鼠标左键按住拖动,观看场景的各个方向;
2、景:实景,真实的场景,三维实景大多是在照片基础之上拼合得到的图像,最大限度的保留了场景的真实性;
3、360:360度环视的效果,虽然照片都是平面的,但是通过软件处理之后得到的360度实景,却能给人以三维立体的空间感觉,使观者犹如身在其中。
全景由于它给人们带来全新的真实现场感和交互式的感受。它可广泛应用于三维电子商务,如在线的房地产楼盘展示、虚拟旅游、虚拟教育等领域。
本篇我们基于上一篇粒子光束 的基础上实现全景背景图
看效果图:
我们用连续的6张天空图片,拼接成了一个无缝的立方体。想想一下我们站在这个立方体的中心,这个时候我们的前后左右上下都充满了天空的图片,不管你的头转向哪边,都能够看见天空。
理论上我们把眼睛旋转360度观察,图上的三个光束会先消失在出现,这就像是我们把立方体旋转了360度又回到了原位置一样。就像下图:
之所以能实现360度旋转,是因为我们用了6张图片并把他们加载成一个立方体。
我们先创建一个模型对象类,即立方体模型。
public class Skybox { private static final int POSITION_COMPONENT_COUNT = 3; private final VertexArray vertexArray; private final ByteBuffer indexArray; public Skybox() { // Create a unit cube. vertexArray = new VertexArray(new float[] { -1, 1, 1, // (0) Top-left near 1, 1, 1, // (1) Top-right near -1, -1, 1, // (2) Bottom-left near 1, -1, 1, // (3) Bottom-right near -1, 1, -1, // (4) Top-left far 1, 1, -1, // (5) Top-right far -1, -1, -1, // (6) Bottom-left far 1, -1, -1 // (7) Bottom-right far }); // 6 indices per cube side indexArray = ByteBuffer.allocateDirect(6 * 6) .put(new byte[] { // Front 1, 3, 0, 0, 3, 2, // Back 4, 6, 5, 5, 6, 7, // Left 0, 2, 4, 4, 2, 6, // Right 5, 7, 1, 1, 7, 3, // Top 5, 1, 4, 4, 1, 0, // Bottom 6, 2, 7, 7, 2, 3 }); indexArray.position(0); } public void bindData(SkyboxShaderProgram skyboxProgram) { vertexArray.setVertexAttribPointer(0, skyboxProgram.getPositionAttributeLocation(), POSITION_COMPONENT_COUNT, 0); } public void draw() { glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indexArray); }}
我们用VertexArray储存立方体的8个顶点。用indexArray 这个索引数组的索引指向每个顶点,把所有顶点分别绑定成三角形组,每个组有立方体上每个面的2个三角形。
bindData方法从内存中加载数据绑定,然后通过 glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indexArray);绘制立方体。
下面我们添加着色器
顶点着色器
uniform mat4 u_Matrix;attribute vec3 a_Position; varying vec3 v_Position;void main() { v_Position = a_Position; //把顶点位置传给片段着色器 v_Position.z = -v_Position.z; //反转Z分量。把右手坐标系转化为左手坐标系 gl_Position = u_Matrix * vec4(a_Position, 1.0);//成u_Matrix即用投影~ gl_Position = gl_Position.xyww;//把Z值变成W,这样透视除法之后为1,即Z始终在1的远平面上。Z=1最远,即在别的物体的后面,就像是背景。}
片段着色器:
precision mediump float; uniform samplerCube u_TextureUnit;//立方体纹理varying vec3 v_Position;void main() { gl_FragColor = textureCube(u_TextureUnit, v_Position); }
然后用java代码封装着色器程序
这里用java代码映射到着色器上
uMatrixLocation = glGetUniformLocation(program, U_MATRIX); uTextureUnitLocation = glGetUniformLocation(program, U_TEXTURE_UNIT); aPositionLocation = glGetAttribLocation(program, A_POSITION); } public void setUniforms(float[] matrix, int textureId) { glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, textureId); glUniform1i(uTextureUnitLocation, 0); }
有了关系映射,就可以绑定数据进行绘制了
@onDrawFrame(GL10 gl10)中
skyboxProgram.useProgram(); skyboxProgram.setUniforms(viewProjectionMatrix, skyboxTexture);//映射 skybox.bindData(skyboxProgram);//绑定数据 skybox.draw();//绘制
下面看手势操作代码
在Activity中监听glSurfaceView
glSurfaceView.setOnTouchListener(new View.OnTouchListener() { float previousX, previousY; @Override public boolean onTouch(View v, MotionEvent event) { if (event != null) { if (event.getAction() == MotionEvent.ACTION_DOWN) { previousX = event.getX(); previousY = event.getY(); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { final float deltaX = event.getX() - previousX; final float deltaY = event.getY() - previousY; previousX = event.getX(); previousY = event.getY(); glSurfaceView.queueEvent(new Runnable() { @Override public void run() { particlesRenderer.handleTouchDrag(deltaX, deltaY); } }); } return true; } else { return false; } } });
因为openGL是在一个单独的线程中的,所以需要 glSurfaceView.queueEvent发送事件
把eltaX, deltaY传递到了Renderer类中
public void handleTouchDrag(float deltaX, float deltaY) { xRotation += deltaX / 16f; //除以16是缩减拖动效果的 yRotation += deltaY / 16f;
然后我们根据这个滑动值,用矩阵去操作立方体变化。
@onDrawFrame
//以 0 0 0为中心绘制,我们站在中心观察 private void drawSkybox() { setIdentityM(viewMatrix, 0); rotateM(viewMatrix, 0, -yRotation, 1f, 0f, 0f);//沿着Y轴旋转 rotateM(viewMatrix, 0, -xRotation, 0f, 1f, 0f);//沿着x轴旋转 FPS模型 multiplyMM(viewProjectionMatrix, 0, projectionMatrix, 0, viewMatrix, 0); skyboxProgram.useProgram(); skyboxProgram.setUniforms(viewProjectionMatrix, skyboxTexture); skybox.bindData(skyboxProgram); skybox.draw(); }
在这之前我们要在onSurfaceCreated里面初始化立方体
skyboxProgram = new SkyboxShaderProgram(context); skybox = new Skybox();
@Override public void onSurfaceChanged(GL10 gl10, int width, int height) { GLES20.glViewport(0, 0, width, height); MatrixHelper.perspectiveM(projectionMatrix, 45, (float) width / (float) height, 1f, 10f); }
- openGL ES进阶教程(二)之全景图片
- openGL ES进阶教程(五)制作一个简单的VR播放器,播放全景视频
- openGL ES进阶教程(一)之粒子光束
- openGL ES进阶教程(六)美颜滤镜之美白,磨皮,红润
- openGL ES进阶教程(四)用openGL ES+MediaPlayer 渲染播放视频+滤镜效果
- android3D绘图之OpenGL ES(二)
- Android OpenGL ES绘图教程之二 : 定义形状
- OpenGL ES学习之二
- openGL ES进阶教程(三)用openGL实现动态壁纸,就是这么简单
- Android OpenGL ES 开发教程(二)
- 笔谈OpenGL ES(二)
- OpenGL ES 光照(二)
- OpenGL ES 纹理压缩之ETC (二)
- Android开发之OpenGL+ES教程
- Android开发之OpenGL+ES教程
- iOS开发OpenGL ES教程之透视
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——1.3 用OpenGL ES 2.0显示一张图片(上)
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——1.4 用OpenGL ES 2.0显示一张图片(下)
- continue to wait, or press S to skip mounting or M for manual recovery
- lnmp的搭建——MySQL
- hibernate 学习细节二
- JS中的继承机制
- 对于Java的swing包中的列表框组件的用法
- openGL ES进阶教程(二)之全景图片
- java cookie跨域操作
- 【cocos2dx 3.3 lua】09 lua配置文件读写
- 数据结构--排序算法--快速排序
- 数据库与文件进行数据存储有哪些区别?
- 蓝桥杯第六届决赛:表格计算
- BZOJ 2241 [SDOI2011] 打地鼠
- 超声波风速风向仪的工作原理
- 对象的序列化和Socket简单使用