2.着色器(shader)

1.什么是着色器:着色器提供了灵活且强大的绘制二维和三维图形的方法,所有WebGL程序必须使用它。着色器处理完的结果存储在颜色缓冲区中。

2.几种着色器:

    顶点着色器(Vertex shader):用来描述顶点特性(如位置、颜色等)的程序。

                        顶点着色器对图像的顶点逐点进行处理,即要执行n次(n为顶点个数)

    片元着色器(Fragment shader):进行逐片元处理过程如光照的程序。

3.JavaScript与着色器程序的执行过程:

    首先着色器代码通过字符串的形式存储在JavaScript变量中(着色器代码必须含有main方法并且必须预处理成单个字符串的形式,用“+”进行连接),当JavaScript代码运行到初始化着色器时,着色器在WebGL系统(不是JavaScript程序)中开始运行,并根据着色器的定义对图形进行操作,然后将结果输出在颜色缓冲区中。

4.着色器代码中的变量在JavaScript中赋值(着色器代码都以字符串形式进行存储):

    存储限定符:attribute  和  uniform。attribute变量传输的是与顶点相关的数据,uniform变量存储的是对于所有顶点都相同(或与顶点无关)的数据。

    注意:getAttribLocation方法如果访问的变量地址不存在,返回-1;而getUniformLocation方法返回的是null

    声明格式:<存储限定符><类型><变量名>

attribute vec4 a_Position
uniform vec4 u_FragColor

  在着色器代码中使用存储限定符修饰声明变量,在JavaScript代码中可以通过预留方法请求到该变量在WebGL系统中的变量地址,并对该变量进行赋值。

    在JavaScript程序中获取着色器中的变量地址并对它进行赋值:

        gl.getAttribLoaction( program , name )

        program : 指定包含着色器的着色器程序对象

        name : 想要获取其存储地址的attribute变量的名称

    gl.vertexAttrib3f( location , v0 , v1 , v2)ver

        location : 要改变的变量的存储位置

        v0 : 指定填充attribute变量的第一个分量,其余分量设为默认值

        v1 : 指定填充attribute变量的第二个分量,其余分量设为默认值

        v2 : 指定填充attribute变量的第三个分量,其余分量设为默认值

    vertexAttrib3f的同族函数:

        首先WebGL相关函数明明规范是:<基础函数名><参数个数><参数类型>

        那么该方法的结构就是:vertexAttrib+n+参数类型+v(可不加),n代表参数个数,参数类型有 i (整数)、f (浮点数),v代表向量即可接受数组作为参数

5.顶点着色器和片元着色器之间的传值

    使用varying变量从顶点着色器传值到片元着色器:在WebGL中,顶点着色器与片元着色器中类型和命名相同的varying变量的值会自动由顶点着色器传入到片元着色器

var SHADER_SOURCE =
'attribute vec4 a_Position;\n'+
'attribute float a_PointSize;\n' +
'attribute vec4 a_Color;\n' +
'varying vec4 v_Color;\n'+
'void main(){\n'+
'gl_Position = a_Position;\n'+
'gl_PointSize = a_PointSize;\n' +
'v_Color = a_Color;\n'+
'}\n';

var FSHADER_SOURCE =
'precision mediump float;\n'+
'varying vec4 v_Color;\n'+
'void main(){\n'+
'gl_FragColor = v_Color;\n'+
'}\n';

function main()
{
var canvas = document.getElementById("webgl");
if(!canvas)
{
console.log("获取canvas标签失败");
}
var gl = canvas.getContext("webgl");
if(!gl)
{
console.log("获取上下文失败");
}
if(!initShaders(gl,SHADER_SOURCE,FSHADER_SOURCE))
{
console.log("加载着色器程序失败");
}

var n = initVertexBuffers(gl);
if(n<0)
{
console.log("设置顶点失败");
}

gl.drawArrays(gl.POINTS,0,n);

}

function initVertexBuffers(gl)
{
var vertices = new Float32Array([
0.0,0.5,10.0,1.0,0.0,0.0,
-0.5,-0.5,20.0,0.0,1.0,0.0,
0.5,-0.5,30.0,0.0,0.0,1.0,
]);
var n = 3; //顶点个数

//创建缓冲区对象
var vertexBuffer = gl.createBuffer();
if(!vertexBuffer)
{
console.log("创建缓冲区失败");
return -1;
}
var FSIZE = vertices.BYTES_PER_ELEMENT;
//将缓冲区对象绑定到目标
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
//向缓冲区对象写入数据
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program,'a_Position');
//将缓冲区对象分配给a_Position变量
gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,FSIZE*6,0);
//连接a_Position变量与分配给他的缓冲区对象
gl.enableVertexAttribArray(a_Position);

var sizeBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,sizeBuffer);
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
var a_PointSize = gl.getAttribLocation(gl.program,'a_PointSize');
gl.vertexAttribPointer(a_PointSize,1,gl.FLOAT,false,FSIZE*6,FSIZE*2);
gl.enableVertexAttribArray(a_PointSize);

var a_Color = gl.getAttribLocation(gl.program,'a_Color');
var colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
gl.vertexAttribPointer(a_Color,3,gl.FLOAT,false,FSIZE*6,FSIZE*3);
gl.enableVertexAttribArray(a_Color);

return n;

}

 

<think>我们正在讨论如何在Android中设置Paint的Shader属性。根据引用[2]和引用[3],我们可以知道: - Paint的shader属性用于在绘制形状时使用着色器(例如渐变、位图平铺等)。 - 当shader为null时,将使用Paint的color属性。 - 设置shader的方法就是直接给paint.setShader(Shader shader)传递一个Shader对象。 具体步骤: 1. 创建所需的Shader对象(如LinearGradient, RadialGradient, SweepGradient, BitmapShader, ComposeShader等)。 2. 调用Paint对象的setShader方法,将创建的Shader对象设置进去。 3. 使用设置了Shader的Paint进行绘制。 下面我们通过代码示例来展示如何设置不同类型的Shader。 ### 1. 线性渐变 (LinearGradient) ```java // 创建线性渐变,从(0,0)(200,200),颜色从红色到蓝色 LinearGradient linearGradient = new LinearGradient(0, 0, 200, 200, Color.RED, Color.BLUE, Shader.TileMode.CLAMP); Paint paint = new Paint(); paint.setShader(linearGradient); // 使用这个paint绘制矩形 canvas.drawRect(0, 0, 200, 200, paint); ``` ### 2. 径向渐变 (RadialGradient) ```java // 创建径向渐变,圆心(100,100),半径100,颜色从红色到蓝色 RadialGradient radialGradient = new RadialGradient(100, 100, 100, Color.RED, Color.BLUE, Shader.TileMode.CLAMP); Paint paint = new Paint(); paint.setShader(radialGradient); // 绘制圆形 canvas.drawCircle(100, 100, 100, paint); ``` ### 3. 扫描渐变 (SweepGradient) ```java // 创建扫描渐变,圆心(100,100),颜色从红色开始,然后到蓝色 SweepGradient sweepGradient = new SweepGradient(100, 100, Color.RED, Color.BLUE); Paint paint = new Paint(); paint.setShader(sweepGradient); // 绘制圆形 canvas.drawCircle(100, 100, 100, paint); ``` ### 4. 位图着色器 (BitmapShader) ```java // 加载位图 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); // 创建位图着色器,使用重复平铺模式 BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); Paint paint = new Paint(); paint.setShader(bitmapShader); // 绘制矩形(将用位图平铺填充) canvas.drawRect(0, 0, 500, 500, paint); ``` ### 5. 组合着色器 (ComposeShader) 组合着色器可以将两个着色器组合在一起,并使用指定的混合模式(PorterDuff.Mode)。 ```java // 创建两个着色器 LinearGradient linearGradient1 = new LinearGradient(0, 0, 200, 0, Color.RED, Color.YELLOW, Shader.TileMode.CLAMP); RadialGradient radialGradient1 = new RadialGradient(100, 100, 100, Color.BLUE, Color.TRANSPARENT, Shader.TileMode.CLAMP); // 组合两个着色器,使用PorterDuff.Mode.SRC_OVER模式(类似于叠加) ComposeShader composeShader = new ComposeShader(linearGradient1, radialGradient1, PorterDuff.Mode.SRC_OVER); Paint paint = new Paint(); paint.setShader(composeShader); // 绘制矩形 canvas.drawRect(0, 0, 200, 200, paint); ``` ### 注意事项: - 设置Shader后,Paint的color属性将不再起作用(除非Shader为null)。 - 可以随时更改Paint的Shader,也可以将Shader设置为null以恢复使用纯色绘制。 - 着色器的性能取决于其类型和大小,应避免在绘制过程中频繁创建和设置新的Shader(尤其是在onDraw方法中),以提高性能。 通过以上方法,就可以在Android中为Paint设置Shader属性,实现各种渐变和纹理效果[^2][^3][^5]。 --- ### §§相关问题§§ 1. 如何动态改变Shader的颜色或参数? 2. 使用Shader时如何避免内存泄漏? 3. 在自定义View中如何高效管理多个Shader? 4. 如何通过Shader实现动态渐变背景? 5. ComposeShader支持哪些混合模式?</think>### 如何在 Android 中设置 Paint 的 Shader 属性 在 Android 中设置 Paint 的 Shader 属性是实现高级渲染效果的关键技术。以下是详细步骤和示例: #### 1. **基本设置方法** ```java // 创建 Paint 对象 Paint paint = new Paint(); // 创建 Shader(例如线性渐变) Shader shader = new LinearGradient( 0, 0, 300, 0, // 起点(x0,y0)到终点(x1,y1) Color.RED, Color.BLUE, // 渐变颜色 Shader.TileMode.CLAMP // 边缘处理模式 ); // 设置 Shader 属性 paint.setShader(shader); // 使用设置了 Shader 的 Paint 绘制 canvas.drawRect(0, 0, 300, 100, paint); ``` [^2][^3] #### 2. **常用 Shader 类型及设置方法** | Shader 类型 | 创建方法 | 应用场景 | |------------|---------|---------| | **线性渐变** | `LinearGradient(startX, startY, endX, endY, colors, positions, tileMode)` | 按钮背景、进度条 | | **径向渐变** | `RadialGradient(centerX, centerY, radius, colors, positions, tileMode)` | 发光效果、圆形按钮 | | **扫描渐变** | `SweepGradient(cx, cy, colors, positions)` | 雷达扫描、色轮 | | **位图着色** | `BitmapShader(bitmap, tileModeX, tileModeY)` | 纹理填充、图案背景 | | **组合着色** | `ComposeShader(shaderA, shaderB, PorterDuff.Mode)` | 复杂混合效果 | #### 3. **完整示例:创建渐变文本** ```java // 创建渐变 Shader Shader textShader = new LinearGradient( 0, 0, 300, 0, new int[]{Color.RED, Color.YELLOW, Color.GREEN}, null, Shader.TileMode.CLAMP ); // 配置 Paint Paint textPaint = new Paint(); textPaint.setShader(textShader); // 设置 Shader textPaint.setTextSize(48); // 设置文本大小 textPaint.setAntiAlias(true); // 开启抗锯齿 // 绘制文本 canvas.drawText("渐变文字效果", 50, 100, textPaint); ``` [^1][^4] #### 4. **高级技巧:组合着色器 (ComposeShader)** ```java // 创建第一个 Shader(位图纹理) Bitmap pattern = BitmapFactory.decodeResource(getResources(), R.drawable.pattern); Shader shader1 = new BitmapShader(pattern, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); // 创建第二个 Shader(径向渐变) Shader shader2 = new RadialGradient(150, 150, 100, Color.TRANSPARENT, Color.BLUE, Shader.TileMode.CLAMP); // 组合两个 Shader(使用 SRC_OVER 混合模式) ComposeShader composeShader = new ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER); // 设置组合 Shader Paint paint = new Paint(); paint.setShader(composeShader); // 绘制圆形 canvas.drawCircle(150, 150, 100, paint); ``` [^5] #### 5. **注意事项** 1. **性能优化**:避免在 `onDraw()` 中频繁创建 Shader 对象,应在初始化时创建 2. **覆盖关系**:Shader 会覆盖 Paint 的 `setColor()` 效果[^2] 3. **尺寸适配**:使用 `Shader.setLocalMatrix(matrix)` 动态调整渐变/纹理比例 4. **混合模式**:ComposeShader 支持 18 种 PorterDuff 混合模式(如 SRC_OVER, MULTIPLY 等)[^5] #### 6. **调试技巧** 当渐变效果不符合预期时: 1. 检查坐标值是否在绘制区域内 2. 确认颜色数组和位置数组长度匹配 3. 测试使用 `Shader.TileMode.MIRROR` 替代 `CLAMP` 4. 暂时移除 `ColorFilter` 属性(会覆盖 Shader 效果)[^2] > 通过合理组合不同类型的 Shader,可以创建出复杂的视觉效果,如动态背景、材质纹理和高级渐变,显著提升 UI 表现力[^1][^3]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值