通过渲染器Shader实现图像变换效果

在上一篇文章中,一起学习了通过设定画笔风格来实现图形变换,没读过的朋友可以点击下面链接:

http://www.cnblogs.com/fuly550871915/p/4886455.html

是不是觉得自己学到的知识更多了呢?那么再多学一点总没坏处。在本篇文章中,将会一起学习通过给画笔设定Shader属性,实现图形变换。并带领读者一起实现两个实际例子,图片渲染器和线性渲染器。有没有发现我们的画笔特别强大呢??确实,我们曾经给它设置过颜色矩阵属性,设置过xfermode风格属性,现在又来设定Shader属性。好了,废话不多说了,进入本章的主要内容吧。

一、基础知识

渲染效果大家都应该见到过,比如下面的这张图片。

上面是一张中规中矩的线性渲染的图片,从蓝色渲染到红色。但是在android中,有一个很奇葩的渲染方法,叫图片渲染。什么是图片渲染呢??没法说清楚,到下面的实战项目中大家看到效果就明白了。其他的渲染,比如线性渐变,矩形渐变等都是大家熟知的了。

对于给画笔设定图片渲染,首先要实例化一个图片渲染对象,然后再设定给画笔。示例代码如下:

//初始化图片渲染器
mBitmapShader = new BitmapShader(bmp, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
//将画笔绑定图片渲染器
paint.setShader(mBitmapShader);

其中bmp是一个Bitmap图片,而渲染的模式有Shader.TileMode.REPEAT,Shader.TileMode.CLAMP,Shader.TileMode.MIRROR。分别是重复模式,拉伸边缘像素模式,镜像模式。这几种模式你现在无法理解,到实战项目中,我们会演示效果,到时候你就明白了。上面的代码是x方向和y方向都设定为重复渲染模式。

对于给画笔设定普通的渲染器,比如说线性渲染,一句代码搞定,如下:

//方法new LinearGradient(x0, y0, x1, y1, color0, color1, tile)
//设置线性渲染器,(x0,y0)是起点坐标,(x1,y1)是终点坐标
//从color0渲染到color1,当然这里的color也可以改为透明度
//最后的tile表示选择一种渲染模式
paint.setShader(new LinearGradient(0, 0, 300, 300, Color.BLUE, Color.RED, Shader.TileMode.CLAMP));

注释中说的很清楚了,至于渲染模式,上面也有解释。

好了,然我们快进入实战,看看这些方法到底是怎么用的吧。

二、图片渲染实战

这里我们需要一张图片资源,读者可以替换为自己的图片,建议图片选的小一点尽量。这样效果看起来方便一些。在上一篇文章的代码基础上我们接着往下写。首先新建MyShaderView继承自view。代码中的注释很详细,在代码中用画笔绑定了图片渲染器然后画了一个圆出来。如下:

 1 package com.fuly.image;
 2
 3 import android.content.Context;
 4 import android.graphics.Bitmap;
 5 import android.graphics.BitmapFactory;
 6 import android.graphics.BitmapShader;
 7 import android.graphics.Canvas;
 8 import android.graphics.Paint;
 9 import android.graphics.Shader;
10 import android.util.AttributeSet;
11 import android.view.View;
12 /**
13  * 利用渲染器shader变换图像
14  * @author fuly1314
15  *
16  */
17 public class MyShaderView extends View{
18
19     private Bitmap bmp;
20     private Paint paint = new Paint();
21     private BitmapShader mBitmapShader;//图片渲染器
22
23
24     public MyShaderView(Context context) {
25         super(context);
26     }
27     public MyShaderView(Context context, AttributeSet attrs) {
28         super(context, attrs);
29
30     }
31     public MyShaderView(Context context, AttributeSet attrs, int defStyleAttr) {
32         super(context, attrs, defStyleAttr);
33     }
34
35
36     protected void onDraw(Canvas canvas) {
37
38         super.onDraw(canvas);
39
40         bmp = BitmapFactory.decodeResource(getResources(), R.drawable.hudie2);
41         //初始化图片渲染器
42         mBitmapShader = new BitmapShader(bmp, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
43         //将画笔绑定图片渲染器
44         paint.setShader(mBitmapShader);
45
46         canvas.drawCircle(150, 150, 300, paint);
47
48     }
49
50 }

然后新建布局imageshader.xml把这个view装进去。如下:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical"
 6     android:gravity="center">
 7
 8   <com.fuly.image.MyShaderView
 9       android:layout_marginLeft="20dp"
10       android:layout_marginTop="20dp"
11       android:layout_width="wrap_content"
12       android:layout_height="wrap_content"/>
13
14 </LinearLayout>

接着新建活动ShaderActivity显示这个布局,此时别忘记给这个活动注册。如下:

 1 package com.fuly.image;
 2
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5
 6 public class ShaderActivity extends Activity{
 7
 8
 9     protected void onCreate(Bundle savedInstanceState) {
10
11         super.onCreate(savedInstanceState);
12         setContentView(R.layout.imageshader);
13
14     }
15
16 }

最后给MainActivity中的按钮添加监听事件,如下:

 1 package com.fuly.image;
 2
 3 import android.os.Bundle;
 4 import android.view.View;
 5 import android.app.Activity;
 6 import android.content.Intent;
 7
 8
 9 public class MainActivity extends Activity {
10
11
12     protected void onCreate(Bundle savedInstanceState) {
13         super.onCreate(savedInstanceState);
14         setContentView(R.layout.activity_main);
15     }
16
17     //下面是按钮事件
18     public void btnMatrix(View v){
19         Intent intent = new Intent(this,MatrixActivity.class);
20         startActivity(intent);
21     }
22     public void btnXFermode(View v){
23         Intent intent = new Intent(this,XFermodeActivity.class);
24         startActivity(intent);
25     }
26     public void btnShader(View v){
27         Intent intent = new Intent(this,ShaderActivity.class);
28         startActivity(intent);
29     }
30
31
32 }

好了,快运行程序看看效果。如下:

注意在图片渲染中,我们使用了REPEAT模式。从效果来看其实就是用我们的这张小蝴蝶的图片来填充我们画的圆,如果发现图片太小,填充不完怎么办,那就不断重复画这个图片直到填充完为止。这下你明白什么是REPEAT模式了吧。下面我们将MyShaderView的第42行,即实例化图片渲染的代码改变一下,变成MIRROR模式,如下:

 //初始化图片渲染器
42 mBitmapShader = new BitmapShader(bmp, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);

只改这一个地方,然后重新运行程序,效果图如下:

有没有发现跟REPEAT模式有什么不同?也就是说在填充的时候,发现图片不够大,那就画它的镜像(即在镜子里的图像,也就是倒影)来填充,如此反复,直到填充完为止。这既是MIRROR模式的效果了。那么CLAMP模式又是什么样的呢?我们仍然修改第42行代码,如下:

//初始化图片渲染器
mBitmapShader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

为了让显示效果更好一点,我们替换为另外一张图片,此时要修改相应的获取bmp的代码。这个即修改第40的代码即可。我就不贴出来了。然后运行程序,效果如下:

                        

上图中,左侧是效果图,右侧就是我所使用的那张原图。可以看到,CLAMP模式的意思其实当发现原来图片不够填充的时候,就拉伸原图片边缘的像素直到填充满为止。

好了。经过那上面的三轮实验,相信你不经对着三种模式有所了解,而且对图片渲染也很熟悉了。那么下面就让我们来实现常规的渲染,比如线性渐变。

三、线性渐变实战

在这里简单起见,我就简单的单纯的只实现一个线性渐变的效果吧。目的是为让大家看看,普通的渲染是怎么绑定画笔的。目前来说,掌握这个就达到这篇文章的目的了。首先老规矩,新建LinearShaderView继承自view,在这里的代码中,将为画笔绑定一个线性渐变的渲染,并用它画出一个矩形。代码如下:

 1 package com.fuly.image;
 2
 3 import android.content.Context;
 4 import android.graphics.Bitmap;
 5 import android.graphics.BitmapFactory;
 6 import android.graphics.BitmapShader;
 7 import android.graphics.Canvas;
 8 import android.graphics.Color;
 9 import android.graphics.LinearGradient;
10 import android.graphics.Paint;
11 import android.graphics.Shader;
12 import android.util.AttributeSet;
13 import android.view.View;
14 /**
15  * 利用线性渲染器shader变换图像
16  * @author fuly1314
17  *
18  */
19 public class LinearShaderView extends View{
20
21     private Paint paint = new Paint();
22
23
24
25     public LinearShaderView(Context context) {
26         super(context);
27     }
28     public LinearShaderView(Context context, AttributeSet attrs) {
29         super(context, attrs);
30
31     }
32     public LinearShaderView(Context context, AttributeSet attrs, int defStyleAttr) {
33         super(context, attrs, defStyleAttr);
34     }
35
36
37     protected void onDraw(Canvas canvas) {
38
39         super.onDraw(canvas);
40         //方法new LinearGradient(x0, y0, x1, y1, color0, color1, tile)
41         //设置线性渲染器,(x0,y0)是起点坐标,(x1,y1)是终点坐标
42         //从color0渲染到color1,当然这里的color也可以改为透明度
43         //最后的tile表示选择一种渲染模式
44         paint.setShader(new LinearGradient(0, 0, 300, 300, Color.BLUE, Color.RED,
45                 Shader.TileMode.CLAMP));
46         //初始化图片渲染器
47
48         canvas.drawRect(0, 0, 300, 300, paint);
49
50     }
51
52 }

新建布局imagelinearshader.xml,将这个布局加进去,代码如下:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical"
 6     android:gravity="center">
 7
 8   <com.fuly.image.LinearShaderView
 9
10       android:layout_width="wrap_content"
11       android:layout_height="wrap_content"/>
12
13 </LinearLayout>

然后该新建活动了LinearShaderActivity用来显示我们的布局,代码如下:

 1 package com.fuly.image;
 2
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5
 6 public class LinearShaderActivity extends Activity{
 7
 8
 9     protected void onCreate(Bundle savedInstanceState) {
10
11         super.onCreate(savedInstanceState);
12         setContentView(R.layout.imagelinearshader);
13
14     }
15
16 }

最后呢,就是MainActivity中的按钮事件了,如下:

 1 package com.fuly.image;
 2
 3 import android.os.Bundle;
 4 import android.view.View;
 5 import android.app.Activity;
 6 import android.content.Intent;
 7
 8
 9 public class MainActivity extends Activity {
10
11
12     protected void onCreate(Bundle savedInstanceState) {
13         super.onCreate(savedInstanceState);
14         setContentView(R.layout.activity_main);
15     }
16
17     //下面是按钮事件
18     public void btnMatrix(View v){
19         Intent intent = new Intent(this,MatrixActivity.class);
20         startActivity(intent);
21     }
22     public void btnXFermode(View v){
23         Intent intent = new Intent(this,XFermodeActivity.class);
24         startActivity(intent);
25     }
26     public void btnShader(View v){
27         Intent intent = new Intent(this,ShaderActivity.class);
28         startActivity(intent);
29     }
30     public void btnLShader(View v){
31         Intent intent = new Intent(this,LinearShaderActivity.class);
32         startActivity(intent);
33     }
34
35
36 }

然后运行程序,效果如下:

好了,至此,你有没有学会怎么给画笔绑定普通的渲染呢?上面实现的效果比较简单,其实利用线性渐变结合xfermode风格可以实现常见的水面倒影效果,这个有兴趣可以自己百度下相关案例。

不知道你有没有发现,不知不觉间我们已经实现了4个按钮的效果了。还有最后一个按钮“像素块实验”没有实现了,下一篇文章中,我们就来看看这个效果吧。然后这个图形变换基础系列文章就完结了。

时间: 2024-10-20 14:02:42

通过渲染器Shader实现图像变换效果的相关文章

Android中自定义视图View之---渲染器Shader对象

下面再来看下一个知识点:颜色渲染Shader对象 为什么我要把Shader对象单独拿出来说一下呢?因为这个对象在对于我们处理图形特效的时候是非常有用的 下面来看一下Android中Shader对象 在Android Api中关于颜色渲染的几个重要的类:Shader,BitmapShader,ComposeShader,LinearGradient,RadialGradient,SweepGradient它们之间的关系是: Shader是后面几个类的父类 该类作为基类主要是返回绘制时颜色的横向跨度

基于OpenGL编写一个简易的2D渲染框架-09 重构渲染器-Shader

Shader 只是进行一些简单的封装,主要功能: 1.编译着色程序 2.绑定 Uniform 数据 3.根据着色程序的顶点属性传递顶点数据到 GPU 着色程序的编译 GLuint Shader::createShaderProgram(const char* vsname, const char* psname) { std::string vShaderSource, fShaderSource; std::ifstream vShaderFile, fShaderFile; vShaderF

Android Shader渲染器:BitmapShader

public class BitmapShader extends Shader BitmapShader,  Shader家族的 专门处理图片渲染的 构造方法: public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) bitmap:原图 tile直译为 瓷砖,瓦片.这里的TileMode 可看成是 铺图的模式. tileX, tileY:x/y 方向铺图的模式 public enum TileMode { CLAMP

android的shader渲染器

android里边的渲染器的使用主要是shader的子类,shader继承自object,他的子类有: 1.BitMapShader:BitMapShader 是bitmap渲染器,看名字就知道, BitmapShader是Shader的子类,可以通过Paint.setShader(Shader shader)进行设置. 这里我们只关注BitmapShader,构造方法: mBitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileM

Android学习笔记12:图像渲染(Shader)

在Android中,提供了Shader类专门用来渲染图像以及一些几何图形. Shader类包括了5个直接子类,分别为:BitmapShader.ComposeShader.LinearGradient.RadialGradient以及SweepGradient.其中,BitmapShader用于图像渲染:ComposeShader用于混合渲染:LinearGradient用于线性渲染:RadialGradient用于环形渲染:而SweepGradient则用于梯度渲染. 使用Shader类进行图

着色器(Shader)

着色器(Shader) 顶点着色器(Vertex shader) 片段着色器(Fragment shader) 几何着色器(Geometry Shader) 提供通用计算能力的着色器(Compute Shader) 顶点着色器(Vertex Shader) 每个顶点都要执行一次Vertex Shader. 它的功能就是把每个顶点在虚拟空间中的三维坐标变换为可以在 屏幕上显示的二维坐标,并带有用于z-buffer的深度信息.可操作属性:位置.颜色.纹理坐标,但是不能创建新的顶点. 主要完成以下工作

Unity Shader实现描边效果

http://gad.qq.com/article/detail/28346 描边效果是游戏里面非常常用的一种效果,一般是为了凸显游戏中的某个对象,会给对象增加一个描边效果.本篇文章和大家介绍下利用Shader实现描边效果,一起来看看吧. 最近又跑回去玩了玩<剑灵>,虽然出了三年了,感觉在现在的网游里面画面仍然算很好的了,剑灵里面走近或者选中NPC的一瞬间,NPC就会出现描边效果,不过这个描边效果是渐变的,会很快减弱最后消失(抓了好久才抓住一张图....) 还有就是最常见的LOL中的塔,我们把

Unity3D着色器Shader编程入门(一)

自学Unity3D也有大半年了,对Shader一直不敢入坑,最近看了些资料,以及通过自己的实践,对Shader还是有一点了解了,分享下仅作入门参考. 因Shader是对图像图像渲染的,学习前可以去了解下图形图像学及GPU编程相关的知识.强烈推荐<GPU 编程与CG 语言之阳春白雪下里巴人>,这本书网上有电子版. 还有一本是关于Unity3D的Shader开发的<Unity着色器和屏幕特效开发秘笈>该书是<Unity Shaders and Effects Cookbook&g

基于Cocos2d-x学习OpenGL ES 2.0系列——OpenGL ES渲染之Shader准备(7)

Cocos2d-x底层图形绘制是使用OpenGL ES协议的.OpenGL ES是什么呢? OpenGL ES(OpenGl for Embedded System)是OpenGL三维图形API的子集,针对手机.Pad和游戏主机等嵌入式设备而设计.该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准.OpenGL ES是OpenGL三维图形API的子集,针对手机.Pad和游戏主机等嵌入式设备而设计.Cocos2d-x底层图形渲染使