EZ² - Unity
type: channel
link: http://erinz.xyz/index.php/tag/Unity/
items: 💡 学点儿丨URP Shader编辑指北[2] - Unlit Shader详细拆解
items: 💡 学点儿丨URP Shader编辑指北[1] - URP Shader Structure
items: 💡学点儿丨关于纹理的亿点点补课1 - 纹理压缩
items: 🔍TOOL丨批处理1.0：Maskmap&FixSettings&Resize👌
items: 🔍TOOL丨写个工具，让自己像个TA - 一键生成maskmap
items: 🌿 | 风吹草低低低低 - 植被动画Ⅰ:顶点色实现
items: 💡学点儿丨预览场景与镜头搭建
items: 💡学点儿丨角色工作流杂谈
items: 💡学点儿丨临阵磨枪PBR！
items: ODOS丨ShaderToy 2 ShaderLab

💡 学点儿丨URP Shader编辑指北[2] - Unlit Shader详细拆解
type: item
date: 2022-05-31T17:08:00+08:00
description: 靠北，这篇写了超级长结果被草稿覆盖了.....我是真的很emo😇😇😇😇😇 就极精简地复述一遍....好难过😭😭 文件结构 URP管线的Shader都位于Packages/Universal RP/Shaders目录，是Shader的主要框架和相关的Pass。通用的渲染方法函数一般位于Packages/Universal RP/Shaders Library目录，这是一个为SRP提供的函数包，可以为我们省去许多重复性的工作。另外涉及到Material面板的文件位于Packages/Universal RP/Editor/Shader GUI. 本文代码块的第一行表示代码所在的目录位置，就不多重复了~ 有关拓展阅读：[URP]内置shader解析笔记_1 Properties [Universal RP/Shaders/Unlit.shader] Properties { [MainTexture] _BaseMap("Texture", 2D) = "white" {} [MainColor] _BaseColor("Color", Color) = (1, 1, 1, 1) _Cutoff("AlphaCutout", Range(0.0, 1.0)) = 0.5 // BlendMode _Surface("__surface", Float) = 0.0 _Blend("__mode", Float) = 0.0 _Cull("__cull", Float) = 2.0 [ToggleUI] _AlphaClip("__clip", Float) = 0.0 [HideInInspector] _BlendOp("__blendop", Float) = 0.0 [HideInInspector] _SrcBlend("__src", Float) = 1.0 [HideInInspector] _DstBlend("__dst", Float) = 0.0 [HideInInspector] _ZWrite("__zw", Float) = 1.0 // Editmode props _QueueOffset("Queue offset", Float) = 0.0 // ObsoleteProperties [HideInInspector] _MainTex("BaseMap", 2D) = "white" {} [HideInInspector] _Color("Base Color", Color) = (0.5, 0.5, 0.5, 1) [HideInInspector] _SampleGI("SampleGI", float) = 0.0 // needed from bakedlit } URP的Shader都使用了Custom Editor，可以看出Properties的声明和面板样式并不相同。其具体样式可见最后一行的索引： [Universal RP/Shaders/Unlit.shader] CustomEditor "UnityEditor.Rendering.Universal.ShaderGUI.UnlitShader" 这个文件位于Universal RP/Editor/ShaderGUI/Shaders，UnityEditor.Rendering.Universal.ShaderGUI是它所在的命名空间。这些脚本文件都继承于BaseShaderGUI类。在BaseShaderGUI中，定义了有关属性的面板和更新关键字的方法。 ShaderGUI BaseShaderGUI继承于ShaderGUI，需要使用UnityEditor命名空间。 它包含了六个代码块： EnumsAndClasses 在这个代码块中，定义了各个选项有关的枚举量，例如SurfaceType,BlendMode等。并定义了一个类Styles。 在Styles中，包含了以static readonly stings[]的形式记录了上述的枚举关键字，和以static readonly GUIContent的方式记录了GUI文本和鼠标悬停时的提示信息。例如： [Universal RP/Editor/ShaderGUI/BaseShaderGUI.cs] public static readonly GUIContent SurfaceOptions = EditorGUIUtility.TrTextContent("Surface Options", "Controls how URP Renders the material on screen."); Variables 这个代码块主要是对变量的声明。 首先是一个Mate…

💡 学点儿丨URP Shader编辑指北[1] - URP Shader Structure
type: item
date: 2022-05-27T17:11:00+08:00
description: 说来惭愧，最近也做了不少把built-in shader转URP/HDRP的工作...但一直在很没出息地用Shader Graph.....趁这几天闲，好好掰扯掰扯URP和HDRP的Shader区别。 本篇引擎版本为Unity 2021.3.3f1c1 Universal RP 12.1.6 从Built-In到URP PASS可用差别 之前Built-in管线写前向渲染时，使用一个pass计算主光，再用多个其他pass叠加光照。但URP中不支持多个渲染Pass。 URP提供的几个默认Shader中包含多个Pass，但是只能有一个渲染Pass： 渲染Pass "LightMode" = "UniversalForward" 输出到帧缓存，只能有一个 投影Pass "LightMode" = "ShadowCaster" 深度Pass "LightMode" = "DepthOnly" 其他Pass 专门用于烘焙的Pass，专门用于2D渲染的Pass等 通过Render Feature可以实现之前多Pass的描边等效果。 为了使URP认识并能渲染所需的pass，要记得在SubShader中加上tag： "RenderPipeline"="UniversalPipeline" CG to HLSL URP和HDRP都使用了HLSL，包含Shader语言的代码块要改为： HLSLPROGRAME ... ENDHLSL 头文件变化 包含的头文件也需要从"UnityCG.cginc"改为 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" Lighting相关的头文件为 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" 对应的一些函数名称也会有变化。 CBUFFER 为使用SRP Batcher，所有贴图外的暴露参数需要用CBUFFER_START(UnityPerMaterial)与CBUFFER_END包裹，并置于Pass之前。 CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; float _Color; CBUFFER_END Basic Shader Structure 以下是一个可以有URP编译的基础Shader： // This shader fills the mesh shape with a color predefined in the code. Shader "Example/URPUnlitShaderBasic" { // The properties block of the Unity shader. In this example this block is empty // because the output color is predefined in the fragment shader code. Properties { } // The SubShader block containing the Shader code. SubShader { // SubShader Tags define when and under which conditions a SubShader block or // a pass is executed. Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" } Pass { // The HLSL code block. Unity SRP uses the HLSL language. HLSLPROGRAM // This line defines the name of the vertex shader. #pragma vertex vert // This line defines the name of the fragment shader. #pragma fragment frag // The Core.hlsl file contains definitions of frequently used HLSL // macros and functions, and also contains #include references to other // HLSL files (for example, Common.hlsl, SpaceTransfor…

💡学点儿丨关于纹理的亿点点补课1 - 纹理压缩
type: item
date: 2022-04-29T09:36:00+08:00
description: 之前写插件的时候，写入纹理时发现与原图的压缩格式不同，做设计课前再来摸会儿🐟补补课。 纹理导入 文件格式 文件格式是图像为了存储信息而使用的对信息的特殊编码方式，它存储在磁盘中，或者内存中，但是并不能被GPU所识别，因为以向量计算见长的GPU对于这些复杂的计算无能为力。 Unity 支持读取以下文件格式 BMP，EXR，GIF，HDR，IFF，JPG，PICT，PNG，PSD，TGA，TIFF Unity 可导入多层PSD文件，导入时自动展平，但图层在资源本身中维护。 这些文件格式当被游戏读入后，还是需要经过CPU解压成R5G6B5，A4R4G4B4，A1R5G5B5，R8G8B8, A8R8G8B8等像素格式，再传送到GPU端进行使用。 纹理尺寸大小 理想情况下，纹理尺寸大小应该是每边为2的整数次幂。Unity 允许使用NOPT（非2的幂）纹理大小；但是，NPOT纹理大小通常需要多一点内存，并且GPU的采样速度可能更慢。 如果平台或GPU不支持NPOT纹理带下，Unity会对纹理进行缩放和填充已达到下一个2的幂的大小。纹理导入后可将Advanced选项选择Not Power of 2，在导入时放大NPOT纹理资源。 纹理压缩 在解释一切之前，先划重点： PC 不带透明通道压缩成DXT1，带透明通道压缩为ETC5，不被4整除的回退到RGBA32 Android 不带透明通道压缩成ETC1，带透明通道压缩成ETC2，不被4整除的回退到RGBA32 IOS 不带透明通道压缩成RGB PVRTC，带透明通道压缩成RGBA PVRTC ，不是2的整数次幂回退到RGBA32 Texture图片拖入的时候，如下图所示; unity会默认设置ToNerest，这样会自动保证Android平台下图片被4整除，IOS平台下图片是2的整除次幂，所以默认情况下图片都可以得到最好的压缩。 BPP 每像素位数 (bpp) 表示单个纹理像素所需的存储量。较低的 bpp 值也意味着 GPU 使用较少的内存带宽来读取纹理像素。GPU 内存带宽通常是帧率的瓶颈，因此纹理压缩有助于避免这一问题。 未压缩纹理 Format BPP 1024*1024(Mb) A8R8G8B8(ARGB32) 32 4 A4R4B4G4(ARGB16) 16 2 R8G8B8(RGB24) 24 3 disk, 4 GPU R5G6B5(RGB16) 16 2 压缩纹理 Format BPP 1024*1024(Mb) RGB Compressed DXT1 4 0.5 RGB Compressed ETC2 4 0.5 RGBA Compressed ETC2 8 1 RGB Compressed PVRTC 4 bits 4 0.5 RGB Compressed PVRTC 2 bits 2 0.25 纹理资源的视觉质量越高，每像素的位数就越高；因此，这会增大构建大小、加载时间和运行时内存使用。在某种程度上，所有纹理压缩格式都是有损的。通常，为了获得最佳运行时性能和磁盘占用空间，对于大多数纹理资源，应该选择目标设备支持的纹理压缩格式，并且实现所需的视觉质量的最小每像素位数。 不同于png、jgp这种硬盘压缩方式而言，DXT,ETC等纹理压缩方式可以在游戏运行中无需CPU解压就被GPU直接采样，可以极大的减少内存和带宽的占用，提升运行效率。 DXT压缩 DXT是一种有损纹理压缩算法，微软的DirectX中支持，DXT的格式包括DXT1~DXT5，其中DXT1和DXT5较为多见，可以认为所有的PC端显卡都支持DXT压缩,是PC下的标准压缩格式。 DXT压缩要求像素长宽必须是4的倍数。另外RGB的24位转为了16位颜色，16位中R&B各占5位，但是G占了6位，这是因为人眼对绿色最为敏感。 DXT1 DXT1格式主要适用于不具透明度的贴图或仅具一位Alpha的贴图（非完全透明则即完全不透明），对于完全RGB565格式的贴图，DXT1具有4：1的压缩比，即平均每个像素颜色占4位. DXT1将每4×4个像素块视为一个压缩单位，压缩后的4×4个像素块占用64位，其中有2个16位的RGB颜色和16个2位索引. DXT5 DXT5要比DXT1大一倍，对alpha通道的储存作了改进，它依旧用64bit储存16个alpha信息。前面2个字节（16bit）保存了当前块的最大alpha值和最小alpha值。接下来的48 bit，每个像素占用3bit空间，刚好描述 4x4个像素。 当alpha_0大于alpha_1 时，我们后面的3bit可以表示8级的插值；反之则保留110和111分别表示alpha为0和255的情况,中间可以有 6 级过度的插值。 DXT并没有在移动端得到很大的支持，在iOS设备中支持的…

🔍TOOL丨批处理1.0：Maskmap&FixSettings&Resize👌
type: item
date: 2022-04-28T14:06:00+08:00
description: 前两天写了一个手动拖入通道来生成maskmap的工具： 在这个的基础上又研究了一下，实现了对于文件夹目录的一键maskmap生成！还做了一键修正贴图导入设置的功能。 留个小尾巴，等有空了可以再写一个自动生成对应的hdrp材质并贴图。不过不清楚第三方资源库的材质和模型的关系..可能还需要从prefab中extract....算了！再说！ 更新下载地址👉TextureTool👈 资产相关类 有关Unity内的资源文件，有这样几个比较关键的类： AssetDatabase UnityEditor : An Interface for accessing assets and performing operations on assets. AssetDatabase是对资产操作的主要接口，可以复制、删除、查询创建文件或文件夹。 e.g. 获取资产路径： string path = AssetDatabase.GetAssetPath(metallic) ; 查找资产： var texture2Ds = AssetDatabase.FindAssets ("t:Texture2D", paths); 第一个字符串是filter，可以使用name/label("l:")/type("t:")检索。其返回值是资产string形式的GUID，需要使用AssetDatabase.GUIDToAssetPath获得其路径，然后使用AssetDatabase.LoadAssetAtPath加载资产。 刷新资源列表 AssetDatabase.Refresh(); 上一篇中，创建材质的方式是直接在对应路径写入文件，所以需要刷新并导入材质，让引擎识别新加入的文件。 AssetImporter UnityEditor ：Base class from which asset importers for specific asset types derive. AssetImporter感觉是记录引擎识别资产的方式，可能与.meta文件相关？ e.g. 利用userData防止重复编辑 var im = AssetImporter.GetAtPath (path); if (im.userData.Contains ("R2;")) continue; im.userData += "R2;"; 转成对应类型的Importer(如TextureImporter),可对其进行详细设置的修改。 对于材质而言，常用的可以设置Texturetype(转normal)，Tetureshapr(转cube)，sRGBTexture等。 （靠 这不写个材质一键检查非srgb？) （写了写了） DirectoryInfo System.IO : Exposes instance methods for creating, moving, and enumerating through directories and subdirectories. This class cannot be inherited. 有关路径的操作，不只限于Editor。 e.g. 查询路径是否存在 // Check if the target directory exists, if not, create it. if (Directory.Exists(target.FullName) == false) { Directory.CreateDirectory(target.FullName); } 获得文件夹中文件的info [FileSystemInfo][12][] fileSystemInfos = directoryInfo.GetFileSystemInfos(); 获取路径和资产 如果已经有某个资产，需要获得它的路径，可以使用AssetDatabase.GetAssetPath()方法，比如上一篇用到的： string path = AssetDatabase.GetAssetPath(metallic); 或者可以让用户选择要操作的文件夹路径： private void SelectFolderPath() { GUILayout.BeginHorizontal(); { FolderPath = EditorGUILayout.TextField("Textures Folder", FolderPath); if (GUILayout.Button("...", GUILayout.Width(25))) { FolderPath = EditorUtility.OpenFolderPanel("Select a folder", "Assets", ""); } E…

🔍TOOL丨写个工具，让自己像个TA - 一键生成maskmap
type: item
date: 2022-04-25T19:49:00+08:00
description: 写在前面 实习以来帮hdrp改了不少资产，每次进ps做maskmap真的好麻烦，试试写个脚本工具来完成这个工作。 它可以—— 点击下载👉MapCreator👈 （下一个目标：批处理！） Unity Editor Window 先放一个完整的代码（Rider的高亮 好爱）： 首先创建一个工具窗口。新建脚本，编辑器窗口继承自EditorWindow类，需要使用UnityEditor命名空间。 using UnityEngine; using UnityEditor; public class ExampleWindow : EditorWindow{ MenuItem可以在菜单栏创建选项。 GetWindow方法可以打开窗口/聚焦到已打开的该窗口，的类型应为所定义的窗口类。 [MenuItem("Window/Tools/Example")] public static void ShowWindow() { GetWindow<ExampleWindow>("Example"); } GetWindow可选参数包括Utility和Title，对于窗口的类型和标题。标题也可以直接赋值窗口类的titleContent.text属性。 UI元素一般属于GUILayout和EditorGUILayout两个类。有一些功能是重复的，不过都可以一样用~ void OnGUI() { //WindowCode GUILayout.Label("A Lable.");//or EditorGUILayout.LabelField("Also A LableField"); GUILayout.Button("A Button"); GUILayout.Toggle(aBool,"A Toggle"); //or EditorGUILayout.Toggle("Also A Toggle",anotherBool); EditorGUILayout.TextField("A TextField"); EditorGUILayout.ColorField("A ColorField", aColor); EditorGUILayout.CurveField("A CurveField", aCurve); EditorGUILayout.Slider(value, 0.0f, 1.0f); } 更详细的内容可以参考： Get to work 工具的框架设计如图： 接下来就一步一步解释一下这个工具都做了啥—— 首先声明我们需要的变量： using System; using System.IO; using UnityEditor; using UnityEngine; public class MapCreator : EditorWindow { private Material mat; private int maptype = 0,_maptype; private string[] maptypes = new string[] {"Mask Map", "Detail Map", "Custom"}; private Texture2D metallic, occlusion, detailmask, smoothness, deAbedo, deNormal, deSmoothness; private bool useRoughness; //用以记录输入是否更新 private bool changed; private Texture2D _metallic, _occlusion, _detailmask, _smoothness, _deAbedo, _deNormal, _deSmoothness; private bool _useRoughness; 我们希望每更换一张贴图时，preview都会刷新，所以设置了一组同名参数以记录参数是否变化。 //创建菜单栏 [MenuItem("Window/Tools/MapCreator")] //创建窗口 static void OpenMapCreator() { MapCreator mapCreator = GetWindow<MapCreator>("Map Creator"); mapCreator.Init(); } //初始化材质 private void Init() { if (mat == null) { mat = new Material(Shader.Find("Hidden/MapCreator"));//create material mat.hideFlags = HideFlags.HideAndDontSave; } } //窗口界面 pub…

🌿 | 风吹草低低低低 - 植被动画Ⅰ:顶点色实现
type: item
date: 2022-04-13T15:29:00+08:00
description: 写在前面 好久没写博客了...最近做完Substance的素材后就在赶中期进度，再加上休了一整个清明周，真是咕了好久。这几天帮忙整理SpeedTree到HDRP的流程，就顺便补一补植被动画的课。 Basic Vertex Animation Shader 首先是比较经典的顶点动画实现方法，这里写了一个Subgraph用来计算顶点位置。 首先，我们希望植被是围绕生长的位置旋转，所以顶点位置的运算在object space进行，以(0,0,0)为旋转中点。 使旋转角度与距离相关，就可以让靠近枝头的顶点旋转得更远，使枝条看起来更柔软。加入基础的正弦动画，则可以得到这样的整体摆动效果。 另外我们希望风强较大时，植被整体会产生倒伏，在周期性摇摆前又增加了一次整体的旋转。 Details from VertexColor 在speedtree或其他dcc软件中可以利用顶点色存储分簇/随机等信息，为动画添加细节。 speedtree在view-render中开启顶点色显示。 在每个节点属性的vertex color一栏可以设置顶点颜色。如果没有这一栏，需要在tree运算器的Compute Flag中开启Vertex Color。 这里记录两种颜色通道的分配方式，首先是kk的教程版： Chris’s version Red Channel R通道用来区分树冠的层次，第一级树枝线性增长，后续层级皆继承父级，总体上红色从内至外分布。 在shader中，用红通道增加了风向的扰动，也用来控制从树干到枝头渐变的各种效果。 Blue Channel B通道用来区分不同的分簇，第一级树枝随机分布，后续层级皆继承父季，使每一簇颜色不同。 在shader中，用蓝通道增加了y方向的变化。 Green Channel G通道用来增加随机性，树枝线性增长，树叶继承后增加随机性。 在shader中用来增加叶片小枝条的动画。 着色后的预览效果如下： ps.这里踩了一个小坑，speedtree有多个版本，之前使用的Unity Subscription Edition就没做顶点色导出的功能，只能换成Game Indie Edition导出为fbx才能使用顶点色信息😤😤。 利用顶点色可以增添更多shader的动画细节： R通道是动画总控，是最主要的mask。后续BG的噪声都可以乘以R以过滤掉主要的树干。 BG通道可以分别为分簇和小叶片增加动画细节，将时间与通道值相加再求sine可以使动画获得不同的相位差。这里首先为分簇增加了y方向的的动画，实现方法为构造一个y值周期变化的Vector3，并与先前的坐标相加。分簇（B通道）的频率低一些，幅度大一些，叶片（G通道）的频率高一些，幅度小一些。为了让叶片的变化差别更大，这里周期长度、相位和幅度都用到了G通道的值： 到这里其实基本的Shader已经完成了。为了更好的视觉效果，我们还可以为叶片再添加一些旋转的细节。 用教程中的素材进行说明，在这里额外引入了一张贴图，r通道标记叶子的左侧，g通道标记叶子的右侧，b通道标记了整体的渐变。 这样单一四边形的叶片也可以拥有简单的弯折动画： Lumberyard version Blue Channel - Overall Stiffness 低频噪声控制整体摆动，255-最小幅度，0-最大幅度。 Red Channel - Leaves Stiffness 外围的高频噪声，0-最小幅度，255-最大幅度。在lumberyard engine中，红色通道需要读取面的法线，叶片的法线必须拥有水平分量。 Green Channel - Leaves Phase 噪声的相位差，也是以一个高频噪声的方式呈现。 speedtree的wind空间可以自动生成lumberyard的顶点色，所以一般不用手动编辑。 Other versions Firewatch中的顶点色设置： Crysis中的顶点色设置：

💡学点儿丨预览场景与镜头搭建
type: item
date: 2022-03-21T15:26:00+08:00
description: 参考教程：《Windup》实时渲染动画全流程技术美术高级课程 安装ProGrid&ProBuilder ProBuilder可以直接在PackageManager-UnityRegistry中找到。 ProGrid就相对麻烦一些，2021之前的Unity版本，需要在ProjectSetting中开启PreviewPackage，然后即可在PackageManager中安装ProGrid。 2021之后版本，需要在PackageManager中点击➕，选择Add Package from git URL，输入com.unity.progrids，即可安装Progrid。 安装好后，可以在Tools下打开二者的工具栏。 ProBuilder Probuilder的第一个工具是创建几何体，可以开启ProGrid的第三个吸附开关，方便吸附格点；右下角的子菜单可以调节分段数。 可以使用Progrid中包含的的grid贴图创建材质，这张帖图是边长1m的方格，可以帮助控制比例。注意搜索时要点一下小眼睛图标，显示Package中的内容。 在Edit-Preference中将刚刚的grid材质拖放给Probuilder的material即可作为默认创建材质。 注意ProBuilder的工具栏是ContentSensitive的，当切换选择模式时会有不同的工具菜单，比如边模式下可以增加循环边。 ProBuilder的操作和常规建模工具很像，可以分别对顶点/边/面进行编辑，也可以选中面shift挤出。 使用Cinemachine 法一 使用VirtualCamera 在运镜的关键位置创建cinemachine-virtual camera。timeline中创建cinemachine track，将main camera拖入对象。将关键镜头视角的camera拖入track，即可运算镜头动画。 利用cinemachine的功能，可以设置look at、damping、soft zone、FOV等，也会在timeline中自动运算动画。 **法二 使用Dolly Camera with Track 创建Dolly Camera with Track，会生成一个cam和一个dolly track，然后可以通过dolly track的关键点编辑轨道路径。 除了将cam放入cinemachine track以外，还需要单独为这个cam创建一个animation track，记录track的position属性。

💡学点儿丨角色工作流杂谈
type: item
date: 2022-03-17T11:35:00+08:00
description: 用到的模型还是之前OverHit的素材。 Mat 皮肤材质制作 可以先用ps粗略定位色块和位置，然后进sp细化。注意皮肤的色调可以参考Pantone的这张皮肤色卡，避免光线导致的色偏。 windup增加皮肤质感的方法非常简单粗暴，因为是小孩子皮肤，只要增加一点色偏就可以了：ps三原色纹理笔刷糊糊，透明度5%。 Wrinkle Map wrinkle map保留了皮肤挤压时的法线信息，常用于写实渲染中。最新的Enemies直接用shadergraph实现的皮肤皱纹，继续等源文件下载ing 学术文字码码： SSS 引擎中的SSS实现分两部分， Separable Subsurface Scattering Rig QuickRig in Maya 首先切换至Rigging菜单页，在skeleton标签下找到Quick Rig Tool。 没有一步步截图，这里需要1.创建新的绑定；2.加入需要绑骨的mesh；3.创建骨骼结点；4.调整关节位置，可以将镜像调整后的骨骼。 创建骨骼，因为我们的模型不是Tpose，最好勾选T-Stand Correction。注意这里其实不应该创建control rig，会影响后续加骨骼。只要skeleton only就可以了。 创建手部骨骼，使用Rigging标签下的Great Joints工具。注意最好在工具设置中勾选Projected Centering，这样新建立的骨骼节点会建立在mesh管的中心。参考windup的教程，手指的比例可以参考1/2，1/4，1/4. 更改命名，使用skeleton-mirror joint镜像对侧骨骼。 将手指骨骼拖入hand层级下（需要拖拽小logo），会自动生成中间连接的骨骼： 创建蒙皮，可以使用Skin菜单下的Paint Skin Weight绘制权重。 导入Unity 导入引擎后，在Rig下将AnimationType改为Humaniod，然后Apply应用。 进入Configure界面可以确认骨骼是否识别正确。 可以创建Timeline预览骨骼绑定结果。这里用的是BasicMotions的免费Package。 使用Mixamo动作素材 使用Mixamo的素材之前，需要先下载一个T-pose模型以创建Mixamo骨骼到Humaniod骨骼的重映射。 首先对T-pose动作进行Humaniod骨骼映射，然后其他下载的动作在Avatar Definition中选择CopyFromOtherAvatar，即可用于我们的模型。

💡学点儿丨临阵磨枪PBR！
type: item
date: 2022-03-15T21:47:00+08:00
description: 周五要面试，狠狠进行一个临阵磨枪。 PBR 划重点： 物理原理和微表面理论 能量守恒：入射=反射+折射，金属无折射，非金属折射部分散射后出射→漫反射 BxDF 渲染方程： 求入射方向半球积分。 BRDF漫反射项：传统Lambert（无roughness/fresnel，Unity移动端用），基于物理Oren-Nayar/Disney（Unity）等 BRDF镜面反射项：D(NDF法线分布函数)/F（菲涅尔）/G（几何函数） Microfacet Cook-Torrance BRDF 其中分母 4(n·l)(n·v）：校正因子（correctionfactor），作为微观几何的局部空间和整个宏观表面的局部空间之间变换的微平面量的校正。 业内常用：D - GGX，F - Schlink（lerp((1-(v·h)^5,1,F0)），G - Schlink-GGX（UE）/Smith-GGX（Unity） 这里留一个毛老师的F0速查表，注意金属的F0是float3，非金属是float。 白炉测试：验证入射总能量为1的光线的反射光线分布是否归一化的测试 基于物理光照：漫反射（辉度环境映射）+环境光照（IBL） 环境光照Image Based Lighting：分解为预过滤环境贴图+环境BRDF 毛星云的白皮书： 【基于物理的渲染（PBR）白皮书】（一） 开篇：PBR核心知识体系总结与概览 【基于物理的渲染（PBR）白皮书】（二） PBR核心理论与渲染光学原理总结 SRP My SRP 咱时间有限，官方文档的内容就不重复了，划重点： A Render Pipeline Instance. This is an instance of a class defines the functionality of your render pipeline. Its script inherits from RenderPipeline, and overrides its Render() method. A Render Pipeline Asset. This is an asset in your Unity Project that stores data about which Render Pipeline Instance to use, and how to configure it. Its script inherits from RenderPipelineAsset and overrides its CreatePipeline() method. 其中Instance的Render方法中有一个很重要的变量ScriptableRenderContext，用于执行绘图命令。需要将命令输入CommandBuffer类，然后调用Context的ExecuteCommandBuffer方法依次执行命令。 CommandBuffer和ScriptableRenderContext都用于记录我们的指令，我们可以创建多个CommandBuffer用于记录不同的指令，但是ScriptableRenderContext只有一个，并且是Unity为我们提供好的。每一个CommandBuffer可以有自己的名称（使用name属性设置），可以记录各种命令，可以使用Clear方法被清空。所有的CommandBuffer最终都需要合并到ScriptableRenderContext中，并且在调用Submit方法的时候被一次性执行。 c#补课时间： Var是C#3.5新增的一个关键字，用来代替某些具体的类型，由编译器自动判断变量类型，编译器可以根据变量的初始化值“推断”变量的类型。 必须在定义时初始化，必须是局部变量。 C#中，方法的参数传递有四种类型：传值（by value），传址（by reference），输出参数（by output），数组参数（by array）。传址参数需要修饰符ref，输出参数需要修饰符out，数组参数需要修饰符params。 对比了一下URP的代码，首先是一些C#补课： sealed作为形容词是封闭的，未知的。sealed修饰类时说明该类将不能被继承或重写，修饰方法（函数或属性）时可防止扩充类重写此方法（函数或属性）。通常用于实现第三方类库时不想被客户端继承，或用于没有必要再继承的类以防止滥用继承造成层次结构体系混乱。恰当的使用sealed修饰符也可以在一定程度上提高运行效率，因为不用考虑继承类会重写该成员。 Partial是局部类型的标志。 局部类型可以实现将一个类、结构或接口分成几个部分，分别放在在几个不同的.cs文件中（当然也可以放在同一个.cs文件中）。 在程序进行编译之后，将会合并成一个完整的类。 延迟渲染…

ODOS丨ShaderToy 2 ShaderLab
type: item
date: 2022-03-01T13:18:00+08:00
description: ShaderLanguage Shader Language目前主要有3种语言：基于OpenGL的OpenGL Shading Language，简称GLSL;基于DirectX的High Level Shading Language,简称HLSL;还有NVIDIA公司的C for Graphic，简称Cg语言。 Unity使用的Shader程序嵌入的小片段是用Cg/HLSL编写的，从“CGPROGRAM”开始，到“CGEND”结束。 ShaderToy使用的WebGL程序由JavaScript编写的句柄和OpenGL Shading Language（GLSL）编写的着色器代码组成，该语言类似于C或C++，并在电脑的图形处理器（GPU）上执行。 所以想在Unity中查看ShaderToy的shader首先要将GLSL语言转化为HLSL/CG语言—— 关键词替换 在开始之前，把shadertoy中的代码粘贴到pass下的CGPROGRAM语句段内： 可直接CtrlF替换 Syntax vec → float mat → floatx fract( → frac( mix( → lerp( texture( → tex2D(/tex3D(/texCUBE KeyWords iTime → _Time.y 需要前文定义 #define atan(x,y) atan2(y,x) #define mod(x,y) x-y*floor(x/y) 手动修改 语义修正 Matrix Multiplication * → mul() 注意顺序：A*=B → A=mul(B,A) A*B → mul(B,A) Type Casting vec3(0) → float3 a = 1或 float3(0,0,0) 需要前文定义/外挂脚本 iMouse 需要在properties 定义fixed4变量，然后在CG程序块里再次声明同名变量。接下来要外挂C#脚本，可以参考乐乐老师的版本：【ShaderToy】开篇 Channel 需要在properties 定义对应种类的变量(2D/3D/CUBE)，然后在CG程序块里再次声明同名变量。 代码结构 （诚邀美女们下载这个VSCode的粉嫩主题-Dracula Official🍓 以jb猫为例 虽然raymarching modeling is not 4 UNITY，但是它可爱。所以就它了! 除去之前提到的注意事项，还有一点点关于AA的修正：因为没有iResolution，所以smoothstep给了定值；另外在主函数中上下左右取样AA的offset用了ddx(uv.x)来做单位，其实不太确定对不对... 但总之It works！ 其实这个写法还是不太规范，uv的运算借用了maintex的运算矩阵来控制offset和scale，但其实没有用到maintex。 注意预览动态材质时要开启alway refreshing： 完整的代码在下面： Shader "Unlit/Shadertoy" { Properties { _iChannel0 ("Channel0",CUBE) = "" {} _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; samplerCUBE _iChannel0; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex);; return o; } #define TMIN 0.01 #define TMAX 200. #define RAYMARCH_TIME 128 #define PRECISION .001 #define AA 3 #define PI 3.1415926 #define S(v,r) smoothstep( r, r+0…