Unity中Shader的BRDF解析(三)

文章目录

  • 前言
  • 一、BRDF中的镜面反射项
  • 二、分别解析每一个参数
    • 1、D、G函数:speclarTerm
    • 2、其他中间步骤
    • 3、光照颜色
    • 4、F函数(菲涅尔函数) :FresnelTerm
    • IBL在下篇文章中继续解析
  • 三、最终代码
    • .cginc文件:
    • Shader文件:


前言

在上篇文章中,我们解析了BRDF的漫反射项,这篇文章我们继续解析BRDF中的镜面反射

  • Unity中Shader的BRDF解析(二)

一、BRDF中的镜面反射项

在这里插入图片描述
在这里插入图片描述

  • 我们返回 specular ,看一下高光效果:

return fixed4(specular,1);

在这里插入图片描述


二、分别解析每一个参数

在这里插入图片描述

1、D、G函数:speclarTerm

//镜面反射中的DV项的计算
//最后乘以PI的原因是因为计算 漫反射 时,等式右边没有除以PI。
//导致算出的结果,等效于分母中多乘了一个PI,所以需要在计算公式时,乘以一个PI,消除PI
float specularTerm = V*D * UNITY_PI; // Torrance-Sparrow model, Fresnel is applied later

在这里插入图片描述

  • roughness:学术粗糙度 = 感性粗糙度 * 感性粗糙度

//声明一个学术上的粗糙度 = perceptualRoughness * perceptualRoughness
float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);

  • UNITY_BRDF_GGX:默认为1

#ifndef UNITY_BRDF_GGX
#define UNITY_BRDF_GGX 1
#endif

  • D函数:法线分布函数

作用:使只有 视线向量 和 光方向向量 的半角向量 与 微平面法线重合时,才将光线 l 进行反射

在这里插入图片描述

  • 公式推导:(float D = GGXTerm (nh, roughness);)

在这里插入图片描述

这里变化公式的原因:为了节省性能
最后,把分母的1替换为 1e-7f的原因:保证分母不为0

inline float GGXTerm (float NdotH, float roughness)
{
float a2 = roughness * roughness;
float d = (NdotH * a2 - NdotH) * NdotH + 1.0f; // 2 mad
return UNITY_INV_PI * a2 / (d * d + 1e-7f); // This function is not intended to be running on Mobile,
// therefore epsilon is smaller than what can be represented by half
}

  • V函数:

在这里插入图片描述

float V = SmithJointGGXVisibilityTerm1 (nl, nv, roughness);


//V函数的计算:
   // Ref: http://jcgt.org/published/0003/02/03/paper.pdf
   inline float SmithJointGGXVisibilityTerm1 (float NdotL, float NdotV, float roughness)
   {
       #if 0
       // Original formulation:
       //  lambda_v    = (-1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;
       //  lambda_l    = (-1 + sqrt(a2 * (1 - NdotV2) / NdotV2 + 1)) * 0.5f;
       //  G           = 1 / (1 + lambda_v + lambda_l);

       // Reorder code to be more optimal
       half a          = roughness;
       half a2         = a * a;

       half lambdaV    = NdotL * sqrt((-NdotV * a2 + NdotV) * NdotV + a2);
       half lambdaL    = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);

       // Simplify visibility term: (2.0f * NdotL * NdotV) /  ((4.0f * NdotL * NdotV) * (lambda_v + lambda_l + 1e-5f));
       return 0.5f / (lambdaV + lambdaL + 1e-5f);  // This function is not intended to be running on Mobile,
       // therefore epsilon is smaller than can be represented by half
       #else
       //上面公式的一个近似实现(简化平方根,数学上不太精确,但是效果比较接近,性能好)
       // Approximation of the above formulation (simplify the sqrt, not mathematically correct but close enough)
       float a = roughness;
       float lambdaV = NdotL * (NdotV * (1 - a) + a);
       float lambdaL = NdotV * (NdotL * (1 - a) + a);

       #if defined(SHADER_API_SWITCH)
       return 0.5f / (lambdaV + lambdaL + UNITY_HALF_MIN);
       #else
       return 0.5f / (lambdaV + lambdaL + 1e-5f);
       #endif

       #endif
   }

在这里插入图片描述

2、其他中间步骤

  • 如果颜色空间为Gamma空间:

//如果颜色空间为Gamma空间:
# ifdef UNITY_COLORSPACE_GAMMA
specularTerm = sqrt(max(1e-4h, specularTerm));
# endif

  • 材质上的镜面高光开关

//材质上的镜面高光开关
#if defined(_SPECULARHIGHLIGHTS_OFF)
specularTerm = 0.0;
#endif

  • any(a)函数:

any (a)
如果a=0或者a中的所有分量为0,则返回0(false);否则返回1(true).
bool any(bool4 a)
{
return a.x || a.y || a.z || a.w;
}

我们在片元着色器中,输出测试一下:

return any(0);

return any(fixed4(0,0,0,0));

在这里插入图片描述

return any(1);

return any(fixed4(0,0,1,0));

在这里插入图片描述

  • 当我们的 metallic = 1时,并且Albedo为纯黑色的情况,不希望有金属反射效果

// To provide true Lambert lighting, we need to be able to kill specular completely.
specularTerm *= any(specColor) ? 1.0 : 0.0;

  • 这句话可能Unity有自己的考虑:

specularTerm *= any(specColor) ? 1.0 : 0.0;
等效于
specularTerm *= any(specColor);

3、光照颜色

光照颜色就是单纯的乘以光照颜色

4、F函数(菲涅尔函数) :FresnelTerm

在这里插入图片描述

FresnelTerm1 (specColor, lh);

//F函数的计算:(菲涅尔效果)
inline half3 FresnelTerm1 (half3 F0, half cosA)
{
half t = Pow5 (1 - cosA); // ala Schlick interpoliation
return F0 + (1-F0) * t;
}

F0代表 视线方向 与 法线方向呈 0°夹角
F90代表 视线方向 与 法线方向呈 90°夹角

  • 参数:lh

公式中使用的是 VdotH。但是,这里传入的是 LdotH 的原因:
视线单位向量 dot 半角单位向量的点积 = 光方向单位向量 dot 半角单位向量的点积
因为,夹角是一样的。所以节省性能,使用 LdotH 代替 VdotH

  • 参数:specColor

由金属度决定的

IBL在下篇文章中继续解析


三、最终代码

.cginc文件:

#ifndef MYPHYSICALLYBASERENDERING_INCLUDE
    #define MYPHYSICALLYBASERENDERING_INCLUDE

    //Standard的漫反射和镜面反射计算↓

    //F函数的计算:(菲涅尔效果)
    inline half3 FresnelTerm1 (half3 F0, half cosA)
    {
        half t = Pow5 (1 - cosA);   // ala Schlick interpoliation
        return F0 + (1-F0) * t;
    }

    //V函数的计算:
    // Ref: http://jcgt.org/published/0003/02/03/paper.pdf
    inline float SmithJointGGXVisibilityTerm1 (float NdotL, float NdotV, float roughness)
    {
        #if 0
        // Original formulation:
        //  lambda_v    = (-1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;
        //  lambda_l    = (-1 + sqrt(a2 * (1 - NdotV2) / NdotV2 + 1)) * 0.5f;
        //  G           = 1 / (1 + lambda_v + lambda_l);

        // Reorder code to be more optimal
        half a          = roughness;
        half a2         = a * a;

        half lambdaV    = NdotL * sqrt((-NdotV * a2 + NdotV) * NdotV + a2);
        half lambdaL    = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);

        // Simplify visibility term: (2.0f * NdotL * NdotV) /  ((4.0f * NdotL * NdotV) * (lambda_v + lambda_l + 1e-5f));
        return 0.5f / (lambdaV + lambdaL + 1e-5f);  // This function is not intended to be running on Mobile,
        // therefore epsilon is smaller than can be represented by half
        #else
        //上面公式的一个近似实现(简化平方根,数学上不太精确,但是效果比较接近,性能好)
        // Approximation of the above formulation (simplify the sqrt, not mathematically correct but close enough)
        float a = roughness;
        float lambdaV = NdotL * (NdotV * (1 - a) + a);
        float lambdaL = NdotV * (NdotL * (1 - a) + a);

        #if defined(SHADER_API_SWITCH)
        return 0.5f / (lambdaV + lambdaL + UNITY_HALF_MIN);
        #else
        return 0.5f / (lambdaV + lambdaL + 1e-5f);
        #endif

        #endif
    }
    //D函数的计算:
    inline float GGXTerm1 (float NdotH, float roughness)
    {
        float a2 = roughness * roughness;
        float d = (NdotH * a2 - NdotH) * NdotH + 1.0f; // 2 mad
        return UNITY_INV_PI * a2 / (d * d + 1e-7f); // This function is not intended to be running on Mobile,
        // therefore epsilon is smaller than what can be represented by half
    }

    //为了保证分母不为0,而使用的一种安全的归一化
    inline float3 Unity_SafeNormalize1(float3 inVec)
    {
        //normalize(v) = rsqrt(dot(v,v)) * v;
        float dp3 = max(0.001f, dot(inVec, inVec));
        return inVec * rsqrt(dp3);
    }
    //迪士尼的漫反射计算
    half DisneyDiffuse1(half NdotV, half NdotL, half LdotH, half perceptualRoughness)
    {
        half fd90 = 0.5 + 2 * LdotH * LdotH * perceptualRoughness;
        // Two schlick fresnel term
        half lightScatter   = (1 + (fd90 - 1) * Pow5(1 - NdotL));
        half viewScatter    = (1 + (fd90 - 1) * Pow5(1 - NdotV));

        return lightScatter * viewScatter;
    }
    // Main Physically Based BRDF
    // Derived from Disney work and based on Torrance-Sparrow micro-facet model
    //
    //   BRDF = kD / pi + kS * (D * V * F) / 4
    //   I = BRDF * NdotL
    //
    // * NDF (depending on UNITY_BRDF_GGX):
    //  a) Normalized BlinnPhong
    //  b) GGX
    // * Smith for Visiblity term
    // * Schlick approximation for Fresnel
    half4 BRDF1_Unity_PBS1 (half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,
        float3 normal, float3 viewDir,
        UnityLight light, UnityIndirect gi)
    {
        //感性的粗糙的 = 1 - smoothness
        float perceptualRoughness = SmoothnessToPerceptualRoughness (smoothness);
        //半角向量(一般用 H 表示): H = 光线向量 + 视线向量(此处的 光线向量 和 视线向量 为单位向量,根据向量相加的四边形法则得出半角向量)
        float3 halfDir = Unity_SafeNormalize1 (float3(light.dir) + viewDir);
        
    //法线 与 视线的点积在可见像素上不应该出现负值,但是他有可能发生在 投影 与 法线 映射 时
    //所以,可以通过某些方式来修正,但是会产生额外的指令运算
    //替代方案采用abs的形式,同样可以工作只是正确性少一些    
    // NdotV should not be negative for visible pixels, but it can happen due to perspective projection and normal mapping
    // In this case normal should be modified to become valid (i.e facing camera) and not cause weird artifacts.
    // but this operation adds few ALU and users may not want it. Alternative is to simply take the abs of NdotV (less correct but works too).
    // Following define allow to control this. Set it to 0 if ALU is critical on your platform.
    // This correction is interesting for GGX with SmithJoint visibility function because artifacts are more visible in this case due to highlight edge of rough surface
    // Edit: Disable this code by default for now as it is not compatible with two sided lighting used in SpeedTree.
    #define UNITY_HANDLE_CORRECTLY_NEGATIVE_NDOTV 0

    #if UNITY_HANDLE_CORRECTLY_NEGATIVE_NDOTV
        // The amount we shift the normal toward the view vector is defined by the dot product.
        half shiftAmount = dot(normal, viewDir);
        normal = shiftAmount < 0.0f ? normal + viewDir * (-shiftAmount + 1e-5f) : normal;
        // A re-normalization should be applied here but as the shift is small we don't do it to save ALU.
        //normal = normalize(normal);

        float nv = saturate(dot(normal, viewDir)); // TODO: this saturate should no be necessary here
    #else
        half nv = abs(dot(normal, viewDir));    // This abs allow to limit artifact
    #endif

        //其他向量之间的点积
        float nl = saturate(dot(normal, light.dir));//法线 点积 光线
        float nh = saturate(dot(normal, halfDir));//法线 点积 半角
        half lv = saturate(dot(light.dir, viewDir));//光线 点积 视线
        half lh = saturate(dot(light.dir, halfDir));//光线 点积 半角

        // Diffuse term
        //迪士尼原则的漫反射
        half diffuseTerm = DisneyDiffuse1(nv, nl, lh, perceptualRoughness) * nl;

        // Specular term
        // HACK: theoretically we should divide diffuseTerm by Pi and not multiply specularTerm!
        // 理论上漫反射项中应该除以 PI,但是由于以下两个原因没有这样做
        // BUT 1) that will make shader look significantly darker than Legacy ones
        //原因一:这样会导致最终效果偏暗
        // and 2) on engine side "Non-important" lights have to be divided by Pi too in cases when they are injected into ambient SH
        //原因二:当引擎光照为 不重要光照 时,进行球谐光照计算,会再除以一个 PI。所以,在Unity计算迪士尼漫反射时,不除以PI

        //声明一个学术上的粗糙度 = perceptualRoughness * perceptualRoughness
        float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);

        //GGX模型拥有比较好的效果,默认使用这个模型(并且,UNITY_BRDF_GGX在定义时,默认为 1)
    #if UNITY_BRDF_GGX
        // GGX with roughtness to 0 would mean no specular at all, using max(roughness, 0.002) here to match HDrenderloop roughtness remapping.
        //使用max来限定 roughtness 最小等于0 的原因:当 roughtness 为0时,结果会直接为0,导致效果丢失
        roughness = max(roughness, 0.002);
        float V = SmithJointGGXVisibilityTerm1 (nl, nv, roughness);
        float D = GGXTerm1 (nh, roughness);
    #else
        // Legacy
        half V = SmithBeckmannVisibilityTerm1 (nl, nv, roughness);
        half D = NDFBlinnPhongNormalizedTerm1 (nh, PerceptualRoughnessToSpecPower(perceptualRoughness));
    #endif

        //镜面反射中的DV项的计算
        //最后乘以PI的原因是因为上面计算漫反射时,等式右边没有除以PI。
        //导致算出的结果,等效于分母中多乘了一个PI,所以需要在计算公式时,乘以一个PI,消除PI
        float specularTerm = V*D * UNITY_PI; // Torrance-Sparrow model, Fresnel is applied later

    //如果颜色空间为Gamma空间:    
    #   ifdef UNITY_COLORSPACE_GAMMA
            specularTerm = sqrt(max(1e-4h, specularTerm));
    #   endif

        // specularTerm * nl can be NaN on Metal in some cases, use max() to make sure it's a sane value
        specularTerm = max(0, specularTerm * nl);

    //材质上的镜面高光开关    
    #if defined(_SPECULARHIGHLIGHTS_OFF)
        specularTerm = 0.0;
    #endif

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

        // To provide true Lambert lighting, we need to be able to kill specular completely.
        // 当我们的 metallic = 1时,并且Albedo为纯黑色的情况,不希望有金属反射效果
        specularTerm *= any(specColor) ? 1.0 : 0.0;

        half grazingTerm = saturate(smoothness + (1-oneMinusReflectivity));

        //漫反射颜色 = 贴图 * (gi漫反射 + 灯光颜色 * 迪士尼漫反射)
        half3 diffuse = diffColor * (gi.diffuse + light.color * diffuseTerm);
        
        //镜面反射 DFG / 4cos(θl)cos(θv)
        //speclarTerm : D G 函数
        //light.color : 光照颜色
        //FresnelTerm (specColor, lh) : F 函数
        half3 specular = specularTerm * light.color * FresnelTerm1 (specColor, lh);
        
        //IBL
        half3 ibl = surfaceReduction * gi.specular * FresnelLerp (specColor, grazingTerm, nv);
        
        half3 color = diffuse + specular + ibl;
        
        return half4(color, 1);
    }

    // Based on Minimalist CookTorrance BRDF
    // Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255
    //
    // * NDF (depending on UNITY_BRDF_GGX):
    //  a) BlinnPhong
    //  b) [Modified] GGX
    // * Modified Kelemen and Szirmay-​Kalos for Visibility term
    // * Fresnel approximated with 1/LdotH
    half4 BRDF2_Unity_PBS1 (half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,
        float3 normal, float3 viewDir,
        UnityLight light, UnityIndirect gi)
    {
        float3 halfDir = Unity_SafeNormalize (float3(light.dir) + viewDir);

        half nl = saturate(dot(normal, light.dir));
        float nh = saturate(dot(normal, halfDir));
        half nv = saturate(dot(normal, viewDir));
        float lh = saturate(dot(light.dir, halfDir));

        // Specular term
        half perceptualRoughness = SmoothnessToPerceptualRoughness (smoothness);
        half roughness = PerceptualRoughnessToRoughness(perceptualRoughness);

    #if UNITY_BRDF_GGX

        // GGX Distribution multiplied by combined approximation of Visibility and Fresnel
        // See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course
        // https://community.arm.com/events/1155
        float a = roughness;
        float a2 = a*a;

        float d = nh * nh * (a2 - 1.f) + 1.00001f;
    #ifdef UNITY_COLORSPACE_GAMMA
        // Tighter approximation for Gamma only rendering mode!
        // DVF = sqrt(DVF);
        // DVF = (a * sqrt(.25)) / (max(sqrt(0.1), lh)*sqrt(roughness + .5) * d);
        float specularTerm = a / (max(0.32f, lh) * (1.5f + roughness) * d);
    #else
        float specularTerm = a2 / (max(0.1f, lh*lh) * (roughness + 0.5f) * (d * d) * 4);
    #endif

        // on mobiles (where half actually means something) denominator have risk of overflow
        // clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
        // sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
    #if defined (SHADER_API_MOBILE)
        specularTerm = specularTerm - 1e-4f;
    #endif

    #else

        // Legacy
        half specularPower = PerceptualRoughnessToSpecPower(perceptualRoughness);
        // Modified with approximate Visibility function that takes roughness into account
        // Original ((n+1)*N.H^n) / (8*Pi * L.H^3) didn't take into account roughness
        // and produced extremely bright specular at grazing angles

        half invV = lh * lh * smoothness + perceptualRoughness * perceptualRoughness; // approx ModifiedKelemenVisibilityTerm(lh, perceptualRoughness);
        half invF = lh;

        half specularTerm = ((specularPower + 1) * pow (nh, specularPower)) / (8 * invV * invF + 1e-4h);

    #ifdef UNITY_COLORSPACE_GAMMA
        specularTerm = sqrt(max(1e-4f, specularTerm));
    #endif

    #endif

    #if defined (SHADER_API_MOBILE)
        specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
    #endif
    #if defined(_SPECULARHIGHLIGHTS_OFF)
        specularTerm = 0.0;
    #endif

        // surfaceReduction = Int D(NdotH) * NdotH * Id(NdotL>0) dH = 1/(realRoughness^2+1)

        // 1-0.28*x^3 as approximation for (1/(x^4+1))^(1/2.2) on the domain [0;1]
        // 1-x^3*(0.6-0.08*x)   approximation for 1/(x^4+1)
    #ifdef UNITY_COLORSPACE_GAMMA
        half surfaceReduction = 0.28;
    #else
        half surfaceReduction = (0.6-0.08*perceptualRoughness);
    #endif

        surfaceReduction = 1.0 - roughness*perceptualRoughness*surfaceReduction;

        half grazingTerm = saturate(smoothness + (1-oneMinusReflectivity));
        half3 color =   (diffColor + specularTerm * specColor) * light.color * nl
                        + gi.diffuse * diffColor
                        + surfaceReduction * gi.specular * FresnelLerpFast (specColor, grazingTerm, nv);

        return half4(color, 1);
    }

    sampler2D_float unity_NHxRoughness1;
    half3 BRDF3_Direct1(half3 diffColor, half3 specColor, half rlPow4, half smoothness)
    {
        half LUT_RANGE = 16.0; // must match range in NHxRoughness() function in GeneratedTextures.cpp
        // Lookup texture to save instructions
        half specular = tex2D(unity_NHxRoughness1, half2(rlPow4, SmoothnessToPerceptualRoughness(smoothness))).r * LUT_RANGE;
    #if defined(_SPECULARHIGHLIGHTS_OFF)
        specular = 0.0;
    #endif

        return diffColor + specular * specColor;
    }

    half3 BRDF3_Indirect1(half3 diffColor, half3 specColor, UnityIndirect indirect, half grazingTerm, half fresnelTerm)
    {
        half3 c = indirect.diffuse * diffColor;
        c += indirect.specular * lerp (specColor, grazingTerm, fresnelTerm);
        return c;
    }

    // Old school, not microfacet based Modified Normalized Blinn-Phong BRDF
    // Implementation uses Lookup texture for performance
    //
    // * Normalized BlinnPhong in RDF form
    // * Implicit Visibility term
    // * No Fresnel term
    //
    // TODO: specular is too weak in Linear rendering mode
    half4 BRDF3_Unity_PBS1 (half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,
        float3 normal, float3 viewDir,
        UnityLight light, UnityIndirect gi)
    {
        float3 reflDir = reflect (viewDir, normal);

        half nl = saturate(dot(normal, light.dir));
        half nv = saturate(dot(normal, viewDir));

        // Vectorize Pow4 to save instructions
        half2 rlPow4AndFresnelTerm = Pow4 (float2(dot(reflDir, light.dir), 1-nv));  // use R.L instead of N.H to save couple of instructions
        half rlPow4 = rlPow4AndFresnelTerm.x; // power exponent must match kHorizontalWarpExp in NHxRoughness() function in GeneratedTextures.cpp
        half fresnelTerm = rlPow4AndFresnelTerm.y;

        half grazingTerm = saturate(smoothness + (1-oneMinusReflectivity));

        
        half3 color = BRDF3_Direct1(diffColor, specColor, rlPow4, smoothness);
        color *= light.color * nl;
        color += BRDF3_Indirect1(diffColor, specColor, gi, grazingTerm, fresnelTerm);

        
        return half4(color, 1);
    }



    // Default BRDF to use:
    //在 ProjectSetting->Graphics->TierSetting中设置
    //StandardShaderQuality = low(UNITY_PBS_USE_BRDF3)
    //StandardShaderQuality = Medium(UNITY_PBS_USE_BRDF2)
    //StandardShaderQuality = High(UNITY_PBS_USE_BRDF1)

    #if !defined (UNITY_BRDF_PBS1) // allow to explicitly override BRDF in custom shader
    // still add safe net for low shader models, otherwise we might end up with shaders failing to compile
    #if SHADER_TARGET < 30 || defined(SHADER_TARGET_SURFACE_ANALYSIS) // only need "something" for surface shader analysis pass; pick the cheap one
        #define UNITY_BRDF_PBS1 BRDF3_Unity_PBS1  //效果最差的BRDF
    #elif defined(UNITY_PBS_USE_BRDF3)
        #define UNITY_BRDF_PBS1 BRDF3_Unity_PBS1
    #elif defined(UNITY_PBS_USE_BRDF2)
        #define UNITY_BRDF_PBS1 BRDF2_Unity_PBS1
    #elif defined(UNITY_PBS_USE_BRDF1)
        #define UNITY_BRDF_PBS1 BRDF1_Unity_PBS1
    #else
        #error something broke in auto-choosing BRDF
    #endif
    #endif

    inline half OneMinusReflectivityFromMetallic1(half metallic)
    {
        // We'll need oneMinusReflectivity, so
        //   1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
        // store (1-dielectricSpec) in unity_ColorSpaceDielectricSpec.a, then
        //   1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
        //                  = alpha - metallic * alpha
        half oneMinusDielectricSpec = unity_ColorSpaceDielectricSpec.a;
        return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
    }

    inline half3 DiffuseAndSpecularFromMetallic1 (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
    {
        //计算镜面高光颜色
        //当metallic为0(即非金属时),返回unity_ColorSpaceDielectricSpec.rgb(0.04)
        //unity_ColorSpaceDielectricSpec.rgb表示的是绝缘体的通用反射颜色
        //迪士尼经大量测量用 0.04 来表示
        //当 metallic = 1 时(金属),返回Albedo,也就是物体本身的颜色
        specColor = lerp (unity_ColorSpaceDielectricSpec.rgb, albedo, metallic);
        oneMinusReflectivity = OneMinusReflectivityFromMetallic1(metallic);
        return albedo * oneMinusReflectivity;
    }

    //s : 物体表面数据信息
    //viewDir : 视线方向
    //gi : 全局光照(GI漫反射 和 GI镜面反射)
    inline half4 LightingStandard1 (SurfaceOutputStandard s, float3 viewDir, UnityGI gi)
    {
        s.Normal = normalize(s.Normal);

        half oneMinusReflectivity;
        //镜面高光颜色
        half3 specColor;
        s.Albedo = DiffuseAndSpecularFromMetallic1 (s.Albedo, s.Metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity);

        // shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)
        // this is necessary to handle transparency in physically correct way - only diffuse component gets affected by alpha
        //当开启半透明模式时,对 Alpha 进行相关计算
        half outputAlpha;
        s.Albedo = PreMultiplyAlpha (s.Albedo, s.Alpha, oneMinusReflectivity, /*out*/ outputAlpha);

        //具体的BRDF计算
        //s.Albedo : 物体表面的基础颜色
        //specColor : 镜面反射颜色
        //oneMinusReflectivity : 漫反射率 = 1 - 镜面反射率
        //s.Smoothness : 物体表面的光滑度
        //s.Normal : 物体表面的法线
        //viewDir : 视线方向
        //gi.light : 直接光信息
        //gi.indirect : GI间接光信息
        half4 c = UNITY_BRDF_PBS1 (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect);
        c.a = outputAlpha;
        return c;
    }


    //Standard的GI计算↓
    half3 Unity_GlossyEnvironment1 (UNITY_ARGS_TEXCUBE(tex), half4 hdr, Unity_GlossyEnvironmentData glossIn)
    {
        half perceptualRoughness = glossIn.roughness /* perceptualRoughness */ ;

        // TODO: CAUTION: remap from Morten may work only with offline convolution, see impact with runtime convolution!
        // For now disabled
        #if 0
        float m = PerceptualRoughnessToRoughness(perceptualRoughness); // m is the real roughness parameter
        const float fEps = 1.192092896e-07F;        // smallest such that 1.0+FLT_EPSILON != 1.0  (+1e-4h is NOT good here. is visibly very wrong)
        float n =  (2.0/max(fEps, m*m))-2.0;        // remap to spec power. See eq. 21 in --> https://dl.dropboxusercontent.com/u/55891920/papers/mm_brdf.pdf

        n /= 4;                                     // remap from n_dot_h formulatino to n_dot_r. See section "Pre-convolved Cube Maps vs Path Tracers" --> https://s3.amazonaws.com/docs.knaldtech.com/knald/1.0.0/lys_power_drops.html

        perceptualRoughness = pow( 2/(n+2), 0.25);      // remap back to square root of real roughness (0.25 include both the sqrt root of the conversion and sqrt for going from roughness to perceptualRoughness)
        #else
        // MM: came up with a surprisingly close approximation to what the #if 0'ed out code above does.
        //r = r * (1.7 - 0.7*r)
        //由于粗糙度与反射探针的mip变化不呈现线性正比,所以需要一个公式来改变
        perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness);
        #endif

        //UNITY_SPECCUBE_LOD_STEPS = 6,表示反射探针的mip级别有 6 档。粗糙度X6得到最终得mip级别
        half mip = perceptualRoughnessToMipmapLevel(perceptualRoughness);
        half3 R = glossIn.reflUVW;
        half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, R, mip);

        return DecodeHDR(rgbm, hdr);
    }



    //GI中的镜面反射
    inline half3 UnityGI_IndirectSpecular1(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn)
    {
        half3 specular;
        //如果开启了反射探针的Box Projection
        #ifdef UNITY_SPECCUBE_BOX_PROJECTION
        // we will tweak reflUVW in glossIn directly (as we pass it to Unity_GlossyEnvironment twice for probe0 and probe1), so keep original to pass into BoxProjectedCubemapDirection
        half3 originalReflUVW = glossIn.reflUVW;
        glossIn.reflUVW = BoxProjectedCubemapDirection (originalReflUVW, data.worldPos, data.probePosition[0], data.boxMin[0], data.boxMax[0]);
        #endif

        #ifdef _GLOSSYREFLECTIONS_OFF
        specular = unity_IndirectSpecColor.rgb;
        #else
        half3 env0 = Unity_GlossyEnvironment1 (UNITY_PASS_TEXCUBE(unity_SpecCube0), data.probeHDR[0], glossIn);
        //如果开启了反射探针混合
        #ifdef UNITY_SPECCUBE_BLENDING
        const float kBlendFactor = 0.99999;
        float blendLerp = data.boxMin[0].w;
        UNITY_BRANCH
        if (blendLerp < kBlendFactor)
        {
            #ifdef UNITY_SPECCUBE_BOX_PROJECTION
            glossIn.reflUVW = BoxProjectedCubemapDirection (originalReflUVW, data.worldPos, data.probePosition[1], data.boxMin[1], data.boxMax[1]);
            #endif

            half3 env1 = Unity_GlossyEnvironment (UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1,unity_SpecCube0), data.probeHDR[1], glossIn);
            specular = lerp(env1, env0, blendLerp);
        }
        else
        {
            specular = env0;
        }
        #else
        specular = env0;
        #endif
        #endif

        return specular * occlusion;
    }


    inline UnityGI UnityGlobalIllumination1 (UnityGIInput data, half occlusion, half3 normalWorld)
    {
        return UnityGI_Base(data, occlusion, normalWorld);
    }
    //GI计算
    inline UnityGI UnityGlobalIllumination1 (UnityGIInput data, half occlusion, half3 normalWorld, Unity_GlossyEnvironmentData glossIn)
    {
        //计算得出GI中的漫反射
        UnityGI o_gi = UnityGI_Base(data, occlusion, normalWorld);
        //计算得出GI中的镜面反射
        o_gi.indirect.specular = UnityGI_IndirectSpecular1(data, occlusion, glossIn);
        return o_gi;
    }
    float SmoothnessToPerceptualRoughness1(float smoothness)
    {
        return (1 - smoothness);
    }
    Unity_GlossyEnvironmentData UnityGlossyEnvironmentSetup1(half Smoothness, half3 worldViewDir, half3 Normal, half3 fresnel0)
    {
        Unity_GlossyEnvironmentData g;
        //粗糙度
        g.roughness /* perceptualRoughness */   = SmoothnessToPerceptualRoughness1(Smoothness);
        //反射球的采样坐标
        g.reflUVW   = reflect(-worldViewDir, Normal);

        return g;
    }

    //PBR光照模型的GI计算
    inline void LightingStandard_GI1(
        SurfaceOutputStandard s,
        UnityGIInput data,
        inout UnityGI gi)
    {
        //如果是延迟渲染PASS并且开启了延迟渲染反射探针的话
        #if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERS
        gi = UnityGlobalIllumination1(data, s.Occlusion, s.Normal);
        #else

        //Unity_GlossyEnvironmentData表示GI中的反射准备数据
        Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup1(s.Smoothness, data.worldViewDir, s.Normal,
                                                                    lerp(unity_ColorSpaceDielectricSpec.rgb, s.Albedo,
                                                                         s.Metallic));
        //进行GI计算并返回输出gi
        gi = UnityGlobalIllumination1(data, s.Occlusion, s.Normal, g);
        #endif
    }


#endif

Shader文件:

//Standard材质
Shader "MyShader/P2_2_8"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        [NoScaleOffset]_MetallicTex("Metallic(R) Smoothness(G) AO(B)",2D) = "white" {}
        [NoScaleOffset][Normal]_NormalTex("NormalTex",2D) = "bump" {}
        
        _Glossiness ("Smoothness", Range(0,1)) = 0.0
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _AO("AO",Range(0,1)) = 1.0
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
        }
        LOD 200

        // ---- forward rendering base pass:
        Pass
        {
            Name "FORWARD"
            Tags
            {
                "LightMode" = "ForwardBase"
            }

            CGPROGRAM
            // compile directives
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0
            #pragma multi_compile_instancing
            #pragma multi_compile_fog
            #pragma multi_compile_fwdbase

            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            #include "UnityPBSLighting.cginc"
            #include "AutoLight.cginc"
            #include "CGInclude/MyPhysicallyBasedRendering.cginc"
                
            sampler2D _MainTex;
            float4 _MainTex_ST;
            half _Glossiness;
            half _Metallic;
            fixed4 _Color;
            sampler2D _MetallicTex;
            half _AO;
            sampler2D _NormalTex;
            
            struct appdata
            {
                float4 vertex : POSITION;
                float4 tangent : TANGENT;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
                float4 texcoord1 : TEXCOORD1;
                float4 texcoord2 : TEXCOORD2;
                float4 texcoord3 : TEXCOORD3;
                fixed4 color : COLOR;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            // vertex-to-fragment interpolation data
            // no lightmaps:
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0; // _MainTex
                float3 worldNormal : TEXCOORD1;
                float3 worldPos : TEXCOORD2;
                #if UNITY_SHOULD_SAMPLE_SH
                    half3 sh : TEXCOORD3; // SH
                #endif
                //切线空间需要使用的矩阵
                float3 tSpace0 : TEXCOORD4;
                float3 tSpace1 : TEXCOORD5;
                float3 tSpace2 : TEXCOORD6;

                UNITY_FOG_COORDS(7)
                UNITY_SHADOW_COORDS(8)
            };

            // vertex shader
            v2f vert(appdata v)
            {
                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
                float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                float3 worldNormal = UnityObjectToWorldNormal(v.normal);

                //世界空间下的切线
                half3 worldTangent = UnityObjectToWorldDir(v.tangent);
                //切线方向
                half tangentSign = v.tangent.w * unity_WorldTransformParams.w;
                //世界空间下的副切线
                half3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
                //切线矩阵
                o.tSpace0 = float3(worldTangent.x, worldBinormal.x, worldNormal.x);
                o.tSpace1 = float3(worldTangent.y, worldBinormal.y, worldNormal.y);
                o.tSpace2 = float3(worldTangent.z, worldBinormal.z, worldNormal.z);

                o.worldPos.xyz = worldPos;
                o.worldNormal = worldNormal;

                // SH/ambient and vertex lights

                #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                    o.sh = 0;
                    // Approximated illumination from non-important point lights
                #ifdef VERTEXLIGHT_ON
                    o.sh += 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, worldPos, worldNormal);
                #endif
                    o.sh = ShadeSHPerVertex (worldNormal, o.sh);
                #endif


                UNITY_TRANSFER_LIGHTING(o, v.texcoord1.xy);

                UNITY_TRANSFER_FOG(o, o.pos); // pass fog coordinates to pixel shader

                return o;
            }

            // fragment shader
            fixed4 frag(v2f i) : SV_Target
            {
                UNITY_EXTRACT_FOG(i);
                
                float3 worldPos = i.worldPos.xyz;
                
                float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));

                SurfaceOutputStandard o;
                UNITY_INITIALIZE_OUTPUT(SurfaceOutputStandard, o);

                fixed4 mainTex = tex2D(_MainTex, i.uv);
                o.Albedo = mainTex.rgb * _Color;

                o.Emission = 0.0;

                fixed4 metallicTex = tex2D(_MetallicTex, i.uv);
                o.Metallic = metallicTex.r * _Metallic;
                o.Smoothness = metallicTex.g * _Glossiness;
                o.Occlusion = metallicTex.b * _AO;
                o.Alpha = 1;


                half3 normalTex = UnpackNormal(tex2D(_NormalTex,i.uv));
                half3 worldNormal = half3(dot(i.tSpace0,normalTex),dot(i.tSpace1,normalTex),dot(i.tSpace2,normalTex));
                o.Normal = worldNormal;


                // compute lighting & shadowing factor
                UNITY_LIGHT_ATTENUATION(atten, i, worldPos)

                // Setup lighting environment
                UnityGI gi;
                UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
                gi.indirect.diffuse = 0;
                gi.indirect.specular = 0;
                gi.light.color = _LightColor0.rgb;
                gi.light.dir = _WorldSpaceLightPos0.xyz;
                // Call GI (lightmaps/SH/reflections) lighting function
                UnityGIInput giInput;
                UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
                giInput.light = gi.light;
                giInput.worldPos = worldPos;
                giInput.worldViewDir = worldViewDir;
                giInput.atten = atten;
                #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                    giInput.lightmapUV = IN.lmap;
                #else
                giInput.lightmapUV = 0.0;
                #endif
                #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                    giInput.ambient = i.sh;
                #else
                giInput.ambient.rgb = 0.0;
                #endif
                giInput.probeHDR[0] = unity_SpecCube0_HDR;
                giInput.probeHDR[1] = unity_SpecCube1_HDR;
                #if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
                    giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
                #endif
                #ifdef UNITY_SPECCUBE_BOX_PROJECTION
                    giInput.boxMax[0] = unity_SpecCube0_BoxMax;
                    giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
                    giInput.boxMax[1] = unity_SpecCube1_BoxMax;
                    giInput.boxMin[1] = unity_SpecCube1_BoxMin;
                    giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
                #endif
                
                LightingStandard_GI1(o, giInput, gi);
                
                //return fixed4(gi.indirect.specular,1);
                
                // PBS的核心计算
                fixed4 c = LightingStandard1(o, worldViewDir, gi);
                
                UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fog
                UNITY_OPAQUE_ALPHA(c.a); //把c的Alpha置1
                
                return c;
            }
            ENDCG

        }
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/198615.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity工具脚本-检测资源文件夹是否有预制件是指定层级

效果&#xff1a; 先在菜单栏里面找到Tools/CheckPrefabLayers打开窗口 代码&#xff1a; using System.Collections; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine;public class CheckPrefabLayers : EditorWindow {public in…

直线(蓝桥杯)

直线 题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 在平面直角坐标系中&#xff0c;两点可以确定一条直线。如果有多点在一条直线上&#xff0c; 那么这些点中任意两点确定的直线是同一条。 给定平面上 2 3 个…

(Linux2.6内核)进程调度队列与切换

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 我们首先来了解几个概念 1. 进程在CPU上运行的时候&#xff0c;一定要运行完才行吗&#xff1f;答案是否定的&#xff0c;我们大部分的操作系统&#xff0c;主流就是分时操作系统&#xff0c;即基于时间片进程轮转执行的。 …

初次尝试http OAuth2验证的请求

第一次对接OAuth2验证的接口&#xff0c; 莫不着门道&#xff0c;后面获取token成功后&#xff0c;发现其实不难&#xff0c; 用postman举例&#xff1a; 其实挺简单。用客户端id秘钥 获取token---》后面的请求带上token 1,在head中增加 Authorization头 内容格式如上图&…

JAVA文件IO, File类, 字符流,字节流

文章目录 文件IO1. File2. IO流2.1 字符流2.1.1 Reader2.1.2 Writer 2.2 字节流2.2.1 InputStream2.2.2 FileInputStream2.2.3 利用Scanner进行字符读取2.2.4 OutputStream 文件IO I: Input, 从硬盘往内存读数据 O: Output, 从内存往硬盘输出数据 1. File Java 中通过 java…

服务器如何做好入侵防护

不管是企业还是个人&#xff0c;网上业务都需要依赖于服务器&#xff0c;服务器一旦被黑客入侵&#xff0c;企业会面临很多安全风险&#xff0c;比如业务被中断、数据被窃取、被加密勒索、服务器不稳定等影响。入侵防护&#xff0c;主机安全也是目前网络安全防护的一个重点。关…

通义千问 Qwen-7B-Chat-Int4 模型本地化部署

如需在本地或离线环境下运行本项目&#xff0c;需要首先将项目所需的模型下载至本地&#xff0c;通常开源 LLM 与 Embedding 模型可以从 HuggingFace 下载。 以本项目中默认使用的 LLM 模型 THUDM/ChatGLM2-6B 与 Embedding 模型 moka-ai/m3e-base 为例&#xff1a; 下载模型…

基于YOLO模型建筑工地个人防护设备目标检测

使用安全装备可以保护他们免受建筑工地的意外事故。据统计&#xff0c;每年有数以万计的工人在建筑工地受到严重伤害&#xff0c;造成终生困难。然而&#xff0c;通过自我监控来确保工人穿戴个人防护装备非常重要。在这方面&#xff0c;需要一个准确和快速的系统来检测工人是否…

怎么在电脑上做工作计划?

对于职场人士来说&#xff0c;想要提高工作效率&#xff0c;提前做好工作计划是非常有必要的。我们可以将所有的任务和工作计划都记录下来&#xff0c;并通过设定提醒时间来提醒自己&#xff0c;可以帮助我们更有效地管理时间&#xff0c;从而不会错过重要的工作和任务。 而在…

视觉测量基础

1. 相机模型 1.1 坐标系转换原理 世界坐标系(world Coords):点在真实世界中的位置&#xff0c;描述相机位置。 相机坐标系(Cameras Coords):以相机光学系统中心&#xff08;镜头中心&#xff09;为原点&#xff0c;建立相机坐标系。 图像物理坐标系(Film Coords):经过小孔成…

【Python 训练营】N_12 打印菱形图案

题目 打印菱形图案 分析 先把图形分成两部分来看待&#xff0c;前四行一个规律&#xff0c;后三行一个规律&#xff0c;利用双重for循环&#xff0c;第一层控制行&#xff0c;第二层控制列。 答案 # 方法一 for i in range(4):block **(2*i1)print({:^7}.format(block))…

前端面试灵魂提问

1.自我介绍 2.在实习中&#xff0c;你负责那一模块 3.any与unknow的异同 相同点&#xff1a;any和unkonwn 可以接受任何值 不同点&#xff1a;any会丢掉类型限制&#xff0c;可以用any 类型的变量随意做任何事情。unknown 变量会强制执行类型检查&#xff0c;所以在使用一个…

【扫雷】C语言实现扫雷小游戏

扫雷 游戏资源介绍游戏功能介绍游戏代码编写教程游戏功能测试自动排雷测试地雷标记测试取消标记测试踩雷判定测试重复游戏测试胜利判定测试 头文件游戏主体文件用户主体文件 游戏资源介绍 本次对之前的扫雷游戏进行了重新编写与更新&#xff0c;在此次的游戏实现中新增加了剩余…

uniapp中uni.navigateBack返回后刷新页面数据

文章目录 一、前言1.1、[uni.navigateBack](https://uniapp.dcloud.net.cn/api/router.html#navigateback) 二、方法2.1、父页面设置钩子函数onBackPress2.2、uni.$emit和uni.$on监听通知数据变更2.2.1、子页面2.2.2、父页面 2.3、onShow钩子函数处理数据2.3.1、子页面2.3.2、父…

解决ant-design-vue中Select组件v-model值为空字符串不显示placeholder的bug

方法一&#xff1a; 1.找到node_modules/ant-design-vue/es/vc-select/SingleSelector.js文件 搜索renderPlacehoder方法 将其修改为 const renderPlacehoder () > {const list props.values.filter(val > val.value ! );if (list[0]) {return null}... }2.在此文件中…

集合框架(二)LinkedList的常见使用

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍LinkedList的常见使用以及部分理论知识 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主收将持续更新学习记录获&#xff0c;友友们有任何问题可以在评论区留言 目…

vue3+ts 实现时间间隔选择器

需求背景解决效果视频效果balancedTimeElement.vue 需求背景 实现一个分片的时间间隔选择器&#xff0c;需要把显示时间段显示成图表&#xff0c;涉及一下集中数据转换 [“02:30-05:30”,“07:30-10:30”,“14:30-17:30”]‘[(2,5),(7,10),(14,17)]’[4, 5, 6, 7, 8, 9, 10, …

Windows10系统卸载服务和删除服务

记录一下Windows10系统卸载服务和删除服务 最近在使用自己win电脑的时候 发现服务里存在很久之前就没有使用的应用&#xff0c;对应的文件夹也都已经删除了&#xff0c;但是在win服务里一直存在&#xff0c;不知道会不会影响性能&#xff0c;看着吧还是强迫自己删掉好一些&…

安防视频监控/视频融合/云存储EasyCVR页面数据显示不全该如何解决?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

linux文件管理命令_切换创建复制移动删除查看修改

1.3 文件管理命令 1.3.1 cd&#xff1a;切换目录&#xff08;change directory&#xff09; cd 绝对路径/相对路径 # 根目录 [rootlocalhost ~]# cd / # 家目录 [rootlocalhost /]# cd [rootlocalhost /]# cd ~ # 父级目录 [rootlocalhost /]# cd .. # 返回上一次目录 [roo…
最新文章