Shader渲染动画
一、概述
先看一下Shader类的介绍:
/**
* Shader is the based class for objects that return horizontal spans of colors during drawing.
* A subclass of Shader is installed in a Paint calling paint.setShader(shader).
* After that any object (other than a bitmap) that is drawn with that paint will get its color(s) from the shader.
*/
Shader起初是为Bitmap着色的,但其作用并不限于此,任何通过设置了Shader的Paint画出来的东西都会获得想要的颜色。换句话说,Paint是画笔,Shader就是颜料,Shader需要通过Paint才能起作用。设置Shader的过程就是调制颜料的过程,有了Shader的加持,Paint不再只是简单地画出“白纸黑字”,也能画出五彩缤纷的世界了。
那么,我们究竟有哪些种类的颜料和涂抹方式呢?
(1)Shader的子类
Shader有如下5个子类:
BitmapShader是图像渲染,LinearGradient是线性渲染,RadialGradient是放射渲染,SweepGradient是梯度渲染,ComposeShader是组合渲染。后面我们会简单介绍各个渲染的用法。
(2)Shader的渲染方式
每种渲染的构造方法都需要指定渲染方式Shader.TileMode,共有三种
public enum TileMode {
/**
* 拉伸 replicate the edge color if the shader draws outside of its original bounds
*/
CLAMP (0),
/**
* 重复 repeat the shader's image horizontally and vertically
*/
REPEAT (1),
/**
* 镜像 repeat the shader's image horizontally and vertically, alternating mirror images so that adjacent images always seam
*/
MIRROR (2);
}
二、LinearGradient应用实战
下面以LinearGradient为例,介绍Shader的一般用法。先看构造函数:
LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],TileMode tile)
x0,y0:表示渐变的起点坐标
x1,y1:表示渐变的终点坐标
colors[]:传入多个颜色,产生更加丰富的渐变效果。
float[]:可以设置在不同的渲染阶段渲染不同的颜色
TileMode:和上面讲的完全一致,不赘述了。
一般用法如下:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int[] mColors = {Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW}; //从红色——绿色——蓝色——黄色线性过渡
float[] loaction=new float[] {0.25F, 0.5F, 0.75F, 1.0F }; //指定过渡分割点
LinearGradient linearGradient=new LinearGradient(0,0,1000,50,mColors,loaction,Shader.TileMode.REPEAT);
paint.setShader(linearGradient);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(10);
canvas.drawRect(new RectF(10,10,1000,50),paint);
}
效果如下:
通过上面的例子我们可以看到,Shader只是简单的静态渲染,本身不具有动画属性。然而实际开发中,我们习惯用动画的手法来不断改变渲染方式以达到动态渲染的效果。以下面效果图为例
核心代码:
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (mViewWidth == 0) {
mViewWidth = getMeasuredWidth();
if (mViewWidth > 0) {
mPaint = getPaint();
//制作一个白色半透明——白色全透明——白色半透明线性渲染
mLinearGradient = new LinearGradient(-mViewWidth, 0, 0, 0, new int[]{0x33ffffff, 0xffffffff, 0x33ffffff}, new float[]{0, 0.5f, 1}, TileMode.CLAMP);
mPaint.setShader(mLinearGradient);
mGradientMatrix = new Matrix();
}
}
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//通过Matrix来不断改变shader位移并重绘,达到动画效果
if (mAnimating && mGradientMatrix != null) {
mTranslate += mViewWidth / 10;
if (mTranslate > 2 * mViewWidth) {
mTranslate = -mViewWidth;
}
mGradientMatrix.setTranslate(mTranslate, 0);
mLinearGradient.setLocalMatrix(mGradientMatrix);
postInvalidateDelayed(60);
}
}
Github源码:https://github.com/JiaxtHome/AnimDemo
三、总结
通过上面LinearGradient的例子,我们知道了如何利用Shader来做动画效果,其他子类也是类似的:每一个Shader都有自己的一个Matrix,通过这个Matrix可以对Shader作平移、缩放等操作,采用动画的方式连续修改这个Matrix并重绘就可以实现一些特殊的动画。不同的Shader可以实现不同形式的效果,加上对Shader颜色透明度等变量的控制,可以实现的动画也是丰富多彩的。学习一个动效,不如学会一种方法,学会了方法,就可以开发更多自己的原创动效,而不仅仅是抄袭模仿别人的。下面列举一些其他Shader子类实现的动画效果:
(1)SweepGradient梯度渲染
效果图:
核心代码:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//将背景设置成白色
canvas.drawColor(Color.WHITE); int mWidth = canvas.getWidth();
//制作一个从透明到蓝色的SweepGradient梯度渲染
if(mSweepGradient == null){
mSweepGradient = new SweepGradient(mWidth / 2, mWidth / 2, new int[]{Color.TRANSPARENT, Color.parseColor("#530000ff")}, null);
} //使用Matrix旋转
mSweepGradient.setLocalMatrix(matrix);
matrix.setRotate(degree, mWidth / 2, mWidth / 2);
degree+=2;
if (degree > 360) {
degree = 0;
}
postInvalidate();
}
(2)BitmapShader图像渲染
BitmapShader一般用于做圆角图像的静态渲染,如:
核心代码:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
mPaint.setShader(bitmapShader);
int min = Math.min(bitmapWidth, bitmapHeight);
//画圆形图
canvas.drawCircle(bitmapWidth / 2, bitmapHeight / 2, min / 2, mPaint);
}
(3)RadialGradient放射渲染
RadialGradient适合做类似水波纹的辐射扩散效果:
核心代码:
int radius = 5;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//禁用硬件加速
setLayerType(LAYER_TYPE_SOFTWARE, null);
canvas.drawColor(Color.parseColor("#FFC9C9C9"));
//制定从白色透明到深灰色辐射状渲染
RadialGradient radialGradient = new RadialGradient(mViewWidth / 2, mViewHeight / 2, radius, 0x00FFFFFF, 0xFFABABAB, Shader.TileMode.CLAMP);
mPaint.setShader(radialGradient);
canvas.drawCircle(mViewWidth / 2, mViewHeight / 2, radius, mPaint);
radius += 3;
if (radius > mViewWidth / 3 * 2) {
radius = 5;
}
postInvalidate();
}
(4)ComposeShader组合渲染
ComposeShader是组合渲染,顾名思义,它是任意两个其他渲染的叠加,叠加方式可以采用Xfermode或者PorterDuff.Mode。我们看一下它的构造方法:
ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode)
ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
对于ComposeShader而言,不管是采用哪种混合模式都应慎用,达到的效果不太好控制,这里不再举例。
Shader渲染动画的更多相关文章
- Three.js粒子特效,shader渲染初探(一篇非常详细的介绍)
Three.js粒子特效,shader渲染初探 转载来源:https://juejin.im/post/5b0ace63f265da0db479270a 这大概是个序 关于Three.js,网上有不多 ...
- unity shader序列帧动画代码,顺便吐槽一下unity shader系统
一.看到UNITY论坛里有些人求unity shader序列帧动画,写shader我擅长啊,就顺势写了个CG的shader.代码很简单,就是变换UV采样序列帧贴图,美术配置行数列数以及变换速度. Sh ...
- Silverlight 2.5D RPG游戏技巧与特效处理:(五)HLSL渲染动画
原文:Silverlight 2.5D RPG游戏技巧与特效处理:(五)HLSL渲染动画 或许大家依旧对上一节中的“黑夜”及“梦回过去”记忆犹新,追问下去HLSL到底是何方神圣能实现如此炫酷之效果?层 ...
- CSharpGL(14)用geometry shader渲染模型的法线(normal)
+BIT祝威+悄悄在此留下版了个权的信息说: CSharpGL(14)用geometry shader渲染模型的法线(normal) +BIT祝威+悄悄在此留下版了个权的信息说: 2016-08-13 ...
- 使用替换shader渲染
相关函数: Camera.RenderWithShader(shader: Shader, replacementTag: string) 使用指定shader渲染,只影响一帧 Camera.SetR ...
- Unity Shader序列帧动画学习笔记
Unity Shader序列帧动画学习笔记 关于无限播放序列帧动画的一点问题 在学shader的序列帧动画时,书上写了这样一段代码: fixed4 frag(v2f i){ // 获得整数时间 flo ...
- Unity进阶之:Shader渲染
版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...
- Unity Shader 序列帧动画
shader中的序列帧动画属于纹理动画中的一种,主要原理是将给定的纹理进行等分,再根据时间的变化循环播放等分中的一部分. Unity Shader 内置时间变量 名称 类型 描述 _Time floa ...
- unity, 替换shader渲染(Rendering with Replaced Shaders)
实现特效,尤其是一些后处理特效,经常需要将各物体的shader替换为另一套shader进行渲染到纹理,再后再进行合成或以某种叠加方式叠加到最后的画面上去. 再复杂一点儿的,可能不同的物体所用的替换sh ...
随机推荐
- windows 下 logstash 安装启动
最新在研究elastic stack (elk) : logstash 安装,下载最新版本的logstash: 点击打开链接 解压到磁盘根目录下:在logstash>bin 1.目录下创建:l ...
- [bzoj3680]吊打XXX_模拟退火
吊打XXX bzoj-3680 题目大意:在平面上给定n个点,每个点有一个权值.请在平面上找出一个点(不一定在这n个点内找)使得这个点到n个点的距离*权值最小,即求这n个点的重心. 注释:$1\le ...
- xtrabackup增量备份mysql +MHA
http://blog.csdn.net/yanggd1987/article/category/2214421 https://www.centos.bz/2013/09/innobackupex- ...
- [LeetCode]Wildcard Matching 通配符匹配(贪心)
一開始採用递归写.TLE. class Solution { public: bool flag; int n,m; void dfs(int id0,const char *s,int id1,co ...
- kvc和kvo的使用情况的了解
了解cocoa:Cocoa是苹果公司为Mac OS X所创建的原生面向对象的API,是Mac OS X上五大API之中的一个(其他四个是Carbon.POSIX.X11和Java). 苹果的面向对象开 ...
- 基于ArcGIS Flex API实现动态标绘(1.0)
标绘作为一种数据展示形式,在多个行业都有需求. 基于ArcGIS Flex API(3.6)实现标绘API,当前版本号1.0 alpha,支持经常使用几种标绘符号,包含: 圆弧.曲线.圆形.椭圆.弓形 ...
- Java 异步转同步 ListenableFuture in Guava
ListenableFuture的说明 并发编程是一个难题,但是一个强大而简单的抽象可以显著的简化并发的编写.出于这样的考虑,Guava 定义了 ListenableFuture接口并继承了JDK c ...
- 轻快的VIM(五):复制
操作相同文本的时候复制尤其有效,在Windows中我们都习惯了先用鼠标选择文本 而Vim下则不用那么麻烦,你甚至可以使用可视模式操作,但这里先略过 我在这一节主要说说命令模式下的复制 在讲复制之前我要 ...
- 国外物联网平台初探(二) ——微软Azure IoT
平台定位 连接设备.其它 M2M 资产和人员,以便在业务和操作中更好地利用数据. 连接 IoT 设备 将所有设备连接到云,从这些设备接收大规模数据,以及管理这些设备的授权和限制. 在将设备连接到云和处 ...
- Node.js:文件系统
ylbtech-Node.js:文件系统 1.返回顶部 1. Node.js 文件系统 Node.js 提供一组类似 UNIX(POSIX)标准的文件操作API. Node 导入文件系统模块(fs)语 ...