【Unity 手写PBR】Build-in管线:实现间接光部分

这篇具有很好参考价值的文章主要介绍了【Unity 手写PBR】Build-in管线:实现间接光部分。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面

直接光昨天已经实现了:【Unity Shader】Build-in管线实现PBR:直接光部分,今天趁热打铁,补完剩下的间接光计算。


1 补一个法线纹理

突然法线直接光部分忽略了法线纹理应用的部分,这当然也是不可或缺的部分,之前学习入门精要的时候,就已经分别在法线空间和世界空间下实现了:

【Unity Shader】纹理实践3.0:切线空间下使用法线纹理

【Unity Shader】纹理实践5.0:世界空间下使用法线纹理

这里要使用Cubemap的话,就必须要用世界空间下的方法了,补充一下就好!

(顺便说明一点,暂时先不考虑必要时候使用half变量来优化整个shader,所以暂时所有变量都用的float,等所有工作都做完后再针对性的优化~)

1.1 UnpackNormalWithScale

我们既然引用了Unity的文件,那就最大可能的不自己算!实现什么的先找找有无对应的封装函数,简化计算!但是在用的过程中需要注意,

  • 不同版本之间:Unity每个版本之间可能存在函数没更新、函数冲突等情况
  • 不同管线之间:我这里是在Build-in固定管线下实现的PBR Shader,其他管线下(例如URP)函数一定会有冲突,需要进行很多的修改

好的,回到这个函数,这个函数会自动对法线贴图使用正确的解码,并缩放法线,意味着它同时具备Unpack和Scale缩放两个功能,之前的老办法是:

        float3 normal = UnpackNormal(tex2D(_NormalMap, i.uv)); // 纹理采样+解码,得到法线方向
        normal.xy *= _NormalScale; // 缩放
        normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));

现在只需要一个函数就解决了:

float3 normal = UnpackNormalWithScale(tex2D(_NormalMap, i.uv), _NormalScale); 

函数源码:

fixed3 UnpackNormalWithScale(fixed4 packednormal, float scale)
{
#ifndef UNITY_NO_DXT5nm
    // Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1)
    // Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5
    packednormal.x *= packednormal.w;
#endif
    fixed3 normal;
    normal.xy = (packednormal.xy * 2 - 1) * scale;
    normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
    return normal;
}

另外关于法线应用部分其他的点,我几乎在之前的两篇文章中都有涉及了,所以这里其他的函数、方法之类的就不再赘述。 

1.2 部分代码展示

首先是vertex shader的输入输出结构体,主要是输出部分吧,有需要传给fragment shader的东西:

        float2 uv : TEXCOORD0;
        float4 pos : SV_POSITION;
        // float4 worldPos : TEXCOORD1; // 存入变换矩阵中,节省空间
        // float3 worldNormal : TEXCOORD2; // 跟着下面的变换矩阵一起传入,节省空间
        float4 TtoW0 : TEXCOORD1;  
        float4 TtoW1 : TEXCOORD2;
        float4 TtoW2 : TEXCOORD3; // xyz存入变换矩阵,w储存世界坐标

然后是vert shader部分,相对来说比较简单,就是加入计算变换矩阵的步骤:

        o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
        o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
        o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);

接着是fragment shader中:

        // 计算世界空间法线
        float3 normal = UnpackNormalWithScale(tex2D(_NormalMap, i.uv), _NormalScale); // 采样+解码+缩放 
        // 原始方法
        //float3 normal = UnpackNormal(tex2D(_NormalMap, i.uv)); // 纹理采样+解码,得到法线方向
        // normal.xy *= _NormalScale; // 缩放
        // normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
        float3 worldNormal = normalize(float3(dot(i.TtoW0.xyz, normal), dot(i.TtoW1.xyz, normal), dot(i.TtoW2.xyz, normal)));

1.3 测测效果

这样整个NormalMap部分就完成了!给个法线贴图试试:

unity间接光设置,Unity Shader学习,unity,游戏引擎

芜湖,一切正常!那我们继续!

2 捋一捋Unity中间接光来源

 回顾一下:【技术美术图形部分】PBR全局光照:理论知识补充

Unity中间接光照有3个来源:Light Probe、LightMap和实时GI,划分的话,这里放上一张简洁明了的图:

unity间接光设置,Unity Shader学习,unity,游戏引擎
图源水印

所以说我们写的Shader是否也要根据光照去分一分呢?伴随着这种想法,我在一众实现间接光只做简单的SH计算的文章中发现了它:【学习笔记】Unity PBR的实现,刚好跟我的想法拟合!那么就重点参考他,继续我们的实现之旅。

2.1 Unity的VertexGIForward

UnityStandardCore.cginc文件中,这个函数做工作大概就是上面那个图里面描述的,把光照方式分门别类,执行各自的计算工作,源码如下:

inline half4 VertexGIForward(VertexInput v, float3 posWorld, half3 normalWorld)
{
    half4 ambientOrLightmapUV = 0;
    // Static lightmaps
    #ifdef LIGHTMAP_ON
        ambientOrLightmapUV.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
        ambientOrLightmapUV.zw = 0;
    // Sample light probe for Dynamic objects only (no static or dynamic lightmaps)
    #elif UNITY_SHOULD_SAMPLE_SH
        #ifdef VERTEXLIGHT_ON
            // Approximated illumination from non-important point lights
            ambientOrLightmapUV.rgb = Shade4PointLights (
                unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
                unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
                unity_4LightAtten0, posWorld, normalWorld);
        #endif

        ambientOrLightmapUV.rgb = ShadeSHPerVertex (normalWorld, ambientOrLightmapUV.rgb);
    #endif

    #ifdef DYNAMICLIGHTMAP_ON
        ambientOrLightmapUV.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
    #endif

    return ambientOrLightmapUV;
}

其中: 

VERTEXLIGHT_ON

这个关键字是需要Pass去自己定义的吧,有些情况下需要用顶点光照用以节省性能。

详细的话可以参考:翻译5 Unity Advanced Lighting - 带着红领巾 - 博客园 (cnblogs.com)

unity_lightmap

从烘焙好的lightmap贴图中获取光照颜色

UNITY_SHOULD_SAMPLE_SH

从light probe中读取光照颜色,有点类似于

ShadeSH9

这个其实不是上面源码中的,其实我也不是很明白ShadeSHPerVertex和ShadeSH9的区别,由于后面我实现这部分想用ShadeSH9,所以这里标出的是ShadeSH9,关于它的源码在后面会有所体现。

2.2 我的实现

// 间接光
inline half4 VertexGIForward(float2 uv1, float2 uv2, float3 posWorld, float3 normalWorld)
{
    half4 ambientOrLightmapUV = 0;
    
    // 静态物体
    
    //勾选了Static
    // 开启Lightmap,计算lightmap坐标
    #ifdef LIGHTMAP_ON
        ambientOrLightmapUV.xy = uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
        ambientOrLightmapUV.zw = 0;
    
    // 动态物体
    // 采样light probe
    #elif UNITY_SHOULD_SAMPLE_SH

    // 计算非重要光源
        #ifdef VERTEXLIGHT_ON
            // 选择不使用探针,计算4个顶点光照
            ambientOrLightmapUV.rgb = Shade4PointLights (
                unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
                unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
                unity_4LightAtten0, posWorld, normalWorld);
        #endif
        // 选择使用探针,计算球谐光照
        ambientOrLightmapUV.rgb = ShadeSH9 (normalWorld);
    #endif

    // 开启动态lightmap
    // 计算动态lightmap坐标
    #ifdef DYNAMICLIGHTMAP_ON
        ambientOrLightmapUV.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
    #endif

    return ambientOrLightmapUV;
}

3 LightPrbe+SH

捋清楚了Unity间接光照分类,下面开始大概解释一下Light Probe和球谐函数把!

3.1 探针照明 Probe Lighting

光照探针Light Probe

 一切还要从睡前有一天看到了这个教程说起:Light Probes 基本理论介绍

对于场景中的静态物体,我们可以预先烘焙好Lightmap.而对于动态物体,Unity采用的是往场景中放很多Light Probe(光照探针)来实现。

想象场景中有很多小球,每个小球保存小球在的这一点的环境光信息,这些信息可以是,

一张Cubemap

但是场景中可能会有很多小球欸!就像下图:

unity间接光设置,Unity Shader学习,unity,游戏引擎
图源 如果恋爱和球谐函数一样简单就好了——序章 (qq.com)

每个小球来一张Cubemap?

这有点类似于给场景中的静物每个都给个Cubemap的操作,反正都是一个缺点——开销太大。

或许可以降低Cubemap精度?

emmm,我们先一步一步来想吧,要么就尽可能把Cubemap缩小,例如256x256缩放成4x4(仅假设),原本需要给100个小球每个分配一张256x256,现在变成了100张4x4,确实节省了很多,但采样效果一定大打折扣!

球谐函数

不行了,继续在Cubemap上绕来绕去似乎必定行不通,需要请出我们的球谐函数——球谐光照。

还记得我们讨论过Cubemap和球谐函数的关联吗?球谐函数是搬出来的救兵,给Cubemap的缺点打补丁的,这里也差不多,过程大概就是:

先给光照信息编码 -> 编码后的信息存入一个大小为27的float数组中 -> 游戏运行起来时,重构光照信息(这个具体过程可以看看后面会体现的Unity中实现过程)

求解间接光漫反射只需要3阶球谐基函数就能模拟个大概,例如下图就是仅仅通过前几项基函数,对某一张Cubemap的重建效果:

unity间接光设置,Unity Shader学习,unity,游戏引擎
图源 如果恋爱和球谐函数一样简单就好了——序章 (qq.com)

噢!我们再分析分析为什么3阶(9个函数)就足够模拟间接光漫反射了?——这与低频信息和高频信息有关。间接光漫反射属于低频环境光照,意味着少量的基函数就能高度拟合,意味着图不用非常清晰!模模糊糊就够用了!

有什么不足?

  • LightProbe会使得动态物体本身不会有反射光:但通常用probe的都是较小的物体,反射的光很微弱,对周围环境的影响也很小
  • LightProbe难以表达出复杂的照明效果:这一点你要么模拟精度高一点(取比3更高阶的基函数),但是这开销又大了,出于性能考虑本身引擎就会限制LightProbe的计算精度

总结总结,LightPrbe应用在小的、凸状物体效果会很好! 

3.2 Unity的思路

球谐基函数

开始进入正题,Unity中间接光漫反射的实现本质上就是采样light probe的过程。Unity使用了3阶的伴随勒让德多项式作为基函数,也就是l=0,l=1,l=2:

unity间接光设置,Unity Shader学习,unity,游戏引擎
截图自百度百科

Unity中定义的系数

9个函数的系数取值如下所示:

unity间接光设置,Unity Shader学习,unity,游戏引擎
图源 如何在Unity中造一个PBR Shader轮子 - 知乎 (zhihu.com)

我们只需要知道,这9个系数实际上是代表着球的每个面的光照就行了,如下图,

unity间接光设置,Unity Shader学习,unity,游戏引擎
图源 如何在Unity中造一个PBR Shader轮子 - 知乎 (zhihu.com)

因为光照颜色是RGB,也就是3通道,每个分量都需要跟这9个系数做运算,运算数字就有27个,Unity把这27个变量存入了7个float4变量中,存在了UnityShaderVariables.cginc文件中,系数定义源码如下:

    // SH lighting environment
    half4 unity_SHAr;
    half4 unity_SHAg;
    half4 unity_SHAb;
    half4 unity_SHBr;
    half4 unity_SHBg;
    half4 unity_SHBb;
    half4 unity_SHC;

从LightProbe重构光照

参考:unity中的球谐光照_unity 球谐光照

最后一步了!要用的时候需要把光照信息取出来,这就是光照信息的重构环节。Unity把这个步骤封装到了ShaderSH9()中,传入法线信息,返回的就是环境光照信息。它的源码:

half3 ShadeSH9 (half4 normal)
{
    // Linear + constant polynomial terms
    half3 res = SHEvalLinearL0L1 (normal);

    // Quadratic polynomials
    res += SHEvalLinearL2 (normal);

#   ifdef UNITY_COLORSPACE_GAMMA
        res = LinearToGammaSpace (res);
#   endif

    return res;
}

它将SHEvalLinearL0L1和SHEvalLinearL2两个函数结果累加,并根据gamma空间的宏决定是否转换到gamma空间。

我们用的话,就用ShadeSH9()就好,传入世界空间下归一化后的法线,就能取出储存的漫反射光照信息。

3.3 实现漫反射

其实就是ShadeSH9函数了,上面的vertexGIForward()函数的属于UNITY_SHOULD_SAMPLE_SH且光源是重要光源的分支就做了计算了。

当然,我希望像参考文章那样,把漫反射和镜面反射都封装出来,而不是制作精要的计算,这样的话代码适用性不强。这样的话,我也为间接光漫反射计算单独建一个函数:

//间接光漫反射
// 参考自https://zhuanlan.zhihu.com/p/60972473
inline half3 ComputeIndirectDiffuse(float4 ambientOrLightmapUV,float occlusion){
    
	half3 indirectDiffuse = 0;

	//动态物体
	#if UNITY_SHOULD_SAMPLE_SH
		indirectDiffuse = ambientOrLightmapUV.rgb; // 顶点or探针SH	
	#endif

	//静态物体
	#ifdef LIGHTMAP_ON
		//对光照贴图进行采样和解码
		//UNITY_SAMPLE_TEX2D定义在HLSLSupport.cginc
		//DecodeLightmap定义在UnityCG.cginc
		indirectDiffuse = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap,ambientOrLightmapUV.xy));
	#endif
	#ifdef DYNAMICLIGHTMAP_ON
		//对动态光照贴图进行采样和解码
		//DecodeRealtimeLightmap定义在UnityCG.cginc
		indirectDiffuse += DecodeRealtimeLightmap(UNITY_SAMPLE_TEX2D(unity_DynamicLightmap,ambientOrLightmapUV.zw));
	#endif

	//将间接光漫反射乘以环境光遮罩,返回
	return indirectDiffuse * occlusion;
}

还需要在vertex shader就传入环境光的UV:

o.ambientOrLightmapUV = VertexGIForward(v.texcoord1, v.texcoord2, worldPos, worldNormal); // 环境光orlightmap的UV坐标

前两个是输入struct定义的,

        struct appdata
        {
            float4 pos : POSITION;
            float2 uv : TEXCOORD0;
            float3 normal : NORMAL;
            float4 tangent : TANGENT;
            float2 texcoord1 : TEXCOORD1; // 储存动态环境光照的uv坐标
            float2 texcoord2 : TEXCOORD2; // 储存静态光照贴图的uv坐标

但说实话,感觉这里面texcoord1和2没起到作用。

事实上,这部分做了这么多,如果不考虑这么复杂,就是一句代码的事

float3 ambient_contrib = ShadeSH9(half4(worldNormal, 1));

这样的话就是完全只能采用采样lightprobe存入SH并重构出环境光颜色的方法去计算间接光漫反射了。 

3.4 效果展示

这里单独输出

float3 result = indirectDiffuse * kd;

unity间接光设置,Unity Shader学习,unity,游戏引擎

金属度=1的两个球完全是黑色,这是因为我们的PBR默认金属没有漫反射,kd=0.

4 镜面反射:采样Cubemap

【学习笔记】Unity PBR的实现在镜面反射部分涉及到了很多探针的内容,我其实没太看明白。这里我还是采用大部分实现PBR的文章的方法吧。

还记得之前的分析文章中说的吗,间接光镜面反射分为两个部分,正常的计算方案是,

  • 前项:根据粗糙度采样Cubemap
  • 后项:预计算LUT

而Unity在计算后项时没有采样LUT贴图,而是选择了曲线拟合的思路。

本小节先介绍如何根据粗糙度采样,后面第5小节介绍Unity的拟合计算方法。

4.1 基于粗糙度计算Mip层

由于Unity的粗糙度和Mip层不是线性关系,如下图:

unity间接光设置,Unity Shader学习,unity,游戏引擎
截图自 unity build-in管线中的PBR材质Shader分析研究_pbr shader_郭大钦的博客-CSDN博客

所以需要拟合一下求出近似的层mip_roughness,至于为什么取值,在这篇文章中作者有所体现,就不赘述了,放代码:

// Mip层
float CubeMapMip(_Roughness){
    //基于粗糙度计算CubeMap的mip层
    float mip_roughness = _Roughness * (1.7 - 0.7 * _Roughness);
    float mip = mip_roughness * UNITY_SPECCUBE_LOD_STEPS;
    return mip;
}

UNITY_SPECCUBE_LOD_STEPS

是个常数值,默认为6,意思是整个粗糙度划分为0-6,7个阶层

4.2 采样贴图LOD

下一步需要对天空盒立方体贴图进行采样,再次封装一个方法:

// 反射探针获取颜色值
inline float3 IndirectSpecularCube(float _Roughness, float3 viewDir, float3 worldNormal, float occlusion){
    float mip = CubeMapMip(_Roughness); // 按粗糙度取mip层
    float3 reflectVec = normalize(reflect(-viewDir, worldNormal)); // 计算采样方向
    float4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectVec, mip); // 采样内部存的一个Cubemap的LOD
    float3 iblSpecular = DecodeHDR(rgbm, unity_SpecCube0_HDR); // 把颜色从HDR编码下解码
    return iblSpecular * occlusion;
}

先按粗糙度取mip层,然后计算了一个反射方向,最后采样,最后那个是解码HDR,因为HDR本身非常亮,要是不解码会让传出的结果不正确?这里我简单试了一下没发现有什么不同,可能是我尝试方式不对吧。。。先不管了,就写在这儿。

反射向量reflectVec

这里相当于基于世界法线对视线方向的负方向做了个镜面,用得到的这个反射向量作为采样Cubemap的方向向量。在Cubemap实现环境映射那篇文章里,已经提到过了:

unity间接光设置,Unity Shader学习,unity,游戏引擎

unity_SpecCube0

UnityShaderVariables.cginc中定义的变量,它会把传入的Cubemap模糊模糊,储存成带LOD的图:

unity间接光设置,Unity Shader学习,unity,游戏引擎
图源水印

 这个变量的类型取决于目标平台。

4.3 单独输出

我们可以单独输出这一项,看看是什么效果:

unity间接光设置,Unity Shader学习,unity,游戏引擎

可以看出这是没有任何光照的反射效果,只是一个采样结果。粗糙度的不同,采样结果也不同。

5 镜面反射:曲线拟合LUT

没有选择传入LUT那个红红的图,Unity选择了用系数拟合。Unity计算这部分的源码:

surfaceReduction * gi.specular * FresnelLerp (specColor, grazingTerm, nv);

其中gi.specular这一项就是我们在第4节里计算的东西,于是!Unity曲线拟合具体应该就是体现在了surfaceReduction这个系数。

5.1 SurfaceReduction

Unity源码计算这一项:

ifdef UNITY_COLORSPACE_GAMMA
        // 1-0.28*x^3 as approximation for (1/(x^4+1))^(1/2.2) on the domain [0;1]
        surfaceReduction = 1.0-0.28*roughness*perceptualRoughness;      
#   else
        // fade \in [0.5;1]
        surfaceReduction = 1.0 / (roughness*roughness + 1.0);           
#   endif

照着写一个: 

        float surfaceReduction = 1.0 / (roughness * roughness + 1.0); // linear空间下
        //float surfaceReduction = 1.0 - 0.28 * roughness * _Roughness; // Gamma

单独给他输出的话,

unity间接光设置,Unity Shader学习,unity,游戏引擎

后面两个roughness=0,前面的roughness=1.

5.2 菲涅尔项的影响

我们可以拿直接光中计算菲涅尔项和间接光的做对比,下面是直接光考虑菲涅尔自定义的函数:

// Unity这里传入的是ldoth,而非vdoth
inline float3 Unity_Fresnel(float3 F0, float cosA){
    float a = pow((1 - cosA), 5);
    return (F0 + (1 - F0) * a);
}

这个是Unity源码中定义的FresnelLerp函数: 

half3 FresnelLerp(half3 F0,half3 F90,half cosA){
half t=Pow5(1-cosA);
return lerp(F0,F90,t);
}

其中,

float3 F0 = lerp(unity_ColorSpaceDielectricSpec.rgb, albedo, metallic);
float grazingTerm = saturate(1 - _Roughness + (1 - kd));

直接光传入的是ldoth,间接光的是ndotv。后者的亮度变化效果完全符合菲涅尔效果的样子,

  • 正对视角F0的地方为0
  • 掠射角F90为1   

这会带来什么最终效果?

我们先只把grazingTerm这一项输出:

unity间接光设置,Unity Shader学习,unity,游戏引擎

噢!影响的是非金属,随着_Roughness的增大而变灰,这一项就是一个灰度值在调整非金属,其实是很符合菲涅尔效应的,越光滑,菲涅尔效应才越强。

再只把FresnelLerp这一项输出,看看效果:

unity间接光设置,Unity Shader学习,unity,游戏引擎

总结一下, 

  • 金属:F0处是albedo值,随着视角向F90移动,边会变成亮度高的白色
  • 非金属:F0处的影响是很大的,会衰减反射效果

5.3 结果

都算了一下,然后整个乘在一起:

        float surfaceReduction = 1.0 / (roughness * roughness + 1.0); // linear空间下
        //float surfaceReduction = 1.0 - 0.28 * roughness * _Roughness; // Gamma
        float grazingTerm = saturate(1 - _Roughness + (1 - kd));
        
        float3 indirectSpecular = surfaceReduction * indirectSpecularPro * FresnelLerp(F0, grazingTerm, ndotv) * occlusion;

场景中给了一个cubemap: 

unity间接光设置,Unity Shader学习,unity,游戏引擎

6 PBR最终效果

忘了标哪一排的,中间一排是我实现的,下面一排是Unity的Standard效果,勉强八九不离十!

unity间接光设置,Unity Shader学习,unity,游戏引擎

这里其实没有把多光源考虑进去!后面会补充。

参考

Unity中的light map - 知乎 (zhihu.com)

URP管线的自学HLSL之路 第三十七篇 造一个PBR的轮子

如果恋爱和球谐函数一样简单就好了

Unity Standard Shader 技术分析 - 知乎 (zhihu.com)

Unity的PBR扩展(二)——PBS代码剖析 - 知乎 (zhihu.com)

Unity PBR Standard Shader 实现详解 (四)BRDF函数计算 - 知乎 (zhihu.com)文章来源地址https://www.toymoban.com/news/detail-702769.html

到了这里,关于【Unity 手写PBR】Build-in管线:实现间接光部分的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity 获取单前场景名字和获取到Build Settings里Scenes In Build里所有场景的名字以及路径

    获取到单前场景的名字的代码 获取到Build Settings里Scenes In Build里所有场景的名字。注:如果当前场景没有放到Build Settings里Scenes In Build里,会额外增加一个场景的名字,放在数组的最后一位 scene_names 为所有场景的名字, scene_paths 所有场景的路径

    2024年02月16日
    浏览(39)
  • FPGA实现mnist手写数字识别(软件部分)

    使用的环境:tf1.12,具体配置见here: 首先打开环境tf1.12,,再安装以下的包: opencv 在这里下载“linux-64/opencv3-3.1.0-py36_0.tar.bz2”,通过共享文件夹copy到download文件夹中,在文件夹下打开终端,输入以下命令进行安装: matplotlib(时刻注意是py36) Pillow(貌似不用了,上面已经安

    2023年04月15日
    浏览(78)
  • Unity SRP 管线【第七讲:URP LOD实现以及Reflections反射探针】

    中文版:https://edu.uwa4d.com/lesson-detail/282/1314/0?isPreview=0 英文原版:https://catlikecoding.com/unity/tutorials/custom-srp/lod-and-reflections/ 1. 首先该组件需要将子类模型置于该组件物体子节点下 2. 可在单个LOD中设置其level的模型,并可设置它的距离范围,即可在不同距离下显示不同的模型 若

    2024年02月20日
    浏览(37)
  • Unity Build时Unity 出现error CS0103: The name ‘AssetDatabase‘ does not exist in the current context

    当对unity进行build操作,报了好几条错误 解决方法如下:打开代码提示的代码文件 registerandload,找到使用AssetDatabase的那行, 用下面这两行代码包裹报错的那行代码。 调整结果如下所示: 这样问题就解决了

    2024年02月13日
    浏览(44)
  • Unity Error: In order to build a player go to ‘Player Settings...‘ to resolve the incompatibility be

    在Unity中切换安卓平台时,出现这个问题,修改Player Setting–OtherSettings–Color Space* -- Gamma 比心~

    2024年02月12日
    浏览(37)
  • Unity URP渲染管线与内置渲染管线的性能差别

    首先,我们来了解一下Unity的内置渲染管线。内置渲染管线是Unity较早版本中使用的默认渲染管线,它使用的是传统的图形渲染技术。内置渲染管线提供了一系列的渲染功能,如阴影、反射、抗锯齿等。但是,由于其较为庞大且复杂的设计,它的性能相对较低。在高质量图形效

    2024年02月08日
    浏览(38)
  • Unity ShaderGraph没有PBR Graph的解决方法

    1.创建光照Shader Graph 2.打开Shader Graph界面 Fragment选项卡上右击——Add Block Note——添加Alpha和Alpha Clip Threshold两个属性 可以看到此时这两个属性是灰色的,并不生效,是因为未启用 Alpha Clipping 3.Graph Inspector选项卡中,勾上 Alpha Clipping ,此时两个属性正常显示为白色 根据自身需

    2024年02月11日
    浏览(39)
  • Unity中Shader的PBR的基础知识与理论

    Unity中Shader的PBR的基础知识与理论 PBR(Physically Based Rendering),中文译为基于物理的渲染 PBR是一种渲染方式 ,是使用基于物理原理和微微、平面理论的光照模型,以及使用从现实中测量的表面参数来准确表示真实世界材质的渲染理念 PBR是一系列技术的集合 ,包含GI、PBS等。 P

    2024年04月26日
    浏览(56)
  • 第二十章 Unity 渲染管线

    渲染管线是计算机图形中最基础最核心的部分,它是将3D场景显示到2D平面的技术过程。在DirectX课程中,我们就介绍了渲染管线,分为固定渲染管线和可编程渲染管线(Shader)。但是在DirectX 10版本之后统一了渲染架构,就是将顶点着色器和像素着色器被合二为一,成为流处理

    2024年02月07日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包