Unity Shader入门精要学习笔记:基于物理的渲染
引言
随着计算机的处理能力越来越强,人们开始考虑使用更加复杂的算法来渲染更加真实的画面。 在二十世纪八十年代左右, 基于物理的渲染技术(Physically Based Shading, PBS) 首次被引入图形学的正统研究中,学者们提出了使用光线追踪的方法来渲染全局光照,由此打开了精确渲染光线传播的大门。
在实时渲染领域, 人们也发现了这种基于物理的光照模型的巨大优势。 在这之前, Lambert光照模型、 Phong 光照模型和 Blinn-Phong 光照模型等经验模型占据了主流。 然而,这种不满足能量守恒的光照模型使得美术人员需要花费大量的时间在参数调节上。 尤其是, 美术人员往往好不容易为一个物体调节好了所有参数,使得它在当前的光照条件下看起来是满意的。然而, 一旦光照环境发生了变化, 这一切都得从头再来。 因此, 近年来游戏从业者开始着手把基于物理的光照模型应用于实时渲染中。
PBS的理论和数学基础
光是什么
在物理学中,光是一种电磁波。首先,光由太阳或其他光源中被发射出来,然后与场景中的对象相交,一些光线被吸收(absorption),而另一些则被散射(scatt ...
xasset 4.0入门指南
什么是xasset 4.0
众所周知,Unity资产管理方面的知识十分细碎,很多细节稍不注意就会导致资源冗余或者内存泄漏,很多前辈也在为解决这个问题不懈的努力。
今天为大家介绍的是之前有直播过的一个开源的Unity项目资源管里利器,因为它发布了新的4.0版本,支持了很多新的特性所以需要重新给大家再介绍下。
我本人的风格一向是从运行Demo开始,逐步分析理解它的架构,所以这个指南也不会一开始就从宏观上带大家去理解(其实是功课没做足,确实不知道是什么个情况 XD),不过有一说一,个人觉得以这种行文方式非常适合做入门指南
下载
https://github.com/xasset/xasset
git大家肯定都会用,如果速度慢,可以从我的xasset码云镜像拉取:https://gitee.com/NKG_admin/xasset_Gitsync.git
环境
游戏引擎: Unity 2019.4.0 LTF
.Net框架:.Net Framework 4.7.2
IDE:Rider 2019.3
xasset版本:截至此Commmit https://github.com/xasse ...
2020.2.3日记
铭记此时的温暖冬阳,奔向更加光明的未来。
对于C++/C#中的i++,++i性能问题探究(汇编分析)
前言
这阵子在看面经,里面有一道题,C中的i和i哪个效率更高。说实话,看到这道题当场就蒙了,平时用C#写项目都是怎么高兴怎么来,到C这里还有这一说了? 不懂就看答案,答案给出的是++i性能更高,理由是i++会有一次临时变量的分配消耗,存储初始i值用来返回,而++i则直接返回i+1后的值。 嗯,看上去很有道理,但是咱也不知道到底实现是不是这样的啊,看汇编去。
C++汇编分析
环境
C++环境:MinGW64 w64 3.4
CMake:Bundled 3.15.3
Debugger:MinGW-w64 GDB 7.8.1
IDE:CLion 2019.3.3
汇编语法:标准的GAS AT&T语法
优化等级 O0(无优化)
前提分析
C只在早期的时候借助C编译器把自己翻译成汇编语言,很久之前就有了自己的编译器,所以直接反编译得到的就是C的汇编代码。
测试用例
源代码
1234567int main(){ int i = 0; i++; ++i; return 0;}
汇编代码
123456789101112131415Du ...
对于游戏中的回放系统设计架构的畅想
前言
今天看到群友提出游戏回放功能怎么设计的问题,感觉挺有意思,胡思乱想片刻,就有了此文。
正文
什么是回放功能
回放功能也可以叫录像功能,指的是玩家可以从服务端拉取数据,然后在本地进行历史游戏的复现。 直观点的例子就是LOL的观战系统还有录像功能,R6或者OC里的死亡回放功能。
各种类型的回放区别
LOL的录像和观战都不是实时的,也就是说一个人并不能一边看录像,一边玩游戏。 R6和OC里的死亡回放是实时的,因为他是在游戏运行时进行的,玩家死了就要死亡回放。 这种差异也直接导致了实现难度的差异。 首先是LOL的录像,解决方案很简单,只需要保存每次玩家输入的消息以及那些会与客户端产生交互的信息,然后解析消息,向系统内发送信息即可。优点很明显,录像文件体积极小,当然了,这种方法也有很大缺点,无法保证回退到播放过的时间段时游戏中的各个实体状态是否与当时的游戏一致,因为并没有记录世界快照,回退也就无从说起了。也就是说,只能进,不能退。 但是OC的死亡回放单纯用上面那种方法却行不通,因为他是实时的,强硬的更改状态会破坏当前游戏逻辑顺序。只能保存每个时间点的世界快照,然后让客户端表现。 ...
接入Recastnavigation寻路到ET5.0
前言
因为Unity版本的更新迭代,老版本的A*插件在新版本Unity已经无法正常使用,包括一些运行时代码也已经过时,重新接入要花费很多时间,干脆接入一个新的寻路方案吧。
这里选择的是久负盛名的https://github.com/recastnavigation/recastnavigation,但因为他是基于C++的,所以我们要使用C#的P/Invoke来调用它的dll来实现寻路。
由于篇幅与操作复杂的原因,本文会更加注重大体的工作流程,而不会有太多细节上的图片,但是会有一个配套的详细教学视频供大家学习,视频链接:https://www.bilibili.com/video/bv1uK4y1E7CV。
C++/C#的桥接源码也会以在码云开源的形式分享给大家,完整的示例可以在我的Moba项目 https://gitee.com/NKG_admin/NKGMobaBasedOnET 中看到。
通过本文和配套视频你将能学习到recastnavigation的大体设计思路,使用方式,Unity/服务器接入recastnavigation的完整流程。
感谢@footman大佬在我学习过程 ...
C#对于非托管资源的释放原理探究
前言
我们都知道CLR有一个使用根的可达性算法的垃圾回收机制来回收托管内存,那么对于那些本机资源(非托管内存)他又是怎么清理的呢?
正文
要看他怎么清理资源,首先要知道这个资源是怎么来的,这里我们用FileStream这一经典类来探讨这些问题。 首先是它的构造函数
12345678910111213141516171819202122[SecuritySafeCritical]public FileStream(string path, FileMode mode) : this(path, mode, mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.None, Path.GetFileName(path), false){}[SecurityCritical]internal FileStream( string path, FileMode mode, FileAccess access, Fi ...
数字图像处理复习纲要
第一章
1.数字图像的概念:
数字图像:数字图像是对连续图像数字化或离 散化的结果,也称离散图像
2.广义的图像处理(图像工程)包含的三个层次
3.像素的概念
一幅图像可分解为许多个单元。每个基本单元叫做图像元素,简称像素
4.灰度图像存储容量的计算
空间分辨率:图像的尺寸(M∗NM*NM∗N),在成像时采了MN个样,图像包含了MN个像素。
幅度分辨率:在成像时量化成了G(G=2kG = 2^kG=2k)个灰度级,存储一幅图像所需的位数b(b=M∗N∗kb = M * N * kb=M∗N∗k)(单位是bit)
第二章
1.像素的邻域
2.像素间距离,三种距离公式
像素间距离 :
欧氏距离(也是范数为2的距离):DE(p,q) = [(x − s)2 + (y − t)2]12D_E(p,q)\;=\;\lbrack{(x\;-\;s)}^2\;+\;{(y\;-\;t)}^2\rbrack^{\frac12}DE(p,q)=[(x−s)2+(y−t)2]21
城区距离(也是范数为1的距离): D4(p,q) = ∣x − s∣ + ∣ ...
数据结构篇:邻接表
每一个顶点后面就是一条链表,每个顶点都存在数组里。 以这张图为例 结构如下 运行截图 结构体定义
12345678910111213141516171819202122 //边表结点typedef struct EdgeNode { //顶点对应的下标 int adjvex; //指向下一个邻接点 struct EdgeNode *next;} edgeNode;//顶点表结点typedef struct VertexNode { //顶点数据 char data; //边表头指针 edgeNode *firstedge;} VertexNode, AdjList[100];//集合typedef struct { AdjList adjList; //顶点数和边数 int numVertexes, num ...
DFS和BFS
深度优先遍历 (DFS)
深度优先遍历,也称作深度优先搜索,缩写为DFS
深度优先遍历从某个顶点出发,访问此顶点,然后从v的未被访问的邻接点触发深度优先便利图,直至所有和v有路径想通的顶点都被访问到。
这样我们一定就访问到所有结点了吗,没有,可能还有的分支我们没有访问到,所以需要回溯(一般情况下都设置一个数组,来记录顶点是否访问到,如果访问到就不执行DFS算法,如果未被访问过就执行DFS算法)
以这张图为例
我们约定,在没有碰到重复顶点的情况下,优先选择右手边
那么按深度优先遍历就是:A B C D E F G H(此时这条线路已经走到尽头,可是还有一个I顶点没有遍历,所以回到G,发现G的邻接点都遍历过了,再回到F,发现F的邻接点也都遍历过了。。。直到D顶点,发现I这个顶点没有遍历,所以把I再遍历,继续回溯,最终回到起点A) I
落实到代码就是
123 //访问标志的数组,为1表示访问过,为0表示未被访问int visted[100];
1234567891011121314151617 //邻接表的深度优先遍历算法void AdjacencyList::DFS(GraphAdj ...