分类 Net 下的文章 - 至高岭
首页
丽琪的炼金工坊
搜 索
1
Openwrt/Linux 启用Https,申请Lets Encrypt证书
302 阅读
2
使用Sqlsugar连接SqlCipher(sqlite)
159 阅读
3
相册模式
156 阅读
4
Softether VPN/Open VPN
135 阅读
5
WIN-ACME
124 阅读
Net
Javascript
Docker
Linux
Vue
Python
工具
资源
其他
登录
搜 索
标签搜索
Markdown
Joe
艾塔
累计撰写
21
篇文章
累计收到
8
条评论
首页
栏目
Net
Javascript
Docker
Linux
Vue
Python
工具
资源
其他
页面
丽琪的炼金工坊
用户登录
登录
找到
16
篇与
Net
相关的结果
2023-05-05
别吃糖(一)
环境VS2022 .NET6 XUnit启用资源管理器。视图-测试资源管理器仓库代码自动属性快捷方式:空白处输入 prop 快速两下 tab - 自动属性 //私有变量 private string _name; private string _name3; public string Name { get set } //自动声明 常用 public string Name2 = "ABC"; //访问限制 只写 public string Name3 { set => _name3 = value; } //只读 public string Name4 = nameof(Name3); //可访问性 public string Name5 { private get set { _name3 = "1"; value += "TTT"; } } //索引器 private byte[] arr = new byte[100]; public byte this[int i] { get set }匿名委托(匿名方法)传统委托写法 public delegate void DoSomething(int a); public delegate string DoSomething2(int a, string b); //定义方法委托 public void DoIt(int a) { Console.WriteLine(a); } //常用于初始化参数 public void Config(DoSomething doMethod, int a) { doMethod(a); } // 常用于配置方法 public string Config(DoSomething2 doMethod) { return doMethod(1,"2"); } //测试 var mc = new AnonDelegate(); //调用定义的方法委托 mc.Config(mc.DoIt, 10); var x = 10; //使用匿名委托 mc.Config(delegate(int a) , 10); //使用lamda表达式 mc.Config(a => Console.WriteLine(a + x), 10); //加强版 //使用匿名委托 mc.Config(delegate(int a, string b) ); //使用lamda表达式 推荐 mc.Config((a, b) => a + b);匿名方法 lambda表达式格式 (参数a,参数b,参数c...)=> { 方法体 } //无参数且只有一行代码简写 ()=> 方法体;匿名类当某个类可能只用一次,用完即销毁,使用匿名类//匿名类型:只能使用一次,仅能在当前的项目中使用 var aPeople = new ; //嵌套匿名类型 var aEmployee = new { JionDate = DateTime.Now, Salary = 8000, aPeople = new }; _testOutputHelper.WriteLine(aEmployee.aPeople.pName);//输出:张三this扩展方法为什么要有扩展方法,就是为了在不修改源码的情况下,为某个类增加新的方法。语法:定义静态类,并添加public的静态方法,第一个参数代表扩展方法的扩展类。它必须放在一个非嵌套、非泛型的静态类中(的静态方法);它至少有一个参数;第一个参数必须附加this关键字;第一个参数不能有任何其他修饰符(out/ref).第一个参数不能是指针类型。注意:1、C#只支持扩展方法,不支持扩展属性、扩展事件等;2、方法名无限制,第一个参数必须带this,表示要扩展的类型;3、扩展方法的命名空间可以使用namespace System,但不推荐;4、定义扩展方法的类必须是静态类;5、扩展方法虽然是public的静态方法,但是生成以后是实例方法,使用时需要先实例化对象,通过对象.方法名进行调用扩展方法 public static class ByteExtension { public static string ToX2(this SampleClass my ,byte value) { return value.ToString("X2"); } }Assert判断
2023年05月05日
19 阅读
1 评论
0 点赞
2023-05-04
多线程基础
暂无简介
2023年05月04日
25 阅读
0 评论
0 点赞
2023-04-24
\r与\n的区别
\r是回车,英文是Carriage return,作用:使光标到行首\n是换行,英文是New line/line feed,作用:使光标下移一行如果用过机械打字机,就知道回车和换行的区别了。回车就是把水平位置复位,不卷动滚筒。换行就是把滚筒卷一格,不改变水平位置。我们平时所说的键盘Enter键换行实则应该叫做叫做回车换行(\r\n)看到一种说法: windows下enter是 \r\n; linux/unix下是\n; mac下是\rWindows 采用 \r\n 是有原因的,Windows 采用了传统的英文打字机的模式。想想看英文打字机是如何换行的呢?英文打字机是选择将小车退回至起点,这个过程称为回车(carriage return, CR),随后把小车调至下一行的位置,这个过程称为换行(line feed, LF),这样就完成了英文打字机中换行过程。回车(CR)在计算机中使用 ASCII 为 13 的字符来表示(0x0D),换行(LF)使用 ASCII 为 10 的字符来表示(0x0A)。注意:1、windows下可直接使用\n来匹配换行符,但仍然推荐使用标准的\r\n来匹配键盘Enter键的换行符;2、使用\r\n组合是有顺序的,调转顺序写成\n\r是错误的,将无法匹配换行符!
2023年04月24日
25 阅读
2 评论
0 点赞
2023-04-12
LATEX
Rendering Equaltion$$ \def\red#1} \def\blue#1} \def\green#1} $$以下就是渲染方程,这个方程是基于辐射度量学的量化地描述渲染过程的公式。$$ L_o(p, \omega) = L_e(p, \omega) + \int_f_r(\omega_o, \omega_i, p)L_i(p, \omega_o)cos d\omega \\\\= L_e(p, \omega) + \int_f_r(\omega_o, \omega_i, p)L_i(p, \omega_o) (\omega_i \cdot n) d\omega $$Cook-Torrance BRDF基于Microfacet模型得到了由Fresnel Formula, Normal Distribution Function 和 Geometry Term 组成的 PBR 的 BRDF.它大概长这样$$ f_r(w_o, w_i, p) = \frac\blue\green} $$其中$h = normalize(\omega_i, \omega_o)$Fresnel Formula考虑到Fresnel Formula的复杂性,在工业上一般使用Fresnel-Schlick近似来模拟真正的Fresnel项。$$ F_(\omega_o, h) = F_0 + (1 - F_0)(1 - (h \cdot \omega_o))^5 $$其中$F_0$用来表示材质的基础反射率,也就是你沿法线方向观察物体,它的反射比重是怎样的。对于水面或塑料而言,你朝球面掠角看过去的话,Fresnel现象越明显,反光就越强。对于导体而言,几乎所有的颜色都由反射贡献,所以它们的$F_0$项差距很大。MeterialFresnel TermSliverrgb(0.95, 0.93, 0.88)Waterrgb(0.02)那么我们用GLSL代码写出来是这样的vec3 fresnelSchlick(float cosTheta, vec3 F0) { return F0 + (1. - F0) * pow(1. - cosTheta, 5.); }Normal Distribution Function简称NDF,NDF做的就是类似之前我们在Blinn-Phong的Specular项里做的。但是这里引入了粗糙度这一物理量roughness.之前工业界采用Beckmann的NDF,但是随着GGX的提出,长拖尾的NDF渲染起来更加自然,所以现代人们普遍使用GGX。比较新的理论是有一种叫GTR(Generalized TR)的模型,它在GGX的基础上加入了新的参数$\gamma$ ,并且随着$\gamma$的变化可以和GGX与Beckmann等价。下面是Trowbridge-Reitz GGX:$$ NDF_(h, n, \alpha) = \frac $$当粗糙度很低(也就是说表面很光滑)的时候,与中间向量取向一致的微平面会高度集中在一个很小的半径范围内。由于这种集中性,NDF最终会生成一个非常明亮的斑点。但是当表面比较粗糙的时候,微平面的取向方向会更加的随机。你将会发现与h向量取向一致的微平面分布在一个大得多的半径范围内,但是同时较低的集中性也会让我们的最终效果显得更加灰暗。我们用GLSL去实现它float GGX(vec3 N, vec3 H, float roughness) { float seq_roughness = roughness * roughness; float NdotH = dot(H, N); float seq_NdotH = NdotH * NdotH; float nom = seq_roughness; float denom = (seq_NdotH * (seq_roughness - 1.) + 1.); denom = PI * denom * denom; return nom / denom; }Geometry Term我们看下面两种情况,当一个平面凹凸不平(粗糙)或入射、反射光在掠角时,光有很明显的自遮挡的情况。这种情况我们需要一个项来修正。另外一种理解方式是,当入射、反射光在掠角时,Cook-Torrance的分母将会无限接近于0,此时,我们的分子同样需要一个很小的项来中和它,来避免不自然的高光。入射光被遮挡叫Shadowing,出射光被遮挡叫Masking.另外,不同的法线分布函数对应的几何函数也互不相同,二者具有很强的依赖关系,需要搭配着一起使用。与NDF类似,几何函数采用一个材料的粗糙度参数作为输入参数,粗糙度较高的表面其微平面间相互遮蔽的概率就越高。我们将要使用的几何函数是GGX与Schlick-Beckmann近似的结合体,因此又称为Schlick-GGX:$$ G_(\omega, n, k(\alpha)) = \frac $$在这里$k(\alpha)$可以根据直接光照或IBL光照进行调整。为了有效的估算Geometry Term,需要将观察方向(几何遮蔽(Geometry Obstruction))和光线方向向量(几何阴影(Geometry Shadowing))都考虑进去。我们可以使用史密斯法(Smith’s method)来把两者都纳入其中$$ G(\omega_i, \omega_o, n, k(\alpha)) = G_(\omega_i, n, k(\alpha)) \cdot G_(\omega_o, n, k(\alpha)) $$G项的值域是[0, 1],这可以简单推出来(主要是1)$$ G < \max_ } \left[ \frac \right] ^2 \leq \frac = 1 $$用GLSL实现一下,这里$G_$可以视为只有两个参数,即$$ G_(\omega \cdot n, k(\alpha)) = G_(\omega, n, k(\alpha)) $$float SchlickGGX(float NdotV, float k) { float nom = NdotV; float denom = NdotV * (1. - k) + k; return nom / denom; } float Smith(vec3 N, vec3 V, vec3 L, float k) { float NdotV = max(0., dot(N, V)); float NdotL = max(0., dot(N, L)); return SchlickGGX(NdotV, k) * SchlickGGX(NdotL, k); }BRDF考虑渲染方程,这里我们同样加入diffuse项$$ L_o(p, \omega) = \int_\left( K_d\frac + K_s\frac\right)L_i(p, \omega_o)cos d\omega \\\\ = \int_\left( (1 - F)\frac + \frac\right)L_i(p, \omega_o)cos d\omega $$下面使用Cook-Torrance BRDF来渲染的样例。out vec4 color; in vec2 texCoord; in vec3 normal; in vec3 worldPos; // uniform terms... // function declaration #define fr(name, begin, end) \ for(int name = begin; name < end; ++name) #define max0f(x) max(0., x) void main() { vec3 N = Normal; vec3 V = normalize(camPos - worldPos); vec3 Lo = vec3(0.); fr(i, 0, LIGHTING_CNT) { vec3 L = normalize(lightPos[i] - worldPos); vec3 H = normalize(L + V); // attenuation float distance = length(lightPos[i] - worldPos); float attenuation = 1. / distance * distance; vec3 radiance = attenuation * lightColor[i]; // brdf float brdf_n = GGX(N, H, roughness); float brdf_g = Smith(N, V, L, roughness); vec3 brdf_f = fresnelSchlick(max(dot(H, V)), F0); vec3 nom = brdf_n * brdf_f * brdf_g; float denom = 4. * max0f(dot(N, L)) * max0f(dot(N, V)); vec3 specular = nom / denom; vec3 ks = F; vec3 kd = vec3(1.) - ks; kd *= 1.0 - metallic; float NdotL = max0f(dot(N, L)); Lo += (kd * albedo / PI + specular) * radiance * NdotL; } // ... }这里我需要补充一下Attenuation和能量守恒这个项其实是光线衰减项,想象一下烟花爆炸,理想情况下烟花是球形爆炸形状,也就是一个球壳上分布着相同的烟花粒子。因为亮度和烟花粒子呈线性关系,而球壳面积和半径的关系是平方关系,那么我们可以得到$$ L \propto R^2 $$相似的,我们可以得到Randiance衰减系数。能量守恒即Ks和Kd项相加和必须为1. 因为导体大部分是反射项,我们让Ks项乘1减金属度。IBL Environment LightingDiffuse Termtheory我们对于环境光照的BRDF可以拆分成diffuse的和specular的。下面是diffuse的$$ L_o(p, \omega) = \int_\left( K_d\frac \right)L_i(p, \omega_o)cos d\omega \\\\ = K_d\frac \int_L_i(p, \omega_o)cos d\omega \\\\ = K_d\frac \int_^\int_^} L_i(p, \phi, \theta) cos\theta sin\theta d\phi d\theta \\\\ \approx K_d\frac \sum_^\sum_^ L_i(p, \phi, \theta) cos\theta sin\theta $$在这里,我们就可以得到某个点的半球积分了。pre-compute我们如果对半球积分采样,就要遍历$\phi, \theta$我们可以画一个cube,然后把上述积分转换成代码就好。vec3 irradiance = vec3(0.); vec3 up = vec3(0., 1., 0.); vec3 right = normalize(cross(up, normal)); up = normalize(cross(normal, right)); float sampleDelta = .025; float nrSamples = .0; for (float phi = .0; phi < 2. * PI; phi += sampleDelta) { for(float theta = .0; theta < .5 * PI; theta += sampleDelta) { vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N; irradiance += texture(environmentCubeMap, sampleVec.rgb) * cos(theta) * sin(theta); nrSamples++; } } irradiance = PI * (irradiance / nrSamples);那么我们就可以计算ambient项了,继续写之前的pbr-rendering.uniform samplerCube irradianceMap; // ... void main() { // pbr rendering. vec3 kS = fresnelSchlick(max(dot(N, V), 0.0), F0); vec3 kD = vec3(1.0) - kS; vec3 irradiance = texture(irradianceMap, N).rgb; vec3 diffuse = irradiance * albedo; vec3 ambient = (kD * diffuse) * ao; }这里有些事很可疑,fresnel项需要一个中程向量H来计算相应的系数,但是考虑到环境光来自四面八方,没用一个单独的中程向量,但是为了模拟fresnel,我们用dot(N, V)模拟这一系数。Fresnel Attenuationthanks to Sébastien Lagarde.这里基于一个理论,当斜视时,经过过滤和未经过滤的立方体贴图造成的光照差距是明显的,后者对多个方向的入射光进行平均并且用单一的Fresnel项计算反射权重,因为未考虑粗糙度,表面反射率总是相对较高。所以对比较粗糙的表面进行矫正:vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) { return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); }然后之前的代码改为:vec3 kS = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); vec3 kD = vec3(1.0) - kS; vec3 irradiance = texture(irradianceMap, N).rgb; vec3 diffuse = irradiance * albedo; vec3 ambient = (kD * diffuse) * ao; 然后接续之前的shader, 当前点的颜色就是color = Lo + ambient;Specular Termtheory然后再看 Specular Term$$ L_o(p, \omega) = \int_ \fracL_i(p, \omega_o)cos d\omega $$pre compute
2023年04月12日
37 阅读
0 评论
0 点赞
2023-04-12
此内容被密码保护
加密文章,请前往内页查看详情
2023年04月12日
4 阅读
0 评论
0 点赞
1
2
3
4