精华内容
下载资源
问答
  • 由iOS开发专家根据OpenGLES*版本撰写,不仅详细讲解了OpenGL ES与GLKit的结合使用,而且还系统讲解OpenGLES的核心概念、技术,以及iOS的图形机制,并通过大量案例讲解了在iOS上进行OpenGL ES开发的方法和技巧。
  • 在上篇文章,我们能够配置好基本的Android OpenGL 使用的环境。但是如果我们不了解OpenGL ES如何定义...本文主要做的事情就是为了讲解Android设备屏幕相关的OpenGL ES坐标系统,定义形状,形状面的基础知识,以及定...

    在上篇文章,我们能够配置好基本的Android OpenGL 使用的环境。但是如果我们不了解OpenGL ES如何定义图像的一些基本知识就使用OpenGL ES进行绘图还是有点棘手的。所以能够在OpenGL ES的View里面定义要绘制的形状是进行高端绘图操作的第一步。
    本文主要做的事情就是为了讲解Android设备屏幕相关的OpenGL ES坐标系统,定义形状,形状面的基础知识,以及定义三角形和正方形。

    一、定义三角形

    OpenGL ES允许你使用三维空间坐标系定义绘制的图像,所以你在绘制一个三角形之前必须要先定义它的坐标。在OpenGL中,这样做的典型方法是为坐标定义浮点数的顶点数组。
    为了获得最大的效率,可以将这些坐标写入ByteBuffer,并传递到OpenGL ES图形管道进行处理。

    public class Triangle {
    
        private FloatBuffer vertexBuffer;
    
        // number of coordinates per vertex in this array
        static final int COORDS_PER_VERTEX = 3;
        static float triangleCoords[] = {   // in counterclockwise order:
                 0.0f,  0.622008459f, 0.0f, // top
                -0.5f, -0.311004243f, 0.0f, // bottom left
                 0.5f, -0.311004243f, 0.0f  // bottom right
        };
    
        // Set color with red, green, blue and alpha (opacity) values
        float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
    
        public Triangle() {
            // initialize vertex byte buffer for shape coordinates
            ByteBuffer bb = ByteBuffer.allocateDirect(
                    // (number of coordinate values * 4 bytes per float)
                    triangleCoords.length * 4);
            // use the device hardware's native byte order
            bb.order(ByteOrder.nativeOrder());
    
            // create a floating point buffer from the ByteBuffer
            vertexBuffer = bb.asFloatBuffer();
            // add the coordinates to the FloatBuffer
            vertexBuffer.put(triangleCoords);
            // set the buffer to read the first coordinate
            vertexBuffer.position(0);
        }
    }

    默认情况下,OpenGL ES采用坐标系,[0,0,0](X,Y,Z)指定GLSurfaceView框架的中心,[1,1,0]是框架的右上角,[ - 1,-1,0]是框架的左下角。 有关此坐标系的说明,请参阅OpenGL ES开发人员指南。

    请注意,此图形的坐标以逆时针顺序定义。 绘图顺序非常重要,因为它定义了哪一面是您通常想要绘制的图形的正面,以及背面。关于这块相关的更多的内容,可以去查看一下相关的OpenGL ES 文档。

    二、定义正方形

    可以看到,在OpenGL里面定义一个三角形很简单。但是如果你想要得到一个更复杂一点的东西呢?比如一个正方形?能够找到很多办法来作到这一点,但是在OpenGL里面绘制这个图形的方式是将两个三角形画在一起。
    682616-20171208130636999-609916321.png
    同样,你应该以逆时针的顺序为这两个代表这个形状的三角形定义顶点,并将这些值放在一个ByteBuffer中。 为避免定义每个三角形共享的两个坐标两次,请使用图纸列表告诉OpenGL ES图形管道如何绘制这些顶点。 这是这个形状的代码:

    public class Square {
    
        private FloatBuffer vertexBuffer;
        private ShortBuffer drawListBuffer;
    
        // number of coordinates per vertex in this array
        static final int COORDS_PER_VERTEX = 3;
        static float squareCoords[] = {
                -0.5f,  0.5f, 0.0f,   // top left
                -0.5f, -0.5f, 0.0f,   // bottom left
                 0.5f, -0.5f, 0.0f,   // bottom right
                 0.5f,  0.5f, 0.0f }; // top right
    
        private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
    
        public Square() {
            // initialize vertex byte buffer for shape coordinates
            ByteBuffer bb = ByteBuffer.allocateDirect(
            // (# of coordinate values * 4 bytes per float)
                    squareCoords.length * 4);
            bb.order(ByteOrder.nativeOrder());
            vertexBuffer = bb.asFloatBuffer();
            vertexBuffer.put(squareCoords);
            vertexBuffer.position(0);
    
            // initialize byte buffer for the draw list
            ByteBuffer dlb = ByteBuffer.allocateDirect(
            // (# of coordinate values * 2 bytes per short)
                    drawOrder.length * 2);
            dlb.order(ByteOrder.nativeOrder());
            drawListBuffer = dlb.asShortBuffer();
            drawListBuffer.put(drawOrder);
            drawListBuffer.position(0);
        }
    }

    这个例子让你了解用OpenGL创建更复杂的形状的过程。 一般来说,您使用三角形的集合来绘制对象。下面的文章里面,将讲述如何在屏幕上绘制这些形状。

    转载于:https://www.cnblogs.com/renhui/p/8000345.html

    展开全文
  • EGL提供了一种方法用于通过客户端API和本地窗口系统进行渲染,客户端API包括用于嵌入式系统的3D渲染器和OpenGLES,用于桌面系统的OpenGL ES的超集OpenGL,2D矢量图形渲染器OpenVG,本地窗口系统包括Windows,X ...

    转自https://www.2cto.com/kf/201806/752471.html

     

    什么是OpenGL?

    Open Graphics Library (OpenGL) is a cross-language, cross-platform application programming interface (API) for rendering 2D and 3D vector graphics. The API is typically used to interact with a graphics processing unit (GPU), to achieve hardware-accelerated rendering.

    OpenGL是和编程语言,平台无关的一套interface,主要是为了rendering 2D和3D图形等。一般这套接口是用来和GPU进行交互的,使用GPU进行rendering硬件加速。

    什么是OpenGL ES?

    Android includes support for high performance 2D and 3D graphics with the Open Graphics Library (OpenGL), specifically, the OpenGL ES API. OpenGL is a cross-platform graphics API that specifies a standard software interface for 3D graphics processing hardware. OpenGL ES is a flavor of the OpenGL specification intended for embedded devices.

    OpenGL ES就是专门为嵌入式设备设计的,当然售后机也是嵌入式,那么OpenGL ES和OpenGL中的函数接口肯定有些是不一样的,因为嵌入式设备和pc等的硬件处理能力还是有差距的,不然手机卡死了。

    既然OpenGL ES只是一组函数接口,那么如何使用呢?我们肯定首先要去实现这些函数接口,而android提供了两种类型的实现:软件实现,硬件实现。

    a, 硬件实现,前面提到这组函数接口主要是为了和GPU这个硬件进行打交道的。所以各个硬件厂商会提供相关的实现,例如高通平台的adreno解决方案;

    b,软件实现,android也提供了一套OpenGL ES的软件实现,就是说不用GPU了,完全用软件实现画图的相关功能,也就是libagl,代码在frameworks\native\opengl\libagl,其makefile中,

    ?

    1

    2

    3

    /软件实现最终编译完保存在system\lib\egl\libGLES_android.so

    LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl

    LOCAL_MODULE:= libGLES_android

    到此,已经有了OpenGL ES的具体实现,但是由于其实现的平台无关系,所以在android上还不能使用,必须借助EGL。

    EGL

    EGL - Native Platform Interface

    EGL is an interface between Khronos rendering APIs such as OpenGL ES or OpenVG and the underlying native platform window system.

    It handles graphics context management, surface/buffer binding, and rendering synchronization and enables high-performance, accelerated, mixed-mode 2D and 3D rendering using other Khronos APIs.

    EGL,它是图形渲染API(如OpenGL ES)与本地平台窗口系统的一层接口,保证了OpenGL ES的平台独立性。EGL提供了若干的功能:创建rendering surface,创建graphics context,同步应用程序和本地平台渲染API,提供对显示设备的访问,提供对渲染配置的管理等。

    EGL提供了一种方法用于通过客户端API和本地窗口系统进行渲染,客户端API包括用于嵌入式系统的3D渲染器和OpenGLES,用于桌面系统的OpenGL ES的超集OpenGL,2D矢量图形渲染器OpenVG,本地窗口系统包括Windows,X

    那么什么是EGL?EGL是OpenGL ES和底层的native window system之间的接口,承上启下。

    EGL is a complement to OpenGL ES. EGL is used for getting surfaces to render to using functions like eglCreateWindowSurface, and you can then draw to that surface with OpenGL ES. Its role is similar to GLX/WGL/CGL.

    Whether or not EGL can give you a context that supports OpenGL ES 2.0 may vary by platform, but if the Android device supports ES 2.0 and EGL, you should be able to get such a context from EGL. Take a look at the EGL_RENDERABLE_TYPE attribute and the EGL_OPENGL_ES2_BIT when requesting an EGLConfig.

    在Android上,EGL完善了OpenGL ES。利用类似eglCreateWindowSurface的EGL函数可以创建surface 用来render ,有了这个surface你就能往这个surface中利用OpenGL ES函数去画图了。

    EGL要做什么

    EGL既然做平台和OpenGL ES的中间层,那EGL做的肯定就是和平台息息相关的事:

    创建绘图窗口

    也就是所谓的FrameBuffer,FrameBuffer可以先到到屏幕上(SurfaceView) 创建渲染环境(Context上下文)

    渲染环境是指OpenGL ES的所有项目运行需要的 数据结构。如顶点,片段着色器,顶点数据矩阵

    OpenGL渲染一般流程:

    这里写图片描述

    EGLConfig属性

    属性 描述 默认值
    EGL_BUFFER_SIZE 颜色缓冲器中所有组成演的的位数 0
    EGL_RED_SIZE 颜色缓冲区中红色位数 0
    EGL_LUMINANCE_SIZE 颜色缓冲区中透明度的位数 0
    EGL_ALPTHA_SIZE 颜色缓冲区中透明位数 0
    EGL_ALPTHHA_MASK_SIZE 遮挡缓冲区透明度掩码位数 0
    EGL_BIND_TO_TEXTURE_RGB 绑定到RGB贴图使能为真 EGL_DONT_CARE
    EGL_BIND_TO_TEXTURE_RGBA 绑定到RGBA贴图使能为真 EGL_DONT_CARE
    EGL_COLOR_BUFFER_TYPE 颜色缓冲区类型 EGL_RGB_BUFFER, 或者EGL_LUMINANCE_BUFFER EGL_RGB_BUFFER
    EGL_CONFIG_CAVEAT 配置有关的警告信息 EGL_DONT_CARE
    EGL_CONFIG_ID 唯一的 EGLConfig 标示值 EGL_DONT_CARE
    EGL_CONFORMANT 使用EGLConfig 创建的上下文符合要求时为真 -
    EGL_DEPTH_SIZE 深度缓冲区位数 0
    EGL_LEVEL 帧缓冲区水平 0
    EGL_MAX_PBUFFER_WIDTH 使用EGLConfig 创建的PBuffer的最大宽度
    EGL_MAX_PBUFFER_HEIGHT 使用EGLConfig 创建的PBuffer最大高度
    EGL_MAX_PBUFFER_PIXELS 使用EGLConfig 创建的PBuffer最大尺寸
    EGL_MAX_SWAP_INTERVAL 最大缓冲区交换间隔 EGL_DONT_CARE
    EGL_MIN_SWAP_INTERVAL 最小缓冲区交换间隔 EGL_DONT_CARE
    EGL_NATIVE_RENDERABLE 如果操作系统渲染库能够使用EGLConfig 创建渲染渲染窗口 EGL_DONT_CARE
    EGL_NATIVE_VISUAL_ID 与操作系统通讯的可视ID句柄 EGL_DONT_CARE
    EGL_NATIVE_VISUAL_TYPE 与操作系统通讯的可视ID类型 EGL_DONT_CARE
    EGL_RENDERABLE_TYPE 渲染窗口支持的布局组成标示符的遮挡位EGL_OPENGL_ES_BIT, EGL_OPENGL_ES2_BIT, orEGL_OPENVG_BIT that EGL_OPENGL_ES_BIT
    EGL_SAMPLE_BUFFERS 可用的多重采样缓冲区位数 0
    EGL_SAMPLES 每像素多重采样数 0
    EGL_S TENCIL_SIZE 模板缓冲区位数 0
    EGL_SURFACE_TYPE EGL 窗口支持的类型EGL_WINDOW_BIT, EGL_PIXMAP_BIT,或EGL_PBUFFER_BIT EGL_WINDOW_BIT
    EGL_TRANSPARENT_TYPE 支持的透明度类型 EGL_NONE
    EGL_TRANSPARENT_RED_VALUE 透明度的红色解释 EGL_DONT_CARE
    EGL_TRANSPARENT_GRE EN_VALUE 透明度的绿色解释 EGL_DONT_CARE
    EGL_TRANSPARENT_BLUE_VALUE 透明度的兰色解释 EGL_DONT_CARE

    一个简单例子:

    OpenGL的渲染是基于线程的,所以我们要创建一个GLLRenderer类继承于HandlerThread:

    ?

    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

    138

    139

    140

    141

    142

    143

    144

    145

    146

    147

    148

    149

    150

    151

    152

    153

    154

    155

    156

    157

    158

    159

    160

    161

    162

    163

    164

    165

    166

    167

    168

    169

    170

    171

    172

    173

    174

    175

    176

    177

    178

    179

    180

    181

    182

    183

    184

    185

    186

    187

    188

    189

    190

    191

    192

    193

    194

    195

    196

    197

    198

    199

    200

    201

    202

    203

    204

    205

    206

    207

    208

    209

    210

    211

    212

    213

    214

    215

    216

    217

    218

    219

    220

    221

    222

    223

    224

    225

    226

    227

    228

    229

    230

    231

    232

    233

    234

    235

    236

    237

    public class GLRenderer extends HandlerThread {

     

     private static final String TAG = "GLRenderer";

     private EGLConfig eglConfig = null;

     private EGLDisplay eglDisplay = EGL14.EGL_NO_DISPLAY;

     private EGLContext eglContext = EGL14.EGL_NO_CONTEXT;

     

     private int program;

     private int vPosition;

     private int uColor;

     

     

     public GLRenderer() {

      super("GLRenderer");

     }

     

     private void createGL(){

      eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);

     

      int[] version = new int[2];

      if (!EGL14.eglInitialize(eglDisplay, version,0,version,1)) {

    throw new RuntimeException("EGL error "+EGL14.eglGetError());

      }

     

      int[] configAttribs = {

     EGL14.EGL_BUFFER_SIZE,32,

     EGL14.EGL_ALPHA_SIZE,8,

     EGL14.EGL_BLUE_SIZE,8,

     EGL14.EGL_GREEN_SIZE,8,

     EGL14.EGL_RED_SIZE,8,

     EGL14.EGL_RENDERABLE_TYPE,EGL14.EGL_OPENGL_ES2_BIT,

     EGL14.EGL_SURFACE_TYPE,EGL14.EGL_WINDOW_BIT,

     EGL14.EGL_NONE

      };//获取framebuffer格式和能力

     

      int[] numConfigs = new int[1];

      EGLConfig[] configs = new EGLConfig[1];

     

      if (!EGL14.eglChooseConfig(eglDisplay, configAttribs,0, configs,

     0,configs.length, numConfigs,0)) {

    throw new RuntimeException("EGL error "+EGL14.eglGetError());

      }

     

      eglConfig = configs[0];

     

     

      //创建OpenGL上下文

      int[] contextAttribs = {

     EGL14.EGL_CONTEXT_CLIENT_VERSION,2,

     EGL14.EGL_NONE

      };

      eglContext = EGL14.eglCreateContext(eglDisplay,eglConfig,EGL14.EGL_NO_CONTEXT,contextAttribs,0);

     

      if(eglContext== EGL14.EGL_NO_CONTEXT) {

    throw new RuntimeException("EGL error "+EGL14.eglGetError());

      }

     }

     

     private void destoryGL(){

      EGL14.eglDestroyContext(eglDisplay,eglContext);

      eglContext = EGL14.EGL_NO_CONTEXT;

      eglDisplay = EGL14.EGL_NO_DISPLAY;

     }

     

     @Override

     public synchronized void start() {

      super.start();

     

      new Handler(getLooper()).post(new Runnable() {

    @Override

    public void run() {

     createGL();

    }

      });

     }

     

     public void release(){

      new Handler(getLooper()).post(new Runnable() {

    @Override

    public void run() {

     destoryGL();

     quit();

    }

      });

     }

     

     /**

      * 加载制定shader的方法

      * @param shaderType shader的类型  GLES20.GL_VERTEX_SHADERGLES20.GL_FRAGMENT_SHADER

      * @param sourceCode shader的脚本

      * @return shader索引

      */

     private int loadShader(int shaderType,String sourceCode) {

      // 创建一个新shader

      int shader = GLES20.glCreateShader(shaderType);

      // 若创建成功则加载shader

      if (shader != 0) {

    // 加载shader的源代码

    GLES20.glShaderSource(shader, sourceCode);

    // 编译shader

    GLES20.glCompileShader(shader);

    // 存放编译成功shader数量的数组

    int[] compiled = new int[1];

    // 获取Shader的编译情况

    GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);

    if (compiled[0] == 0) {//若编译失败则显示错误日志并删除此shader

     Log.e("ES20_ERROR", "Could not compile shader " + shaderType + ":");

     Log.e("ES20_ERROR", GLES20.glGetShaderInfoLog(shader));

     GLES20.glDeleteShader(shader);

     shader = 0;

    }

      }

      return shader;

     }

     

     

     /**

      * 创建shader程序的方法

      */

     private int createProgram(String vertexSource, String fragmentSource) {

      //加载顶点着色器

      int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);

      if (vertexShader == 0) {

    return 0;

      }

     

      // 加载片元着色器

      int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);

      if (pixelShader == 0) {

    return 0;

      }

     

      // 创建程序

      int program = GLES20.glCreateProgram();

      // 若程序创建成功则向程序中加入顶点着色器与片元着色器

      if (program != 0) {

    // 向程序中加入顶点着色器

    GLES20.glAttachShader(program, vertexShader);

    // 向程序中加入片元着色器

    GLES20.glAttachShader(program, pixelShader);

    // 链接程序

    GLES20.glLinkProgram(program);

    // 存放链接成功program数量的数组

    int[] linkStatus = new int[1];

    // 获取program的链接情况

    GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);

    // 若链接失败则报错并删除程序

    if (linkStatus[0] != GLES20.GL_TRUE) {

     Log.e("ES20_ERROR", "Could not link program: ");

     Log.e("ES20_ERROR", GLES20.glGetProgramInfoLog(program));

     GLES20.glDeleteProgram(program);

     program = 0;

    }

      }

      return program;

     }

     

     /**

      * 获取图形的顶点

      * 特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer

      * 转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题

      *

      * @return 顶点Buffer

      */

     private FloatBuffer getVertices() {

      float vertices[] = {

     0.0f,0.5f,

     -0.5f, -0.5f,

     0.5f,  -0.5f,

      };

     

      // 创建顶点坐标数据缓冲

      // vertices.length*4是因为一个float占四个字节

      ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);

      vbb.order(ByteOrder.nativeOrder()); //设置字节顺序

      FloatBuffer vertexBuf = vbb.asFloatBuffer(); //转换为Float型缓冲

      vertexBuf.put(vertices);//向缓冲区中放入顶点坐标数据

      vertexBuf.position(0);  //设置缓冲区起始位置

     

      return vertexBuf;

     }

     

     public void render(Surface surface, int width, int height){

      final int[] surfaceAttribs = { EGL14.EGL_NONE };

      EGLSurface eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, eglConfig, surface, surfaceAttribs, 0);

      EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);

     

      // 初始化着色器

      // 基于顶点着色器与片元着色器创建程序

      program = createProgram(verticesShader, fragmentShader);

      // 获取着色器中的属性引用id(传入的字符串就是我们着色器脚本中的属性名)

      vPosition = GLES20.glGetAttribLocation(program, "vPosition");

      uColor = GLES20.glGetUniformLocation(program, "uColor");

     

      // 设置clear color颜色RGBA(这里仅仅是设置清屏时GLES20.glClear()用的颜色值而不是执行清屏)

      GLES20.glClearColor(1.0f, 0, 0, 1.0f);

      // 设置绘图的窗口(可以理解成在画布上划出一块区域来画图)

      GLES20.glViewport(0,0,width,height);

      // 获取图形的顶点坐标

      FloatBuffer vertices = getVertices();

     

      // 清屏

      GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

      // 使用某套shader程序

      GLES20.glUseProgram(program);

      // 为画笔指定顶点位置数据(vPosition)

      GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 0, vertices);

      // 允许顶点位置数据数组

      GLES20.glEnableVertexAttribArray(vPosition);

      // 设置属性uColor(颜色 索引,R,G,B,A)

      GLES20.glUniform4f(uColor, 0.0f, 1.0f, 0.0f, 1.0f);

      // 绘制

      GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 3);

     

      // 交换显存(将surface显存和显示器的显存交换)

      EGL14.eglSwapBuffers(eglDisplay, eglSurface);

     

      EGL14.eglDestroySurface(eglDisplay, eglSurface);

     }

     

     // 顶点着色器的脚本

     private static final String verticesShader

    = "attribute vec2 vPosition;\n" // 顶点位置属性vPosition

    + "void main(){ \n"

    + "gl_Position = vec4(vPosition,0,1);\n" // 确定顶点位置

    + "}";

     

     // 片元着色器的脚本

     private static final String fragmentShader

    = "precision mediump float;\n" // 声明float类型的精度为中等(精度越高越耗资源)

    + "uniform vec4 uColor; \n" // uniform的属性uColor

    + "void main(){\n"

    + "gl_FragColor = uColor;  \n" // 给此片元的填充色

    + "}";

     

     

    }

    createGL()方法获取了一个默认的显示设备(也就是手机屏幕),初始化并返回当前系统使用的OpenGL版本(主版本+子版本),然后通过配置(主要以键值对的方式配置,最后由EGL_NONE结尾)得到一个EGLConfig,最后创建一个EGLContext。

    destroyGL()方法则是释放掉OpenGL的资源(主要就是EGLContext)。

    render()方法中主要是渲染,这里为了方便把渲染的环境和渲染写在一起并只渲染一次(我们只画了一个三角形),前三行代码我们创建了一个EGLSurface并设置为当前的渲染对象,后面eglSwapBuffers()交换了显示器和EGLSurface的显存,也就是将我们渲染的东西放到显示器去显示,这样我们就看到我们绘制的三角形了,最后就是销毁我们创建的EGLSurface。

    然后在Activity中使用它:

    ?

    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

    public class MainActivity extends Activity {

     private GLRenderer glRenderer;

     

     @Override

     protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      setContentView(R.layout.activity_main);

     

      SurfaceView sv = (SurfaceView)findViewById(R.id.sv_main_demo);

      glRenderer = new GLRenderer();

      glRenderer.start();

     

      sv.getHolder().addCallback(new SurfaceHolder.Callback() {

    @Override

    public void surfaceCreated(SurfaceHolder surfaceHolder) {

     

    }

     

    @Override

    public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {

     glRenderer.render(surfaceHolder.getSurface(),width,height);

    }

     

    @Override

    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

     

    }

      });

     }

     

     @Override

     protected void onDestroy() {

      glRenderer.release();

      glRenderer = null;

      super.onDestroy();

     }

    }

    然后我们就可以得到一个:
    这里写图片描述

    然后我们继续学习:

    EGL创建EGLSurface有三个方法:glCreateWindowSurface()、eglCreatePbufferSurface()和eglCreatePixmapSurface()。

    WindowSurface:是和窗口相关的,也就是在屏幕闪给的一块显示区的封装,渲染后即显示在界面上。 PbufferSurface:在显存中开辟一个控件,将渲染后的数据(帧)存放在这里 pixmapSurface:以位图的形式存放在内存中(支持性不好)

    做离屏渲染我们可以选择PbufferSurface或者PixmapSurface(其实WindowSurface也是可以的)

    (帧缓存对象FBO是对帧缓存的封装,性能要优于Pbuffer但并非可以完全替代Pbuffer)。

    OpenGL操作的最终目标实际上是帧缓存(Frame Buffer)后面的各种表现形式则是EGL对Frame Buffer的封装
    这里写图片描述

    对之前的代码进行整理:

    新建GLSurface类,对EGLSurface进行封装 将GLRenderer类改为抽象类,继承于Thread GLRenderer添加一个阻塞队列(消息队列),用于交互和解耦 GLRenderer添加一个Event内部类 GLRenderer中添加生命周期,将渲染之类的具体工作放到实现类中 添加ShaderUtil类,将着色器创建的代码封装到这个类中

    代码:

    ?

    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

    package com.example.asus1.camerawithopengl;

     

    import android.opengl.EGL14;

    import android.opengl.EGLSurface;

    import android.view.Surface;

     

    public class GLSurface {

     

     public static final int TYPE_WINDOW_SURFACE  = 0;

     public static final int TYPE_PBUFFER_SURFACE = 1;

     public static final int TYPE_PIXMAP_SURFACE  = 2;

     

     

     protected final int type;

     protected Object surface;

     protected EGLSurface eglSurface = EGL14.EGL_NO_SURFACE;

     protected Viewport viewport = new Viewport();

     

     public GLSurface(int width,int height){

      setViewport(0,0,width,height);

      surface = null;

      type = TYPE_PBUFFER_SURFACE;

     }

     public GLSurface(Surface surface, int width, int height) {

     

      this(surface,0,0,width,height);

     }

     

     public GLSurface(Surface surface, int x, int y, int width, int height) {

      setViewport(x, y, width, height);

      this.surface = surface;

      type = TYPE_WINDOW_SURFACE;

     }

     

     

     public void setViewport(int x,int y,int width,int height){

      viewport.x = x;

      viewport.y = y;

      viewport.width = width;

      viewport.height = height;

     }

     

     public Viewport getViewport(){

      return viewport;

     }

     

    }

    ?

    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

    138

    139

    140

    141

    142

    143

    144

    145

    146

    147

    148

    149

    150

    151

    152

    153

    154

    155

    156

    157

    158

    159

    160

    161

    162

    163

    164

    165

    166

    167

    168

    169

    170

    171

    172

    173

    174

    175

    176

    177

    178

    179

    180

    181

    182

    183

    184

    185

    186

    187

    188

    189

    190

    191

    192

    193

    194

    195

    196

    197

    198

    199

    200

    201

    202

    203

    204

    205

    206

    207

    208

    209

    210

    211

    212

    213

    214

    215

    216

    217

    218

    219

    220

    221

    222

    223

    224

    225

    226

    227

    228

    229

    230

    231

    232

    233

    234

    235

    236

    237

    238

    239

    240

    241

    242

    243

    244

    245

    246

    247

    248

    249

    250

    251

    252

    253

    254

    255

    256

    257

    258

    259

    260

    261

    262

    263

    264

    265

    266

    267

    268

    269

    270

    271

    272

    273

    274

    275

    276

    277

    278

    279

    280

    281

    282

    283

    284

    285

    286

    287

    288

    289

    290

    291

    292

    293

    294

    295

    296

    297

    298

    299

    300

    301

    302

    303

    304

    305

    306

    307

    308

    309

    310

    311

    312

    313

    314

    public abstract class GLRenderer1 extends Thread{

     

     private static final String TAG = "GLThread";

     private EGLConfig eglConfig = null;

     private EGLDisplay eglDisplay = EGL14.EGL_NO_DISPLAY;

     private EGLContext eglContext = EGL14.EGL_NO_CONTEXT;

     

     private ArrayBlockingQueue<event> eventQueue;

     private final List<glsurface> outputSurfaces;

     private boolean rendering;

     private boolean isRelease;

     

     public GLRenderer1() {

      setName("GLRenderer-"+getId());

      outputSurfaces = new ArrayList<>();

      rendering = false;

      isRelease = false;

     

      eventQueue = new ArrayBlockingQueue<>(100);

     }

     

     private boolean makeOutputSurface(GLSurface surface) {

      // 创建Surface缓存

      try {

    switch (surface.type) {

     case GLSurface.TYPE_WINDOW_SURFACE: {

      final int[] attributes = {EGL14.EGL_NONE};

      // 创建失败时返回EGL14.EGL_NO_SURFACE

      surface.eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, eglConfig, surface.surface, attributes, 0);

      break;

     }

     case GLSurface.TYPE_PBUFFER_SURFACE: {

      final int[] attributes = {

     EGL14.EGL_WIDTH, surface.viewport.width,

     EGL14.EGL_HEIGHT, surface.viewport.height,

     EGL14.EGL_NONE};

      // 创建失败时返回EGL14.EGL_NO_SURFACE

      surface.eglSurface = EGL14.eglCreatePbufferSurface(eglDisplay, eglConfig, attributes, 0);

      break;

     }

     case GLSurface.TYPE_PIXMAP_SURFACE: {

      Log.w(TAG, "nonsupport pixmap surface");

      return false;

     }

     default:

      Log.w(TAG, "surface type error " + surface.type);

      return false;

    }

      } catch (Exception e) {

    Log.w(TAG, "can't create eglSurface");

    surface.eglSurface = EGL14.EGL_NO_SURFACE;

    return false;

      }

     

      return true;

     }

     

     public void addSurface(@NonNull final GLSurface surface){

      Event event = new Event(Event.ADD_SURFACE);

      event.param = surface;

      if(!eventQueue.offer(event))

    Log.e(TAG,"queue full");

     }

     

     public void removeSurface(@NonNull final GLSurface surface){

      Event event = new Event(Event.REMOVE_SURFACE);

      event.param = surface;

      if(!eventQueue.offer(event))

    Log.e(TAG,"queue full");

     }

     

     /**

      * 开始渲染

      * 启动线程并等待初始化完毕

      */

     public void startRender(){

      if(!eventQueue.offer(new Event(Event.START_RENDER)))

    Log.e(TAG,"queue full");

      if(getState()==State.NEW) {

    super.start(); // 启动渲染线程

      }

     }

     

     public void stopRender(){

      if(!eventQueue.offer(new Event(Event.STOP_RENDER)))

    Log.e(TAG,"queue full");

     }

     

     public boolean postRunnable(@NonNull Runnable runnable){

      Event event = new Event(Event.RUNNABLE);

      event.param = runnable;

      if(!eventQueue.offer(event)) {

    Log.e(TAG, "queue full");

    return false;

      }

     

      return true;

     }

     

     @Override

     public void start() {

      Log.w(TAG,"Don't call this function");

     }

     

     public void requestRender(){

      eventQueue.offer(new Event(Event.REQ_RENDER));

     }

     

     /**

      * 创建OpenGL环境

      */

     private void createGL() {

      // 获取显示设备(默认的显示设备)

      eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);

      // 初始化

      int[] version = new int[2];

      if (!EGL14.eglInitialize(eglDisplay, version, 0, version, 1)) {

    throw new RuntimeException("EGL error " + EGL14.eglGetError());

      }

      // 获取FrameBuffer格式和能力

      int[] configAttribs = {

     EGL14.EGL_BUFFER_SIZE, 32,

     EGL14.EGL_ALPHA_SIZE, 8,

     EGL14.EGL_BLUE_SIZE, 8,

     EGL14.EGL_GREEN_SIZE, 8,

     EGL14.EGL_RED_SIZE, 8,

     EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,

     EGL14.EGL_SURFACE_TYPE, EGL14.EGL_WINDOW_BIT,

     EGL14.EGL_NONE

      };

      int[] numConfigs = new int[1];

      EGLConfig[] configs = new EGLConfig[1];

      if (!EGL14.eglChooseConfig(eglDisplay, configAttribs, 0, configs, 0, configs.length, numConfigs, 0)) {

    throw new RuntimeException("EGL error " + EGL14.eglGetError());

      }

      eglConfig = configs[0];

      // 创建OpenGL上下文(可以先不设置EGLSurface,但EGLContext必须创建,

      // 因为后面调用GLES方法基本都要依赖于EGLContext)

      int[] contextAttribs = {

     EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,

     EGL14.EGL_NONE

      };

      eglContext = EGL14.eglCreateContext(eglDisplay, eglConfig, EGL14.EGL_NO_CONTEXT, contextAttribs, 0);

      if (eglContext == EGL14.EGL_NO_CONTEXT) {

    throw new RuntimeException("EGL error " + EGL14.eglGetError());

      }

      // 设置默认的上下文环境和输出缓冲区(小米4上如果不设置有效的eglSurface后面创建着色器会失败,可以先创建一个默认的eglSurface)

      //EGL14.eglMakeCurrent(eglDisplay, surface.eglSurface, surface.eglSurface, eglContext);

      EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, eglContext);

     }

     

     /**

      * 销毁OpenGL环境

      */

     private void destroyGL() {

      EGL14.eglDestroyContext(eglDisplay, eglContext);

      eglContext = EGL14.EGL_NO_CONTEXT;

      eglDisplay = EGL14.EGL_NO_DISPLAY;

     }

     

     /**

      * 渲染到各个eglSurface

      */

     private void render(){

      // 渲染(绘制)

      for(GLSurface output:outputSurfaces){

    if(output.eglSurface== EGL14.EGL_NO_SURFACE) {

     if(!makeOutputSurface(output))

      continue;

    }

    // 设置当前的上下文环境和输出缓冲区

    EGL14.eglMakeCurrent(eglDisplay, output.eglSurface, output.eglSurface, eglContext);

    // 设置视窗大小及位置

    GLES20.glViewport(output.viewport.x, output.viewport.y, output.viewport.width, output.viewport.height);

    // 绘制

    onDrawFrame(output);

    // 交换显存(将surface显存和显示器的显存交换)

    EGL14.eglSwapBuffers(eglDisplay, output.eglSurface);

      }

     }

     

     @Override

     public void run() {

      Event event;

     

      Log.d(TAG,getName()+": render create");

      createGL();//创建display,config,context,现在是没有surface的,只是将contxt联系起来

      onCreated();//得到program,postion,color和顶点的buffer

      // 渲染

      while(!isRelease){

    try {

     event = eventQueue.take();

     switch(event.event){

      case Event.ADD_SURFACE: {

    // 创建eglSurface

    GLSurface surface = (GLSurface)event.param;

    Log.d(TAG,"add:"+surface);

    makeOutputSurface(surface);

    outputSurfaces.add(surface);

    break;

      }

      case Event.REMOVE_SURFACE: {

    GLSurface surface = (GLSurface)event.param;

    Log.d(TAG,"remove:"+surface);

    EGL14.eglDestroySurface(eglDisplay, surface.eglSurface);

    outputSurfaces.remove(surface);

     

    break;

      }

      case Event.START_RENDER:

    rendering = true;

    break;

      case Event.REQ_RENDER: // 渲染

    if(rendering) {

     Log.d(TAG, "run: rendering");

     onUpdate();

     render(); // 如果surface缓存没有释放(被消费)那么这里将卡住

    }

    break;

      case Event.STOP_RENDER:

    rendering = false;

    break;

      case Event.RUNNABLE:

    ((Runnable)event.param).run();

    break;

      case Event.RELEASE:

    isRelease = true;

    break;

      default:

    Log.e(TAG,"event error: "+event);

    break;

     }

    } catch (InterruptedException e) {

     e.printStackTrace();

    }

      }

      // 回调

      onDestroy();

      // 销毁eglSurface

      for(GLSurface outputSurface:outputSurfaces){

    EGL14.eglDestroySurface(eglDisplay, outputSurface.eglSurface);

    outputSurface.eglSurface = EGL14.EGL_NO_SURFACE;

      }

      destroyGL();

      eventQueue.clear();

      Log.d(TAG,getName()+": render release");

     }

     

     /**

      * 退出OpenGL渲染并释放资源

      * 这里先将渲染器释放(renderer)再退出looper,因为renderer里面可能持有这个looper的handler,

      * 先退出looper再释放renderer可能会报一些警告信息(sending message to a Handler on a dead thread)

      */

     public void release(){

      if(eventQueue.offer(new Event(Event.RELEASE))){

    // 等待线程结束,如果不等待,在快速开关的时候可能会导致资源竞争(如竞争摄像头)

    // 但这样操作可能会引起界面卡顿,择优取舍

    while (isAlive()){

     try {

      this.join(1000);

     } catch (InterruptedException e) {

      e.printStackTrace();

     }

    }

      }

     }

     

     /**

      * 当创建完基本的OpenGL环境后调用此方法,可以在这里初始化纹理之类的东西

      */

     public abstract void onCreated();

     

     /**

      * 在渲染之前调用,用于更新纹理数据。渲染一帧调用一次

      */

     public abstract void onUpdate();

     

     /**

      * 绘制渲染,每次绘制都会调用,一帧数据可能调用多次(不同是输出缓存)

      * @param outputSurface 输出缓存位置surface

      */

     public abstract void onDrawFrame(GLSurface outputSurface);

     

     /**

      * 当渲染器销毁前调用,用户回收释放资源

      */

     public abstract void onDestroy();

     

     

     private static String getEGLErrorString() {

      return GLUtils.getEGLErrorString(EGL14.eglGetError());

     }

     

     private static class Event {

      static final int ADD_SURFACE = 1; // 添加输出的surface

      static final int REMOVE_SURFACE = 2; // 移除输出的surface

      static final int START_RENDER = 3; // 开始渲染

      static final int REQ_RENDER = 4; // 请求渲染

      static final int STOP_RENDER = 5; // 结束渲染

      static final int RUNNABLE = 6; //

      static final int RELEASE = 7; // 释放渲染器

     

      final int event;

      Object param;

     

      Event(int event) {

    this.event = event;

      }

     }

     

     

     

    }

    </glsurface></event>

    离屏渲染关键部分就是在makeOutputSurface()方法中的GLSurface.TYPE_PBUFFER_SURFACE这个case里面

    其实// 交换显存(将surface显存和显示器的显存交换)
    EGL14.eglSwapBuffers(eglDisplay, output.eglSurface);对于离屏渲染是没有用的,因为本来就没有显示屏幕,于是我们可以这样:

    ?

    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

    package com.example.asus1.camerawithopengl;

     

    import android.opengl.GLES20;

     

    import java.nio.ByteBuffer;

    import java.nio.ByteOrder;

    import java.nio.FloatBuffer;

     

    public class TestRenderer extends GLRenderer1 {

     

     private static final String TAG = "TestRenderer";

     private int program;

     private int vPosition;

     private int uColor;

     

     private FloatBuffer vertices;

     

     

     /**

      * 获取图形的顶点

      * 特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer

      * 转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题

      *

      * @return 顶点Buffer

      */

     private FloatBuffer getVertices() {

      float vertices[] = {

     0.0f,0.5f,

     -0.5f, -0.5f,

     0.5f,  -0.5f,

      };

     

      // 创建顶点坐标数据缓冲

      // vertices.length*4是因为一个float占四个字节

      ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);

      vbb.order(ByteOrder.nativeOrder()); //设置字节顺序

      FloatBuffer vertexBuf = vbb.asFloatBuffer(); //转换为Float型缓冲

      vertexBuf.put(vertices);//向缓冲区中放入顶点坐标数据

      vertexBuf.position(0);  //设置缓冲区起始位置

     

      return vertexBuf;

     }

     

     

     

     @Override

     public void onCreated() {

     

      program = ShaderUtil.createProgram(verticesShader,fragmentShader);

      vPosition = GLES20.glGetAttribLocation(program,"vPosition");

      uColor = GLES20.glGetUniformLocation(program,"uColor");

     

      vertices = getVertices();

     

     }

     

     @Override

     public void onUpdate() {

     

     }

     

     @Override

     public void onDrawFrame(GLSurface outputSurface) {

    // 设置clear color颜色RGBA(这里仅仅是设置清屏时GLES20.glClear()用的颜色值而不是执行清屏)

      GLES20.glClearColor(1.0f, 0, 0, 1.0f);

     

      // 清除深度缓冲与颜色缓冲(清屏,否则会出现绘制之外的区域花屏)

      GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

      // 使用某套shader程序

      GLES20.glUseProgram(program);

      // 为画笔指定顶点位置数据(vPosition)

      GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 0, vertices);

      // 允许顶点位置数据数组

      GLES20.glEnableVertexAttribArray(vPosition);

      // 设置属性uColor(颜色 索引,R,G,B,A)

      GLES20.glUniform4f(uColor, 0.0f, 1.0f, 0.0f, 1.0f);

      // 绘制

      GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 3);

     

     }

     

     @Override

     public void onDestroy() {

     

     }

     

     // 顶点着色器的脚本

     private static final String verticesShader

    = "attribute vec2 vPosition;\n" // 顶点位置属性vPosition

    + "void main(){ \n"

    + "gl_Position = vec4(vPosition,0,1);\n" // 确定顶点位置

    + "}";

     

     // 片元着色器的脚本

     private static final String fragmentShader

    = "precision mediump float;\n" // 声明float类型的精度为中等(精度越高越耗资源)

    + "uniform vec4 uColor; \n" // uniform的属性uColor

    + "void main(){\n"

    + "gl_FragColor = uColor;  \n" // 给此片元的填充色

    + "}";

     

    }

    在activity中

    ?

    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

      @Override

     protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

     

      setContentView(R.layout.activity_main);

      final SurfaceView surfaceView = (SurfaceView)findViewById(R.id.surface);

      mImageView = (ImageView)findViewById(R.id.image);

      glRenderer = new TestRenderer();

      GLSurface glPbufferSurface = new GLSurface(512,512);

      glRenderer.addSurface(glPbufferSurface);

      glRenderer.startRender();

      glRenderer.requestRender();

     

      glRenderer.postRunnable(new Runnable() {

    @Override

    public void run() {

     IntBuffer i = IntBuffer.allocate(512*512);

     GLES20.glReadPixels(0, 0, 512, 512, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, i);

     

     final Bitmap bitmap = frameToBitmap(512,512,i);

     new Handler(Looper.getMainLooper()).post(new Runnable() {

      @Override

      public void run() {

    mImageView.setImageBitmap(bitmap);

      }

     });

    }

      });

      surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {

    @Override

    public void surfaceCreated(SurfaceHolder holder) {

     

    }

     

    @Override

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

     // glRenderer.render(holder.getSurface(),width,height);

     GLSurface glWindowSurface = new GLSurface(holder.getSurface(),width,height);

     glRenderer.addSurface(glWindowSurface);

     glRenderer.requestRender();

     

     

    }

     

    @Override

    public void surfaceDestroyed(SurfaceHolder holder) {

     

    }

      });

     

     

     

     }

     

     @Override

     protected void onDestroy() {

     // mPreview.destoryCamera();

      glRenderer.release();

      glRenderer = null;

      super.onDestroy();

     

     }

     

     /**

      * 将数据转换成bitmap(OpenGL和Android的Bitmap色彩空间不一致,这里需要做转换)

      *

      * @param width 图像宽度

      * @param height 图像高度

      * @param ib 图像数据

      * @return bitmap

      */

     private static Bitmap frameToBitmap(int width, int height, IntBuffer ib) {

      int pixs[] = ib.array();

      // 扫描转置(OpenGl:左上->右下 Bitmap:左下->右上)

      for (int y = 0; y < height / 2; y++) {

    for (int x = 0; x < width; x++) {

     int pos1 = y * width + x;

     int pos2 = (height - 1 - y) * width + x;

     

     int tmp = pixs[pos1];

     pixs[pos1] = (pixs[pos2] & 0xFF00FF00) | ((pixs[pos2] >> 16) & 0xff) | ((pixs[pos2] << 16) & 0x00ff0000); // ABGR->ARGB

     pixs[pos2] = (tmp & 0xFF00FF00) | ((tmp >> 16) & 0xff) | ((tmp << 16) & 0x00ff0000);

    }

      }

      if (height % 2 == 1) { // 中间一行

    for (int x = 0; x < width; x++) {

     int pos = (height / 2 + 1) * width + x;

     pixs[pos] = (pixs[pos] & 0xFF00FF00) | ((pixs[pos] >> 16) & 0xff) | ((pixs[pos] << 16) & 0x00ff0000);

    }

      }

     

      return Bitmap.createBitmap(pixs, width, height, Bitmap.Config.ARGB_8888);

     }

    我们可以看到我们其实进行了两次渲染,第一次是离屏,第二次使用的是window_surface。为了看到离屏的效果,我们必须从OpenGL的线程中取出像素数据,然后转换成Bitmap设置给ImageView。
    然后就能看到两个三角形了,顶部的小三角形就是在后台渲染的图像了

    这里写图片描述

    知识补充

    Display

    EGL提供了图形API如OpenGL ES和原生窗口系统如Linux 的X Window之间的一个结合层次,在EGL能够确定可用的Surface类型之前,它必须打开和窗口系统的通信渠道,因为是跨平台的,每个窗口系统都有不同的遗言,所以EGL提供基本的不透明类型的EGLDisplai,该类型封装了所有系统的相关属性,用于原生窗口的系统接口,不同的窗口系统定义了不同的DIsplay属性,最终都会Native化。任何使用EGL的应用程序必须执行的第一个操作是创建与初始化与本地EGL Display的连接:

    ?

    1

    2

    eglGetDisplay(EGLNativeDisplayType display_id);

    eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)

    eglGetDisplay用于获取EGL DIsplay连接,display_id指定需要连接的Display,一般取默认值EGL_DEFAULT_DISPLAY
    eglInitialize用于对Display进行初始化,初始化已经初始化了Display对这个Display没有影响,major和minor获取当前的EGL版本号

    #配置Surface

    EGL初始化Display完成后,就可以对Surface进行配置了,一种是查询每个Surface配置,找出最好的选择,另一种是指定一组需求,让EGL推荐最佳匹配,两者都返回一个EGLConfig,包括Surface相关的所有属性。

    ?

    1

    2

    3

    4

    5

    6

    7

    eglGetConfigs(EGLDisplay dpy, EGLConfig *configs,

     EGLint config_size, EGLint *num_config);

     eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,

    EGLint attribute, EGLint *value);

     eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,

    EGLConfig *configs, EGLint config_size,

    EGLint *num_config);

    eglGetConfigs用于获取Display的frame buffer配置列表,dpy为对应的Display,configs返回配置列表(可以为NULL而只是通过num_config获取配置列表可用的配置条目),size指定配置列表的大小(size大于1时configs需要有足够的存储空间),num_config返回配置列表获取的配置条目。

    eglGetConfigAttrib用于获取EGL的frame buffer配置列表中某个具体属性的值,dpy为对应的Display,config为待查询的配置列表,attribute为待查询的具体属性,value返回查询的属性值,

    eglChooseConfig用于获取Display的frame buffer配置列表,不过这个配置列表要与指定的属性列表attrib_list匹配,dpy为对应的Display,attrib_list为config需要匹配的属性列表,configs返回配置列表(非NULL时,size为最大值,num_configs为实际值,为NULL时,忽略size),size指定配置列表的大小(size大于1时configs需要有足够的存储空间),num_config返回配置列表获取的配置条目

    创建Surface

    Window Surface:可以理解为EGL窗口,是屏幕上的渲染区域,有eglCreateWindowSurface创建

    ?

    1

    2

    3

    eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,

    EGLNativeWindowType win,

    const EGLint *attrib_list);

    eglCreateWindowSurface用于创建Window Surface,dpy为对应的EGL Display连接,config为EGL frame buffer配置,定义了可用于Surface的frame buffer资源,win为Native Window,是个平台相关的类型,attrib_list为Window Surface属性列表,可以为NULL。

    ?

    1

    eglDestroySurface(EGLDisplay dpy, EGLSurface surface

    用于销毁surface,dpy为对应的Display,surface为将要销毁的Surface,如果任何其它线程都没有使用这个Surface时,Surface将被立即销毁,否则要等到这个Surface不被任何线程使用时才销毁,另外,对于一个PBuffer Surface来说,其资源要等到绑定到纹理对象的颜色缓冲区释放后才被销毁。

    ?

    1

    2

    glQuerySurface(EGLDisplay dpy, EGLSurface surface,

    EGLint attribute, EGLint *value);

    于获取Surface信息,dpy为对应的Display,surface待查询的Surface,attribute为待查询的Surface属性,value用于返回Surface属性值

    PBuffer Surface:称作PBuffer(像素缓冲区Pixel Buffer的缩写)的不可见屏幕外表面,和窗口一样,PBuffer可以利用OpenGL ES 3.0中的任何硬件加速,PBuffer最常用于生成纹理贴图,如果想要做的是渲染到一个纹理,那么建议使用帧缓冲区对象(FBO)代替PBuffer,因为帧缓冲区更高效,不过在某些FBO无法使用的情况下,PBuffer仍然有用,

    ?

    1

    2

    glCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,

     const EGLint *attrib_list);

    eglCreatePbufferSurface用于创建off-screen的pixel buffer Surface,dpy为对应的Display,config为frame buffer配置,attrib_list为PBuffer属性列表,可以为NULL

    Pixmap Surface:

    ?

    1

    2

    3

    eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,

    EGLNativePixmapType pixmap,

    const EGLint *attrib_list);

    用于创建off-screen的Pixmap Surface,dpy为对应的Display,config为frame buffer配置,pixmap为Native Pixmap,attrib_list为Pixmap属性列表,可以为NULL

    三种Surface的区别

    window是on-screen的,
    pbuffer和pixmap是off-screen的, window绑定到了NativeWindow
    ,pixmap绑定到了NativePixmap,
    pbuffer没有任何本地绑定 window是双缓冲区的
    pbuffer和pixmap是单缓冲区的, window默认在back buffer渲染,通过eglSwapBuffers交换到屏幕上显示,
    pbuffer在显存中分配,由EGL_HEIGHT和EGL_WIDTH指定大小,常用作纹理数据,
    pixmap绑定到本地的像素缓冲区,这个缓冲区可以被其它API使用。 创建不同的EGLSurface时,需要在EGLConfig中配置EGL_SURFACE_TYPE,window、pbuffer、pixmap分别对应于EGL_WINDOW_BIT、EGL_PBUFFER_BIT、EGL_PIXMAP_BUFFER。


    ?

    1

    eglSwapBuffers——

    对于Window Surface或back buffer来说,还需要通过eglSwapBuffers把off-sreen的back buffer交换到screen buffer,也就是说把EGL Surface的颜色缓冲区post到Native Window,内部调用了渲染API的Flush命令,返回EGL_FALSE时可能的原因为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_SURFACE、EGL_CONTEXT_LOST。
    eglSwapBuffers对PBuffer Surface和Pixmap Surface无效。

    创建Context

    ?

    1

    2

    3

    eglCreateContext(EGLDisplay dpy, EGLConfig config,

     EGLContext share_context,

     const EGLint *attrib_list);

    eglCreateContext用于创建EGL渲染Context,dpy为对应的Display,config为frame buffer配置,share_context为其它的共享Context,可以设置为EGL_NO_CONTEXT,attrib_list为Context属性列表,成功时返回新创建的EGLContext,失败时返回EGL_NO_CONTEXT

    ttrib_list属性目前只有EGL_CONTEXT_CLIENT_VERSION,整数值,指定OpenGL ES版本,默认值为1,还可以是2、3等其它版本值,创建OpenGL ES Context时设置这个属性,也就是说渲染API为EGL_OPENGL_ES_API时才设置这个属性

    ?

    1

    2

    eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,

      EGLSurface read, EGLContext ctx);

    创建了Surface和Context之后,因为可能有多个Surface和Context,所以需要通过eglMakeCurrent绑定Context到Surface,dpy为对应的Display,draw用于绘制,read用于读,ctx为要绑定的Context

     

    展开全文
  • 为了在Android应用程序中使用OpenGL ES绘制图形,必须要为他们创建一个视图容器。其中最直接或者最常用的方式就是实现一个GLSurfaceView和一个GLSurfaceView.Renderer。GLSurfaceView是用OpenGL绘制图形的视图容器,...

    零:环境搭建目的

    为了在Android应用程序中使用OpenGL ES绘制图形,必须要为他们创建一个视图容器。其中最直接或者最常用的方式就是实现一个GLSurfaceView和一个GLSurfaceView.Renderer。GLSurfaceView是用OpenGL绘制图形的视图容器,GLSurfaceView.Renderer控制在该视图内绘制的内容。

    下面将讲解如何使用GLSurfaceView 和 GLSurfaceView.Renderer 在一个简单的应用程序的Activity上面做一个最小的实现。

    一:在Manifest中声明OpenGL ES使用

    为了让你的应用程序能够使用OpenGL ES 2.0的API,你必须添加以下声明到manifest:

    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
    

    如果你的应用程序需要使用纹理压缩,你还需要声明你的应用程序需要支持哪种压缩格式,以便他们安装在兼容的设备上。

    <supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
    <supports-gl-texture android:name="GL_OES_compressed_paletted_texture" />
    

    关于更多的纹理压缩格式的知识,可以到 https://developer.android.com/guide/topics/graphics/opengl.html#textures 做进一步的了解。

    二:创建一个Activity 用于展示OpenGL ES 图形

    使用OpenGL ES的应用程序的Activity和其他应用程的Activity一样,不同的地方在于你设置的Activity的布局。在许多使用OpenGL ES的app中,你可以添加TextView,Button和ListView,还可以添加GLSurfaceView。

    下面的代码展示了使用GLSurfaceView做为主视图的基本实现:

    public class OpenGLES20Activity extends Activity {
    
        private GLSurfaceView mGLView;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // Create a GLSurfaceView instance and set it
            // as the ContentView for this Activity.
            mGLView = new MyGLSurfaceView(this);
            setContentView(mGLView);
        }
    }
    

    注意:OpenGL ES 2.0 需要的Android版本是2.2及以上,请确保你的Android项目针对的版本是否符合。

    三、创建GLSurfaceView对象

    GLSurfaceView是一个特殊的View,通过这个View你可以绘制OpenGL图像。但是View本身没有做太多的事情,主要的绘制是通过设置在View里面的GLSurfaceView.Renderer 来控制的。实际上,创建这个对象的代码是很少的,你能会想尝试跳过extends的操作,只去创建一个没有被修改的GLSurfaceView实例,但是不建议这样去做。因为在某些情况下,你需要扩展这个类来捕获触摸的事件,捕获触摸的事件的方式会在后面的文章里面做介绍。
    GLSurfaceView的基本代码很少,为了快速的实现,通常会在使用它的Activity中创建一个内部类来做实现:

    class MyGLSurfaceView extends GLSurfaceView {
    
        private final MyGLRenderer mRenderer;
    
        public MyGLSurfaceView(Context context){
            super(context);
    
            // Create an OpenGL ES 2.0 context
            setEGLContextClientVersion(2);
    
            mRenderer = new MyGLRenderer();
    
            // Set the Renderer for drawing on the GLSurfaceView
            setRenderer(mRenderer);
        }
    }
    

    你可以通过设置GLSurfaceView.RENDERMODE_WHEN_DIRTY来让你的GLSurfaceView监听到数据变化的时候再去刷新,即修改GLSurfaceView的渲染模式。这个设置可以防止重绘GLSurfaceView,直到你调用了requestRender(),这个设置在默写层面上来说,对你的APP是更有好处的。

    四、创建一个Renderer类

    实现了GLSurfaceView.Renderer 类才是真正算是开始能够在应用中使用OpenGL ES。这个类控制着与它关联的GLSurfaceView 绘制的内容。在renderer 里面有三个方法能够被Android系统调用,以便知道在GLSurfaceView绘制什么以及如何绘制

    • onSurfaceCreated() - 在View的OpenGL环境被创建的时候调用。
    • onDrawFrame() - 每一次View的重绘都会调用
    • onSurfaceChanged() - 如果视图的几何形状发生变化(例如,当设备的屏幕方向改变时),则调用此方法。

    下面是使用OpenGL ES 渲染器的基本实现,仅仅做的事情就是在GLSurfaceView绘制一个黑色背景。

    public class MyGLRenderer implements GLSurfaceView.Renderer {
    
        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
            // Set the background frame color
            GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        }
    
        public void onDrawFrame(GL10 unused) {
            // Redraw background color
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        }
    
        public void onSurfaceChanged(GL10 unused, int width, int height) {
            GLES20.glViewport(0, 0, width, height);
        }
    }
    

    五、总结

    上述的内容就是基本的OpenGL ES基本的环境配置,本文的代码仅仅是创建一个简单的Android应用然后使用OpenGL展示一个黑板。虽然没有做其他更加有趣的事情,但是,通过创建这些类,你应该已经拥有了使用OpenGL绘制图形元素的基础了。

    注:你可能很好奇为什么在使用OpenGL ES 2.0的API的时候会看到GL10的参数,因为这些方法签名被简单地用于2.0 API这样可以保持Android框架代码的简单。

    如果你熟悉OpenGL的API,现在你应该可以在你的APP里面创建一个OpenGL ES的环境,并开始进行画图了。但是如果需要更多的帮助来使用OpenGL,就请期待下面的文章吧。

    展开全文
  • 由资深iOS开发专家根据OpenGL ES最新版本撰写,不仅详细讲解了OpenGL ES与GLKit的结合使用,而且还系统讲解OpenGL ES的核心概念、技术,以及iOS的图形机制,并通过大量案例讲解了在iOS上进行OpenGL ES开发的方法和...
  • ES的程序开发

    2020-03-30 02:59:17
    系统搜索推广活动,由以前的数据库模糊匹配的方式切换为搜索引擎的方式,选用的内容以ElasticSearch为主,本篇文档主要记录了使用ES进行单节点部署以及开发ES搜索的代码讲解,最后会上传部分代码供大家参考。...

    背景描述:

           系统搜索推广活动,由以前的数据库模糊匹配的方式切换为搜索引擎的方式,选用的内容以ElasticSearch为主,本篇文档主要记录了使用ES进行单节点部署以及开发ES搜索的代码讲解,最后会上传部分代码供大家参考。

     

    系统环境:

            部署环境:CentOS 6.7 + JDK 1.7 + ElasticSearch 2.3.5

            开发环境:Window 10 + JDK 1.7 + IDEA 2017

     

    环境准备:

            集成POM依赖:

          
    <dependency> 
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.4</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-elasticsearch</artifactId>
        <version>2.0.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>2.3.5</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.7.1</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.7.1</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.17</version>
    </dependency>
     

     

          添加Spring配置:

     

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop" 
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
           xsi:schemaLocation="
          http://www.springframework.org/schema/beans 
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          http://www.springframework.org/schema/context 
          http://www.springframework.org/schema/context/spring-context-3.0.xsd
          http://www.springframework.org/schema/aop 
          http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
          http://www.springframework.org/schema/tx 
          http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
          http://www.springframework.org/schema/data/elasticsearch 
          http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch.xsd
          ">

        <!-- 开启配置扫描 -->
        <context:component-scan base-package="com.jiangzh"></context:component-scan>

        <!-- 随便配置一个ES的节点信息,并且开启嗅探功能,会自动发现集群 -->
        <elasticsearch:transport-client id="client"
                                        cluster-name="my-application" 
                                        client-transport-sniff="true"
                                        cluster-nodes="192.168.4.109:9300" />

        <!-- 配置Spring-data对es提供的template -->
        <bean name="elasticsearchTemplate"
              class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
            <constructor-arg name="client" ref="client" />
        </bean>

    </beans>
     

     

         创建数据实体,与数据字段一一对应,用来进行快速查询使用:

      

    public class AppPOJO {

        private int res_pk;
        private String res_kaipk;
        private String res_name;
        // 省略getter和setter方法

    }
     

        创建VO实体,按实际需要,将数据实体转换为业务实体,并返回:

       

    @Document(indexName = "testidex",type = "estype")
    public class AppModel {
        @Id
    private Integer appId; private String resName; 
        // 省略其他属性以及getter和setter方法
    }
     

     

        

     开发搜索功能:

       

           1、数据层:

           提供了基本的数据支撑,包含了基本的CRUD操作:

           新增功能的核心实现:

              

    String pid = et.index(new IndexQueryBuilder()
            // 获取数据操作的index
            .withIndexName(ESConst.ESIndexEnum.APPSEARCH.getName())
            // 获取数据操作的Type
            .withType(ESConst.ESTypeEnum.APPSEARCH.getName())
            // 设置数据ID,如果不设置会自动生成
            .withId("" + pojo.getRes_pk())
            // 具体新增的数据
            .withSource(jsonData)
            .build()
    );

      

            2、修改功能核心实现

     

    IndexRequest indexRequest = new IndexRequest();
    indexRequest.source(jsonData);
    UpdateQuery updateQuery = new UpdateQueryBuilder()
            .withIndexName(ESConst.ESTypeEnum.APPSEARCH.getName())
            .withType(ESConst.ESTypeEnum.APPSEARCH.getName())
            .withId(""+pojo.getRes_pk())
            .withIndexRequest(indexRequest)
            .withClass(AppPOJO.class)
            .build();
    et.update(updateQuery);
     

        3、删除功能核心实现

       

    DeleteQuery deleteQuery = new DeleteQuery();
    deleteQuery.setQuery(QueryBuilders.termQuery("appId", ""+appUid));
    deleteQuery.setIndex(ESConst.ESIndexEnum.APPSEARCH.getName());
    deleteQuery.setType(ESConst.ESTypeEnum.APPSEARCH.getName());
    et.delete(deleteQuery);
     

     

      4、根据主键进行查询

    StringQuery query = new StringQuery(
            QueryBuilders.termQuery("appId",appUid).toString()
    );
    AppPOJO appPOJO = et.queryForObject(query,AppPOJO.class);
      这里一定要注意,使用这个API的时候,要对实体Model进行注解标记,详见代码

     

     

    5、查询所有数据,用于首页展示,核心代码如下:

    // 使用Scan方式进行扫描,可以提高查询速度
    // 设置查询条件
    SearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withIndices(ESConst.ESIndexEnum.APPSEARCH.getName())
            .withTypes(ESConst.ESTypeEnum.APPSEARCH.getName())
            .withQuery(QueryBuilders.matchAllQuery())
            .withFilter(QueryBuilders.termQuery("res_online","y"))
            .withPageable(new PageRequest(0,1)).build();

    // 通过查询条件,生成扫描编号
    String scrollId = et.scan(searchQuery, 1000, false);

    // 通过扫描编号进行数据匹配
    Page page = et.scroll(scrollId, 5000L,AppPOJO.class);
    List<AppPOJO> content = null;
    if(page.hasContent()){
        content = page.getContent();
    }else{
        break;
    }
     

     

    6、获取查询的总数据,主要用于前台页面分页使用

    SearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withIndices(ESConst.ESIndexEnum.APPSEARCH.getName())
            .withTypes(ESConst.ESTypeEnum.APPSEARCH.getName())
            .withQuery(QueryBuilders.multiMatchQuery(condition
                    ,"column1","column2"))
            .build();
    long count = et.count(searchQuery);
     

    以上,所有数据层的基础API已经完成,其余业务代码由于每个人的业务都不相同,我就不一一分享了,大家可以自行脑补。

     

    最后,上述都是核心代码

    展开全文
  • OpenGL ES 应用开发实践指南 iOS卷,系统讲解 OpenGL ES 的核心概念、技术以及iOS的图形机制
  • 2.2、Codec的注册 看下dts 后es8323_i2c_probe成功会调用到snd_soc_register_codec(&i2c->dev, &soc_codec_dev_es8323, &es8323_dai, 1); 进行 codec dai 的注册, 3、platform Soc/Platform平台驱动有 soc 厂商做好...
  • 由资深Android开发专家根据OpenGLES2.0版本撰写,不仅系统地讲解了OpenGLES的核心概念、技术,以及Android的图形机制,还通过大量案例讲解了在Android上进行OpenGLES开发的方法和技巧。  《OpenGL ES应用开发实践...
  • 平台 内核版本 安卓版本 RK3399 Linux4.4 Android7.1 ...文章目录Codec Block Diagram录音过程(ADC data)放音... PeriodCodec驱动(es8323.c)硬件连接DeviceTree DescribeMachine驱动(rk_es8323.c rockchip平台)De...
  • 在前一篇博客我们知道了Android中OpenGL ES是什么,然后知道了怎么搭建一个OpenGL ES的运行环境,现在我们就来开始绘制我们自己想要的图形了(绘制图片会在后面讲解,因为绘制图形是绘制图片的基础),我们最先开始...
  • 在没有es6之前采用es5的时候也是需要模块化开发的,下面就详细讲解一下es5模块化开发. //html代码(在底部引入js文件) <scrpit src='aaa.js'></script> <scrpit src='bbb.js'></script> ...
  • ES部署以及程序开发

    千次阅读 2017-12-28 14:51:53
     系统搜索推广活动,由以前的数据库模糊匹配的方式切换为搜索引擎的方式,选用的内容以ElasticSearch为主,本篇文档主要记录了使用ES进行单节点部署以及开发ES搜索的代码讲解,最后会上传部分代码供大家参考。...
  • 内容包括:基础概念的讲解,如何使用 GLKit 来渲染纹理,如何使用 GLSL 编写的着色器来渲染纹理。 前言 OpenGL(Open Graphics Library)是 Khronos Group (一个图形软硬件行业协会,该协会主要关注图形和多媒体...
  • 由资深Android开发专家根据OpenGLES2.0版本撰写,不仅系统地讲解了OpenGLES的核心概念、技术,以及Android的图形机制,还通过大量案例讲解了在Android上进行OpenGLES开发的方法和技巧。  《OpenGL ES应用开发实践...
  • 平台 内核版本 安卓版本 RK3399 Linux4.4 Android7.1 ...文章目录1、原理图2、ALSA DAPM2.1、控制寄存器的种类2.2、利用辅助宏定义`widget`所需要的`dapm kcontrol`2.2、配置寄存器:3、...es8388 :The device s...
  • 如标志板、天空盒、镜像绘制等,介绍了OpenGL ES 3.0中经常使用的几种剪裁与测试,包括剪裁测试、Alpha测试、模板测试以及任意剪裁平面等,讲解了传感器应用开发和Android 及iOS平台下的OpenGL ES开发。通过两大案例...
  • 第2章讲解了如何使用苹果xcode开发工具和cocoa touch面向对象的框架在iphone、ipod touch和ipad中开发包括3d图形的程序;第3章涵盖了纹理的底层概念和常用选项;第4章介绍灯光模拟背后的概念,以及利用glkit并使用...
  • 如标志板、天空盒、镜像绘制等,介绍了OpenGL ES 3.0中经常使用的几种剪裁与测试,包括剪裁测试、Alpha测试、模板测试以及任意剪裁平面等,讲解了传感器应用开发和Android 及 iOS平台下的OpenGL ES开发。最后,通过...
  • 本文主要介绍,如何使用 OpenGL ES 来渲染一张图片。内容包括:基础概念的讲解,如何使用 GLKit 来渲染纹理,如何使用 GLSL 编写的着色器来渲染纹理。 前言 OpenGL(Open Graphics Library) 是 Khronos Group (一...
  • 不仅详细讲解了 OpenGL ES与 GLKit的结合使用,而且还系统讲解 OpenGL ES的核心概 念、技术,以及 iOS的图形机制,并通过大量案例讲解了在 iOS上进行 OpenGL ES开发的方法和技巧。 对其内容详细阅读
  • 这是一部实用教程,逐步配图讲解如果利用方正ES207快速开发平台开发一个完整的行政审批系统,零编程,零基础,10分钟即可完成。 本文档包含:1、建立组织结构 2、添加用户 3、建立应用 4、建数据表 5、设计表单 6、...
  • 如题,Android 3D游戏开发技术宝典:OpenGL ES 2.0书中的全部源代码。该书由浅入深的讲解了OpenGL ES 2.0在3D游戏开发中的各个方面,还给出了BN赛艇、火力篮球、夜鹰行动三个经典游戏的全部源代码。
  • 这本书将讲解如何在android上创建引人注目的图形的所有知识,通过构建一个简单的空气曲棍球游戏,你会学习到OpenGL的基础内容,在这个开发过程中,你会看到如何初始化OpenGL,以及使用着色器编写图形管道。...
  • 同时为了便于读者的学习,《Android 3D游戏开发技术宝典:OpenGL ES 2.0》附赠的光盘中包含了书中所有案例的完整源代码,同时给出了最后3个完整大型3D游戏案例的讲解视频,最大限度地帮助读者快速掌握相应的开发技术...

空空如也

空空如也

1 2 3 4 5 ... 17
收藏数 327
精华内容 130
关键字:

es开发讲解