深入URP之Shader篇14: GPU Instancing

news2024/12/24 10:43:36

GPU Instancing

必须是同一个模型,材质也必须相同,但材质的参数可以不同(使用MaterialPropertyBlock指定),然后基于一个Instanced Draw Call,一次性绘制多个模型。
参考:https://docs.unity3d.com/Manual/GPUInstancing.html

SRP中几种Bathcing方式的优先级

  • 如果物体是静态的(Batching Static),则会使用Static Batching。如果物体的材质兼容SRP Batcher,则会同时使用SRP Batcher。
  • 如果物体的材质和Renderer兼容GPU Instancing,则会启用GPU Instancing
  • 如果开启了Dynamic Batching,则会使用动态Batch。
    由上可知,如果想启用GPU Instancing,必须不能开启Static Batching,且不能满足SRP Batcher条件。
    如果材质是兼容GPU Instancing的,且物体是开启了Static Batching的,则Unity会在物体的Inspector中给出提示:
    在这里插入图片描述

GPU Instacing开启的条件

  • 首先Shader必须兼容与Instancing。
  • 材质开启 Enable GPU Instancing
  • SRP Batcher的优先级高于GPU Instancing,对于Game Objects,如果SRP Batcher能被使用(Shader兼容SRP Batcher,节点本身也兼容等),则就会使用SRP Batcher,即便材质开启了Enable GPU Instancing也没用。
  • 如果SPR Batcher的条件被破坏,例如使用了MaterialPropertyBlock,且开启了Enable GPU Instancing,则GPU Instancing则会启用。

GPU Instancing的性能

  • GPU Instancing对于顶点数比较少的模型不一定能提高性能,因为顶点数少时GPU不能充分的分配资源去绘制多个实例,这个顶点数的阈值根据不同显卡是不一样的,但一般来说少于256个顶点是不合适的。
  • 如果有很多顶点少的物体需要绘制,可以将他们合并到一个mesh中进行绘制。

自定义Shader兼容GPU Instancing

UNITY_INSTANCING_BUFFER_START(UnityPerMaterial)
    UNITY_DEFINE_INSTANCED_PROP(float4, _BaseColor)
UNITY_INSTANCING_BUFFER_END(UnityPerMaterial)


struct Attributes
{
    float3 positionOS : POSITION;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct Varyings
{
    float4 positionCS : SV_POSITION;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

Varyings UnlitPassVertex(Attributes input)
{
    Varyings output;
    UNITY_SETUP_INSTANCE_ID(input);
    UNITY_TRANSFER_INSTANCE_ID(input, output);
    float3 positionWS = TransformObjectToWorld(input.positionOS);
    output.positionCS = TransformWorldToHClip(positionWS);
    return output;
}

float4 UnlitPassFragment(Varyings input) : SV_TARGET
{
    UNITY_SETUP_INSTANCE_ID(input);
    return UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _BaseColor);
}
  • 首先,定义PerMaterial Uniform block时,要使用INSTANCING相关的宏UNITY_INSTANCING_BUFFER_STARTUNITY_INSTANCING_BUFFER_ENDUNITY_DEFINE_INSTANCED_PROP。这些宏的作用是将Uniform block定义成数组。需要注意的是,只有当同一个材质下面的不同Instance存在逐Instance不同的属性时,才需要将UnityPerMaterial的CBuffer改成使用这些宏,否则是不需要的,因为这些宏只是为了将属性定义成数组,然后可以使用Instance索引去得到数组里面不同Instance各自的属性。另外,由于CBuffer的名字不能冲突,所以也不能仅仅将不同的属性单独拿出来使用这些宏包裹,如果需要拿出来就得全部拿出来,也就是将SRPBatcher使用的CBuffer的宏替换成这些宏。
  • VS和FS的输入都要使用结构体作为参数,且结构体中需要使用宏UNITY_VERTEX_INPUT_INSTANCE_ID定义逐物体的instance id。
  • 在VS和FS中,都要使用宏UNITY_SETUP_INSTANCE_ID来设置instance id变量,这个宏的作用是使用一个base instance id和input中的instance id组合出一个instance id变量来作为数组索引获取相应的属性值。
  • 如果需要在FS中获取属性,则VS中需要使用宏UNITY_TRANSFER_INSTANCE_ID从input向output传递instance id。然后在FS中使用宏UNITY_ACCESS_INSTANCED_PROP获取属性。当然如果是在VS中获取所有属性进行计算,则不需要传递,直接在VS中使用宏UNITY_ACCESS_INSTANCED_PROP获取属性。
  • 另外,必须要添加#pragma multi_compile_instancing

让Shader不兼容SRP Batcher

使用上面这些宏,其实也就同时兼容了SRP Batcher。如果在Renderer上使用MaterialPropertyBlock,则会破坏SPR Batcher的兼容性,从而可以使用GPU Instancing。但如果不使用MaterialPropertyBlock呢?也可以通过修改Shader来让Shader不兼容于SRP Batcher,方法是在材质的Properties中定义一个属性,但是这个属性不要放到UnityPerMaterial的block中。具体文档是这么说的:

Removing shader compatibility
You can make both hand-written and Shader Graph shaders incompatible with the SRP Batcher. However, for Shader Graph shaders, if you change and recompile the Shader Graph often, it’s simpler to make the renderer incompatible instead.
To make a Unity shader incompatible with the SRP Batcher, you need to make changes to the shader source file:
For hand-written shaders, open the shader source file. For Shader Graph shaders, copy the Shader Graph’s compiled shader source code into a new shader source file. Use the new shader source file in your application instead of the Shader Graph.
Add a new material property declaration into the shader’s Properties block. Don’t declare the new material property in the UnityPerMaterial constant buffer.
The material property doesn’t need to do anything; just having a material property that doesn’t exist in the UnityPerMaterial constant buffer makes the shader incompatible with the SRP Batcher.
Warning: If you use a Shader Graph, be aware that every time you edit and recompile the Shader Graph, you must repeat this process.

但我实际测试发现,这个新定义的属性必须在Shader中用到,否则就不会去除SRP Batcher的兼容,我猜测是Shader代码编译时优化掉了不使用的属性。

参考

  • Unity文档:GPUInstancing
  • catlikecoding.com

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

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

相关文章

整合SSM:Mybatis层

SSM(SpringSpringMVCMyBatis)框架集由Spring、MyBatis两个开源框架整合而成.为了加深记忆学习,也为了后续资源方便使用.所以决定就对SSM做一个整合,首先是Mybatis层。 思路: 1.开发环境 基本环境: IDEA MySQL 8.0.22 Tomcat 9…

java实现生成RSA公私钥、SHA256withRSA加密以及验证工具类

前言: RSA属于非对称加密。所谓非对称加密,需要两个密钥:公钥 (publickey) 和私钥 (privatekey)。公钥和私钥是一对,如果用公钥对数据加密,那么只能用对应的私钥解密。如果用私钥对数据加密,只能用对应的公…

android系统启动流程之zygote(Native)启动分析

zygote有一部分运行在native,有一部分运行在java层,它是第一个进入java层的进程 zygote在启动时,在init.${ro.zygote}.rc脚本中,里面描述了zygote是如何被启动的, 当init进程解析到zygote.rc文件时,将根据解析出来的命…

蓝桥杯数论必考算法------快速幂

快速幂 目录 快速幂一.暴力解法 O(n∗b) 会TLE二.快速幂解法 O(n∗logb)2.1快速幂之迭代版 O(n∗logb)2.2快速幂之递归版 O(n∗logb) 三&#xff1a;快速幂练习(快速幂求逆元) 一.暴力解法 O(n∗b) 会TLE #include<iostream> using namespace std; int main() {int n;cin…

Matlab图像处理-减法运算

减法运算 图像减法也称为差分方法&#xff0c;是一种常用于检测图像变化及运动物体的图像处理方法。常用来检测一系列相同场景图像的差异&#xff0c;其主要的应用在于检测同一场景下两幅图像之间的变化或是混合图像的分离。 差影法 将同一景物在不同时问拍摄的图像或同一景…

飞腾E2000从eMMC或SD启动U-boot和系统

本文讲解了,如何设置uboot环境变量和编译linux内核,实现将uboot和系统同时放置到SD卡或eMMC后,从SD或者eMMC启动uboot,引导系统启动的过程。 同时使用E2000Q-demo,演示了从SD卡启动和从eMMC启动的过程。 1、制作MMC(eMMC/SD卡)启动镜像文件 1.1、重新编译u-boot.bin,…

印花税减半!上次调整A股全部涨停

财政部、税务总局公告&#xff0c;为活跃资本市场、提振投资者信心&#xff0c;自2023年8月28日起&#xff0c;证券交易印花税实施减半征收。 值得一提的是&#xff0c;8月初&#xff0c;证券时报、经济日报、央广网等三大官媒共同发声&#xff0c;为活跃资本市场、提振投资者信…

慢SQL调优第一弹——更新中

基础知识 Explain性能分析 通过explain我们可以获得以下信息&#xff1a; 表的读取顺序 数据读取操作的操作类型 哪些索引可以被使用 哪些索引真正被使用 表的直接引用 每张表的有多少行被优化器查询了 1&#xff09;ID字段说明 select查询的序列号&#xff0c;包含一组数…

Matlab之统计一维数组直方图 bin 计数函数histcounts

一、语法 [N,edges] histcounts(X) [N,edges] histcounts(X,nbins) [N,edges] histcounts(X,edges) 解释&#xff1a; 1.1 [N,edges] histcounts(X) 将 X 的值划分为多个 bin&#xff0c;并返回每个 bin 中的计数以及 bin 边界。histcounts 函数使用自动分 bin 算法&am…

Visual Studio编译出来的程序无法在其它电脑上运行

在其它电脑&#xff08;比如Windows Server 2012&#xff09;上运行Visual Studio编译出来的应用程序&#xff0c;结果报错&#xff1a;“无法启动此程序&#xff0c;因为计算机中丢失VCRUNTIME140.dll。尝试重新安装该程序以解决此问题。” 解决方法&#xff1a; 属性 -> …

python实例方法,类方法和静态方法区别

为python中的装饰器 实例方法 实例方法时直接定义在类中的函数&#xff0c;不需要任何修饰。只能通过类的实例化对象来调用。不能通过类名来调用。 类方法 类方法&#xff0c;是类中使用classmethod修饰的函数。类方法在定义的时候需要有表示类对象的参数(一般命名为cls&#…

春秋云镜 CVE-2019-12422

春秋云镜 CVE-2019-12422 Shiro < 1.4.2 cookie oracle padding漏洞 靶标介绍 Apache Shiro是美国阿帕奇&#xff08;Apache&#xff09;软件基金会的一套用于执行认证、授权、加密和会话管理的Java安全框架。 Apache Shiro 1.4.2之前版本中存在安全漏洞。当Apache Shiro使…

BM80 买卖股票的最好时机(一)

目录 1.题目描述 2.题目分析 3.编写代码 4.总结 这是牛客网上的一道题目 1.题目描述 题目链接&#xff1a;买卖股票的最好时机(一)_牛客题霸_牛客网 (nowcoder.com) 2.题目分析 我们看到这个题目中一个数组表示每一天的股价&#xff0c;那么最大利润怎么算呢&#xff0c…

《入门级-Cocos2dx4.0 塔防游戏开发》---第七课:游戏界面开发(自定义Layer)

目录 一、开发环境 二、开发内容 2.1 添加资源文件 2.2 游戏MenuLayer开发 2.3 GameLayer开发 三、演示效果 四、知识点 4.1 sprite、layer、scene区别 4.2 setAnchorPoint 一、开发环境 操作系统&#xff1a;UOS1060专业版本。 cocos2dx:版本4.0 环境搭建教程&…

【核磁共振成像】部分傅里叶重建

目录 一、部分傅里叶重建二、部分傅里叶重建算法2.1 填零2.2 零差处理 一、部分傅里叶重建 在部分傅里叶采集中&#xff0c;数据并不是绕K空间中心对称收集的&#xff0c;而是K空间的一半是完全填充的&#xff0c;另一半只收集了一小部分数据。   部分傅里叶采集所依据的原理…

bindService的调用流程

使用bindService去调用service&#xff0c;如果有多个客户端调用&#xff0c;onBind方法只会被调用一次&#xff0c;由于bindService嗲处理中&#xff0c;AMS是一个中间商&#xff0c;猜测这个处理也是AMS里进行的&#xff0c;这里我们再看看bindService的调用流程 public clas…

剑指 Offer 19. 正则表达式匹配(C++实现)

剑指 Offer 19. 正则表达式匹配https://leetcode.cn/problems/zheng-ze-biao-da-shi-pi-pei-lcof/ 动态规划&#xff1a;通过dp数组剪枝 只需要对各种情况进行分类处理即可 vector<vector<int>> dp;bool helper(const string& s, const int i, const string&am…

R语言常用数学函数

目录 1. - * / ^ 2.%/%和%% 3.ceiling,floor,round 4.signif,trunc,zapsamll 5.max,min,mean,pmax,pmin 6.range和sum 7.prod 8.cumsum,cumprod,cummax,cummin 9.sort 10. approx 11.approx fun 12.diff 13.sign 14.var和sd 15.median 16.IQR 17.ave 18.five…

YOLOv5、YOLOv8改进:NAMAttention注意力机制

目录 1.简介 2.YOLOv5代码修改 2.1增加以下NAMAttention.yaml文件 2.2common.py配置 2.3yolo.py配置 1.简介 paper:https://arxiv.org/pdf/2111.12419.pdf code:https://github.com/Christian-lyc/NAM 摘要 注意机制是近年来人们普遍关注的研究兴趣之一。它帮助…

day 28 地图

from pyecharts.charts import Map from pyecharts.options import VisualMapOpts# 创建一个地图对象 map Map() # 准备数据 data [("北京市", 99),("上海市", 199),("湖南省", 399),("广东省", 499) ] # 添加数据 map map.add(&qu…