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

Unity shader内置standard代码解析

最近有相关需求制作,所以这里编写一个文档,方便后续的流程查看。

下载源码

由于unity内置的shader是无法查看源码的,你需要去官网下载对应版本内置源码查看
在这里插入图片描述
在引擎下载那里,会有一个Built in Shaders,下载
在这里插入图片描述
打开以后,就是对应的shader
在这里插入图片描述
内置的shandard在DefaultResourcesExtra目录内,打开便是。

shader解析

Standard里面分了两套,一套正常的,一套精简版的,
在这里插入图片描述
这两套渲染的切换是通过设置shader的lod进行切换的。
每个shader下面由5个pass组成(简化版的不支持延迟渲染)

  1. 前向渲染主光源
  2. 前向渲染副光源
  3. 阴影渲染
  4. 延迟渲染
  5. 烘焙
    在这里插入图片描述

简化版本的渲染也不支持视差偏移,它们是通过宏去控制的,更多不同在渲染代码内部。

ForwardBase 和ForwardAdd引用的一套渲染逻辑,然后通过定义的宏和调用不同的顶点/片元着色器函数来区分到底是base还是add。

base的是这样在这里插入图片描述

add是这样
在这里插入图片描述
它们都引用的UnityStandardCoreForward渲染逻辑

在这里插入图片描述
在这个文件里面,是一些主要函数的定义,区分是否为简化的shader,如果简化的shader,则引入简化的库文件,非简化,则引入了UnityStandardCore.cginc,在这里定义了pass里面调用的顶点着色器和片元着色器函数,函数内直接调用了对应的UnityStandardCore库里的函数,这里也是standard的核心代码。
在这里插入图片描述
上面还引入了UnityStandardConfig.cginc,这个文件则是一些配置,主要定义的宏,抽几个比较重要的
下面定义了立体图贴图的曝光度以及lod层级数
在这里插入图片描述
定义brdf GGX
在这里插入图片描述

UnityStandardCore.cginc

里面代码的一些库的引用,核心库也是基于这些库实现的最终渲染
在这里插入图片描述
ForwardBase渲染主要就是调用了

VertexOutputForwardBase vertBase (VertexInput v) { return vertForwardBase(v); }
half4 fragBase (VertexOutputForwardBase i) : SV_Target { return fragForwardBaseInternal(i); }

VertexInput 就是在UnityStandardInput.cginc内实现的需要传入到顶点着色器的数据
VertexOutputForwardBase 则是从顶点传入到片元的数据
在这里插入图片描述
vertForwardBase 函数里对位置,UV,法向等做了一些处理,更复杂的还有lightmap的UV,还有视差偏移
在这里插入图片描述
重点函数,片元着色器fragForwardBaseInternal,有点代码越少越狠的节奏,后面我将一个个的函数解析
在这里插入图片描述

UNITY_APPLY_DITHER_CROSSFADE(i.pos.xy)

这个是为了实现淡入淡出的效果
在这里插入图片描述
unity_DitherMask 为unity内置生成的抖动noise贴图
unity_LODFade 为需要设置的变量,在UnityShaderVariables.cginc里面定义

float4 unity_LODFade; // x is the fade value ranging within [0,1]. y is x quantized into 16 levels

FRAGMENT_SETUP(s)

这个函数主要是生成后续使用的数据FragmentCommonData,定义为FragmentSetup函数

#define FRAGMENT_SETUP(x) FragmentCommonData x = FragmentSetup(i.tex, i.eyeVec.xyz, IN_VIEWDIR4PARALLAX(i), i.tangentToWorldAndPackedData, IN_WORLDPOS(i));

i.tex 顶点着色器计算的uv
i.eyeVec.xyz 摄像机朝向
IN_VIEWDIR4PARALLAX(i) 摄像机朝向基于视差偏移的法向值
i.tangentToWorldAndPackedData 切线坐标系转世界坐标系矩阵 [3x3:tangentToWorld | 1x3:viewDirForParallax or worldPos]
IN_WORLDPOS(i) 渲染目标世界坐标位置

FragmentCommonData 则是返回从顶点着色器拿到的数据处理后的数据,后续获取通过s变量获取。oneMinusReflectivity 为1-反射率
在这里插入图片描述
然后就是函数FragmentSetup,设置数据,截图里面我也加了注释
在这里插入图片描述
这里主要讲的是UNITY_SETUP_BRDF_INPUT函数,它可以根据工作流去设置数据,有三种 SpecularSetup RoughnessSetup MetallicSetup分别对应 高光工作流 粗糙度工作里 金属度工作流,standard.shader里面定义了金属度工作流
在这里插入图片描述
如果没有定义的话,会切换高光工作流
在这里插入图片描述
由于我这里使用的是金属度工作流,这里讲解一些金属度工作流的相关内容,MetallicSetup函数,函数内有两个函数,第一个函数去获取贴图的值,第二个函数为计算漫反射颜色,镜面反射颜色和反射率
在这里插入图片描述
MetallicGloss内返回二维向量,x为金属度,y为光滑度,光滑度还可以选择是使用的_MetallicGlossMap的a通道还是_MainTex的a通道
在这里插入图片描述
DiffuseAndSpecularFromMetallic
unity_ColorSpaceDielectricSpec的值在线性空间中默认是 half4(0.04, 0.04, 0.04, 1.0 - 0.04),这也是物理渲染中默认反射率
在这里插入图片描述
根据金属度求出反射率
在这里插入图片描述

MainLight

    UnityLight mainLight = MainLight(); //主光源UNITY_LIGHT_ATTENUATION(atten, i, s.posWorld); //合并阴影

UnityLight 结构里面有三个值 color 光的颜色 dir 光的朝向 ndotl 法向和光的点乘值(已弃用),MainLight函数里面就是获取第一盏灯的颜色和朝向
在这里插入图片描述
UNITY_LIGHT_ATTENUATION 计算阴影遮挡。会根据光的类型调用不同的函数,一般主光源都是平衡光,这里看一下平衡光的实现,代码在AutoLight.cginc里面
在这里插入图片描述
在AutoLight.cginc中,对多种情况的处理,比如屏幕空间阴影,包含烘焙阴影
在这里插入图片描述
这里我们看最简单的使用SHADOW_ATTENUATION生成的unitySampleShadow函数,这个函数会去获取shadowmap的值来做处理

#define UNITY_SAMPLE_SCREEN_SHADOW(tex, uv) UNITY_SAMPLE_TEX2DARRAY(tex, float3((uv).x / (uv).w, (uv).y / (uv).w, (float)unity_StereoEyeIndex)).r

在这里插入图片描述
这一块解析起来确实麻烦,如果你需要阴影的话,记得直接使用UNITY_LIGHT_ATTENUATION函数。第一个值就是阴影的值。

FragmentGI

全局光照,包含了lightmap,sh球谐光照,ibl等对物体影响的内容

UnityGI gi = FragmentGI(s, occlusion, i.ambientOrLightmapUV, atten, mainLight); //全局光照

UnityGI包含全局光照有光的数据,以及间接光的漫反射和镜面反射颜色
在这里插入图片描述
FragmentGI 函数主要是设置一些所需要的值,然后调用UnityGlobalIllumination生成最终所需的UnityGI数据
在这里插入图片描述
UnityGlossyEnvironmentSetup 主要是求出了两个值 SmoothnessToPerceptualRoughness是通过光滑度求出粗糙度,也就是1-光滑度,reflUVW,根据眼睛和法向求出反射方向
在这里插入图片描述
准备好需要的全局光照计算数据以后,就要开始调用UnityGlobalIllumination计算了,分别去计算间接光漫反射,以及间接光镜面反射
在这里插入图片描述
在间接光漫反射里面,考虑光照贴图和动态光照贴图,这个我在之前我的文章里面说过,这里就不再多解释。
在这里插入图片描述
解析一下,上图比较重要的几行代码:

o_gi.light.color *= data.atten;
o_gi.indirect.diffuse = ShadeSHPerPixel(normalWorld, data.ambient, data.worldPos);
o_gi.indirect.diffuse *= occlusion;

ShadeSHPerPixel 计算间接光漫反射,相对于lightmap里面获取的,它具有动态性。球谐光照是由七个四维向量组成,
在这里插入图片描述

由引擎设置参数。unity还兼容的3d纹理方式的SHEvalLinearL0L1_SampleProbeVolume
在这里插入图片描述
计算完成间接光漫反射以后,就是计算间接光镜面反射,在unity里面是通过,实现原理就是通过立方体贴图去拾取颜色作为镜面反射的颜色
在这里插入图片描述
里面主要的方法就是Unity_GlossyEnvironment,这个去拾取引擎设置的立方体贴图,并获取颜色
在这里插入图片描述
perceptualRoughnessToMipmapLevel就是粗糙度乘以LOD级数UNITY_SPECCUBE_LOD_STEPS,粗糙度越低,表示越光滑,那么lod层级就越低,图片拾取的也最清晰。
在这里插入图片描述
最后,将全局光的灯光颜色,间接光漫反射,间接光镜面反射计算完成,交给物理渲染BRDF函数实现最后的颜色。

UNITY_BRDF_PBS

half4 c = UNITY_BRDF_PBS(s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect); //基于物理的渲染

看代码,standard里面内置了三套方式,

  1. BRDF1_Unity_PBS 是基于物理的BRDF(Bidirectional Reflectance Distribution Function,双向反射分布函数)
  2. BRDF2_Unity_PBS 是基于极简的微表面理论的BRDF http://www.thetenthplanet.de/archives/255
  3. BRDF3_Unity_PBS 是不是微表面的基于修正归一化的 Blinn-Phong BRDF
    在这里插入图片描述
    这里,我只介绍质量最好的第一种BRDF1_Unity_PBS,看注释,也能了解到它的模型是如何计算的
    直接光漫反射 kD / pi
    直接光镜面反射 kS * (D * V * F) / 4
    最后乘以NdotL
    BRDF里面还有两种,一种是GGX的高光,另一种是老旧的BlinnPhong的
    在这里插入图片描述
    首先函数获取到需要用的数据,粗糙度,半角向量halfDir,NdotV,NdotL,NdotH,LdotV,LdotH
    在这里插入图片描述
    然后基于数据求直接光漫反射
    // Diffuse termhalf diffuseTerm = DisneyDiffuse(nv, nl, lh, perceptualRoughness) * nl;

求漫反射,还给注释迪士尼的漫反射必须除以PI,在函数外实现,貌似unity都亮了PI,所以不用除以PI了
在这里插入图片描述
然后解释了一下为什么不除以PI
在这里插入图片描述
接下来,先求出BRDF的D项和V项
在这里插入图片描述
然后在最后颜色合并的时候,求出菲涅尔项 F,怪不得之前听朋友说,unity的BRDF写的很难看,确实难看
在这里插入图片描述
最终计算出来了颜色加上自发光合并雾效,返回片元颜色
在这里插入图片描述

相关文章:

Unity shader内置standard代码解析

最近有相关需求制作,所以这里编写一个文档,方便后续的流程查看。 下载源码 由于unity内置的shader是无法查看源码的,你需要去官网下载对应版本内置源码查看 在引擎下载那里,会有一个Built in Shaders,下载 打开以后…...

Redis 有序集合操作实战(全)

目录 ZADD 加入有序集 ZCARD 取成员数量 ZCOUNT 计算区间成员数量 ZINCRBY 运算 ZRANGE 取区间成员(升序) ZRANGEBYSCORE 按分值排序取成员 ZRANK 取成员排名 ZREM 移除成员 ZREMRANGEBYRANK 按位置区间批量移除 ZREMRANGEBYSCORE 按分值区间移除 ZREVRANGE 取区间成…...

化工DCS/SIS/MIS系统时钟同步(NTP服务器)建设

化工DCS/SIS/MIS系统时钟同步(NTP服务器)建设 化工DCS/SIS/MIS系统时钟同步(NTP服务器)建设 目前计算机网络中各主机和服务器等网络设备的时间基本处于无序的状态。 随着计算机网络应用的不断涌现,计算机的时间同步问…...

计算机网络工程师多选题系列——操作系统

得多选者得天下啊同志们! 摘录按照章节顺序,但事实上各章节习题有交叉。 1 操作系统 1.1 操作系统概论 操作系统的主要功能:进程管理、存储管理、文件管理、设备管理和用户接口。 操作系统的主要功能——设备管理:为用户程序提…...

matlab读写json文件

Background 通常,在matlab中使用mat文件进行数据存储。MAT文件是MATLAB中用来存储数据的二进制文件格式。MAT文件可以包含各种数据类型,包括数字、矩阵、向量、结构体、字符和函数等。但是,当和其他语言有交互时,mat文件会不太方便…...

数据治理-数据仓库环境

数据仓库环境包括一系列组织起来以满足企业需求的架构组件,从源系统流动到数据暂存区,数据可以在这里被清晰,当数据集成并存储在数据仓库或操作数据存储中时,可以对其进行补充丰富。在数据仓库中,可以通过数据集市或数…...

DevOps与CI/CD常见面试问题汇总

01 您能告诉我们DevOps和Agile(敏捷)之间的根本区别吗? 答:尽管DevOps与敏捷方法(这是最流行的SDLC[Software Development Life Cycle]方法之一)有一些相似之处,但两者在软件开发方面都是根本不同的方法。以下是两者之…...

OJ练习第178题——收集树中金币

收集树中金币 力扣链接:2603. 收集树中金币 题目描述 给你一个 n 个节点的无向无根树,节点编号从 0 到 n - 1 。给你整数 n 和一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] [ai, bi] 表示树中节点 ai 和 bi 之间有一条边。再给…...

uni-app打包iOS ipa文件后不上架App store为用户提供下载解决过程记录

写在前面,itms-services协议是什么 itms-services协议是苹果提供的一种让iOS应用在用户设备上无线安装或升级的协议。 具体来说: itms-services表示iOS应用无线安装服务的URL方案,格式为:itms-services://?actiondownload-manifest&urlMANIFEST_URL其中MANIF…...

MySQL学习系列(2)-每天学习10个知识

目录 1. INNER JOIN 和 ON 子句2. 死锁3. SELECT * 和 SELECT column1, column24. 数据库的视图5. MySQL的触发器类型6. MySQL表的备份和恢复7. MySQL存储引擎8. 索引优化9. MySQL中的子查询10. 使用连接(JOIN)从多个表中检索数据 👍 点赞&am…...

黑马JVM总结(十四)

(1)分代回收_1 Java虚拟机都是结合前面几种算法,让他们协同工作,具体实现是虚拟机里面一个叫做分代的垃圾回收机制,把我们堆内存大的区域划分为两块新生代、老年代 新生代有划分为伊甸园、幸存区Form、幸存区To 为什…...

vue项目升级webpack

vue项目升级webpack 目录 1. vue项目中影响webpack版本的是什么 2.理解package.json中库前缀^和~区别 3.升级webpack4到5操作 1. vue项目中影响webpack版本的是什么 答案是:vue/cli-service版本 2.理解package.json中库前缀^和~区别 x.y.z x代表大版本&#xf…...

ubuntu的root用户修改密码失败

解决如下: 查看文件属性是否有a或i lsattr /etc/group /etc/passwd /etc/shadow 移除a和i的属性权限 chattr -ai /etc/group /etc/passwd /etc/shadow 再次使用passwd进行修改密码,就成功了...

C++---链表

1、链表 1.1、链表的结构 每个链表开头都有一个头指针Head尾节点的指针域为NULL,用于判断此列表是否结束 如果一个链表开始就为NULL,那么该链表为空链表 链表中的先后不代表在真实内存中的位置,只是单纯的逻辑上关系 1.2、创建链表 我们首…...

Unity使用Mirror制作局域网的同步

1.脚本布置.参考tank那个demo制作 1.新建空物体,为管理脚本的物体:manager,挂载NetworkManager,kcpTransport,NetworkManagerHud. 2.设置玩家出生点,spawnPoint,设置好初始化的position的位置(*),挂载NetworkStartPosition的脚本 3.新建Player的预制体,挂载NetworkIdentity,Ne…...

算法 N皇后问题-(递归回溯)

牛客网 BM59. 解题思路: 行列、斜叉不在一条直线上。 命令行为 row, 列为col, row 从0开始递归直到最后一行,列从0开始遍历,直到最后一列,中间每一步记录或清除位置状态,状态分为 m1[col] 1, m2[row-col] 1, m3[r…...

个人博客搭建记录

个人博客地址:www.jiasun.top 使用github pagehexo搭建,主题为fluid,搭建步骤参照:Github hexo 实现自己的个人博客、配置主题(超详细) 主题:https://hexo.fluid-dev.com/ 搭建时的问题&…...

下载vscode 更新

将下载地址的主地址加入一下镜像网址 http://vscode.cdn.azure.cn下面是访问页面 http://vscode.cdn.azure.cn/stable/abd2f3db4bdb28f9e95536dfa84d8479f1eb312d/VSCodeUserSetup-x64-1.82.2.exe...

std::async简单使用

std::async介绍并使用 std::async是C11引入的一个用于异步执行函数或函数对象的工具。它可以用于并行地执行函数&#xff0c;并在需要时获取函数的返回值。下面是一个简单的示例&#xff0c;演示了如何使用std::async&#xff1a; #include <iostream> #include <fu…...

【编程实践】在VS studio中配置Eigen库

1 介绍 Eigen库是C标准模板库&#xff0c;能够进行向量运算、矩阵运算、矢量运算、数值分析等操作&#xff0c;并且包含相应的运算算法。 Eigen官方地址: 地址 可在官网下载指定版本的压缩包&#xff0c;将压缩包解压至后面配置的“附件包含目录”中。 2 配置 2.1 VS studi…...

SQLite 3.43 发布,性能大提升!

前言 SQLite是一种被广泛运用的嵌入式关系型数据库管理系统&#xff0c;最新发布的SQLite 3.43版本带来了一个重要的改进&#xff0c;大幅提升了对JSON数据的处理性能&#xff0c;达到了之前的两倍。 主要更新 添加对 Contentless-Delete FTS5 索引的支持。这是 FTS5 全文搜索…...

数据中心液冷服务器详情说明

目录 前言 何为液冷服务器&#xff1f; 为什么需要液冷&#xff1f; 1.数据中心降低PUE的需求 2.政策导向 3.芯片热功率已经达到风冷散热极限 4.液冷比热远大于空气 液冷VS风冷&#xff0c;区别在哪&#xff1f; 1.液冷服务器跟风冷服务器的区别 2.液冷数据中心跟风冷…...

Openresty(二十二)ngx.balance和balance_by_lua终结篇

一 灰度发布铺垫 ① init_by_lua* init_by_lua init_by_lua_block 特点: 在openresty start、reload、restart时执行,属于master init 阶段机制&#xff1a; nginx master 主进程加载配置文件时&#xff0c;运行全局Lua VM级别上的参数指定的Lua代码场景&#xff1a; …...

Docker注入环境变量且设置多个环境变量

方式一 运行docker命令修改 在运行docker时&#xff0c;直接使用-e或–env&#xff0c;输入需要改变的变量 例如&#xff1a;springboot配置文件如下,可注入环境变量启动端口SERVER_PORT&#xff0c;以及启动配置文件NODE_ENV:dev server:port: ${SERVER_PORT:8400} spring…...

代码随想录二刷Day 15

102. Binary Tree Level Order Traversal vector<int>() it is basically constructor of std::vector class and will create a new empty vector. You can also mention the size of required vector in brackets. 访问二维vector的元素: 如果指定外层和内层向量的大…...

Node.js环境安装与服务设置,结合内网穿透随时随地公网访问!

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 前言 Node.js 是能够在服务器端运行 JavaScript 的开放源代码、跨平台运行环境。Node.js 由 OpenJS Foundation&#xff0…...

八、数据类型转换

数据类型转换 1.数据类型转换1.1.隐式类型转换1.2.显式类型转换1.3.训练11.4.训练2 —————————————————————————————————————————————————— 1.数据类型转换 类型转换是将一个值从一种类型更改为另一种类型的过程。例如&…...

2023数学建模研赛华为杯E题思路-出血性脑卒中临床智能诊疗建模

E 题 出血性脑卒中临床智能诊疗建模 三、请建模回答如下问题 1血肿扩张风险相关因素探索建模。 a)请根据“表1”&#xff08;字段&#xff1a;入院首次影像检查流水号&#xff0c;发病到首次影像检查时间间隔&#xff09;&#xff0c;“表2”&#xff08;字段&#xff1a;各时…...

Windows Server 2012 R2系统远程桌面的数字证书算法SHA1升级到SHA256

问题描述&#xff1a; 最近项目进行密评的时候&#xff0c;Windows Server 2012 R2发现了以下证书问题&#xff1a; Windows Server 2012 R2系统远程桌面的TLS 1.2协议使用SHA1算法数字证书&#xff0c;且证书有效日期截止23年10月&#xff0c;建议注意证书到期时间&#xff…...

windows进程管理相关命令

windows进程管理相关命令 根据进程名找到进程 例如python进程 PS C:\Users\27467> tasklist | findstr python python.exe 7088 Console 2 3,364 K python.exe 1580 Console 2 41,…...

石家庄网站建设公司哪个好/链接购买平台

前言 TCP&#xff08;Transmisson Control Protocol&#xff09;又叫传输控制协议作为传输层最重要的协议&#xff0c;对于信息的可靠传输有着重要的意义&#xff0c;针对这一协议的攻击也数不胜数&#xff0c;这里就对这一协议以及相关内容进行详细的总结&#xff0c;将从以下…...

给女朋友做网站的素材/常德网站建设公司

MyBatis&#xff1a;ResultMap详解 一、前言                               MyBatis是基于“数据库结构不可控”的思想建立的&#xff0c;也就是我们希望数据库遵循第三范式或BCNF&#xff0c;但实际事与愿违&#xff0c;那么结果集映射就是My…...

怎么做淘宝企业网站/婚恋网站排名前十名

&、|是操作数运算符&#xff0c;在if条件中不会造成短路&#xff1b;&运算布尔值时&#xff0c;只要有一个为false结果就为false&#xff0c;|运算布尔值时&#xff0c;只要有一个为true结果就为true。 &&、||是逻辑运算符&#xff0c;在if条件中会造成短路。…...

如何使用ftp上传网站/搜索引擎快速优化排名

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 TODO:写完再整理 文章目录系列文章目录前言一、简介二、电机执行器类型1.力控电动电机执行器2.液压执行机构3.系列弹性执行机构三、执行电机设计1.模块化2.电控性能要求3…...

男女做爰全过程网站/搜索引擎推广和优化方案

搭建LNMP网站平台实战 LNMP是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写。L指Linux&#xff0c;N指Nginx&#xff0c;M一般指MySQL&#xff0c;也可以指MariaDB&#xff0c;P一般指PHP&#xff0c;也可以指Perl或Python。 1、自定义网络 docker netw…...

广告平面设计基础知识/嘉兴seo优化

Vue——插槽 一、插槽的基本使用 插槽的作用&#xff1a; Vue插槽是Vue中常见的一种组件间的相互通信方式&#xff0c;作用是让父组件可以向子组件指定位置插入html结构&#xff0c;适用于父组件>子组件&#xff0c;在要接收数据的组件页面通过<slot>标签来表示&am…...