当前位置: 首页 > news >正文

#pragma multi_compile #pragma shader_feature

参考网址:
https://docs.unity3d.com/Manual/SL-MultipleProgramVariants.html
https://blog.csdn.net/candycat1992/article/details/51417965
http://blog.songyang.net/379.html
https://gameinstitute.qq.com/community/detail/121999

making multiple shader program variants
often it is convenient to keep most of a piece of shader code fixed but also allow slightly different shader “variants” to be produced. this is commonly called “mega shaders” or “ubder shaders”, and is achieved by compiling the shader code multiple times with different preprocessor directives for each case.
to achieve this in unity, u can add a #pragma multi_compile or #pragma shader_feature directive to a shader snippet. this also works in surface shaders.

at run time, unity picks up the appropriate variant from the material keywords (Material.EnableKeyword and Material.DisbaleKeyword) or global shader keywords (Shader.EnableKeyword and Shader.DisableKeyword).

how multi_compile_works

example directive:

#pragma multi_compile FANCY_STUFF_OFF FANCY_STUFF_ON

this example directive produces two shader variants : one with FANCY_STUFF_OFF , and another with FANCY_STUFF_ON. at run time, unity activates one of them based on the material or global shader keywords. if neither of these keywords are enabled, then unity uses the first one (in this example, FANCY_STUFF_OFF).

u can add more than two keywords on a multi_compile line, for example:
#pragma multi_compile SIMPLE_SHADING BETTER_SHADING GOOD_SHADING BEST_SHADING

this example directive produces four shader varients: SIMPLE_SHADING, BETTER_SHADING,GOOD_SHADING, and BEST_SHADING.

to produce a shader variant with no preprocessor macro define, add a name that is just underscores (__). 两个下划线. this is common technique to avoid using up two keywords,这个技术可以避免使用两个关键字。because there is a limit on how many u can use in a project (see later section on keyword limits). for example:

#pragma multi_compile __ FOO_ON

this directive produces two shader variants: one with nothing defined(__), and one with FOO_ON defined.

difference between shader_feature and multi_compile
shader_feature is very similar to multi_compile. the only difference is that unity does not include unused variants of shader_feature in the build. for this reason, u should use shader_feature for keywords that are set from the materials, while multi_compile is better for keywords that are set from code globally.

additionally, there is shorthand notation with just one keyword:

#pragma shader_feature FANCY_STUFF

which is just shortcut for #pragma shader_feature __ FANCY_STUFF. it expands into two shader variants(first one without the define; second one with it).

combing several multi_compile lines
if u provide multi_compile lines, unity compiles the resulting shader for all possible combinations of the lines, for example:

#pragma multi_compile A B C
#pragma multi_compile D E

this produces three variants for the first line, and two for the second line. in total, it produces total six shader variants (A+D, A+E, B+D, B+E, C+D, C+E).

think of each multi_compile lines as controlling a single shader “feature”. keep in mind that the total number of shader variants grows really fast this way. for example ten multi_compile features, each with two options, produces 1024 shader variants in total.

keyword limits
when using shader variants, there is limit of 256 keywords in unity, and unity uses around 60 of them internally (therefore lowering the available limit). the keywords are enabled globally across a unity project, so be careful not to exceed the limit when u define multiple keywords in several different shaders.

一个项目的总的关键字的数量不能超过256个。

local keywords the main disadvantage of shader_feature and multi_compile is that all keywords defined in them contribute towards unity’s global keyword count limit 256 global keywords, plust 64 local keywords. to avoid this issue, u an use different shader variant directives: shader_feature_local and multi_compile_local.

shader_feature_local: similar to shader_feature, but enumerated keywords are local.
multi_compile_local: similar to multi_compile, but enumerated keywords are local.

local directives keep defined keywords under them specific to that shader, rather than applying them to the whole project. for this reason, u should use local keywords instead of global keywords. unless u are planning to enable those particular keywords through the global api.

u might see a change in performance when u start using local keywords, but the difference depends on how your projects is set up. the total number of local and global keywords per shader affects performance: in an idea set-up, use more local keywords and fewer global keywords, to reduce the total keyword count per shader. 多用局部关键字,减少全局关键字,可以提高性能。

if there are global and local keywords with the same name, unity priorities the local keyword.

limitations:
u can not use local keywords with APIs that make global keyword changes (such as Shader.EnableKeyword or CommandBuffer.EnableShaderKeyword).
there is a maximum of 64 unique local keywords per shader.
if a material has a local keyword enabled, and its shader changes to one that is no longer declared, unity creates a new global keyword.

example

#pragma multi_compile_local __ FOO_ON

this directive produces two shader variants: one with nothing defined (__), and one with FOO_ON defined as a local keyword.

the process for enabling local keywords is the same as enabling global keywords:

public Material mat;
private void Start()
{
	mat.EnableKeyword("FOO_ON");
}

built-in multi_compile shortcuts

there are several “shortcut” notations for compiling multiple shader variants. these are mostly to deal with different light, shadow and lightmap types in unity. see documentation on the rendering.pipeline for details.

multi_compile_fwdbase compiles all variants needed by PassType.ForwardBase. the variants deal with different lightmap types, and the main directional light’s shadows being enabled or disabled.

multi_compile_fwdadd compiles variants for PassType.ForwardAdd. this compiles variants to handle directional, spot or point light types and their variants with cookie textures.

multi_compile_fwdadd_fullshadows, same as multi_compile_fwdadd, but also includes ability for the lights to have real-time shadows.

multi_compile_fog expands to several variants to handle different fog types (off/linear/exp/exp2).

举例:

Shader "MyShader/TestFeature"
{
	SubShader
	{
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#pragma shader_feature AA

			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
			};

			struct v2f
			{
				float4 vertex : SV_POSITION;
			};


			v2f vert(appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				return o;
			}

			fixed4 frag(v2f i) : SV_Target
			{
				fixed4 col = fixed4(0,0,0,0);
				#ifdef AA
					col = fixed4(1, 0, 0, 1);
				#else
					col = fixed4(1, 1, 0, 1);
				#endif
					return col;
			}
			ENDCG
		}
	}
}

这里使用的是shader_feature 关键字,我们看看在未运行的时候,为我们编译出了几个变体:
在这里插入图片描述

只有一个空的,AA被忽略,因为未运行的时候AA没有被使用。

我们写个测试代码:

 public MeshRenderer meshRender;
 void Start()
  {
      meshRender = this.GetComponent<MeshRenderer>();
      Material mat = meshRender.material;
      mat.EnableKeyword("AA");
  }

运行后:
在这里插入图片描述

unity生成了两个变体。

ok如果我们改为:

#pragma multi_compile AA

这里没有生成一个啥都没有的__
我们看看未运行的时候:
在这里插入图片描述

可以看到untiy不管你运行还是未运行:keywords always included into build。
生成一个AA变体。

如果运行了,还是一个变体:
那么怎么使用multi_compile也生成一个空的变体呢?直接写为:
在这里插入图片描述

所以总结:
shader_feature会将那些没有用到的变体忽略掉,而且是在未运行的时候忽略,如果运行的时候通过 EnableKeyword的形式打开了关键字,unity还是会生成对应关键字变体的。
shader_compile,正如名字一样在compile阶段就生成了和关键字数量对应的变体。

我们可以可以理解为shader_feature为动态链接库,而multi_compile为静态链接库,后者一次全部编译出来多个变体。前者是运行的时候决定编译哪个变体。

相关文章:

  • 全局光照
  • Springboot学习之–将springboot注册为windows系统服务(转)
  • django xadmin 安装和使用
  • Linux-Vim基本操作
  • unity手动创建网格
  • hibernate一级缓存session的操作
  • baked lighting
  • 201902142017_《Node.js之事件一二事(1)》
  • machine_math
  • baked light+bake indirect+sampling lightmap
  • linux基础随记
  • 随手练——十六进制转八进制 (不限制长度)
  • 认识DiffuseAndSpecularFromMetallic和UNITY_BRDF_PBS
  • 如何将自发光和漫反射添加到烘焙贴图中
  • Qt+QGIS二次开发:QGIS中使用QgsRubberBand类创建临时图形
  • 《Java8实战》-第四章读书笔记(引入流Stream)
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • conda常用的命令
  • Cookie 在前端中的实践
  • C语言笔记(第一章:C语言编程)
  • ES6系列(二)变量的解构赋值
  • FineReport中如何实现自动滚屏效果
  • Java 网络编程(2):UDP 的使用
  • MYSQL 的 IF 函数
  • Ruby 2.x 源代码分析:扩展 概述
  • Windows Containers 大冒险: 容器网络
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 前端性能优化--懒加载和预加载
  • 树莓派 - 使用须知
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 一道面试题引发的“血案”
  • 做一名精致的JavaScripter 01:JavaScript简介
  • Java总结 - String - 这篇请使劲喷我
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • ![CDATA[ ]] 是什么东东
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (二)fiber的基本认识
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (转)程序员技术练级攻略
  • (转载)hibernate缓存
  • (轉貼) 2008 Altera 亞洲創新大賽 台灣學生成果傲視全球 [照片花絮] (SOC) (News)
  • ***测试-HTTP方法
  • .bat批处理(八):各种形式的变量%0、%i、%%i、var、%var%、!var!的含义和区别
  • .NET HttpWebRequest、WebClient、HttpClient
  • .net中我喜欢的两种验证码
  • /etc/shadow字段详解
  • /run/containerd/containerd.sock connect: connection refused
  • [ vulhub漏洞复现篇 ] GhostScript 沙箱绕过(任意命令执行)漏洞CVE-2019-6116
  • [Android]使用Android打包Unity工程
  • [AUTOSAR][诊断管理][ECU][$37] 请求退出传输。终止数据传输的(上传/下载)
  • [BZOJ1178][Apio2009]CONVENTION会议中心
  • [C#7] 1.Tuples(元组)