ARcore

https://blog.csdn.net/p106786860/rss/list

1024工场新技术,新未来,尽在1024工场…
[原]Android自动化测试:Appium简介
一、什么是Appium
一个自动化测试开源工具;
支持Android和IOS平台原生应用、移动Web应用和混合应用;
一个跨平台的工具,允许测试人员使用同样的接口基于不同的平台(Andorid,IOS)写自动化测试脚本;
二、Appinum的理念
无需为了自动化,而重新编译或者修改我们的应用(黑盒测试);
不必局限于某种语言或者框架来写和运行测试脚本;
不应该在接口上重复造轮子(移动自动化接口统一);
开源;
三、Appium的设计
真正的工作引擎其实是第三方自动化框架,不需要再引用中植入Appium和第三方代码;
这些第三方框架封装成一套API-WebDriver API,指定了客户端到服务端的协议,可以使用任何语言来编写客户端,向服务端发送恰当的HTTP请求;
扩充了WebDriver的协议,在原有的基础上添加移动自动化相关的API方法;
四、Appinum概念
C/S架构:核心是一个Web服务器,提供一套REST接口,收到客户端的连接、监听的命令、在移动设备上执行这些命令,将执行结果在HTTP响应中返回客户端;
Session:自动化总是在一个Session上下文中运行,客户端初始化一个和服务端交互的Session,服务端开始一个自动化Session,返回一个Session ID,客户端用这个ID发送后续的命令;
Desired Capabilities:一些键值对集合,客户端将这些键值对发送给服务端,告诉服务端要启动怎么样的自动化Session,如启动Android或IOS Session;
Appium Server:用nodejs写的,可以用源码编译或者从NPM直接安装;
Appium服务端:有很多语言库Java、Ruby、Python、PHP、JavaScript和C#等,实现了Appinum对WebDriver协议的扩展;
Appium.app,Appinum.exe:提供了GUI封装的Appium Server下载,封装了运行Appium Sever所有依赖元素,包含了一个Inspector工具,检查应用元素的层级;
1.新技术,新未来!尽在1024工场。时刻关注最前沿技术资讯,发布最棒技术博文!(甭客气!尽情的扫描或者长按!)
1024工场服务号

作者:p106786860 发表于 2018/03/31 10:38:30 原文链接 https://blog.csdn.net/p106786860/article/details/79766649
阅读:161
[原]ARCore:相机预览背景绘制
在完成了OpenGL ES和ARCore基本的实现后,下一步肯定就是图像绘制了。在Google为ARCore提供的Demo中,主要进行了相机预览、检测点云、检测平面和Android小机器人的绘制。本节我们将跟大家介绍相机预览背景的绘制过程和原理。

一、OpenGL ES渲染管线
OpenGL ES渲染管线其实就是渲染流水线,实质上指的是一系列的绘制过程。这些过程输入的是待渲染3D物理的相关描述信息数据,经过渲染管线,输出一帧想要的图像。

OpenGL ES渲染管线,如下图所示:
这里写图片描述

1.基本处理
在该阶段设定3D空间中物体的顶点坐标、顶点对应的颜色、顶点纹理坐标等属性,并指定绘制方式,如点绘制、线段绘制或者三角形绘制等。

OpenGL ES支持2D和3D图形的绘制。当你希望在2D界面绘制一条任意的曲线的时候,把这边曲线放的足够大来看,会发现这条曲线其实是由许多足够短的直线连接起来的。那么绘制3D图形,即使你看见的是一个“圆滑曲面”的3D图形,实际上足够放大它依然是由多个小平面组成的。所以对于2D图形,可能是由很多“曲线”组成;而3D图形可能是由很多“曲面”组成。
这里写图片描述

2.顶点缓冲对象
该阶段在应用程序中是可选的。在整个场景中顶点的基本数据不变的情况。可以在初始化阶段将顶点数据经过基本处理后送入顶点缓冲对象,在绘制每一帧想要的图像就省去了顶点IO的麻烦,直接从顶点缓冲对象中获取顶点数据即可。

3.顶点着色器
顶点着色器是一个可编程处理单元,为执行顶点变换、光照、材质的应用与计算等顶点相关的操作,每个顶点执行一次。工作过程首先将原始的几何信息及其他属性传送到顶点着色器中,经过自己开发的顶点着色器处理后产生纹理坐标、颜色、点位置等后流程需要的各项顶点属性信息,然后将其传递给图元装配阶段。

顶点着色器输入主要为待处理顶点相应的attribute(属性)变量、uniform(一致)变量、采样器以及临时变量;输出主要为经过顶点着色器后生成的varying(易变)变量以及一些内建输出变量。
这里写图片描述

4.图元装配
该阶段主要任务是图元组装和图元处理。

图元组装是指顶点数据根据设置的绘制方式被结合成完整的图元。如点绘制每个顶点为一个图元;线段绘制方式每个图元则为两个顶点;三角形绘制方式下需要3个顶点构造成一个图元。

图元处理最重要的工作是剪裁,其任务是消除位于半空间之外的部分几何图元。之所以进行剪裁,是因为随着观察位置、角度不同,并不能总看到特定3D物体某个图元的全部。剪裁时,若图元完全位置视景体以及自定义裁剪平面的内部,则将图元传递到后面步骤进行处理;如果其完全位于视景体或者自定义剪裁平面的外部,则丢弃该图元。
这里写图片描述

5.光栅化
虚拟3D世界中的物体的几何信息一般采用连续的数学向量来表示,因此投影的平面结果也是用连续的数学向量表示的。但目前的显示设备都是离散化的(由一个一个的像素组成),因此还需要将投影的结果离散化。将其分解为一个一个离散化的小单元。
这里写图片描述

6.片元着色器
片元着色器是用于处理片元值以及相关数据的可编程单元,其可以执行纹理的采样、颜色的汇总、计算雾颜色等操作,每片元执行一次。片元着色器通过重复执行,将3D物体中的图元光栅化后产生的每个片元的颜色等属性计算出来后送入后续阶段,如剪裁测试、深度测试及模板测试等。

片元着色器输入是从顶点着色器传递到片元着色器的易变变量(Varying0~n),输出为内建变量(gl_FragColor)是片元的最终颜色。
这里写图片描述

7.剪裁测试
OpenGL ES会检查每个片元在帧缓冲中对应的位置,若对应位置在剪裁窗口中则将此片元送入下一阶段,否则丢弃此片元。

8.深度测试和模板测试
深度测试指将输入片元的深度值与缓冲区中存储的对应位置的深度值进行比较,若输入片元的深度值小于则将输入片元送入下一个阶段准备覆盖帧缓冲中的原片元或帧缓冲中的原片元缓冲,否则丢弃输入片元。

模板测试的主要功能是为将绘制区域限定在一定范围内,一般应用在湖面倒影、镜像等场合。

9.颜色缓冲混合
若程序开启的Alpha混合,则根据混合因子将上一阶段送来的片元帧缓冲对应的位置的片元进行Alpha混合,否则送入的片元将覆盖帧缓冲中对应位置的片元。

10.抖动
抖动是一种简单的操作,允许只使用少量的颜色模拟出更宽的颜色显示范围,从而使颜色视觉更丰富。

11.帧缓冲
OpenGL ES中的物体绘制并不是直接绘制在屏幕上进行的,而是预先在帧缓冲区中进行绘制,每绘制完一帧再将绘制的结果交换到屏幕上。因此,在每次绘制更新一帧都需要清除缓冲区中的相关数据。

二、纹理映射
除了基本基本图形的绘制,如果想要绘制更加真实、炫酷的3D物体,就需要用到纹理映射。它就是把一幅纹理应用到相应的几何图元,告知渲染系统如何进行纹理映射。告知的方式就是为图元中的每个顶点指定恰当纹理坐标,然后通过纹理坐标在纹理图中可以确定选中的纹理区域,最后将选中的纹理区域中的内容根据纹理坐标映射到指定的图元上。
这里写图片描述

三 、相机预览背景绘制步骤
1.绘制背景准备
在该过程,完成了顶点和纹理坐标数据的提供,纹理id的生成获取、绑定和设置,创建顶点坐标和纹理坐标顶点缓冲对象,加载并绑定背景顶点和片元着色器,获取顶点和纹理坐标位置属性等。

2.背景纹理和Session摄像头纹理绑定
在该过程中,将背景纹理id和Session摄像头纹理id进行绑定。

3.执行背景绘制
该阶段处理显示旋转纹理坐标的变换,设置深度测试,告知OpenGL应用的纹理id和使用的程序,将顶点和纹理坐标传送渲染管线,启动顶点和纹理id数据,执行背景绘制和禁用顶点数据等。

四、案例源码分析
1.绘制背景准备
com\google\ar\core\examples\java\helloar\rendering\BackgroundRender.java

public class BackgroundRenderer {
private static final String TAG = BackgroundRenderer.class.getSimpleName();
private static final int COORDS_PER_VERTEX = 3;
private static final int TEXCOORDS_PER_VERTEX = 2;
private static final int FLOAT_SIZE = 4;

//顶点坐标数据
public static final float[] QUAD_COORDS = new float[]{
        -1.0f, -1.0f, 0.0f,     //左下顶点
        -1.0f, +1.0f, 0.0f,    //左上顶点
        +1.0f, -1.0f, 0.0f,    //右下顶点
        +1.0f, +1.0f, 0.0f,   //右上顶点
};

//纹理坐标数据
public static final float[] QUAD_TEXCOORDS = new float[]{
        0.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 1.0f,
        1.0f, 0.0f,
};

//顶点坐标,纹理坐标和顶点变换数据内存
private FloatBuffer mQuadVertices;
private FloatBuffer mQuadTexCoord;
private FloatBuffer mQuadTexCoordTransformed;

//背景着色器程序
private int mQuadProgram;
//背景绘制顶点和纹理属性
private int mQuadPositionParam;
private int mQuadTexCoordParam;

//背景纹理渲染id
private int mTextureId = -1;
private int mTextureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES;

public BackgroundRenderer() {
}

... ... 

/**
* 分配和初始化背景渲染器的需要的OpenGL资源。必须在OpenGL线程中调用,通常在GLSurfaceView.Render
* (GL10,EGLConfig)
*/
public void createOnGlThread(Context context) {
    //生成背景纹理
    int textures[] = new int[1];
    GLES20.glGenTextures(1, textures, 0);
    //获取加载图像后OpenGL纹理id
    mTextureId = textures[0];

    //告诉OpenGL后面的纹理调用应该应用mTextureId这个纹理对象
    GLES20.glBindTexture(mTextureTarget, mTextureId);

    //当纹理大小被扩大或者缩小的时候,我们就会使用到纹理过滤
    //为mTextureTarget纹理设置属性,纹理放大和缩小的滤波方式,横向和纵向平铺方式
    GLES20.glTexParameteri(mTextureTarget, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(mTextureTarget, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(mTextureTarget, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(mTextureTarget, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

    int numVertices = 4;
    if (numVertices != QUAD_COORDS.length / COORDS_PER_VERTEX) {
      throw new RuntimeException("Unexpected number of vertices in BackgroundRenderer.");
    }

    //OpenGL作为本地系统直接运行在硬件上,没有虚拟机。所以需要把Java虚拟机中的内存复制到本地堆中
    //分配一块本地内存bbVertices,告诉缓冲区按照本地字节组织它的内容
    ByteBuffer bbVertices = ByteBuffer.allocateDirect(QUAD_COORDS.length * FLOAT_SIZE);
    bbVertices.order(ByteOrder.nativeOrder());
    //获取一个可以反映底层字节的FloatBuffer类实例,把顶点QUAD_COORDS数据放到本地内存中
    mQuadVertices = bbVertices.asFloatBuffer();
    mQuadVertices.put(QUAD_COORDS);
    mQuadVertices.position(0);

    //同上
    ByteBuffer bbTexCoords = ByteBuffer.allocateDirect(numVertices * TEXCOORDS_PER_VERTEX * FLOAT_SIZE);
    bbTexCoords.order(ByteOrder.nativeOrder());
    mQuadTexCoord = bbTexCoords.asFloatBuffer();
    mQuadTexCoord.put(QUAD_TEXCOORDS);
    mQuadTexCoord.position(0);

    //同上
    ByteBuffer bbTexCoordsTransformed = ByteBuffer.allocateDirect(numVertices * TEXCOORDS_PER_VERTEX * FLOAT_SIZE);
    bbTexCoordsTransformed.order(ByteOrder.nativeOrder());
    mQuadTexCoordTransformed = bbTexCoordsTransformed.asFloatBuffer();

    //加载背景顶点和片元着色器
    int vertexShader = ShaderUtil.loadGLShader(TAG, context,GLES20.GL_VERTEX_SHADER, R.raw.screenquad_vertex);
    int fragmentShader = ShaderUtil.loadGLShader(TAG, context,GLES20.GL_FRAGMENT_SHADER, R.raw.screenquad_fragment_oes);

    //把顶点和Fragment着色器绑定放在一个单个的程序中一起工作:
    //新建程序对象mQuadProgram,并把vertexShader和fragmentShader附加到程序中
    mQuadProgram = GLES20.glCreateProgram();
    GLES20.glAttachShader(mQuadProgram, vertexShader);
    GLES20.glAttachShader(mQuadProgram, fragmentShader);
    //把这些着色器联合起来,并且告诉OpenGL在绘制背景的时候使用这个定义的程序
    GLES20.glLinkProgram(mQuadProgram);
    GLES20.glUseProgram(mQuadProgram);

    //获取顶点位置纹理坐标属性
    ShaderUtil.checkGLError(TAG, "Program creation");
    mQuadPositionParam = GLES20.glGetAttribLocation(mQuadProgram, "a_Position");
    mQuadTexCoordParam = GLES20.glGetAttribLocation(mQuadProgram, "a_TexCoord");
    ShaderUtil.checkGLError(TAG, "Program parameters");
}

... ... 

}
com\google\ar\core\examples\java\helloar\rendering\ShaderUtil.java

public class ShaderUtil {
/**
* 将原始文本文件(保存为资源)转换为OpenGL ES着色程序。
*/
public static int loadGLShader(String tag, Context context, int type, int resId) {
//通过着色器代码原始资源文件id,读取代码为字符串
String code = readRawTextFile(context, resId);

    //创建一个类型的着色器对象
    int shader = GLES20.glCreateShader(type);
    //把着色器源代码上传上着色器对象里,它与shader引用的着色器对象关联起来
    GLES20.glShaderSource(shader, code);
    //编译着色器
    GLES20.glCompileShader(shader);

    //取出编译状态,检查OpenGL是否能成功地编译这个着色器,如果编译失败则删除着色器
    final int[] compileStatus = new int[1];
    GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
    if (compileStatus[0] == 0) {
        Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader));
        GLES20.glDeleteShader(shader);
        shader = 0;
    }

    //编译成功,返回着色器引用id
    if (shader == 0) {
        throw new RuntimeException("Error creating shader.");
    }
    return shader;
}

/**
* 将原始文本文件转换为字符串:从原始资源中通过流读取字符串
*/
private static String readRawTextFile(Context context, int resId) {
    InputStream inputStream = context.getResources().openRawResource(resId);
    try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line).append("\n");
        }
        reader.close();
        return sb.toString();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

}
java_arcore_hello_ar\app\src\main\res\raw\screenquad_vertex.shader

attribute vec4 a_Position; //3D物理每个顶点各自不同的顶点位置信息
attribute vec2 a_TexCoord; //3D物理每个顶点各自不同的纹理坐标信息
varying vec2 v_TexCoord; //从顶点着色器计算产生并传递到片元着色器的纹理坐标信息

void main() {
gl_Position = a_Position; //顶点着色器从渲染管线中获得原始顶点信息a_Position,写入gl_Position内建变量传递到渲染管线的后阶段继续处理
v_TexCoord = a_TexCoord; //顶点着色器从渲染管线中获得纹理坐标信息a_TexCoord,传递给片元着色器继续处理
}
java_arcore_hello_ar\app\src\main\res\raw\screenquad_fragment_oes.shader

precision mediump float; //给出默认的浮点精度
varying vec2 v_TexCoord; //从顶点着色器传来的纹理坐标
uniform samplerExternalOES sTexture; //纹理内容数据

void main() {
gl_FragColor = texture2D(sTexture, v_TexCoord); //根据纹理坐标采样出颜色值
}
2.背景纹理和Session摄像头纹理绑定
com\google\ar\core\examples\java\helloar\HelloArActivity.java

public class HelloArActivity extends AppCompatActivity implements GLSurfaceView.Renderer {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//OpenGL环境被设置的时候,调用一次
//设置背景帧的颜色
GLES20.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

    //准备背景渲染对象
    mBackgroundRenderer.createOnGlThread(this);
    //创建纹理,并且将它传递给ARCore Session,在update()的时候填充,允许GPU访问相机图像
    mSession.setCameraTextureName(mBackgroundRenderer.getTextureId());
}

}
com\google\ar\core\examples\java\helloar\rendering\BackgroundRender.java

public class BackgroundRenderer {
… …

//背景纹理id
private int mTextureId = -1;
private int mTextureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES;
... ... 

//获取背景纹理id
public int getTextureId() {
    return mTextureId;
}
... ... 

}
3.执行背景绘制
com\google\ar\core\examples\java\helloar\rendering\BackgroundRender.java

public class BackgroundRenderer {
private static final String TAG = BackgroundRenderer.class.getSimpleName();
private static final int COORDS_PER_VERTEX = 3;
private static final int TEXCOORDS_PER_VERTEX = 2;
private static final int FLOAT_SIZE = 4;

private FloatBuffer mQuadVertices;
private FloatBuffer mQuadTexCoord;
private FloatBuffer mQuadTexCoordTransformed;

private int mQuadProgram;
private int mQuadPositionParam;
private int mQuadTexCoordParam;

private int mTextureId = -1;
private int mTextureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES;

 /**
 * 绘制AR背景图片。这个图片将会使用Frame.getViewMatrix(float[], int)和Session.getProjectionMatrix(
 * float[], int, float, float)提供的矩阵绘制,将准确的跟踪静态物理对象,它必须在绘制虚拟对象之前调用
 * @param frame 通过Session.update()返回的最新Frame
 */
public void draw(Frame frame) {
    //如果显示旋转(也包括尺寸的改变),我们需要重新查询屏幕rect的uv坐标,因为它们可能发生了变化
    if (frame.isDisplayRotationChanged()) {
        frame.transformDisplayUvCoords(mQuadTexCoord, mQuadTexCoordTransformed);
    }

    //不需要测试或者写入深度,屏幕顶点具有任意深度,预计将首先绘制
    GLES20.glDisable(GLES20.GL_DEPTH_TEST);
    GLES20.glDepthMask(false);

    //告诉OpenGL纹理调用应该应用mTextureId这个纹理对象
    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureId);
    //告诉OpenGL在绘制背景的时候使用这个定义的程序
    GLES20.glUseProgram(mQuadProgram);

    //将顶点位置数据传送进渲染管线
    GLES20.glVertexAttribPointer(mQuadPositionParam, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, mQuadVertices);
    //将顶点纹理坐标数据传送进渲染管线
    GLES20.glVertexAttribPointer(mQuadTexCoordParam, TEXCOORDS_PER_VERTEX,GLES20.GL_FLOAT, false, 0, mQuadTexCoordTransformed);

    //启动顶点位置和着色数据
    GLES20.glEnableVertexAttribArray(mQuadPositionParam);
    GLES20.glEnableVertexAttribArray(mQuadTexCoordParam);

    //执行背景绘制
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

    //禁用顶点数组
    GLES20.glDisableVertexAttribArray(mQuadPositionParam);
    GLES20.glDisableVertexAttribArray(mQuadTexCoordParam);

    //恢复深度状态以作进一步绘图。
    GLES20.glDepthMask(true);
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    ShaderUtil.checkGLError(TAG, "Draw");
}

}
1.新技术,新未来!尽在1024工场。时刻关注最前沿技术资讯,发布最棒技术博文!(甭客气!尽情的扫描或者长按!)
1024工场服务号

2.完整和持续更新的《使用Android打开AR的开发大门—ARCore》文档,欢迎大家阅读!
https://www.kancloud.cn/p3243986735/arcore_develop/457951
这里写图片描述

作者:p106786860 发表于 2018/01/01 23:40:39 原文链接 https://blog.csdn.net/p106786860/article/details/78948227
阅读:403 评论:1 查看评论
[原]ARCore:OpenGL ES环境搭建
估计大部分Anroid开发的同学,对OpenGL ES的了解可能也仅仅停留在三维图形的渲染,入门模板代码的编写阶段。在ARCore开发中,如果你选择使用Android+OpenGL ES的开发技术栈,就需要大家深入的学习和了解OpenGL ES技术了。那么接下来我们就分如下主题和大家来唠唠:

一、OpenGL ES概述
1. Open GL是做什么的?

高效、简洁的开放图形库接口,跨编程语言、跨平台的编程接口规范,主要用于三维图形编程;
遵照接口,不同平台上有不同的实现,思想完全一致,方法名称和使用也基本一致;
2. OpenGL ES和OpenGL是什么关系?

OpenGL ES(OpenGL for Embedded System)是Open GL三维图形API的子集,针对手机、PAD和游戏主机等嵌入式设备;
相对于Open GL来说更轻量级,减少了许多不必要的数据类型,去掉了不必须的功能,对代价大的功能做了限制;
OpenGL ES中没有四边形、多边形、无论多复杂的图形都是由点、线和三角形组成的,也去除了glBegin/glEnd等方法;
3. OpenGL ES在ARCore中的作用?
OpenGL ES在ARCore中,结合ARCore对环境的理解,返回的位置和光线等信息,完成2d或者3d图像的渲染。

二、OpenGL ES环境搭建
进行ARCore开发的第一步就是建立一个OpenGL ES环境,主要由如下几个步骤:
1. 创建GLSurfaveView或者其子类,调用setContentView()设置为Activity显示视图。
2. 获取GLSurfaveView或其子类的实例,在Activity中的onResume()和onPause()方法中处理相应的生命周期方法。
3. 设置GLSurfaveView的配置,如渲染器,渲染模式,EGLContext是否保存和GLContextClient版本等;
4. 实现GLSurfaveView.Render接口,重写onSurfaceCreate(),onDrawFrame()和onSurfaceChanged()方法;

三、案例源码解析
相信大家对OpenGL ES应该有了初步的了解。那么接下来我们将会依照ARCore官方提供的Demo的源代码,给大家逐步讲解ARCore是如何开发的。

  1. 创建GLSurfaceView实例
    java_arcore_hello_ar\app\src\main\res\layout\activity_main.xml

猜你喜欢

转载自blog.csdn.net/zhangxy0605/article/details/80704775
今日推荐