绘图Canvas十八般武器之Shader详解及实战
Posted 郭霖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了绘图Canvas十八般武器之Shader详解及实战相关的知识,希望对你有一定的参考价值。
近日,京东集团CEO刘强东与美的集团董事长方洪波签署了一份年度规模高达200亿的全面战略合作协议。根据协议,双方将进一步加强此前已经非常成功的战略合作关系,全面深化在智能家电、智能家居、渠道拓展、产品定制、大数据分析等领域的战略合作,共同推动家电行业的升级转型。
http://blog.csdn.net/briblue
android 中绘图离不开的就是 Canvas 了,Canvas 是一个庞大的知识体系,有Java层的,也有jni层深入到 Framework。Canvas 有许多的知识内容,构建了一个武器库一般,所谓十八般武艺是也,Paint 是 Canvas 的一个重要的合作伙伴,但今天要讲的不是 Canvas 也不是 Paint,而是与 Paint 相关的知识点 Shader.
Shader 在英语辞典中被解释为着色器。查阅维基百科,有以下结论:
In the field of computer graphics, a shader is a computer program that is used to do shading: the production of appropriate levels of color within an image, or, in the modern era, also to produce special effects or do video post-processing. A definition in layperson’s terms might be given as “a program that tells a computer how to draw something in a specific and unique way.
在计算机图形领域,一个 Shader 是指一段用来着色的计算机程序,通常用来生成一张图片中适当等级的颜色值,或者是生成特殊的视觉效果,或者是对视频画面进行处理。对于非专业人士的角度来看,它可以被描述为–“一种告诉计算机怎么样通过某种特殊手段绘制一些图像的程序”。
看起来还是比较抽象难懂,但是我觉得正确理解它的定义是应该的,这能让我们真正写出非常高效的代码。
Android 中也有 Shader 的概念,对照上面的定义,它应该也是将图形画面产生某种特殊效果的一类东西。具体是不是这样的呢?我可以先告诉你答案–是的。
为了提高大家对 Shader 的兴趣,先让大家看看通过 Shader 得到的一些效果图片。
是不是挺有趣啊?如果你对这些感兴趣,请跟随我的节奏,看下面内容。
Shader
https://developer.android.google.cn/reference/android/graphics/Shader.html
Android中对 Shader 是这样解释的:
Shader 是一种基类对象,它在图形绘制过程中返回一段段颜色值,通过调用 Paint.setShader() 方法,可以将它的子类安装进画笔,这样 Paint 对象在绘制过程中所获取的颜色就是来自 Shader 对象。
上面提到了Shader的子类,Shader 有5个子类 BitmapShader, ComposeShader, LinearGradient, RadialGradient,SweepGradient。 本文的目的也是分别讲它的各个子类。
BitmapShader 将一张图片当作纹理(在 OpenGL 中,纹理就是贴图的意思,可以理解为一个没有颜色的正方形被贴上了一张图片,这样视觉效果就是一张正方形的图片)来绘制。而这张图片可以通过设置 BitmapShader 的 tiling mode 来达到镜面和重复的效果。
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
上面是 BitmapShader 的构造方法。
bitmap 是指纹理图片
tileX 是指在X方向轴的 tiling mode
tileY 是指在Y方向轴的 tiling mode
很多人可能有疑问,这个 TileMode 是什么?
神秘莫测的TileMode
什么是 TileMode 呢? 事实上它只是一个枚举而已。它只有三个值。
Shader.TileMode CLAMP
Shader.TileMode MIRROR
Shader.TileMode REPEAT
CLAMP
它的意思当要绘制的区间大于图片纹理本身的区间时,多出来的空间位置将被纹理图片的边缘颜色填充。文字很难解释,我用图片来代替吧。原图如下:
原图的分辨率是562*336
我们编写一个自定义View – CustomView。然后在它的 onDraw() 方法中画一个矩形,并且设置画笔的 Shader 为 BitmapShader,Shader 的 tiling 模式为 CLAMP.代码如下:
大家现在只需要关注 mShader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);这行代码就可以了,剩下的呆会讲。
在 MainActivity 中的布局文件中,我们加入这个自定义View。
我们可以看到 CustomView 的宽占手机整个屏幕,高是 400dp.
我们在代码中以 CustomView 的宽高画一个矩形,并以上面的图片作为贴图纹理,效果如下:
好像和原图有点不一样? 红框外面的是什么?我们把手机弄成横屏再看:
这次双不一样了!红框右边也和下边一个德行了
让我们把注意力回到 CLAMP 的定义。
它的意思当要绘制的区间大于图片纹理本身的区间时,多出来的空间位置将被纹理图片的边缘颜色填充。
结合例子看,这下应该能明白它的含义了吧。上面的例子中,如果贴图的纹理本身小于要绘制的区域,那么超出部分将会以边缘的颜色填充。所以就造成了上面的现象。大家可以细细体会一下。我们看下一个知识点。
MIRROR
这个模式能够让纹理以镜像的方式在X和Y方向复制。这个模式很容易理解大家看图。
这就是镜像的效果
REPEAT
它的作用是将图片纹理沿XY轴进行复制。什么意思?看图就懂,在这里,我要换一张图片,作为演示效果。
然后代码如下:
哇噻!!!好多小狗狗。
大家有没有觉得Repeat模式特别有用呢?一张图就铺满整个空间。
混合双打
上面讲过的内容都是针对XY方向为同一种模式。能不能混合使用呢?
X —-> CLAMP Y —-> MIRROR
mShader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.MIRROR);
狗狗看起来更忧伤了
X —-> MIRROR Y —-> CLAMP
mShader = new BitmapShader(bmp, Shader.TileMode.MIRROR, Shader.TileMode.CLAMP);
有点恐怖是不是?
X —-> CLAMP Y —-> REPEAT
mShader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.REPEAT);
可以看到右边的部分拉伸了,然后上下复制同样的图像。
X —-> REPEAT Y —-> CLAMP
mShader = new BitmapShader(bmp, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
可以看到右边进行了复制,下面进行了拉伸。
X —-> REPEAT Y —-> MIRROR
mShader = new BitmapShader(bmp, Shader.TileMode.REPEAT, Shader.TileMode.MIRROR);
右边的复制,下面的是镜像
X —-> MIRROR Y —-> REPEAT
mShader = new BitmapShader(bmp, Shader.TileMode.MIRROR, Shader.TileMode.REPEAT);
右边的是镜像,下面的是上面图像的复制。
好了,TILEMODE讲完了,我们进入主题(感觉怪怪的,这篇文章不是讲TILEMODE的吗?)
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
我们再来回顾下它的构造方法,bitmap 是纹理图片,两个 TileMode 的参数对象我们也已经知道了含义与用法。现在我们来了解一下它的用法。
上面的代码是绘制一个圆形,然后用图片重复铺图。效果如下:
是不是很有感觉? 像自定义圆形图片控件效果一样。这小狗忧伤的让我想想起了张嘉佳的《从你的全世界路过》的梅茜和刘大黑。
我们再发散思维下圆形图像控件代码编写?
相信大家都知道,用可以设置先用canvas绘制一张图片,然后设置画笔的 XfermodePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 然后再绘制一个圆。
现在我们尝试用 BitmapShader 的方式去编写这么一个功能。思路:
1. 首先我们要确保这个自定义View是正方形的。
2. 我们以目标图片创建一个BitmapShader,然后设置进画笔。
3. 我们用设置好的画笔利用Canvas绘制一个圆形。
4. 关键一点,我们需要对原始的bitmap进行尺寸的调整,使得它的宽高至少要等于圆形的半径。
好了,编写代码:
效果图:
忧伤的小狗又出来了
更牛X的功能
我们已经知道怎么样通过 BitmapShader 去渲染一个矩形或者是圆形了,但它的神奇之处就在于此吗?
当然不是! Shader 被称为着色器,它用来渲染物体。在 OPENGL 3d 世界中,纹理可以看作是光秃秃的模型的皮肤,它可以为正文体,圆球,甚至复杂的人像模型着色。而在 Canvas 的范畴内,Shader 肯定只是为了2d平面着色,除了矩形,圆形,它肯定还适用于三角形和其它多边形以及任何闭合的不规则图形,如何的图形称为不规则图形呢?
我想说文字算不算?看图说话:
小狗狗的图像粘贴到文字上了。代码却十分的简单。
好了,讲完了,意犹未尽的感觉。
http://blog.csdn.net/briblue/article/details/53694042
以上是关于绘图Canvas十八般武器之Shader详解及实战的主要内容,如果未能解决你的问题,请参考以下文章
Android自定义View实战教程5??---Canvas详解及代码绘制安卓机器人