【Android】RuntimeShader 应用

news/2025/10/4 12:10:34/文章来源:https://www.cnblogs.com/zhyan8/p/19123012

1 简介

​ RuntimeShader 是 Android 13(T)中新增的特性,用于逐像素渲染界面,它使用 AGSL(Android Graphics Shading Language)编写着色器代码,底层基于 Skia 图形渲染引擎。官方介绍详见 → RuntimeShader。

​ 相较于 OpenGL ES,RuntimeShader 具有以下特点。

  • RuntimeShader 中只有片元着色器,没有顶点着色器。
  • RuntimeShader 中用户不用输入顶点数据,简化了输入操作。
  • RuntimeShader 基于 AGSL 语言,OpenGL ES 基于 GLSL 语言。
  • AGSL 中纹理坐标值域与 View 的宽高对应,GLSL 中纹理坐标一般归一化了。

​ 本文完整资源见 → RuntimeShader应用。

2 对 View 进行二次渲染

​ MainActivity.java

package com.zhyan8.shaderdemo;import androidx.appcompat.app.AppCompatActivity;import android.graphics.RenderEffect;
import android.graphics.RuntimeShader;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;import com.zhyan8.shaderdemo.utils.ScreenUtils;
import com.zhyan8.shaderdemo.utils.StringUtils;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);LinearLayout parentView = findViewById(R.id.parent);float[] resolution = ScreenUtils.getScreenSizeF(this);applyRuntimeShader(parentView, resolution);}private void applyRuntimeShader(View view, float[] resolution) {String shaderCode = StringUtils.loadString(this, "shaders/dazzling.agsl");RuntimeShader shader = new RuntimeShader(shaderCode);shader.setFloatUniform("u_resolution", resolution);RenderEffect effect = RenderEffect.createRuntimeShaderEffect(shader, "u_texture");view.setRenderEffect(effect);}
}

​ activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"android:orientation="vertical"android:gravity="center"android:background="#FFFFFF"android:id="@+id/parent"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World"android:textSize="60sp"android:textColor="#669933"/></LinearLayout>

​ dazzling.agsl

uniform shader u_texture;
uniform vec2 u_resolution;vec4 main(vec2 coords) {vec4 tex = u_texture.eval(coords);vec2 normUV = coords / u_resolution;vec3 color = tex.rgb * vec3(normUV.x, normUV.y, 0.5);return vec4(color, 1.0);
}

​ 说明:coords 的值域与 View 的宽高对应,并不是归一化的坐标。

​ 运行效果如下。

img

3 通过 Canvas 进行渲染

3.1 简单应用

​ MainActivity.java

package com.zhyan8.shaderdemo;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.WindowManager;
import android.widget.LinearLayout;import com.zhyan8.shaderdemo.graphics.ShaderView;public class MainActivity extends AppCompatActivity {private ShaderView mShaderView;private LinearLayout mParentView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mParentView = findViewById(R.id.parent);addView();MyRenderer renderer = new MyRenderer(this);mShaderView.setRenderer(renderer);mShaderView.requestRender(true);}private void addView() {mShaderView = new ShaderView(this);WindowManager.LayoutParams lp = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);lp.width = WindowManager.LayoutParams.MATCH_PARENT;lp.height = WindowManager.LayoutParams.MATCH_PARENT;mParentView.addView(mShaderView, lp);}
}

​ ShaderView.java

package com.zhyan8.shaderdemo.graphics;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RuntimeShader;
import android.os.Handler;
import android.os.Looper;
import android.view.Choreographer;
import android.view.View;/*** 自定义view, 承载渲染环境作用, 类比GLSurfaceView* @author little fat sheep*/
public class ShaderView extends View {private Paint mPaint = new Paint();private Renderer mRenderer;private float[] mResolution;private long mStartTime = 0L;private long mRunTime = 0L;private Choreographer mChoreographer;private Handler mHandler;public ShaderView(Context context) {super(context);mChoreographer = Choreographer.getInstance();mHandler = new Handler(Looper.getMainLooper());}public void setRenderer(Renderer renderer) {this.mRenderer = renderer;RuntimeShader shader = renderer.onSurfaceCreated();mPaint.setShader(shader);mStartTime = System.currentTimeMillis();}public void requestRender() {invalidate();}public void requestRender(long duration) {mHandler.removeCallbacksAndMessages(null);mHandler.post(() -> {mChoreographer.postFrameCallback(mFrameCallback);});mHandler.postDelayed(() -> {mChoreographer.removeFrameCallback(mFrameCallback);}, duration);}public void requestRender(boolean continuous) {if (continuous) {mChoreographer.postFrameCallback(mFrameCallback);} else {invalidate();}}public void stopRenderer() {mChoreographer.removeFrameCallback(mFrameCallback);}public void stopRenderer(long delay) {mHandler.removeCallbacksAndMessages(null);mHandler.postDelayed(() -> {mChoreographer.removeFrameCallback(mFrameCallback);}, delay);}@Overridepublic void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mResolution = new float[] { w, h };mRenderer.onSurfaceChanged(w, h);}@Overridepublic void onDraw(Canvas canvas) {super.onDraw(canvas);mRunTime = System.currentTimeMillis() - mStartTime;mRenderer.onDrawFrame(mRunTime);canvas.drawRect(0f, 0f, mResolution[0], mResolution[1], mPaint);}private Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {@Overridepublic void doFrame(long frameTimeNanos) {mChoreographer.postFrameCallback(this);ShaderView.this.invalidate();}};/*** 渲染器接口, 类比GLSurfaceView.Renderer* @author little fat sheep*/public interface Renderer {RuntimeShader onSurfaceCreated();void onSurfaceChanged(int width, int height);void onDrawFrame(long runTime);}
}

​ BitmapTexture.java

package com.zhyan8.shaderdemo.graphics;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.RuntimeShader;
import android.graphics.Shader;import com.zhyan8.shaderdemo.utils.BitmapUtils;/*** Bitmap纹理* @author little fat sheep*/
public class BitmapTexture {private BitmapShader mBitmapShader;private float[] mSize;private BitmapTexture(BitmapShader bitmapShader, float[] size) {this.mBitmapShader = bitmapShader;this.mSize = size;}public static BitmapTexture create(Context context, String assetPath) {Bitmap bitmap = BitmapUtils.loadBitmapFromAsset(context, assetPath);return create(bitmap);}public static BitmapTexture create(Context context, int rawId) {Bitmap bitmap = BitmapUtils.loadBitmapFromRaw(context, rawId);return create(bitmap);}public static BitmapTexture create(Bitmap bitmap) {BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);float[] size = new float[] { bitmap.getWidth(), bitmap.getHeight() };return new BitmapTexture(bitmapShader, size);}public void bind(RuntimeShader shader, String textureName, String sizeName) {shader.setInputShader(textureName, mBitmapShader);shader.setFloatUniform(sizeName, mSize);}
}

​ MyRenderer.java

package com.zhyan8.shaderdemo;import android.content.Context;
import android.graphics.RuntimeShader;import com.zhyan8.shaderdemo.graphics.BitmapTexture;
import com.zhyan8.shaderdemo.graphics.ShaderView;
import com.zhyan8.shaderdemo.utils.StringUtils;public class MyRenderer implements ShaderView.Renderer {private Context mContext;private RuntimeShader mShader;private float[] mResolution;private BitmapTexture mBitmapTexture;public MyRenderer(Context context) {this.mContext = context;}@Overridepublic RuntimeShader onSurfaceCreated() {String shaderCode = StringUtils.loadString(mContext, "shaders/jelly.agsl");mShader = new RuntimeShader(shaderCode);mBitmapTexture = BitmapTexture.create(mContext, "textures/photo.png");return mShader;}@Overridepublic void onSurfaceChanged(int width, int height) {mResolution = new float[] { width, height };}@Overridepublic void onDrawFrame(long runTime) {mBitmapTexture.bind(mShader, "u_texture", "u_textureSize");mShader.setFloatUniform("u_resolution", mResolution);mShader.setFloatUniform("u_time", runTime / 1000f);}
}

​ jelly.agsl

uniform shader u_texture;
uniform vec2 u_textureSize;
uniform vec2 u_resolution;
uniform float u_time;vec4 texture(vec2 normUV) { // 纹理采样vec2 uv = normUV * u_textureSize;return u_texture.eval(uv);
}vec2 fun(vec2 uv, float aspect) { // 畸变函数vec2 center = vec2(0.5, 0.5 / aspect);vec2 dire = normalize(uv - center);float dist = distance(uv, center);vec2 uv1 = uv + sin(dist * 2.2 + u_time * 3.5) * 0.025;return uv1;
}vec4 main(vec2 coords) {vec2 normUV = coords / u_resolution;float aspect = u_resolution.x / u_resolution.y;normUV.y /= aspect;vec2 uv = fun(normUV, aspect);uv.y *= aspect;return texture(uv);
}

​ 运行效果如下。

img

3.2 二次渲染

​ 本节将对 3.1 节中 MyRenderer 进行修改,使用两个 RuntimeShader 实现二次渲染。

​ MyRenderer.java

package com.zhyan8.shaderdemo;import android.content.Context;
import android.graphics.RuntimeShader;import com.zhyan8.shaderdemo.graphics.BitmapTexture;
import com.zhyan8.shaderdemo.graphics.ShaderView;
import com.zhyan8.shaderdemo.utils.StringUtils;public class MyRenderer implements ShaderView.Renderer {private Context mContext;private RuntimeShader mShader1;private RuntimeShader mShader2;private float[] mResolution;private BitmapTexture mBitmapTexture;public MyRenderer(Context context) {this.mContext = context;}@Overridepublic RuntimeShader onSurfaceCreated() {String shaderCode1 = StringUtils.loadString(mContext, "shaders/dispersion.agsl");mShader1 = new RuntimeShader(shaderCode1);String shaderCode2 = StringUtils.loadString(mContext, "shaders/jelly.agsl");mShader2 = new RuntimeShader(shaderCode2);mBitmapTexture = BitmapTexture.create(mContext, "textures/photo.jpg");return mShader2;}@Overridepublic void onSurfaceChanged(int width, int height) {mResolution = new float[] { width, height };}@Overridepublic void onDrawFrame(long runTime) {mBitmapTexture.bind(mShader1, "u_texture", "u_textureSize");mShader1.setFloatUniform("u_resolution", mResolution);mShader1.setFloatUniform("u_time", runTime / 1000f);mShader2.setInputShader("u_texture", mShader1);mShader2.setFloatUniform("u_textureSize", mResolution);mShader2.setFloatUniform("u_resolution", mResolution);mShader2.setFloatUniform("u_time", runTime / 1000f);}
}

​ dispersion.agsl

uniform shader u_texture;
uniform vec2 u_textureSize;
uniform vec2 u_resolution;
uniform float u_time;vec4 texture(vec2 normUV) { // 纹理采样vec2 uv = normUV * u_textureSize;return u_texture.eval(uv);
}vec2 getOffset() { // 偏移函数float time = u_time * 1.5;vec2 dire = vec2(sin(time), cos(time));float strength = sin(u_time * 2.0) * 0.01;return dire * strength;
}vec4 main(vec2 coords) {vec2 normUV = coords / u_resolution;vec4 color = texture(normUV);vec2 offset = getOffset();color.r = texture(normUV + offset).r;color.b = texture(normUV - offset).b;return color;
}

​ 运行效果如下,可以看到叠加了果冻畸变和 RGB 色散效果。

img

​ 声明:本文转自【Android】RuntimeShader 应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/927118.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个公司多个网站做优化程序开发平台

1&#xff0c;已经创建了通用树结构&#xff0c;有必要创建另一种树结构吗&#xff1f; 2&#xff0c;简化树就直接减少结点中孩子的数量&#xff0c;但是这样树还能通用吗&#xff1f; 3&#xff0c;通用树结构的回顾&#xff1a; 1&#xff0c;双亲孩子表示法&#xff1a; 1&…

【Rive】rive-android源码分析

1 前言 ​ 本文基于 rive-android 10.1.0 进行源码分析,主要介绍 Rive 的渲染类型、RendererType 透传流程、Surface 透传流程、渲染流程、启动渲染流程、暂停渲染流程等内容。 ​ rive-android 类图框架如下。…

惠州专业网站建设价格wordpress网站维护教程

技术复盘--git 资料地址原理图安装配置基本命令分支命令对接gitee练习:远程仓库操作 资料地址 学习地址-B站黑马&#xff1a;https://www.bilibili.com/video/BV1MU4y1Y7h5 git官方&#xff1a;https://git-scm.com/ gitee官网&#xff1a;https://gitee.com/ 原理图 说明&am…

zkSync Era主网上线:首个zkEVM全面开放的技术突破

zkSync Era主网正式对外开放,这是全球首个完全开放的zkEVM解决方案。文章详细介绍了其独特的技术架构,包括原生账户抽象、LLVM编译器、数据压缩和超扩展性设计,以及经过多重安全审计的系统安全保障机制。gm zkEVM!…

企业网站开发知名品牌有哪些建设银行网站点击次数

公司简介 陕西集群物联网服务管理股份有限公司旗下的“集群e家”是专注于社区商圈O2O服务的平台&#xff0c;为社区&#xff08;乡村&#xff09;家庭提供创新的家庭消费服务及消费体验。集群e家智慧生活是以社区&#xff08;乡村&#xff09;为中心&#xff0c;以“互联网”的…

免费建商城网站快速网站seo效果

【Java】全套云HIS&#xff08;医院信息管理系统&#xff09;可对接医保 采用云端SaaS模式部署 SaaS 模式的云 HIS 更适用于基层医疗机构&#xff0c;而传统的 HIS 已经在大中型医疗机构大规模应用。过去&#xff0c;国内的大中型医疗机构投入了大量的资金来进行信息化系统建设…

建站推广网站收费做网站

#基础概念# #入门 数据库的主要分类 关系型数据库&#xff08;RDBMS&#xff09; 数据以表格形式存储&#xff0c;通过预定义的关系模型建立数据间的连接&#xff0c;使用SQL作为查询语言。常见的例子包括MySQL、Oracle、SQL Server、PostgreSQL、IBM DB2等。 非关系型数据库…

鄂尔多斯网站建设公司小程序模板源码免费下载

1. opencv概述 OpenCV是一个开源的计算机视觉库&#xff0c;它提供了一系列丰富的图像处理和计算机视觉算法&#xff0c;包括图像读取、显示、滤波、特征检测、目标跟踪等功能。 opencv官网&#xff1a;https://opencv.org/ opencv官网文档&#xff1a;https://docs.opencv.or…

完整教程:基于Spring Boot的爱琴海购物公园网上商城系统的设计与实现

完整教程:基于Spring Boot的爱琴海购物公园网上商城系统的设计与实现2025-10-04 11:55 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto…

Microsoft Access SQL 查询中的通配符 - 详解

Microsoft Access SQL 查询中的通配符 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &qu…

洛谷P11738 [集训队互测 2015] 未来程序改

这道题很显然是一道编译原理的题…… 本文简单的介绍了下Lexer, Parser和Interpreter的写法(实际上写编译器需要的是CodeGen) 可以看看,但是对OI似乎没什么用懒得写这么大的模拟了,想学的可以去看看我的项目QAQ很显…

mcp 面试题

什么是 MCP(Model Context Protocol) MCP 是 OpenAI 推出的 大模型上下文交互协议。它的作用是标准化 LLM 与外部工具、数据源、事件系统的交互方式。 在没有 MCP 之前,开发者需要为每个插件单独设计接口,成本高且…

做qq空间动态皮肤网站网络营销常用的方法

个人博客&#xff1a;代码菌-CSDN博客 专栏&#xff1a;C杂货铺_代码菌的博客-CSDN博客 目录 &#x1f308;前言&#x1f308; &#x1f4c1; 初始化列表&#xff08;灰常重要&#xff09; &#x1f4c2; 引入 &#x1f4c2; 概念 &#x1f4c2; 特性 &#x1f4c1; 拓展构…

6_什么是知识图谱

知识图谱(Knowledge Graph)是一种用于表示和存储知识的结构化数据模型。它以图的形式组织信息,其中实体(entities)作为节点,关系(relationships)作为边,形成一个相互连接的知识网络。 知识图谱的核心特点:实…

实用指南:[创业之路-645]:手机属于通信?还是属于消费类电子?还是移动互联网?

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

【开题答辩过程】以《基于SpringBoot+Vue+uni-app的智慧校园服务系统的设计与搭建》为例,不会开题答辩的可能进来看看

【开题答辩过程】以《基于SpringBoot+Vue+uni-app的智慧校园服务系统的设计与搭建》为例,不会开题答辩的可能进来看看pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !importan…

c 网站开发案例专业网络推广方案

C语言acm竞赛习题集锦.doc杭州电子科技大学 acm 习题精选 第 1 页 共 21 页 目录 1、 数塔问题 2 2、 并查集类问题 4 3、 递推类问题 9 4、 动态规划系列 10 5、 概率类题型 13 6、 组合数学类题型 15 7、 贪心策略 16 8、 几何问题 .19 杭州电子科技大学 acm 习题精选 第 2 页…

丽水做网站公司本地电脑做服务器建网站

0x00 简介本期主要会教大家如何从流量中还原出来文件。下面我将会用多种办法来讲解。使用系统&#xff1a;Kali Linux0x01 tcpxtract工具网络流量提取文件(方法1)Kali Linux默认没有安装该工具&#xff0c;需要自己安装安装命令&#xff1a;sudo apt install tcpxtract使用方法…

微信ipad协议个微机器人开发API

微信ipad协议个微机器人开发API,微信群机器人API 微信iPad协议,采用最新的ASE加密,以及最新的算法,iPad协议是一套微信个人号接口,基于web开发,它能实现微信中的百分之八十的功能,并辅助微信执行各种操作,提供…

做乒乓球网站的图片网络建设与维护是什么工作

2.1 数组 &#xff08;1) 概述 定义 在计算机科学中&#xff0c;数组是由一组元素&#xff08;值或变量&#xff09;组成的数据结构&#xff0c;每个元素有至少一个索引或键来标识 因为数组内的元素是连续存储的&#xff0c;所以数组中元素的地址&#xff0c;可以通过其索引…