android-magic-surface-view

这是一个 android 动画特效库, 可以实现各种炫酷动画。

github地址: https://github.com/gplibs/android-magic-surface-view

1. 安装

gradle:

dependencies {
compile 'com.gplibs:magic-surface-view:1.0.0'
}

2. 一些示例效果

此文档只做一些简单说明, 具体使用方法还请参考其示例项目 (上面github地址可以找到示例项目) .

以下是一些示例效果:

启动及退出动画 :

模仿MacWindow动画 :

其他几个示例效果,可以下载其示例项目运行查看。


3. 概述

一个MagicSurfaceView只能同时渲染一个MagicScene

一个MagicScene可以包含多个MagicSurface

一个MagicSurface可以对应一个View或者Bitmap对象

场景创建及渲染

// 创建一个Surface对象
MagicSurface surface = new MagicSurface(view) // view为要进行动画操作的View
.setVisible(true) // 设置模型是否要渲染 (默认为true)
.setShininess(64) // 设置模型材质光泽度,默认64; 数值越大越光滑, 只对光照生效,无光照效果可忽略.
.setGrid(30, 40) // 设置网格模型行列数,行列数越多效果越精致,但也更耗性能; 默认 30,30
.setEnableBlend(true) // 是否开启混合,为透明对象时需开启,(默认为开启)
.setEnableDepthTest(true) // 是否开启深度测试,开启后会按三维坐标正常显示,如果关闭,绘制时将覆盖之前已经绘制的东西,(默认为开启)
.setModelUpdater(modelUpdater) // 设置模型更新器, 可以执行顶点坐标及颜色相关动画操作; 详情见 "5. 模型更新器 MagicSurfaceModelUpdater"
.setMatrixUpdater(matrixUpdater) // 设置矩阵更新器, 可以执行矩阵变换相关动画操作; 详情见 "6. 矩阵更新器 MagicSurfaceMatrixUpdater"
.drawGrid(false); // 设置绘制时是否只绘制网络,默认false. (调试动画找问题时可以只画网格,可能有点帮助)
// 创建场景
MagicScene scene = new MagicSceneBuilder(mSurfaceView)
.addSurfaces(surface) // 添加Surface对象;可以添加多个 如: addSurfaces(surface, surface1, surface2)
.ambientColor(0XFF222222) // 设置场景环境光, 默认为0XFFFFFFFF
.addLights(light) // 添加光源对象,类型可以为PointLight或者DirectionalLight; 可以添加多个 如: addLights(light, light1, light2)
.setUpdater(sceneUpdater) // 添加场景更新器, 可以执行场景相关变量的动画操作; 详情见 "4. 场景更新器 MagicSceneUpdater"
.build();
// 渲染
myMagicSurfaceView.render(scene);

模型更新器 MagicSurfaceModelUpdater 动画原理:

MagicSurfaceModelUpdater 原理相对麻烦些,单独说明如下:

渲染使用openGL;每个MagicSurface对象都包含一个SurfaceModel,这个SurfaceModel即是openGl要绘制的曲面模型;

SurfaceModel中包含着openGL绘制时需要的一些必要元素, 顶点坐标集合、顶点索引集合、法向量集合等;

构造MagicSurface时传入View后,会转为Bitmap 作为纹理绑定到曲面模型上。

曲面模型的生成,及纹理绑定过程都由此库自动完成。

我们可以做的是:

SurfaceModel中的顶点集合,是一个 r(行) * c(列) 的一个矩形网格;

我们修改这个矩形网格上每个点的属性,渲染效果就会有相应的变化;(网格的点与点之间每像素点的属性,由openGL根据我们设置的网格关键点的属性进行插值计算自动完成)

网格上每个点可以修改的属性包含:

  1. 顶点坐标。修改网格上某一点的顶点坐标后,绑定在该点上的纹理也会跟着发生相应的形变。
  2. 顶点颜色。修改网格上某一点的顶点颜色后,该点上的最终颜色会按 "顶点最终颜色计算过程" 那样进行变化。

顶点最终颜色计算过程 为:

顶点最终颜色 = 原始颜色 * 顶点颜色 * 场景环境光颜色 + 原始颜色 * 顶点颜色 * 灯光颜色

原始颜色:构建MagicSurface时传入的View或者Bitmap生成的纹理在对应坐标的颜色值.

顶点颜色:默认为rgba(1,1,1,1); 可以由 模型更新器 修改.

场景环境光颜色:默认为rgba(1,1,1,1); 可以由 MagicSceneUpdater 修改.

灯光颜色:构建MagicScene时传入的灯光对象集合,在模型对应顶点产生的光照颜色值; 如果未设置灯光,灯光颜色值为rgba(0,0,0,0); 可以由 MagicSceneUpdater 修改.

颜色相乘算法为:(其中r,g,b,a都为0~1的浮点数, 对应整形颜色值0~255)

color1(r1, g1, b1, a1) * color2(r2, g2, b2, a2) == color3(r1* r2, g1* g2, b1* b2, a1* a2)

颜色相加算法为:(其中r,g,b,a都为0~1的浮点数, 对应整形颜色值0~255)

color1(r1, g1, b1, a1) + color2(r2, g2, b2, a2) == color3(r1+r2, g1+g2, b1+b2, a1+a2)

场景坐标(即openGL坐标):

跟坐标相关的动画操作都使用场景坐标,与Android的View的坐标系无关

MagicSurfaceView的中心即为场景坐标原点(0,0,0); x轴向右 y轴向上 z轴向屏幕外.

MagicSurface网格模型各点坐标z轴默认为0

MagicSurfaceView 及 MagicSurface 相关点场景坐标获取方法 参考 "5. 模型更新器 MagicSurfaceModelUpdater"

关于偏移量:

当一个MagicSurface上同时使用模型更新器和矩阵更新器时.

两个只能有一个应用偏移量,不然位置会出现偏差。

偏移量具体说明,参考 模型更新器 和 矩阵更新器。

Updater性能优化:

MagicSceneUpdater, MagicSurfaceModelUpdater及MagicSurfaceMatrixUpdater 都为 MagicUpdater 的子类

当同时有多个MagicUpdater运行时,可以考虑进行分组

MagicUpdater都有一个可以传入分组参数的构造函数和一个setGroup方法可以对他们进行分组; (setGroup必须要在调用render方法之前执行)

如果不进行分组,它们会独自开启一线程更新。将一些计算量较少的MagicUpdater分到同一组,他们将在一个线程中执行,这样可以节约资源,提升性能。


4. 场景更新器 MagicSceneUpdater

MagicSceneUpdater 对场景变量进行修改; 场景变量包含 环境光和光源。

调用过程为 willStart -> didStart -> (update [此部分通过notifyChanged触发,循环调用直到 调用Updater stop方法]) -> didStop

public class MySceneUpdater extends MagicSceneUpdater {

    public MySceneUpdater(int group) {
super(group);
} // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作)
@Override
protected void willStart(MagicScene scene) {
} // 在开始绘制后调用(绘制第一帧后调用,一般动画可以在此开始)
// 动画有更新时,需调用 notifyChanged()方法 通知框架可以调用 update 相关方法进行更新。
@Override
protected void didStart(MagicScene scene) {
} // 当调用Updater 的 stop() 方法之后,真正停止后会回调此方法
@Override
protected void didStop(MagicScene scene) {
} // 更新环境光及灯光
@Override
protected void update(MagicScene scene, Vec outAmbientColor) { // 修改环境光
// outAmbientColor.setColor(...) // 获取第0个光源并修改 假设是点光源
// PointLight pl = scene.getLight(0);
// pl.setColor(...);
// pl.setPosition(...); // 获取第1个光源并修改 假设是方向光源
// DirectionalLight dl = scene.getLight(1);
// dl.setColor(...);
// dl.setDirction(...); // 根据需要还可以使用如下方法获取某个MagicSurface对象
// scene.getSurface(index);
}
}

5. 模型更新器 MagicSurfaceModelUpdater

MagicSurfaceModelUpdater 对MagicSurface网格模型各顶点坐标及颜色值进行修改,

调用过程为 willStart -> didStart -> (updateBegin -> (updatePosition [遍历网格每个点]) -> updateEnd [此部分通过notifyChanged触发,循环调用直到 调用 Updater stop方法]) -> didStop

public class MyModelUpdater extends MagicSurfaceModelUpdater {

    public MyModelUpdater() {
} // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作)
@Override
protected void willStart(MagicSurface surface) {
} // 在开始绘制后调用(绘制第一帧后调用,一般动画可以在此开始)
// 动画有更新时,需调用 notifyChanged()方法 通知框架可以调用 update 相关方法进行更新。
@Override
protected void didStart(MagicSurface surface) {
} // 当调用 updater stop方法之后,真正停止后会回调此方法
@Override
protected void didStop(MagicSurface surface) {
} // 每次顶点更新之前调用
@Override
protected void updateBegin(MagicSurface surface) {
} /**
* 修改网格模型 r行, c列处 的坐标及颜色, 修改后的值存到 outPos 和 outColor
* (只需要修改网格模型各行各列点及可,点与点之间的坐标和颜色由 openGL 自动进行插值计算完成)
* 注:此方法执行频率非常高;一般不要有分配新的堆内存的逻辑,会频繁产生gc操作影响性能
*
* @param surface
* @param r 行
* @param c 列
* @param outPos 默认值为 r行c列点包含偏移量的原始坐标, 计算完成后的新坐标要更新到此变量
* @param outColor 默认值为 rgba(1,1,1,1), 计算完成后的新颜色要更新到此变量
*/
@Override
protected void updatePosition(MagicSurface surface, int r, int c, Vec outPos, Vec outColor) {
} // 每次所有顶点更新完成后调用
@Override
protected void updateEnd(MagicSurface surface) {
// 有光照效果时,顶点坐标值更新后, 需要更新法向量以得到正常光照效果,但按标准法向量计算方法开销过大,顶点数较少时可以使用
// surface.getModel().updateModelNormal(); //可以在此方法里判断动画是否结束,结束需调用 stop()方法,以结束updater.
} }

MagicSurfaceModelUpdater相关方法说明:

在Updater生命周期内 以下这些方法都是可以有效调用的。

// 获取 MagicSurfaceView 在openGL坐标系中的宽度
surface.getScene().getWidth(); // 获取 MagicSurfaceView 在openGL坐标系中的高度
surface.getScene().getHeight(); // 获取 MagicSurfaceView 某点在openGL坐标系中的坐标并存入pos
// 比如 surface.getScene().getPosition(0.0f, 0.0f, pos); 获取 MagicSurfaceView 左上角的坐标
// 比如 surface.getScene().getPosition(0.0f, 1.0f, pos); 获取 MagicSurfaceView 左下角的坐标
// 比如 surface.getScene().getPosition(1.0f, 0.0f, pos); 获取 MagicSurfaceView 右上角的坐标
// 比如 surface.getScene().getPosition(1.0f, 1.0f, pos); 获取 MagicSurfaceView 右下角的坐标
surface.getScene().getPosition(ratioX, ratioY, pos); // 获取 MagicSurface 在openGL坐标系中的宽度
surface.getModel().getWidth(); // 获取 MagicSurface 在openGL坐标系中的高度
surface.getModel().getHeight(); // 获取 MagicSurface 网格模型总行数
surface.getModel().getRowLineCount(); // 获取 MagicSurface 网格模型总列数
surface.getModel().getColLineCount(); // 获取 MagicSurface 网格模型 r行 c列 在openGL坐标系中的坐标并存入pos
// 注: 此方法包含偏移量,模型中心在 场景中心+偏移量 的位置; 偏移量是在创建SurfaceView时根据传入的View与MagicSurfaceView相对位置自动生成.
surface.getModel().getPosition(r, c, pos); // 获取 MagicSurface 网格模型 r行 c列 在openGL坐标系中的坐标并存入pos
// 注: 此方法不包含偏移量,模型中心在场景中心处
surface.getModel().getPositionExcludeOffset(r, c, pos);

6. 矩阵更新器 MagicSurfaceMatrixUpdater

MagicSurfaceMatrixUpdater 对MagicSurface网格模型进行各种矩阵变换(缩放,旋转,平移).

调用过程为 willStart -> didStart -> (updateMatrix [此部分通过notifyChanged触发,循环调用直到 调用 Updater stop方法]) -> didStop

public class MyMatrixUpdater extends MagicSurfaceMatrixUpdater {

    public MyMatrixUpdater(int gorup) {
super(group);
} // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作)
@Override
protected void willStart(MagicSurface surface) {
} // 在开始绘制后调用;(绘制第一帧后调用,一般动画可以在此开始)
// 动画有更新时,需调用 notifyChanged()方法 通知框架可以调用 update 相关方法进行更新。
@Override
protected void didStart(MagicSurface surface) {
} // 当调用 updater stop方法之后,真正停止后会回调此方法
@Override
protected void didStop(MagicSurface surface) {
} /**
* 矩阵变换
* @param surface 需更新的MagicSurface对象
* @param offset offse为模型相对场景中心的坐标偏移量, 如果不进行 offset 位移, model 就会显示在场景中心;
*
* 当使用 View 构造 MagicSurface 时,
* View中心位置 相对 MagicSurfaceView中心位置的坐标偏移量 在场景坐标系中的表现就是 offset。
*
* @param matrix 矩阵
*/
@Override
protected void updateMatrix(MagicSurface surface, Vec offset, float[] matrix) {
// 重置matrix
reset(matrix); // 缩放
scale(matrix, xScale, yScale, zScale); // 包含偏移量的位移
translate(matrix, x + offset.x(), y + offset.y(), z + offset.z()); // 位移
// translate(matrix, x, y, z); // 绕 axis轴 旋转 angle度。
rotate(matrix, axis, angle); // 注: 当同时有位移和旋转操作时,位移操作要放在前面。
}
}

一个使用openGL渲染的炫丽Android动画库的更多相关文章

  1. 一个使用openGL渲染的炫丽Android动画库二(碎片化曲面动画)

    续一个使用openGL渲染的炫丽Android动画库 MagicSurfaceView v1.1.0发布, 新增碎片化曲面动画 地址:https://github.com/gplibs/android ...

  2. 【轮子】发现一个效果丰富酷炫的Android动画库

    没有什么比发现一个好轮子更让人开心的了. 这个库分分钟提高交互体验 :AndroidViewAnimations 一张图说明一切 配置和使用也相当简单 GitHub地址

  3. 让动画不再僵硬:Facebook Rebound Android动画库介绍

    introduction official site:http://facebook.github.io/reboundgithub : https://github.com/facebook/reb ...

  4. Facebook Rebound 弹性动画库 源码分析

    Rebound源码分析 让动画不再僵硬:Facebook Rebound Android动画库介绍一文中介绍了rebound这个库. 对于想体验一下rebound的效果,又懒得clone和编译代码的, ...

  5. android动效开篇

    大神博客:http://blog.csdn.net/tianjian4592/article/details/44155147 在现在的Android App开发中,动效越来越受到产品和设计师同学的重 ...

  6. android完整智能家居、备忘录、蓝牙配对、3D动画库、购物车页面、版本更新自动安装等源码

    Android精选源码 app 版本更新.下载完毕自动自动安装 android指针式分数仪表盘 ANdroid蓝牙设备搜索.配对 Android 图片水印框架,支持隐形数字水印 android3D旋转 ...

  7. CSharpGL(31)[译]OpenGL渲染管道那些事

    CSharpGL(31)[译]OpenGL渲染管道那些事 +BIT祝威+悄悄在此留下版了个权的信息说: 开始 自认为对OpenGL的掌握到了一个小瓶颈,现在回头细细地捋一遍OpenGL渲染管道应当是一 ...

  8. OpenGL渲染流程

    一.什么是openGL OpenGL被定义为“图形硬件的一种软件接口”.从本质上说,它是一个3D图形和模型库,具有高度的可移植性,具有非常快的速度. 二.管线 管线这个术语描述了opengl渲染的整个 ...

  9. 初始化glew,创建OpenGL渲染上下文

    void RegisterWinDowClass(HINSTANCE hInstance,std::string className,WNDPROC proc) { WNDCLASS wndClass ...

随机推荐

  1. Python Number(数字)

    ---Number类型的细节,其包含的基本数字类型 ---Number基本数字类型之间的数值转换 ---Number上面的数学函数,有些可以直接调用,有些需要导入库 参见http://www.runo ...

  2. java操作txt文本(一):遇到指定字符换行

    想法由来:有时查看网页源代码的css文件内容,竟是恼人的压缩后代码(不换行),如下图所示-- 它的可读性很差,所以写了下面这个简单的程序,实现自动换行. 适用条件:遇到指定字符换行(本例中遇到'}'换 ...

  3. 解决MVC中JsonResult返回 弹出文件下载对话框

    设置一下返回类型为HTML TEXT就可以了 JsonResult json = Json(xxx, JsonRequestBehavior.DenyGet); json.ContentType = ...

  4. [译]Selenium Python文档:五、Waits等待

    大多数现代web应用都使用了AJAX技术.当浏览器加载一个页面的时候,该页面内的元素可能在不用的时间间隔内进行加载.这使得元素定位变得比较困难:如果一个元素还没有出现在DOM中,定位函数将会抛出一个E ...

  5. Java程序员应当知道的10个面向对象设计原则

    面向对象设计原则是OOPS编程的核心, 但我见过的大多数Java程序员热心于像Singleton (单例) . Decorator(装饰器).Observer(观察者) 等设计模式,而没有把足够多的注 ...

  6. Spring:利用PerformanceMonitorInterceptor来协助应用性能优化

    前段时间对公司产品做性能优化,如果单依赖于测试,进度就会很慢.所以就通过对代码的方式来完成,并以此来加快项目进度.具体的执行方案自然就是要知道各个业务执行时间,针对业务来进行优化. 因为项目中使用了S ...

  7. 基于CDIF实现的——API在线自动化测试

    传统的测试工具在测试一个API的时候,必须手动填写这个API所需要接收的所有信息,比如一个查询航班动态的API,他接收两个输入字段,一个叫flight, 一个叫date,那么测试这个API的用户,需要 ...

  8. 20155215 2016-2017-2 《Java程序设计》第5周学习总结

    学号 2006-2007-2 <Java程序设计>第5周学习总结 教材学习内容总结 第八章 尝试捕捉错误对象,try,catch. 如何抛出错误对象,throw语法. error代表系统错 ...

  9. Struts2之i18N国际化

    对于i18n其实没有太多内容,一般的公司用不到这些内容,除非是跨国公司,但即便是跨国公司也不一定会使用i18n来进行国际化处理,所以本篇内容仅供大家了解,不做深入的探讨,希望通过本篇内容,可以帮助大家 ...

  10. Android敏感词过滤主要类

    package com.tradeaider.app.utils; import com.tradeaider.app.activity.MyApplication;import java.util. ...