[转载]OpenGL ES基础教程 - Android实例教程 - Android开发论坛 - 安卓开发论坛 - Android开发 - 安卓论坛 - 移动互联网门户

mikel阅读(671)

OpenGL ES基础教程 ,Android开发论坛 – 安卓开发论坛 – Android开发 – 安卓论坛 – 移动互联网门户

来源: [转载]OpenGL ES基础教程 – Android实例教程 – Android开发论坛 – 安卓开发论坛 – Android开发 – 安卓论坛 – 移动互联网门户

一、设置OpenGL ES视图

设置OpenGL视图并不难,Android上也较简单。我们一般只需要2个步骤。

GLSurfaceView

我们要为GLSurfaceView提供一个专门用于渲染的接口

public void  setRenderer(GLSurfaceView.Renderer renderer)

 

GLSurfaceView.Renderer

GLSurfaceView.Renderer是一个通用渲染接口。我们必须实现下面的三个抽象方法:

// 画面创建

public void onSurfaceCreated(GL10 gl, EGLConfig config)

// 画面绘制

public void onDrawFrame(GL10 gl)

// 画面改变

public void onSurfaceChanged(GL10 gl, int width, int height)

onSurfaceCreated

在这里我们主要进行一些初始化工作,比如对透视进行修正、设置清屏所用颜色等。

onDrawFrame

绘制当前画面

onSurfaceChanged

当设备水平或者垂直变化时调用此方法,设置新的显示比例

 

案例代码:

 

  1. public class OpenGLDemo extends Activity {
  2.     @Override
  3.     public void onCreate(Bundle savedInstanceState) {
  4.         GLSurfaceView view = new GLSurfaceView(this);
  5.         view.setRenderer(new OpenGLRenderer());
  6.         setContentView(view);
  7.     }
  8. }

复制代码

实现renderer需要更多的设置

  1.     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  2.         // 黑色背景
  3.         gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
  4.         // 启用阴影平滑(不是必须的)
  5.         gl.glShadeModel(GL10.GL_SMOOTH);
  6.         // 设置深度缓存
  7.         gl.glClearDepthf(1.0f);
  8.         // 启用深度测试
  9.         gl.glEnable(GL10.GL_DEPTH_TEST);
  10.         // 所作深度测试的类型
  11.         gl.glDepthFunc(GL10.GL_LEQUAL);
  12.         // 对透视进行修正
  13.         gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
  14.     }
  15.     public void onDrawFrame(GL10 gl) {
  16.         // 清除屏幕和深度缓存
  17.         gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
  18.     }
  19.     public void onSurfaceChanged(GL10 gl, int width, int height) {
  20.         // 设置画面的大小
  21.         gl.glViewport(0, 0, width, height);
  22.         // 设置投影矩阵
  23.         gl.glMatrixMode(GL10.GL_PROJECTION);
  24.         // 重置投影矩阵
  25.         gl.glLoadIdentity();
  26.         // 设置画面比例
  27.         GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f,100.0f);
  28.         // 选择模型观察矩阵
  29.         gl.glMatrixMode(GL10.GL_MODELVIEW);
  30.         // 重置模型观察矩阵
  31.         gl.glLoadIdentity();
  32.     }
  33. }

复制代码

只要加入这段代码到OpenGLDemo class里就可实现全屏this.requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
设置完视图后,即可编译运行,可以看到一个“漂亮”的黑屏 = =!

OpenGLDemo01.rar (48.38 KB, 下载次数: 209)

 

二、绘制多边形前面的教程都是关于设置GLSurfaceView.的,接下来的教程将教我们渲染出一个多边形。3D模型用较小的元素创建(点,边,面),他们可以被分别操作。
顶点

 

在Android中,我们通过float数组定义顶点,并将它放到字节型缓冲区内来获取更好的性能。下例的代码即为上图所示顶点。OpenGL ES的很多功能都必须手动的开启和关闭。

  1. gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  2. // 设置顶点数据,3代表XYZ坐标系
  3. gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
  4. // 关闭顶点设置
  5. gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

复制代码

计算多边形面的时候,一定要注意正确的方向.。因为这将决定哪一面为正面哪一面为背面。 所以我们尽量保证整个项目都使用相同的环绕。gl.glFrontFace(GL10.GL_CCW);控制多边形的正面是如何决定的。在默认情况下,mode是GL_CCW。mode的值为:   GL_CCW 表示窗口坐标上投影多边形的顶点顺序为逆时针方向的表面为正面。   GL_CW 表示顶点顺序为顺时针方向的表面为正面。顶点的方向又称为环绕。gl.glEnable(GL10.GL_CULL_FACE);gl.glCullFace(GL10.GL_BACK);剔除多边形的背面,禁用多边形背面上的光照、阴影和颜色计算及操作。gl.glDisable(GL10.GL_CULL_FACE);
多边形

到了绘制面的时候了, 我们使用默认的逆时针环绕。下例代码将绘制上图多边形。

  1.     // 将坐标数组放入字节缓存中
  2.     // (1) 分配缓存,一个short为2个字节,所以要乘以2
  3.     ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
  4.     // (2) 设置字节处理规则
  5.     ibb.order(ByteOrder.nativeOrder());
  6.     // (3) 转换为short型字符
  7.     ShortBuffer indexBuffer = ibb.asShortBuffer();
  8.     // (4) 放入坐标数组
  9.     indexBuffer.put(indices);
  10.     // (5) 复位
  11.     indexBuffer.position(0);

复制代码

渲染是时候弄些玩意儿到屏幕上去了,绘制时我们将用到两个函数public abstract void glDrawArrays(int mode, int first, int count)通过我们构造的顶点缓存来绘制顶点public abstract void glDrawElements(int mode, int count, int type, Buffer indices)和 glDrawArrays类似,但需要直接传入type(索引值的类型,如GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT),和indices(索引缓存)两者的共同点是,都必须知道他们需要画什么。怎样渲染图元,有不同方式,为了帮助调试, 我们应该了解它们。
Mode:GL_POINTS绘制独立的点到屏幕

GL_LINE_STRIP连续的连线,第n个顶点与第n-1个顶点绘制一条直线

GL_LINE_LOOP和上面相同,但首尾相连

GL_LINES各对独立的线段

GL_TRIANGLES各个独立的三角形

GL_TRIANGLE_STRIP
绘制一系列的三角形,先是顶点 v0, v1, v2, 然后是 v2, v1, v3 (注意规律), 然后v2, v3, v4等。该规律确保所有的三角形都以相同的方向绘制。

GL_TRIANGLE_FAN和GL_TRIANGLE_STRIP类似, 但其先绘制 v0, v1, v2, 再是 v0, v2, v3, 然后 v0, v3, v4等。
我认为GL_TRIANGLES是使用最方便的,所以我们将先使用它。

  1. public class Square {
  2.     // 顶点坐标数组
  3.     private float vertices[] = { -1.0f, 1.0f, 0.0f, // 0, 左上
  4.         -1.0f, -1.0f, 0.0f, // 1, 左下
  5.         1.0f, -1.0f, 0.0f, // 2, 右下
  6.         1.0f, 1.0f, 0.0f, // 3, 右上
  7.     };
  8.     // 连接规则
  9.     private short[] indices = { 0, 1, 2, 0, 2, 3 };
  10.     // 顶点缓存
  11.     private FloatBuffer vertexBuffer;
  12.     // 索引缓存
  13.     private ShortBuffer indexBuffer;
  14.     public Square() {
  15.         // 一个float为4 bytes, 因此要乘以4
  16.         ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
  17.         vbb.order(ByteOrder.nativeOrder());
  18.         vertexBuffer = vbb.asFloatBuffer();
  19.         vertexBuffer.put(vertices);
  20.         vertexBuffer.position(0);
  21.         // short类型同理
  22.         ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
  23.         ibb.order(ByteOrder.nativeOrder());
  24.         indexBuffer = ibb.asShortBuffer();
  25.         indexBuffer.put(indices);
  26.         indexBuffer.position(0);
  27.         }
  28.     /**
  29.      * 绘制正方形到屏幕
  30.      *
  31.      * @param gl
  32.      */
  33.     public void draw(GL10 gl) {
  34.         // 逆时针环绕
  35.         gl.glFrontFace(GL10.GL_CCW);
  36.         // 开启剔除功能
  37.         gl.glEnable(GL10.GL_CULL_FACE);
  38.         // 剔除背面
  39.         gl.glCullFace(GL10.GL_BACK);
  40.         // 开启顶点缓存写入功能
  41.         gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  42.         // 设置顶点
  43.         // size:每个顶点有几个数指描述。
  44.         // type:数组中每个顶点的坐标类型。
  45.         // stride:数组中每个顶点间的间隔,步长(字节位移)。
  46.         // pointer:存储着每个顶点的坐标值。初始值为0
  47.         gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
  48.         gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
  49.         GL10.GL_UNSIGNED_SHORT, indexBuffer);
  50.         // 关闭各个功能
  51.         gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
  52.         gl.glDisable(GL10.GL_CULL_FACE);
  53.     }
  54. }

复制代码

我们必须在OpenGLRenderer类中初始化square

  1. square = new Square();<!–EndFragment–>

复制代码

并在主绘制方法中调用square的绘制方法

  1. public void onDrawFrame(GL10 gl) {
  2.     // 清除屏幕和深度缓存
  3.     gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
  4.     // 绘制正方形
  5.     square.draw(gl);
  6. }

复制代码

如果你现在运行应用,我们又看到了华丽的黑屏,为什么?因为OpenGL ES渲染默认的当前位置为(0,0,0),窗口的定位也一样。而且OpenGL ES不渲染太靠近窗体定位的东西。解决方法就是移动绘制的位置。

  1. gl.glTranslatef(0, 0, -4);  <!–EndFragment–>

复制代码

再次运行应用你将看到该正方形已经被绘制,但是它好像离我们越来越远一样,最后消失了。OpenGL ES不会在画面之间复位绘制点,所以我们要自己完成。

  1. // 重置当前的模型观察矩阵
  2. gl.glLoadIdentity();<!–EndFragment–>

复制代码

现在,我们运行应用将会看到一个固定位置的正方形。

OpenGLDemo02.rar (64.87 KB, 下载次数: 279)

[转载]玩转Android Camera开发(三):国内首发---使用GLSurfaceView预览Camera 基础拍照demo - chenlinyunyi - 博客园

mikel阅读(796)

来源: [转载][转载]玩转Android Camera开发(三):国内首发—使用GLSurfaceView预览Camera 基础拍照demo – chenlinyunyi – 博客园

GLSurfaceView 是OpenGL中的一个类,也是可以预览Camera的,而且在预览Camera上有其独到之处。独到之处在哪?当使用Surfaceview无能为力、 痛不欲生时就只有使用GLSurfaceView了,它能够真正做到让Camera的数据和显示分离,所以搞明白了这个,像Camera只开预览不显示这 都是小菜,妥妥的。Android4.0的自带Camera源码是用SurfaceView预览的,但到了4.2就换成了GLSurfaceView来预 览。如今到了4.4又用了自家的TextureView,所以从中可以窥探出新增TextureView的用意。

虽 说Android4.2的Camera源码是用GLSurfaceView预览的,但是进行了大量的封装又封装的,由于是OpenGL小白,真是看的不知 所云。俺滴要求不高,只想弄个可拍照的摸清GLSurfaceView在预览Camera上的使用流程。经过一番百度一无所获,后来翻出去Google一 大圈也没发现可用的。倒是很多人都在用GLSurfaceView和Surfaceview同时预览Camera,Surfaceview用来预览数据, 在上面又铺了一层GLSurfaceView绘制一些信息。无奈自己摸索,整出来的是能拍照也能得到数据,但是界面上不是一块白板就是一块黑板啥都不显 示。后来在stackoverflow终于找到了一个可用的链接,哈哈,苍天啊,终于柳暗花明了!参考此链接,自己又改改摸索了一天才彻底搞定。之所以费这么多时间是不明白OpenGL ES2.0的绘制基本流程,跟简单的OpenGL的绘制还是稍有区别。下面上源码:

一、CameraGLSurfaceView.java 此类继承GLSurfaceView,并实现了两个接口

  1. <span style=“font-family:Comic Sans MS;font-size:18px;”>package org.yanzi.camera.preview;  
  2. import javax.microedition.khronos.egl.EGLConfig;  
  3. import javax.microedition.khronos.opengles.GL10;  
  4. import org.yanzi.camera.CameraInterface;  
  5. import Android.content.Context;  
  6. import android.graphics.SurfaceTexture;  
  7. import android.opengl.GLES11Ext;  
  8. import android.opengl.GLES20;  
  9. import android.opengl.GLSurfaceView;  
  10. import android.opengl.GLSurfaceView.Renderer;  
  11. import android.util.AttributeSet;  
  12. import android.util.Log;  
  13. public class CameraGLSurfaceView extends GLSurfaceView implements Renderer, SurfaceTexture.OnFrameAvailableListener {  
  14.     private static final String TAG = “yanzi”;  
  15.     Context mContext;
  16.     SurfaceTexture mSurface;
  17.     int mTextureID = –1;  
  18.     DirectDrawer mDirectDrawer;
  19.     public CameraGLSurfaceView(Context context, AttributeSet attrs) {  
  20.         super(context, attrs);  
  21.         // TODO Auto-generated constructor stub  
  22.         mContext = context;
  23.         setEGLContextClientVersion(2);  
  24.         setRenderer(this);  
  25.         setRenderMode(RENDERMODE_WHEN_DIRTY);
  26.     }
  27.     @Override  
  28.     public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
  29.         // TODO Auto-generated method stub  
  30.         Log.i(TAG, “onSurfaceCreated…”);  
  31.         mTextureID = createTextureID();
  32.         mSurface = new SurfaceTexture(mTextureID);  
  33.         mSurface.setOnFrameAvailableListener(this);  
  34.         mDirectDrawer = new DirectDrawer(mTextureID);  
  35.         CameraInterface.getInstance().doOpenCamera(null);  
  36.     }
  37.     @Override  
  38.     public void onSurfaceChanged(GL10 gl, int width, int height) {  
  39.         // TODO Auto-generated method stub  
  40.         Log.i(TAG, “onSurfaceChanged…”);  
  41.         GLES20.glViewport(0, 0, width, height);  
  42.         if(!CameraInterface.getInstance().isPreviewing()){  
  43.             CameraInterface.getInstance().doStartPreview(mSurface, 1.33f);  
  44.         }
  45.     }
  46.     @Override  
  47.     public void onDrawFrame(GL10 gl) {  
  48.         // TODO Auto-generated method stub  
  49.         Log.i(TAG, “onDrawFrame…”);  
  50.         GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);  
  51.         GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
  52.         mSurface.updateTexImage();
  53.         float[] mtx = new float[16];  
  54.         mSurface.getTransformMatrix(mtx);
  55.         mDirectDrawer.draw(mtx);
  56.     }
  57.     @Override  
  58.     public void onPause() {  
  59.         // TODO Auto-generated method stub  
  60.         super.onPause();  
  61.         CameraInterface.getInstance().doStopCamera();
  62.     }
  63.     private int createTextureID()  
  64.     {
  65.         int[] texture = new int[1];  
  66.         GLES20.glGenTextures(1, texture, 0);  
  67.         GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[0]);  
  68.         GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
  69.                 GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR);
  70.         GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
  71.                 GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
  72.         GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
  73.                 GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
  74.         GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
  75.                 GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
  76.         return texture[0];  
  77.     }
  78.     public SurfaceTexture _getSurfaceTexture(){  
  79.         return mSurface;  
  80.     }
  81.     @Override  
  82.     public void onFrameAvailable(SurfaceTexture surfaceTexture) {  
  83.         // TODO Auto-generated method stub  
  84.         Log.i(TAG, “onFrameAvailable…”);  
  85.         this.requestRender();  
  86.     }
  87. }
  88. </span>

关于这个类进行简单说明:

1、 Renderer这个接口里有三个回调: onSurfaceCreated() onSurfaceChanged() onDrawFrame(), 在onSurfaceCreated里设置了GLSurfaceView的版本: setEGLContextClientVersion(2); 如果没这个设置是啥都画不出来了,因为Android支持OpenGL ES1.1和2.0及最新的3.0,而且版本间差别很大。不告诉他版本他不知道用哪个版本的api渲染。在设置setRenderer(this);后, 再设置它的模式为RENDERMODE_WHEN_DIRTY。这个也很关键,看api:

When renderMode is RENDERMODE_CONTINUOUSLY, the renderer is called repeatedly to re-render the scene. When renderMode is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface is created, or when requestRender is called. Defaults to RENDERMODE_CONTINUOUSLY.

Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance by allowing the GPU and CPU to idle when the view does not need to be updated.

大 意是RENDERMODE_CONTINUOUSLY模式就会一直Render,如果设置成RENDERMODE_WHEN_DIRTY,就是当有数据时 才rendered或者主动调用了GLSurfaceView的requestRender.默认是连续模式,很显然Camera适合脏模式,一秒30 帧,当有数据来时再渲染。

2、 正因是RENDERMODE_WHEN_DIRTY所以就要告诉GLSurfaceView什么时候Render,也就是啥时候进到 onDrawFrame()这个函数里。SurfaceTexture.OnFrameAvailableListener这个接口就干了这么一件事,当 有数据上来后会进到

public void onFrameAvailable(SurfaceTexture surfaceTexture) {
// TODO Auto-generated method stub
Log.i(TAG, “onFrameAvailable…”);
this.requestRender();
}

这里,然后执行requestRender()。

3、网上有一些OpenGL ES的示例是在Activity里实现了SurfaceTexture.OnFrameAvailableListener此接口,其实这个无所谓。无论是被谁实现,关键看在回调里干了什么事。

4、与TextureView里对比可知,TextureView预览时因为实现了SurfaceTextureListener会自动创建SurfaceTexture。但在GLSurfaceView里则要手动创建同时绑定一个纹理ID。

5、 本文在onSurfaceCreated()里打开Camera,在onSurfaceChanged()里开启预览,默认1.33的比例。原因是相比前 两种预览,此处SurfaceTexture创建需要一定时间。如果想要开预览时由Activity发起,则要GLSurfaceView利用 Handler将创建的SurfaceTexture传递给Activity。

 

二、DirectDrawer.java 此类非常关键,负责将SurfaceTexture内容绘制到屏幕上

  1. <span style=“font-family:Comic Sans MS;font-size:18px;”>package org.yanzi.camera.preview;  
  2. import java.nio.ByteBuffer;  
  3. import java.nio.ByteOrder;  
  4. import java.nio.FloatBuffer;  
  5. import java.nio.ShortBuffer;  
  6. import android.opengl.GLES11Ext;  
  7. import android.opengl.GLES20;  
  8. import android.opengl.Matrix;  
  9. public class DirectDrawer {  
  10.     private final String vertexShaderCode =  
  11.             “attribute vec4 vPosition;” +  
  12.             “attribute vec2 inputTextureCoordinate;” +  
  13.             “varying vec2 textureCoordinate;” +  
  14.             “void main()” +  
  15.             “{“+  
  16.                 “gl_Position = vPosition;”+  
  17.                 “textureCoordinate = inputTextureCoordinate;” +  
  18.             “}”;  
  19.     private final String fragmentShaderCode =  
  20.             “#extension GL_OES_EGL_image_external : require\n”+  
  21.             “precision mediump float;” +  
  22.             “varying vec2 textureCoordinate;\n” +  
  23.             “uniform samplerExternalOES s_texture;\n” +  
  24.             “void main() {” +  
  25.             ”  gl_FragColor = texture2D( s_texture, textureCoordinate );\n” +  
  26.             “}”;  
  27.     private FloatBuffer vertexBuffer, textureVerticesBuffer;  
  28.     private ShortBuffer drawListBuffer;  
  29.     private final int mProgram;  
  30.     private int mPositionHandle;  
  31.     private int mTextureCoordHandle;  
  32.     private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices  
  33.     // number of coordinates per vertex in this array  
  34.     private static final int COORDS_PER_VERTEX = 2;  
  35.     private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex  
  36.     static float squareCoords[] = {  
  37.        –1.0f,  1.0f,  
  38.        –1.0f, -1.0f,  
  39.         1.0f, -1.0f,  
  40.         1.0f,  1.0f,  
  41.     };
  42.     static float textureVertices[] = {  
  43.         0.0f, 1.0f,  
  44.         1.0f, 1.0f,  
  45.         1.0f, 0.0f,  
  46.         0.0f, 0.0f,  
  47.     };
  48.     private int texture;  
  49.     public DirectDrawer(int texture)  
  50.     {
  51.         this.texture = texture;  
  52.         // initialize vertex byte buffer for shape coordinates  
  53.         ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);  
  54.         bb.order(ByteOrder.nativeOrder());
  55.         vertexBuffer = bb.asFloatBuffer();
  56.         vertexBuffer.put(squareCoords);
  57.         vertexBuffer.position(0);  
  58.         // initialize byte buffer for the draw list  
  59.         ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);  
  60.         dlb.order(ByteOrder.nativeOrder());
  61.         drawListBuffer = dlb.asShortBuffer();
  62.         drawListBuffer.put(drawOrder);
  63.         drawListBuffer.position(0);  
  64.         ByteBuffer bb2 = ByteBuffer.allocateDirect(textureVertices.length * 4);  
  65.         bb2.order(ByteOrder.nativeOrder());
  66.         textureVerticesBuffer = bb2.asFloatBuffer();
  67.         textureVerticesBuffer.put(textureVertices);
  68.         textureVerticesBuffer.position(0);  
  69.         int vertexShader    = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);  
  70.         int fragmentShader  = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);  
  71.         mProgram = GLES20.glCreateProgram();             // create empty OpenGL ES Program  
  72.         GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program  
  73.         GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program  
  74.         GLES20.glLinkProgram(mProgram);                  // creates OpenGL ES program executables  
  75.     }
  76.     public void draw(float[] mtx)  
  77.     {
  78.         GLES20.glUseProgram(mProgram);
  79.         GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
  80.         GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture);
  81.         // get handle to vertex shader’s vPosition member  
  82.         mPositionHandle = GLES20.glGetAttribLocation(mProgram, “vPosition”);  
  83.         // Enable a handle to the triangle vertices  
  84.         GLES20.glEnableVertexAttribArray(mPositionHandle);
  85.         // Prepare the <insert shape here> coordinate data  
  86.         GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);  
  87.         mTextureCoordHandle = GLES20.glGetAttribLocation(mProgram, “inputTextureCoordinate”);  
  88.         GLES20.glEnableVertexAttribArray(mTextureCoordHandle);
  89. //        textureVerticesBuffer.clear();  
  90. //        textureVerticesBuffer.put( transformTextureCoordinates( textureVertices, mtx ));  
  91. //        textureVerticesBuffer.position(0);  
  92.         GLES20.glVertexAttribPointer(mTextureCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureVerticesBuffer);  
  93.         GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
  94.         // Disable vertex array  
  95.         GLES20.glDisableVertexAttribArray(mPositionHandle);
  96.         GLES20.glDisableVertexAttribArray(mTextureCoordHandle);
  97.     }
  98.     private  int loadShader(int type, String shaderCode){  
  99.         // create a vertex shader type (GLES20.GL_VERTEX_SHADER)  
  100.         // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)  
  101.         int shader = GLES20.glCreateShader(type);  
  102.         // add the source code to the shader and compile it  
  103.         GLES20.glShaderSource(shader, shaderCode);
  104.         GLES20.glCompileShader(shader);
  105.         return shader;  
  106.     }
  107.     private float[] transformTextureCoordinates( float[] coords, float[] matrix)  
  108.     {
  109.        float[] result = new float[ coords.length ];          
  110.        float[] vt = new float[4];        
  111.        for ( int i = 0 ; i < coords.length ; i += 2 ) {  
  112.            float[] v = { coords[i], coords[i+1], 0 , 1  };  
  113.            Matrix.multiplyMV(vt, 0, matrix, 0, v, 0);  
  114.            result[i] = vt[0];  
  115.            result[i+1] = vt[1];  
  116.        }
  117.        return result;  
  118.     }
  119. }
  120. </span>

三、有了上面两个类就完成95%的工作,可以将GLSurfaceView看成是有生命周期的。在onPause里进行关闭Camera,在Activity里复写两个方法:

  1. <span style=“font-family:Comic Sans MS;font-size:18px;”>    @Override  
  2.     protected void onResume() {  
  3.         // TODO Auto-generated method stub  
  4.         super.onResume();  
  5.         glSurfaceView.bringToFront();
  6.     }
  7.     @Override  
  8.     protected void onPause() {  
  9.         // TODO Auto-generated method stub  
  10.         super.onPause();  
  11.         glSurfaceView.onPause();
  12.     }</span>

这个glSurfaceView.bringToFront();其实不写也中。在布局里写入自定义的GLSurfaceView就ok了:

  1. <span style=“font-family:Comic Sans MS;font-size:18px;”>    <FrameLayout  
  2.         android:layout_width=“wrap_content”  
  3.         android:layout_height=“wrap_content” >  
  4.         <org.yanzi.camera.preview.CameraGLSurfaceView  
  5.             android:id=“@+id/camera_textureview”  
  6.             android:layout_width=“0dip”  
  7.             android:layout_height=“0dip” />  
  8.     </FrameLayout></span>  

CameraActivity里只负责UI部分,CameraGLSurfaceView负责开Camera、预览,并调用DirectDrawer里的draw()进行绘制。其他代码就不上了。

注意事项:

1、在onDrawFrame()里,如果不调用mDirectDrawer.draw(mtx);是啥都显示不出来的!!!这是GLSurfaceView的特别之处。为啥呢?因为GLSurfaceView不是Android亲生的,而Surfaceview和TextureView是。所以得自己按照OpenGL ES的流程画。

2、 究竟mDirectDrawer.draw(mtx)里在哪获取的Buffer目前杂家还么看太明白,貌似么有请求buffer,而是根据 GLSurfaceView里创建的SurfaceTexture之前,生成的有个纹理ID。这个纹理ID一方面跟SurfaceTexture是绑定在 一起的,另一方面跟DirectDrawer绑定,而SurfaceTexture作渲染载体。

3、参考链接里有,有人为了解决问题,给出了下面三段代码:

@Override
public void onDrawFrame(GL10 gl)
{
    float[] mtx = new float[16];
    mSurface.updateTexImage();
    mSurface.getTransformMatrix(mtx);    

    mDirectVideo.draw(mtx);
}
 private float[] transformTextureCoordinates( float[] coords, float[] matrix)
 {          
    float[] result = new float[ coords.length ];        
    float[] vt = new float[4];      

    for ( int i = 0 ; i < coords.length ; i += 2 ) {
        float[] v = { coords[i], coords[i+1], 0 , 1  };
        Matrix.multiplyMV(vt, 0, matrix, 0, v, 0);
        result[i] = vt[0];
        result[i+1] = vt[1];
    }
    return result;
 }
textureVerticesBuffer.clear();
textureVerticesBuffer.put( transformTextureCoordinates( textureVertices, mtx ));
textureVerticesBuffer.position(0);

我已经把代码都融入到了此demo,只不过在draw()方法里么有使用。原因是使用之后,得到的预览画面反而是变形的,而不用的话是ok的。上面的代码是得到SurfaceTexture的变换矩阵:mSurface.getTransformMatrix

然后将此矩阵传递给draw(),在draw的时候对textureVerticesBuffer作一个变化,然后再画。

下图是未加这个矩阵变换效果时:

下图为使用了变换矩阵,划片扭曲的还真说不上来咋扭曲的,但足以说明OpenGL ES在渲染效果上的强大,就是设置了个矩阵,不用一帧帧处理,就能得到不一样显示效果。

 

 

 

—————————–本文系原创,转载请注明作者yanzi1225627

版本号:PlayCamera_V3.0.0[2014-6-22].zip

CSDN下载链接:http://download.csdn.net/detail/yanzi1225627/7547263

百度云盘:

附个OpenGL ES简明教程:http://www.apkbus.com/android-20427-1-1.html

Android调用camera错误setParameters failed深层解析

mikel阅读(1041)

1. Camera

Camera是Android framework里面支持的,允许你拍照和拍摄视频的设备,那么,在使用camera开发中总是会遇到一些问题,例如以下这样子的:

E/AndroidRuntime(1542): java.lang.RuntimeException: setParameters failed
E/AndroidRuntime(1542): at android.hardware.Camera.native_setParameters(Native Method)
E/AndroidRuntime(1542): at android.hardware.Camera.setParameters(Camera.java:914)
出现这种错误,根据错误提示我们可以知道是android的setParameters方法出错了。

2、那该如何解决呢?

我们知道camera的parameters中也有很多参数设置的,是哪个出错了呢?很多人不知所以然就上网开始找,找不到就开始各种猜测,一个个 参数设置过去,其实最有效的方式是到底层找原因。ok,让我们打开android代码找到camera类。然后查找setParameters方法。

1
2
3
4
5
6
7
8
9
10
11
12
private native final void native_setParameters(String params);
   /**
    * Changes the settings for this Camera service.
    *
    * @param params the Parameters to use for this Camera service
    * @throws RuntimeException if any parameter is invalid or not supported.
    * @see #getParameters()
    */
   public void setParameters(Parameters params) {
       native_setParameters(params.flatten());
   }

从这段代码中代码中,我们可以得到什么信息呢,setParameters方法是调用jni方法native_setParameters的方法,其实看 到这里就差并不多了,因为再去查看jni方法是很麻烦的,毕竟我们日常开发使用大部分是java代码。我们可以发现传输进来的是Parameters参 数,调用了Parameters的flatten方法。我们查找flatten的代码进行查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
        * Creates a single string with all the parameters set in
        * this Parameters object.
        * <p>The {@link #unflatten(String)} method does the reverse.</p>
        *
        * @return a String with all values from this Parameters object, in
        *         semi-colon delimited key-value pairs
        */
       public String flatten() {
           StringBuilder flattened = new StringBuilder();
           for (String k : mMap.keySet()) {
               flattened.append(k);
               flattened.append("=");
               flattened.append(mMap.get(k));
               flattened.append(";");
           }
           // chop off the extra semicolon at the end
           flattened.deleteCharAt(flattened.length()-1);
           return flattened.toString();
       }

从这段代码中,我们又能得到什么信息呢。我们可以看到提供数据的时候,数据都是从mMap中获取的。ok,接下来,我们查看一下mMap是有几个方法对其进行了赋值呢。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/**
         * Takes a flattened string of parameters and adds each one to
         * this Parameters object.
         * <p>The {@link #flatten()} method does the reverse.</p>
         *
         * @param flattened a String of parameters (key-value paired) that
         *                  are semi-colon delimited
         */
        public void unflatten(String flattened) {
            mMap.clear();
            StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
            while (tokenizer.hasMoreElements()) {
                String kv = tokenizer.nextToken();
                int pos = kv.indexOf('=');
                if (pos == -1) {
                    continue;
                }
                String k = kv.substring(0, pos);
                String v = kv.substring(pos + 1);
                mMap.put(k, v);
            }
        }
        /**
         * Sets a String parameter.
         *
         * @param key   the key name for the parameter
         * @param value the String value of the parameter
         */
        public void set(String key, String value) {
            if (key.indexOf('=') != -1 || key.indexOf(';') != -1) {
                Log.e(TAG, "Key \"" + key + "\" contains invalid character (= or ;)");
                return;
            }
            if (value.indexOf('=') != -1 || value.indexOf(';') != -1) {
                Log.e(TAG, "Value \"" + value + "\" contains invalid character (= or ;)");
                return;
            }
            mMap.put(key, value);
        }
        /**
         * Sets an integer parameter.
         *
         * @param key   the key name for the parameter
         * @param value the int value of the parameter
         */
        public void set(String key, int value) {
            mMap.put(key, Integer.toString(value));
        }
        private void set(String key, List areas) {
            if (areas == null) {
                set(key, "(0,0,0,0,0)");
            } else {
                StringBuilder buffer = new StringBuilder();
                for (int i = 0; i < areas.size(); i++) {
                    Area area = areas.get(i);
                    Rect rect = area.rect;
                    buffer.append('(');
                    buffer.append(rect.left);
                    buffer.append(',');
                    buffer.append(rect.top);
                    buffer.append(',');
                    buffer.append(rect.right);
                    buffer.append(',');
                    buffer.append(rect.bottom);
                    buffer.append(',');
                    buffer.append(area.weight);
                    buffer.append(')');
                    if (i != areas.size() - 1) buffer.append(',');
                }
                set(key, buffer.toString());
            }
        }
        /**
         * Returns the value of a String parameter.
         *
         * @param key the key name for the parameter
         * @return the String value of the parameter
         */
        public String get(String key) {
            return mMap.get(key);
        }
        /**
         * Sets the dimensions for preview pictures. If the preview has already
         * started, applications should stop the preview first before changing
         * preview size.
         *
         * The sides of width and height are based on camera orientation. That
         * is, the preview size is the size before it is rotated by display
         * orientation. So applications need to consider the display orientation
         * while setting preview size. For example, suppose the camera supports
         * both 480x320 and 320x480 preview sizes. The application wants a 3:2
         * preview ratio. If the display orientation is set to 0 or 180, preview
         * size should be set to 480x320. If the display orientation is set to
         * 90 or 270, preview size should be set to 320x480. The display
         * orientation should also be considered while setting picture size and
         * thumbnail size.
         *
         * @param width  the width of the pictures, in pixels
         * @param height the height of the pictures, in pixels
         * @see #setDisplayOrientation(int)
         * @see #getCameraInfo(int, CameraInfo)
         * @see #setPictureSize(int, int)
         * @see #setJpegThumbnailSize(int, int)
         */
        public void setPreviewSize(int width, int height) {
            String v = Integer.toString(width) + "x" + Integer.toString(height);
            set(KEY_PREVIEW_SIZE, v);
        }

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
         * <p>Sets the dimensions for EXIF thumbnail in Jpeg picture. If
         * applications set both width and height to 0, EXIF will not contain
         * thumbnail.</p>
         *
         * <p>Applications need to consider the display orientation. See {@link
         * #setPreviewSize(int,int)} for reference.</p>
         *
         * @param width  the width of the thumbnail, in pixels
         * @param height the height of the thumbnail, in pixels
         * @see #setPreviewSize(int,int)
         */
        public void setJpegThumbnailSize(int width, int height) {
            set(KEY_JPEG_THUMBNAIL_WIDTH, width);
            set(KEY_JPEG_THUMBNAIL_HEIGHT, height);
        }
      
        /**
         * Sets the quality of the EXIF thumbnail in Jpeg picture.
         *
         * @param quality the JPEG quality of the EXIF thumbnail. The range is 1
         *                to 100, with 100 being the best.
         */
        public void setJpegThumbnailQuality(int quality) {
            set(KEY_JPEG_THUMBNAIL_QUALITY, quality);
        }
     
        /**
         * Sets Jpeg quality of captured picture.
         *
         * @param quality the JPEG quality of captured picture. The range is 1
         *                to 100, with 100 being the best.
         */
        public void setJpegQuality(int quality) {
            set(KEY_JPEG_QUALITY, quality);
        }
      
        /**
         * Sets the rate at which preview frames are received. This is the
         * target frame rate. The actual frame rate depends on the driver.
         *
         * @param fps the frame rate (frames per second)
         * @deprecated replaced by {@link #setPreviewFpsRange(int,int)}
         */
        @Deprecated
        public void setPreviewFrameRate(int fps) {
            set(KEY_PREVIEW_FRAME_RATE, fps);
        }
       
        /**
         * Sets the maximum and maximum preview fps. This controls the rate of
         * preview frames received in {@link PreviewCallback}. The minimum and
         * maximum preview fps must be one of the elements from {@link
         * #getSupportedPreviewFpsRange}.
         *
         * @param min the minimum preview fps (scaled by 1000).
         * @param max the maximum preview fps (scaled by 1000).
         * @throws RuntimeException if fps range is invalid.
         * @see #setPreviewCallbackWithBuffer(Camera.PreviewCallback)
         * @see #getSupportedPreviewFpsRange()
         */
        public void setPreviewFpsRange(int min, int max) {
            set(KEY_PREVIEW_FPS_RANGE, "" + min + "," + max);
        }
       
       
        /**
         * Sets the image format for preview pictures.
         * <p>If this is never called, the default format will be
         * {@link android.graphics.ImageFormat#NV21}, which
         * uses the NV21 encoding format.</p>
         *
         * @param pixel_format the desired preview picture format, defined
         *   by one of the {@link android.graphics.ImageFormat} constants.
         *   (E.g., <var>ImageFormat.NV21</var> (default),
         *                      <var>ImageFormat.RGB_565</var>, or
         *                      <var>ImageFormat.JPEG</var>)
         * @see android.graphics.ImageFormat
         */
        public void setPreviewFormat(int pixel_format) {
            String s = cameraFormatForPixelFormat(pixel_format);
            if (s == null) {
                throw new IllegalArgumentException(
                        "Invalid pixel_format=" + pixel_format);
            }
            set(KEY_PREVIEW_FORMAT, s);
        }
    
       
        /**
         * <p>Sets the dimensions for pictures.</p>
         *
         * <p>Applications need to consider the display orientation. See {@link
         * #setPreviewSize(int,int)} for reference.</p>
         *
         * @param width  the width for pictures, in pixels
         * @param height the height for pictures, in pixels
         * @see #setPreviewSize(int,int)
         *
         */
        public void setPictureSize(int width, int height) {
            String v = Integer.toString(width) + "x" + Integer.toString(height);
            set(KEY_PICTURE_SIZE, v);
        }
   
        /**
         * Sets the image format for pictures.
         *
         * @param pixel_format the desired picture format
         *                     (<var>ImageFormat.NV21</var>,
         *                      <var>ImageFormat.RGB_565</var>, or
         *                      <var>ImageFormat.JPEG</var>)
         * @see android.graphics.ImageFormat
         */
        public void setPictureFormat(int pixel_format) {
            String s = cameraFormatForPixelFormat(pixel_format);
            if (s == null) {
                throw new IllegalArgumentException(
                        "Invalid pixel_format=" + pixel_format);
            }
            set(KEY_PICTURE_FORMAT, s);
        }

 

ok,错误的地方,我们就定位在这么几个地方了。在自己写的代码里面,查看一下是否调用了这几个方法~~~。android源码还是注释得比较清晰的,看看方法英文说明,看是否参数有出现了错误。

当时我的是使用setPictureSize时出现了错误,根据方法说明,我简单解释下,为什么会出错。因为parameters.setPictureSize(320, 480)(设置分辨率)的参数有误,如果不清楚分辨率可以却掉这句话,再运行就OK了。

注:最后找了一下原因,感觉很简单,在实际 开发中,有时候一个小问题,就让人忙乎一个下午也是正常滴。

学习Camera开发时遇到的问题

mikel阅读(795)

    总结:

1、用模拟器启动不了camera,提示:java.lang.runtimeException:setparameters failed…..
因为parameters.setPictureSize(320, 480)(设置分辨率)的参数有误

    这个可以看logcat中

ERROR/QualcommCameraHardware(93): picture_size_values=    640×480,320×240,176×144,160×120 找这句 在这个当中选择
如果不清楚分辨率可以却掉这句话,再运行就OK 了。

  2、连续两次以上的拍照,会出现异常:java.lang.RuntimeException:fail to connect to camera service。
因为没有对camera进行释放,或者说系统有自动释放功能但是还没有被处理。可以通过手动释放:
/**
* 停止预览
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
mCamera.stopPreview();

                     //手动释放 一定得加!
mCamera.release();

                mCamera=null;

}

 还有记得权限一定要加上

—————————————————————————————————————–

camera 打开之后就出现了 java.lang.RuntimeException: Fail to connect to camera service
由于版本原因引起的,在2.1系统的是不是正常的,然后再试试2.2,2.3的!
根据2.2.和 2.3 构造函数的源码

在建项目时要建2.3以上的,如已经建好但是在window-preferences中改版本也是没用的,这个是我出现的问题

记住:camera.open(0) 是后置摄像头 camera.open(1)  是前置摄像头 这是我试验出来的

 2.3版本
Camera(int cameraId) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mZoomListener = null;

Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}

native_setup(new WeakReference<Camera>(this), cameraId);
}

2.2版本

Camera() {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mZoomCallback = null;

Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}

native_setup(new WeakReference<Camera>(this));
}

2.3 多了一个参数 cameraId

多了一个构造函数 Camera(int cameraId)

希望对大家有所帮助

android 3D系列之入门实践篇

mikel阅读(861)

By 何明桂(http://blog.csdn.net/hmg25) 转载请注明出处
通过之前文章–概念篇的学习,我们今天编写一个简单的入门程序,实现一个不断绕x轴,y轴旋转的彩色立方体,效果如下:

Android中我们使用GLSurfaceView来显示OpenGL视图,GLSurfaceView:是其中很重要的一个类,此类位于 Android.opengl包下,用于管理是一块可以是复合视图机器人系统的内存的特殊的曲面。管理一个使表面呈现 OpenGL 的 EGL 显示。接受一个用户提供输入Render对象进行显示。从 UI 线程实现一个专用线程渲染界面实现3D性能。支持按需要和连续的呈现。 包装、 跟踪,和检查 OpenGL 渲染器调用的错误。所以首先我们需要创建一个GLSurfaceView。


&nbsp;
<ul>
	<li class="alt"><span class="keyword">public</span> <span class="keyword">class</span> mainActivity <span class="keyword">extends</span> Activity {</li>
	<li class="">    CubeRenderer mCubeRenderer;  <span class="comment">//我们自定义的立方体Renderer</span></li>
	<li class="alt">    <span class="annotation">@Override</span></li>
	<li class="">    <span class="keyword">public</span> <span class="keyword">void</span> onCreate(Bundle savedInstanceState) {</li>
	<li class="alt">        <span class="keyword">super</span>.onCreate(savedInstanceState);</li>
	<li class="">        requestWindowFeature(Window.FEATURE_NO_TITLE); <span class="comment">// 去掉标题</span></li>
	<li class="alt">        GLSurfaceView GLView = <span class="keyword">new</span> GLSurfaceView(<span class="keyword">this</span>); <span class="comment">//创建一个GLSurfaceView</span></li>
	<li class="">           mCubeRenderer = <span class="keyword">new</span> CubeRenderer();</li>
	<li class="alt">        GLView.setRenderer(mCubeRenderer);</li>
	<li class="">        setContentView(GLView);</li>
	<li class="alt"></li>
	<li class="">    }</li>
	<li class="alt">}</li>
	<li class="alt">

接下来我们的主要工作就是去创建一个继承Renderer接口的CubeRenderer。Renderer是一个专门用来渲染3D的接口。继承它,我们需要重载以下方法:    public void onDrawFrame(GL10 gl)

{

//渲染的绘图操作,重绘时调用

}

public void onSurfaceChanged(GL10 gl, int width, int height)

{

//视窗改变时调用,通常在此设置视窗范围以及透视,投影范围

}

public void onSurfaceCreated(GL10 gl, EGLConfig config)

{

//创建时调用,通常在此进行初始化设置

}

以下是我们CubeRenderer的完整代码:

  • </li>
    	<li class="alt">
    <ol class="dp-j" start="1">
    	<li class="alt"><span class="keyword">public</span> <span class="keyword">class</span> CubeRenderer <span class="keyword">implements</span> Renderer {</li>
    	<li class=""></li>
    	<li class="alt">    <span class="keyword">float</span> box[] = <span class="keyword">new</span> <span class="keyword">float</span>[] {</li>
    	<li class="">            <span class="comment">// FRONT</span></li>
    	<li class="alt">            -<span class="number">0</span>.5f, -<span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="">             <span class="number">0</span>.5f, -<span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="alt">            -<span class="number">0</span>.5f,  <span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="">             <span class="number">0</span>.5f,  <span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="alt">            <span class="comment">// BACK</span></li>
    	<li class="">            -<span class="number">0</span>.5f, -<span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="alt">            -<span class="number">0</span>.5f,  <span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="">             <span class="number">0</span>.5f, -<span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="alt">             <span class="number">0</span>.5f,  <span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="">            <span class="comment">// LEFT</span></li>
    	<li class="alt">            -<span class="number">0</span>.5f, -<span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="">            -<span class="number">0</span>.5f,  <span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="alt">            -<span class="number">0</span>.5f, -<span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="">            -<span class="number">0</span>.5f,  <span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="alt">            <span class="comment">// RIGHT</span></li>
    	<li class="">             <span class="number">0</span>.5f, -<span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="alt">             <span class="number">0</span>.5f,  <span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="">             <span class="number">0</span>.5f, -<span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="alt">             <span class="number">0</span>.5f,  <span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="">            <span class="comment">// TOP</span></li>
    	<li class="alt">            -<span class="number">0</span>.5f,  <span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="">             <span class="number">0</span>.5f,  <span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="alt">             -<span class="number">0</span>.5f,  <span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="">             <span class="number">0</span>.5f,  <span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="alt">            <span class="comment">// BOTTOM</span></li>
    	<li class="">            -<span class="number">0</span>.5f, -<span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="alt">            -<span class="number">0</span>.5f, -<span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="">             <span class="number">0</span>.5f, -<span class="number">0</span>.5f,  <span class="number">0</span>.5f,</li>
    	<li class="alt">             <span class="number">0</span>.5f, -<span class="number">0</span>.5f, -<span class="number">0</span>.5f,</li>
    	<li class="">        };</li>
    	<li class="alt"></li>
    	<li class="">    FloatBuffer cubeBuff;</li>
    	<li class="alt"></li>
    	<li class="">    <span class="keyword">float</span> xrot = <span class="number">0</span>.0f;</li>
    	<li class="alt">    <span class="keyword">float</span> yrot = <span class="number">0</span>.0f;</li>
    	<li class=""></li>
    	<li class="alt">    <span class="comment">/**</span></li>
    	<li class=""><span class="comment">     * 将float数组转换存储在字节缓冲数组</span></li>
    	<li class="alt"><span class="comment">     * @param arr</span></li>
    	<li class=""><span class="comment">     * @return</span></li>
    	<li class="alt"><span class="comment">     */</span></li>
    	<li class="">    <span class="keyword">public</span> FloatBuffer makeFloatBuffer(<span class="keyword">float</span>[] arr) {</li>
    	<li class="alt">        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * <span class="number">4</span>);<span class="comment">//分配缓冲空间,一个float占4个字节</span></li>
    	<li class="">        bb.order(ByteOrder.nativeOrder()); <span class="comment">//设置字节顺序, 其中ByteOrder.nativeOrder()是获取本机字节顺序</span></li>
    	<li class="alt">        FloatBuffer fb = bb.asFloatBuffer(); <span class="comment">//转换为float型</span></li>
    	<li class="">        fb.put(arr);        <span class="comment">//添加数据</span></li>
    	<li class="alt">        fb.position(<span class="number">0</span>);      <span class="comment">//设置数组的起始位置</span></li>
    	<li class="">        <span class="keyword">return</span> fb;</li>
    	<li class="alt">    }</li>
    	<li class=""></li>
    	<li class="alt">    <span class="keyword">public</span> CubeRenderer() {</li>
    	<li class="">        <span class="comment">// TODO Auto-generated constructor stub</span></li>
    	<li class="alt">        cubeBuff = makeFloatBuffer(box);<span class="comment">//转换float数组</span></li>
    	<li class="">    }</li>
    	<li class="alt"></li>
    	<li class=""></li>
    	<li class="alt">    <span class="keyword">protected</span> <span class="keyword">void</span> init(GL10 gl) {</li>
    	<li class="">        gl.glClearColor(<span class="number">0</span>.0f, <span class="number">0</span>.0f, <span class="number">0</span>.0f, <span class="number">1</span>.0f);<span class="comment">//设置清屏时背景的颜色,R,G,B,A</span></li>
    	<li class="alt"></li>
    	<li class="">        gl.glEnable(GL10.GL_DEPTH_TEST); <span class="comment">//启用深度缓存</span></li>
    	<li class="alt">        gl.glEnable(GL10.GL_CULL_FACE);  <span class="comment">//启用背面剪裁</span></li>
    	<li class="">        gl.glClearDepthf(<span class="number">1</span>.0f);    <span class="comment">// 设置深度缓存值</span></li>
    	<li class="alt">        gl.glDepthFunc(GL10.GL_LEQUAL);  <span class="comment">// 设置深度缓存比较函数,GL_LEQUAL表示新的像素的深度缓存值小于等于当前像素的深度缓存值(通过gl.glClearDepthf(1.0f)设置)时通过深度测试   </span></li>
    	<li class="">        gl.glShadeModel(GL10.GL_SMOOTH);<span class="comment">// 设置阴影模式GL_SMOOTH</span></li>
    	<li class="alt">    }</li>
    	<li class=""></li>
    	<li class="alt">    <span class="annotation">@Override</span></li>
    	<li class="">    <span class="keyword">public</span> <span class="keyword">void</span> onSurfaceCreated(GL10 gl, EGLConfig config) {</li>
    	<li class="alt">        <span class="comment">// TODO Auto-generated method stub</span></li>
    	<li class="">        init(gl);</li>
    	<li class="alt">    }</li>
    	<li class=""></li>
    	<li class="alt">    <span class="annotation">@Override</span></li>
    	<li class="">    <span class="keyword">public</span> <span class="keyword">void</span> onSurfaceChanged(GL10 gl, <span class="keyword">int</span> w, <span class="keyword">int</span> h) {</li>
    	<li class="alt">        <span class="comment">// TODO Auto-generated method stub</span></li>
    	<li class="">        gl.glViewport(<span class="number">0</span>, <span class="number">0</span>, w, h); <span class="comment">//设置视窗</span></li>
    	<li class="alt">        gl.glMatrixMode(GL10.GL_PROJECTION); <span class="comment">// 设置投影矩阵</span></li>
    	<li class="">        gl.glLoadIdentity();  <span class="comment">//设置矩阵为单位矩阵,相当于重置矩阵       </span></li>
    	<li class="alt">        GLU.gluPerspective(gl, <span class="number">45</span>.0f, ((<span class="keyword">float</span>) w) / h, <span class="number">0</span>.1f, 10f);<span class="comment">//设置透视范围  </span></li>
    	<li class="">    }</li>
    	<li class="alt"></li>
    	<li class="">    <span class="annotation">@Override</span></li>
    	<li class="alt">    <span class="keyword">public</span> <span class="keyword">void</span> onDrawFrame(GL10 gl) {</li>
    	<li class="">        <span class="comment">// TODO Auto-generated method stub</span></li>
    	<li class="alt">        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);<span class="comment">// 清除屏幕和深度缓存</span></li>
    	<li class=""></li>
    	<li class="alt">        gl.glMatrixMode(GL10.GL_MODELVIEW);   <span class="comment">//切换至模型观察矩阵</span></li>
    	<li class="">        gl.glLoadIdentity();<span class="comment">// 重置当前的模型观察矩阵</span></li>
    	<li class="alt">        GLU.gluLookAt(gl, <span class="number">0</span>, <span class="number">0</span>, <span class="number">3</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);<span class="comment">//设置视点和模型中心位置</span></li>
    	<li class=""></li>
    	<li class="alt">        gl.glVertexPointer(<span class="number">3</span>, GL10.GL_FLOAT, <span class="number">0</span>, cubeBuff);<span class="comment">//设置顶点数据</span></li>
    	<li class="">        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);</li>
    	<li class="alt"></li>
    	<li class="">        gl.glRotatef(xrot, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>);  <span class="comment">//绕着(0,0,0)与(1,0,0)即x轴旋转</span></li>
    	<li class="alt">        gl.glRotatef(yrot, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</li>
    	<li class=""></li>
    	<li class="alt">        gl.glColor4f(<span class="number">1</span>.0f, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>.0f);   <span class="comment">//设置颜色,红色</span></li>
    	<li class="">        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, <span class="number">0</span>, <span class="number">4</span>);  <span class="comment">//绘制正方型FRONT面</span></li>
    	<li class="alt">        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, <span class="number">4</span>, <span class="number">4</span>);</li>
    	<li class=""></li>
    	<li class="alt">        gl.glColor4f(<span class="number">0</span>, <span class="number">1</span>.0f, <span class="number">0</span>, <span class="number">1</span>.0f);</li>
    	<li class="">        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, <span class="number">8</span>, <span class="number">4</span>);</li>
    	<li class="alt">        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, <span class="number">12</span>, <span class="number">4</span>);</li>
    	<li class=""></li>
    	<li class="alt">        gl.glColor4f(<span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>.0f, <span class="number">1</span>.0f);</li>
    	<li class="">        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, <span class="number">16</span>, <span class="number">4</span>);</li>
    	<li class="alt">        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, <span class="number">20</span>, <span class="number">4</span>);</li>
    	<li class=""></li>
    	<li class="alt">        xrot += <span class="number">1</span>.0f;</li>
    	<li class="">        yrot += <span class="number">0</span>.5f;</li>
    	<li class="alt">    }</li>
    	<li class=""></li>
    	<li class="alt">}</li>
    	<li class="alt">
  • 源码工程,下载地址:http://download.csdn.net/source/3566635
  •  

    [转载]用c#开发微信 (22) 微信商城 - 微信支付 (c#源码) - 疯吻IT - 博客园

    mikel阅读(865)

    来源: [转载]用c#开发微信 (22) 微信商城 – 微信支付 (c#源码) – 疯吻IT – 博客园

    微信支付有几种支付模式:刷卡支付扫码支付公众号支付APP支付。本文介绍用于在微信商城里的公众号支付。

     

     

    1. 效果图

    在商城里购买商品后,到支付页面:

    Screenshot_2015-07-29-11-41-10

    点击上面的确认支付,转到下面微信支付页面:

    Screenshot_2015-07-29-11-40-54

     

    可关注微信号 webuscn 或扫描下面二维码,进入微商城体验:

    202235130988418

     

     

    作者:疯吻IT 出处:http://fengwenit.cnblogs.com

     

    2. 申请微信支付

    申请成为公众账号支付商户需要满足以下条件:

    1、拥有公众帐号,且为服务号、企业号;

    2、公众帐号须通过微信认证;(未认证用户,可先申请微信认证)

    3、政府、媒体两大类型的订阅号支持申请微信支付(点此了解更多)。

    4、企业号也支持申请微信支付,请在企业号管理平台发起申请。

    温馨提示:

    1、微信支付商户申请无开通费用及保证金;

    2、微信认证资质审核通过后,即可申请微信支付功能;

    3、订阅号可先升级为服务号,升级方法点击这里了解。

     

    详细步骤请参考官方文档:

    http://kf.qq.com/faq/140225MveaUz150107UVFNjy.html

     

     

    3.  实现

    3.1 配置

    首先要配置支付授权目录:

    image

    在你的微商城系统里配置商户信息:

    image

     

    3.2 前台代码

    这个页面就是上面配置的支付授权目录下面的页面。

    先定义一个支付按钮:

    <a href="javascript:void(0);" class="btn" id="getBrandWCPayRequest">确认支付</a>

     

    当微信内置浏览器完成内部初始化后会触发WeixinJSBridgeReady事件:

            document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
                //公众号支付
                jQuery('a#getBrandWCPayRequest').click(function (e) {
    
    
                    WeixinJSBridge.invoke('getBrandWCPayRequest', {
                       <%=packageValue%>
                    }, function (res) {
                        var newurl = "/api/payment/wxpay/payResult.aspx?wid=" + <%=wid%> + "&otid=" + '<%=otid_str%>' + "&openid=" + '<%=openid%>' + "";
                        if (res.err_msg == "get_brand_wcpay_request:ok") {
                            //支付成功后清空我的订单
                            $.post("/shop/shopmgr.ashx?myact=clearMyOrder", { wid: '<%=wid%>', openid: '<%=openid%>' }, function (data) { }, "json")
    
    
                            alert("微信支付成功,点击右上角返回!");
                            window.location.href = newurl;
                        } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
                            alert("您取消了支付!");
                        } else {
                            alert(res.err_msg);
                            alert("您支付失败了!");
                        }
                    });
    
    
                });
    
    
                WeixinJSBridge.log('yo~ ready.');
    
    
            }, false);

     

    使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
    因此微信团队建议,当收到ok返回时,向商户后台询问是否收到交易成功的通知,若收到通知,前端展示交易成功的界面;若此时未收到通知,商户后台主动调用查询订单接口,查询订单的当前状态,并反馈给前端展示相应的界面。

     

    网页端接口参数详细列表:

    https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7

     

    3.3 后台代码

    主要是生成前台所需要的 packageValue :

    //先设置基本信息
               string MchId = paymentInfo.partnerId; // "1218574001";//
    
    
               string partnerKey = paymentInfo.partnerKey;// 商户支付密钥Key。登录微信商户后台,进入栏目【账户设置】【密码安全】【API 安全】【API 密钥】
    
    
               string notify_url = "http://" + HttpContext.Current.Request.Url.Authority + "/api/payment/wxpay/notify_url.aspx";
    
    
    
    
               string timeStamp = "";
               string nonceStr = "";
               string paySign = "";
    
    
               string sp_billno = out_trade_no;
               //当前时间 yyyyMMdd
               string date = DateTime.Now.ToString("yyyyMMdd");
    
    
               if (null == sp_billno)
               {
                   //生成订单10位序列号,此处用时间和随机数生成,商户根据自己调整,保证唯一
                   sp_billno = DateTime.Now.ToString("HHmmss") + TenPayV3Util.BuildRandomStr(28);
               }
    
    
    
    
               //创建支付应答对象
               Senparc.Weixin.MP.TenPayLibV3.RequestHandler packageReqHandler = new Senparc.Weixin.MP.TenPayLibV3.RequestHandler(null);
               //初始化
               packageReqHandler.Init();
               //packageReqHandler.SetKey(""/*TenPayV3Info.Key*/);
    
    
               timeStamp = TenPayV3Util.GetTimestamp();
               nonceStr = TenPayV3Util.GetNoncestr();
    
    
               //设置package订单参数
               packageReqHandler.SetParameter("appid", uwEntity.AppId);          //公众账号ID
               packageReqHandler.SetParameter("mch_id", MchId);          //商户号
               packageReqHandler.SetParameter("nonce_str", nonceStr);                    //随机字符串
               packageReqHandler.SetParameter("body", busiBody);  //商品描述
               packageReqHandler.SetParameter("attach", wid + "|" + busiBody);
               packageReqHandler.SetParameter("out_trade_no", sp_billno);        //商家订单号
               packageReqHandler.SetParameter("total_fee", ((int)(ttFee * 100)).ToString());                    //商品金额,以分为单位(money * 100).ToString()
               packageReqHandler.SetParameter("spbill_create_ip", Request.UserHostAddress);   //用户的公网ip,不是商户服务器IP
               packageReqHandler.SetParameter("notify_url", notify_url);            //接收财付通通知的URL
               packageReqHandler.SetParameter("trade_type", TenPayV3Type.JSAPI.ToString());//交易类型
               packageReqHandler.SetParameter("openid", openid);                        //用户的openId
    
    
               string sign = packageReqHandler.CreateMd5Sign("key", partnerKey);
               packageReqHandler.SetParameter("sign", sign);                        //签名
    
    
               string data = packageReqHandler.ParseXML();
    
    
               var result = TenPayV3.Unifiedorder(data);
    
    
               var res = XDocument.Parse(result);
               prepayId = res.Element("xml").Element("prepay_id").Value;
    
    
               //设置支付参数
               Senparc.Weixin.MP.TenPayLibV3.RequestHandler paySignReqHandler = new Senparc.Weixin.MP.TenPayLibV3.RequestHandler(null);
               paySignReqHandler.SetParameter("appId", uwEntity.AppId);
               paySignReqHandler.SetParameter("timeStamp", timeStamp);
               paySignReqHandler.SetParameter("nonceStr", nonceStr);
               paySignReqHandler.SetParameter("package", string.Format("prepay_id={0}", prepayId));
               paySignReqHandler.SetParameter("signType", "MD5");
               paySign = paySignReqHandler.CreateMd5Sign("key", partnerKey);
    
    
               packageValue = "";
               packageValue += " \"appId\": \"" + uwEntity.AppId + "\", ";
               packageValue += " \"timeStamp\": \"" + timeStamp + "\", ";
               packageValue += " \"nonceStr\": \"" + nonceStr + "\", ";
               packageValue += " \"package\": \"" + string.Format("prepay_id={0}", prepayId) + "\", ";
               packageValue += " \"signType\": \"MD5\", ";
               packageValue += " \"paySign\": \"" + paySign + "\"";

     

     

    用c#开发微信 系列汇总


    如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。

    camera与opengl es的融合显示(AR基础)

    mikel阅读(1196)

    本文简单介绍一下,camera取景画面与opengl es绘制的画面融合显示。其实说直接一点就是SurfaceView与GLSurfaceView的叠加。直接上代码吧!

    
    package com.scy.cameraopengl;
    
    import java.io.IOException;
    
    import android.graphics.PixelFormat;
    import android.hardware.Camera;
    import android.hardware.Camera.Parameters;
    import android.opengl.GLSurfaceView;
    import android.os.Bundle;
    import android.provider.Settings.System;
    import android.app.Activity;
    import android.view.Display;
    import android.view.Menu;
    import android.view.Surface;
    import android.view.SurfaceHolder;
    import android.view.Window;
    import android.view.SurfaceHolder.Callback;
    import android.view.ViewGroup.LayoutParams;
    import android.view.SurfaceView;
    import android.view.WindowManager;
    import android.widget.FrameLayout;
    
    public class MainActivity extends Activity
    {
    FrameLayout frameLayout;
    
    Camera camera;
    SurfaceView surface;
    SurfaceHolder holder;
    GLSurfaceView surfaceView;
    MyRender render;
    
    int width,height;
    boolean isPreview = false;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    WindowManager wManager = (WindowManager)getSystemService(WINDOW_SERVICE);
    Display display = wManager.getDefaultDisplay();
    width = display.getWidth();
    height = display.getHeight();
    setContentView(R.layout.activity_main);
    frameLayout = (FrameLayout)findViewById(R.id.framlayout);
    
    /**
    * 先添加GLSurfaceView
    */
    surfaceView = new GLSurfaceView(this);
    surfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
    /**
    * Set the desired PixelFormat of the surface. The default is OPAQUE. When working with a SurfaceView,
    * this must be called from the same thread running the SurfaceView's window.
    */
    surfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
    render = new MyRender();
    surfaceView.setRenderer(render);
    frameLayout.addView(surfaceView, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
    /**
    * 再添加SurfaceView图层
    */
    surface = new SurfaceView(this);
    holder = surface.getHolder();
    holder.addCallback(new Callback()
    {
    @Override
    public void surfaceDestroyed(SurfaceHolder holder)
    {
    if (camera!=null)
    {
    if (isPreview)
    {
    camera.stopPreview();
    }
    camera.release();
    camera = null;
    }
    }
    
    @Override
    public void surfaceCreated(SurfaceHolder holder)
    {
    if (!isPreview)
    {
    camera = Camera.open();
    }
    if (!isPreview&amp;&amp;camera!=null)
    {
    try {
    Parameters parameters = camera.getParameters();
    parameters.setPictureSize(width, height);
    parameters.setPreviewSize(width, height);
    parameters.setPreviewFrameRate(6);
    camera.setParameters(parameters);
    camera.setPreviewDisplay(holder);
    camera.startPreview();
    camera.autoFocus(null);
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    isPreview = true;
    }
    }
    
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
    int height)
    {
    }
    });
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    frameLayout.addView(surface, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    
    }
    
    @Override
    protected void onResume() {
    super.onResume();
    }
    
    @Override
    protected void onStop()
    {
    super.onStop();
    }
    
    }
    
    &nbsp;
    
    package com.scy.cameraopengl;
    
    import java.nio.FloatBuffer;
    import java.nio.IntBuffer;
    
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;
    
    import android.R.integer;
    import android.opengl.GLSurfaceView.Renderer;
    
    public class MyRender implements Renderer
    {
    float[] verteices = new float[]
    {
    0.1f,0.6f,0.0f,
    -0.3f,0.0f,0.0f,
    0.3f,0.1f,0.0f
    };
    int[] colors = new int[]
    {
    65535,0,0,0,
    0,65535,0,0,
    0,0,65535,0
    };
    
    FloatBuffer vBuffer = MemUtil.makeFloatBuffer(verteices);
    IntBuffer cBuffer = MemUtil.makeIntBuffer(colors);
    
    @Override
    public void onDrawFrame(GL10 gl)
    {
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    gl.glTranslatef(0.0f, 0.0f, -1.0f);
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vBuffer);
    gl.glColorPointer(4, GL10.GL_FIXED, 0, cBuffer);
    gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
    gl.glFinish();
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
    }
    
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height)
    {
    gl.glViewport(0, 0, width, height);
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glLoadIdentity();
    float ratio = (float)width/height;
    gl.glFrustumf(-ratio, ratio, -1, 1, 1, 9);
    }
    
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config)
    {
    gl.glDisable(GL10.GL_DITHER);
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
    gl.glClearColor(0, 0, 0, 0);
    gl.glShadeModel(GL10.GL_SMOOTH);
    gl.glEnable(GL10.GL_DEPTH_TEST);
    gl.glDepthFunc(GL10.GL_LEQUAL);
    }
    
    }
    
    
    package com.example.ar;
     
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.nio.FloatBuffer;
    import java.nio.IntBuffer;
     
    public class MemUtil {
        public static FloatBuffer makeFloatBufferFromArray(float[] arr) {
            ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);
            bb.order(ByteOrder.nativeOrder());
            FloatBuffer fb = bb.asFloatBuffer();
            fb.put(arr);
            fb.position(0);
            return fb;
        }
     
        /**
         * creates a floatbuffer of the given size.
         * 
         * @param size
         * @return
         */
        public static FloatBuffer makeFloatBuffer(int size) {
            ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
            bb.order(ByteOrder.nativeOrder());
            FloatBuffer fb = bb.asFloatBuffer();
            fb.position(0);
            return fb;
        }
     
        public static FloatBuffer makeFloatBuffer(float[] arr) {
            ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);
            bb.order(ByteOrder.nativeOrder());
            FloatBuffer fb = bb.asFloatBuffer();
            fb.put(arr);
            fb.position(0);
            return fb;
        }
     
        public static IntBuffer makeIntBuffer(int[] buff) {
            ByteBuffer bb = ByteBuffer.allocateDirect(buff.length * 4);
            bb.order(ByteOrder.nativeOrder());
            IntBuffer sb = bb.asIntBuffer();
            sb.put(buff);
            sb.position(0);
            return sb;
        }
     
    }
    

    运行的效果就是摄像头取景的真实环境,上面显示一个opengl绘制的三角形面。通过这种方式结合传感器,可以实现一个简单的增强现实应用。大家有兴趣的话可以自己试试。

    AR的昨天、今天和明天

    mikel阅读(1050)

    前言

    随着CES的召开和微软的HoloLens的亮相,增强现实技术 (AugmentedReality,简称AR)似乎成为科技界的一个热门话题。这对于像我这样的AR开发者和爱好者来说,确实是个激动人心的好消息。 (其实我一直看好AR,不然也不会裸辞了,:-))今天就以我的微薄知识,讲讲AR的《昨天、今天和明天》,希望达到抛砖引玉的效果,也希望结识更多的朋 友。

     

    一、AR的昨天

     

    增 强现实技术在虚拟现实技术上发展起来,也被称为“混合现实”、“扩增实境”。它是通过计算机系统提供的信息提高用户对现实世界感知能力和交互体验的技术, 将虚拟信息应用到真实世界,并将计算机生成的虚拟物体、场景或系统提示信息叠加到真实场景中,从而实现对现实场景的增强。

    1968 年,Ivan Sutherland创建了第一个增强现实系统,也是第一个虚拟现实系统。它使用一个光学透视式头盔显示器,通过两个6自由度的跟踪器进行跟踪注册:一个 机械式跟踪器,一个超声波跟踪器。由于当时计算机处理性能的限制,只能实时显示非常简单的线框模型。如图1-1(a)所示为系统使用情景,(b)为增强现 实场景。

    目 前对于增强现实有两种被广泛接受的定义,一种是Paul Milgram和Fumio Kishino于1994年定义的“现实-虚拟连续体”。他们描述了从真实环境到虚拟环境的连续体。如图1-2所示,真实场景和虚拟场景分布在两端,在这 两者之间接近真实环境的是增强现实,接近虚拟场景的是增强虚拟(扩增虚境),而位于中间的部分叫做混合实境。另外一种定义是1997年北卡大学的 Ronald Azuma提出的增强现实的定义。他认为增强现实技术应具有三个具体特征:三维注册、虚实融合以及实时交互。

    按照AR技术的定义,需要具备三个特征:注册、虚实融合以及实时交互。

    据 我所知,最先出现的AR主要是基于PC的。我们实验室的师兄之前都是用ARToolkit来做开发,到我的时候才开始做移动端的AR,那大概是12年的时 候。ARToolkit几乎做AR的人都会知道,识别算法稳定性比较好,但还有一些局限性,比如黑白框的标识不美观、不能被遮挡、容易受到光照影响等。虽 然如此,ARToolkit开源,是很多AR开发者甚至是程序员的启蒙老师。后来随着智能手机的发展,尤其是Android系统的快速发展,AR由PC端 转到移动端,出现了基于ARToolkit开发的AndAR,依然是黑白框的图片标识。

    图 1-3 Marker AR

     

    二、AR的今天

     

    AR技术从最开始的黑白框,发展到现在的基于一般的图片(2D Image),这其中经历的过程也是漫长的。然而基于2d图片的AR技术(我们叫做Markerless AR, 无标识AR)已经相当成熟,市面上也有很多成熟的商业应用,并且也出现了很多十分成熟并被开发者广泛使用的SDK商用和免费的产品。并且这些产品的性能和 功能都十分强大。比如Qualcomm的Vuforia SDK,与手机硬件的结合非常紧密。低功耗、高性能,减少了应用在运行时的发热。同时,也利用了手机各种特性,如更好的支持手机摄像头的自动对焦功能,这 是相对其他AR工具厂商得天独厚的优势。这些都是好事,使得开发者能够快速有效地开发AR应用,也能让普通人更好滴接触并接受AR技术,这些也从一定程度 上促进了AR技术的发展。要我说,AR技术发展到现在这么火热的地步,和他们的贡献有莫大的关系。在某种程度上,是他们推动了AR技术的发展。

     

    但 是AR技术目前普通使用比较多得场景是展览展示,传媒营销,互动娱乐等,例如房地产楼书、广告展示、商场大屏互动等等。这些应用都很成熟,却十分小众,粘 着力很差。那么AR技术能不能像传统互联网那样,让人们离不开呢?其实据我所知,目前还没有出现成功的解决方案。有两个将AR技术与移动互联网相结合的产 品,也是我有所参与的。其中一个上线,一个还没上线,但是反应都不是很好。有时候AR对一些人来说,可能就是个噱头,因为确实可以在视觉上有所冲击。有了 它,可能获取更多的投资,而并没有从深层次去思考该怎么将AR技术融入移动互联网的血液。最近通过调查得到,有个专业从事AR的创业公司设计了一个商业模 式,而这个模式跟那两家做AR与移动互联网结合的公司本质上是一样的,但是他成功了。就让我思考到一点,现在的AR技术其实不是问题,主要还是创意和推广 营销的问题。最近教育类的产品获得成功,也证明了这一点。

    图 1-4 卡牌教育类AR产品

    基 于卡牌类的AR产品,看来只能这样了,与互联网之间的交集似乎比较小。因为很多这种产品都是单机的,或者采用离线下载资源的方式。没有移动互联网的实时交 互等等属性。也正是由于如此,这个方向还是一片未开垦的宝地,对于未来应该还是会有更多的可能性吧。这些都是一部分的愿景了。另外,基于LBS的AR应 用,能够和互联网很好的结合,这个就不多说,也是比较容易理解的事情。

    图 1-5 Markerless AR

    图 1-6 基于LBS的AR应用

    三、AR的明天

     

    基 于2D图片的AR技术已经发展的很成熟,剩下来思考的多是应用场景的问题。为什么说是一部分的愿景呢?AR技术的未来肯定不是依靠卡牌或者图片,这样对我 们的限制也会很多。未来的AR将会是什么样的?现在大家都在谈论可穿戴设备、物联网、大数据。没错,这些都是未来几年热门并有希望改变人们生活习惯的技 术。未来AR技术必定要和这些技术融合。AR技术也将会改变人们的交互方式。

     

    借 助于可穿戴设备,比如Qualcomm的Vuforia SDK,AR将真正连接云端的数据,一同出现在人们的视野中。AR技术将会像《未来生活的一天》所描述的那样,或者像《钢铁侠》电影中的场景。那时候,给 人们带来的直观感受将会是:一切都悬在空中,一切都渗透到空气里。微软发布的HoloLens全息眼镜的发布,更为这些的实现,带来了无限可能。如下图所 见,这就是未来AR该有的模样!

    图 1-7 HoloLens与钢铁侠

    再 借助于物联网,智能家居,在家中,随时随地都是屏幕,在借助大数据,随时随地都能办公和交友聊天娱乐。在厕所,不用担心手机掉厕所;在厨房,不用弯着腰看 书学习炒菜;躺在床上,不用担心手拿着平板看东西会手酸,你眼前任何一片区域都可能是电脑屏幕。等等这一切,都离不开AR技术。

     

    目 前AR基本不涉及到很多数据,因为没有实时交互,目前的交互大都是模型的交互。未来AR,将不仅仅是模型的交互,更多的是数据的交互。比如建筑,医疗、教 育、社交等涉及到传统行业的工作事务。或者结合大数据,将所有的事物存储,通过AR可以识别任何实物,并且获取相关信息。明天AR可能成为搜索的一种方式 也未必呢!(PS:识别3D Object的AR现在也有应用,但是应用场景相当少,不多说了,有兴趣留言 :-))

    我画了一个图:简单说明一下AR与这三者之间的关系:

    图 1-8 未来AR与IOT、可穿戴、大数据的关系

    通过这个图可以看出,三者未来是个三角关系,而这三角由AR技术构建。这是我对未来AR的一种设想。

    目 前,很多做AR的公司,都是靠接品牌厂商的项目过活,也有赚到钱的(和政府部门做生意的除外)。而自己做产品的大多不成功,除了前面说到的,这几个月出现 的少数的AR教育类的产品。所以,大部分AR公司都是不温不火的。智能眼镜未来会发展,包括国内厂家、也包括国外比如微软、甚至Google未来的眼镜2 代等,这些都需要AR软件商提供软件产品,那么未来,开发AR的产品会不会像现在这么流行的手机APP开发产品这样呢?谁都说不准,不过,我还是抱有一些 幻想的!哈哈!:-)

     

    总之,我相信大家的选择是正确的,相信AR未来会更好!

    版权声明:本文为博主原创文章,未经博主允许不得转载。

    [转载]Vuforia开发技巧一-提高Target的识别率(第一部分) - Vuforia - ARSchool

    mikel阅读(837)

    Vuforia有个Targe

    来源: [转载]Vuforia开发技巧一-提高Target的识别率(第一部分) – Vuforia – ARSchool

    Vuforia有个Target Manager,这里主要负责处理待识别的Target,在最新的4.0版本中,可识别的标志包括以下四种类型:

    一般使用较多的是Single Image,那么如何提高这类图片的识别度呢?识别度关系到什么呢?
    比如识别之后,增强显示信息不稳定,会抖动;或者很难识别出Target,无法出现增强信息。
    1、星级
    Vuforia识别的原理是通过检测自然特征点的匹配来完成的。将Target Manager中的image检测出的特征点保存在数据库中,然后在实时检测出真实图像中的特征点与数据库中模板图片的特征点数据进行匹配。
    星级评判标准看这篇文章:
    https://developer.vuforia.com/library/articles/Solution/Natural-Features-and-Ratings
    当然,有时候会发现,即使1-2颗星也能很好的识别,但是为了保证稳定性,最好提高Target的星级。

    星级越高识别度越好。

    Attribute Example
    信息丰富 街景、人群等
    对比度高 有明有暗的区域
    没有重复的特征 草地、房屋正面门窗、石子地面

    关于如何增强局部对比度,看下面这篇文章:
    https://developer.vuforia.com/library/articles/Solution/Local-Contrast-Enhancement

    2、摄像头对焦
    Vuforia的demo中是设置为自动对焦的。当无法自动对焦时,拍摄到的实时场景是模糊的,这样对Target的识别有很大的影响。检测和跟踪的性能被大大降低了。
    1、开启现行对焦模式(FOCUS_MODE_CONTINUOUS_AUTO)
    这种模式可以使设备根据当前场景进行自动对焦
    2、Vuforia其他对焦模式
    并不是所有的设备都支持线性对焦的,所以需要启用其他对焦模式
    3、触发自动对焦(FOCUS_MODE_TRIGGER_AUTO)
    点击屏幕触发自动对焦模式,这个在Vuforiademo中都有涉及到。

    更多关于摄像头对焦的模式看下面的文章:
    https://developer.vuforia.com/library/articles/Solution/Camera-Focus-Modes

    3、光照
    AR算法中,光照条件也是个不容忽视的问题。在很多论文中,当实验算法的稳定性时,都会对光照条件进行检测。因为光照条件将会在很大程度上影响检测和跟踪的效果。
    1、环境中光照足够,保证摄像头能够清晰地获取图像中的信息。
    2、保证光照的稳定和可控。
    这就是室内AR和室外AR在算法上有一定的区别的原因。Vuforia的应用大多是室内。
    3、活用闪光灯
    闪光灯的作用就是补光,不管是用作手电筒还是camera中。如果你的应用需要在黑暗的环境中运行,那么需要打开闪光灯才行。
    Vuforia API:
    CameraDevice.Instance.SetFlashTorchMode( true );
    Unity3d中:
    CameraDevice.Instance.SetFlashTorchMode( true );

    [转载]一步一步教你写OpenGLES之HelloWorld - OpenGL - ARSchool

    mikel阅读(1256)

    #Action 在写第一个GL “Hello w

    来源: [转载]一步一步教你写OpenGLES之HelloWorld – OpenGL – ARSchool

    #Action
    在写第一个GL “Hello world”程序之前,相关的环境配置就不多说了。开发平台自然是google新推荐的AndroidStudio(由于之前项目一直用Eclipse, 因此,对于AndroidStudio也是边实践边摸索)。

    #相关简述
    OpenGLES1.0 大多是官方内置的API,不允许用户对其更改,对于OpenGL的开发虽然简单,但是灵活度和定制性太差。
    OpenGLES2.0 允许用户加大自由的写出自己的图形程序,也是现在Android平台主流的OpenGL API  Android 2.3以上支持
    OpenGLES3.0  现在相对来说还不成熟,但是在OpenGLES2.0的基础上加了许多新的特性 Android4.3以上支持

    #begin
    OpenGL在正式编写之前,需要一些初始化的工作,如:
    创建一个窗口,配置好其颜色格式,深度buffer大小,以及为其分配一个上下文
    创建一个background线程,尽量保证OpenGL的所有API都运行在这个线程里面

    好在Android平台上,GLSurfaceView为我们准备好了这一切,我们只需要在其Renderer接口的相应方法里写相应的逻辑即可。
    GLSurfaceView实际上实在Android的屏幕上创建了自己的窗口, 然后在View的继承体系中开了个“洞”,使得OpenGL surface能够显示内容。但是GLSurfaceView却不能像其它View一样实现动画和变换效果。 好在Android4.0以上,推出了TextureView, 它可以不在另开一个窗口的前提下,用来渲染OpenGL(后续的教程会使用到)

    # create Activity
    在AndroidStudio上创键一个Android工程就像在Eclipse上一样简单。花一定的时间,了解一下AndroidStudio的视图结构,我们就可以开始编程了。
    在工程目录,Scr/Main/Java下是我们创建好的package包,在该包下创建一个Activity,名字叫MyGL.java
    大致如下:

    复制代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public class MyGL extends ActionBarActivity {
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
             
            setContentView(main.xml);
        }
        
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.menu_my_gl, menu);
            return true;
        }
        
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
        
            //noinspection SimplifiableIfStatement
            if (id == R.id.action_settings) {
                return true;
            }
        
            return super.onOptionsItemSelected(item);
        }
    }

    接下来,在Activity的Filed里加两个私有变量

    复制代码

    1
    2
    private GLSurfaceView glSurfaceView;  //GL窗口
    private boolean rendererSet; //判断GL是否开始运行

    在onCreate方法里,创建GL窗口

    复制代码

    1
    2
    super.onCreate(savedInstanceState);
    glSurfaceView = new GLSurfaceView(this);

    你可以用 ActivityManager的getDeviceConfigureationInfo().reqGLEsVersion 是否大于 0x20000来判断,你的机子是否支持OpenGL ES2.0,这里我默认设备都支持

    接着,为GLSurfaceView的窗口配置OpenGL ES2.0的上下文和一个渲染的线程类

    复制代码

    1
    2
    3
    glSurfaceView.setEGLContextClientVersion(2);
    glSurfaceView.setRenderer(new MyGLRenderer());
    rendererSet = true;


    最后将setContentView(main.xml)修改为setContentView(glSurfaceView);

    GLSurfaceView一旦创建以后,就会有一个渲染线程不停的负责刷新窗口,渲染图形。因此,我们需要让改渲染线程与 Activity的生命周期进行同步:

    复制代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    @Override
       protected void onResume() {
           super.onResume();
           if(rendererSet)
           {
               glSurfaceView.onResume();
           }
       }
        
       @Override
       protected void onPause() {
           super.onPause();
           if(rendererSet)
           {
               glSurfaceView.onPause();
           }
       }

    以 上步骤完成后,我们还需要创建一个渲染类,我们的虚拟世界,就是在这个类中进行构建的。 渲染类继承自GLSurfaceView的Renderer接口,该接口,有三个方法onSurfaceCreated onSurfaceChanged, onDrawFrame。 这三个方法会被GL线程调用,其方法具体的实现需要我们自己实现。

    在我们的package包下创建一个继承GLSurfaceView的Renderer类,名字叫MyGLRenderer 如下:

    复制代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class MyGLRenderer implements GLSurfaceView.Renderer {
        
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            // 当GLurfaceView初始创建或者设备唤醒时或者重新切换回该Activity时
            // 该方法会被调用
            glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
        }
        
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            // 当GLSurfaceView初始创建时,或者GLSurfaceView的大小改变时
           //该方法会被调用
          glViewport(0, 0, width, height);
        
        }
        
        @Override
        public void onDrawFrame(GL10 gl) {
           glClear(GL_COLOR_BUFFER_BIT);
        
        }
    }

    重点说下onDrawFrame方法, 它会被GL线程一直循环调用。每循环一次,它就会将我们编写的内容画在屏幕上。 最简单的就是如上程序,为其添加一个背景色。
    每个屏幕窗口,都会为GL分配几个buffer,一般最多有16个:
    4个color buffer
    1个 depth buffer
    1个stencil buffer
    1个多采样buffer
    1个或多个辅助buffer

    而glClearColor就是每次向color buffer 填上色彩。 其4个参数分别是 r, g, b, a 前三个表示色彩,最后一个表示透明度在每次onDrawFrame迭代中,要使用glClear来清空color buffer,这样保证了,每一次内容的更新

    在Renderer的三个接口中,都接受了GL10 gl这样的参数。这是因为,如果我们需要调用GLES1.0的Api可以使用该对象,而我们在调用GLES api时也没有使用GLES20 的前缀。 这个可以通过设置静态导入,来将其省略,便于我们的编写。在AndroidStudio的标题栏,File里,点击 Settings>Editor>Java  然后添加import static android.openg.GLES20.*; 即可

    好了。到此我们这个OpenGL ES2.0的Hello world程序就写完了。
    #end
    看到红色效果了么?