《Unity Shader 入门精要》第6章 Unity 中的基础光照

news2024/11/15 3:53:06

第6章 Unity 中的基础光照

6.1 我们是如何看到这个世界的

通常来说我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象:

  • 首先,光线从光源(light source)中被发射出来
  • 然后,光线和场景中的一些物体相交,一些光线被吸收,一些被散射到其他方向
  • 最后,摄像机吸收一些光,产生了一张图片

光源

在光学中,我们使用辐照度(irradiance)来量化光,对于平行光,它的辐射度可通过计算在垂直于光线方向的单位面积上的单位时间内穿过的能量来得到。
在这里插入图片描述
因为辐照度和照射到物体表面时光线之间的距离 d/cos 成反比,所以其与 cos 成正比,cos 可以使用光源方向和表面法线 n 的点积来得到。

吸收和散射

光线由光源发射出去后,就会和一些物体相交,相交的结果有两个:散射(scattering)吸收(absorption)。散射只改变光线的方向,不改变光线的密度和颜色;而吸收只改变光线的密度和颜色,但不改变光线的方向。
光线在物体表面经过散射后,有两种方向:一种将会散射到物体内部,这种现象称为折射(refraction)透射(transmission);另一种将会散射到外部,这种现象被称为反射(reflection)。对于不透明物体,折射进入物体内部的光线还会继续与内部的颗粒相交,其中一些光线最后会重新发射出物体表面,而另一些则被物体吸收。那些从物体表面重新发射出的光线将具有和入射光线不同的方向分布和颜色。
在这里插入图片描述
为了区分这两种不同的散射方向,我们在光照模型中使用了不同的部分来计算它们:高光反射(specular)部分表示物体表面是如何反射光线的,而漫反射(diffuse)部分则表示有多少光线会被折射、吸收和散射出表面。根据入射光线的数量和方向,我们通常使用出射度(exitance)来描述它。辐照度和出射度之间是满足线性关系的,而它们之间的比值就是材质的漫反射和高光反射属性。

着色

着色(shading)是指根据材质属性、光源信息,使用一个等式去计算沿某个观察方向的出射度的过程,我们通常也把这个等式称为光照模型(Lighting Model)

BRDF

BRDF(Bidirectional Reflectance Distribution Function)指定义了光如何在不透明表面反射的四个实变量的函数。当给定入射光线的方向和辐照度后,BRDF 可以给出在某个出射方向上的光照能量分布。本章涉及的 BRDF 都是对真实场景进行理想化和简化后的模型,也就是说,它们并不能真实地反映物体和光线之间的交互,这些光照模型被称为是经验模型。尽管如此,这些经验模型仍然在实时渲染领域被应用了多年。有时我们希望可以更加真实地模拟光和物体的交互,这就出现了基于物理的 BRDF 模型,我们会在后续看到这些更加复杂的光照模型。

6.2 标准光照模型

虽然光照模型有很多种类,但在早期的游戏引擎中往往只使用了一个光照模型,那就是标准光照模型。它的基本方法是把进入摄像机内的光线分为4个部分,每个部分使用一种方法来计算它的贡献度:

  • 自发光(emissive),这个部分用于描述当给定一个方向时,一个表面本身会向该方向发射多少辐射度。如果没有使用全局光照(global illumination),这些自发光表面不会真的照亮周围的物体,而只是使它们自身看起来更亮了而已。
  • 高光反射(specular),这个部分用于描述当光线从光源照射到模型表面时,该表面在完全镜面反射方向散射多少辐射量。
  • 漫反射(diffuse),这个部分用来描述当光线从光源照射到模型表面时,该表面会向每个方向散射多少辐射量。
  • 环境光(ambient),这个部分用于描述其他所有的间接光照。

环境光

虽然标准光照模型的重点在于描述直接光照,但在真实世界中,物体也可以被间接光照(indirect light)照亮。间接光照指的是,在多个物体间进行反射,最后进入摄像机的光线。
在标准光照模型中,我们使用了一种被称为环境光的部分来近似模拟间接光照。环境光的计算非常简单,它通常是一个全局变量,即场景中的所有物体都使用这个环境光:
在这里插入图片描述

自发光

光线也可以直接从光源发射并进入摄像机。标准光照模型使用自发光来计算这部分的贡献度,它的计算也很简单,就是直接使用了该材质的自发光颜色:
在这里插入图片描述
通常的实时渲染中,自发光的表面并不会照亮周围的表面,也就是说,这个物体并不会被当作一个光源。Unity 5引入的全局光照系统则可以模拟这类自发光物体对周围物体的影响。

漫反射

漫反射光照是用于对那些被物体表面随机散射到各个方向的辐射度进行建模的,在漫反射中,视角的位置是不重要的,因为反射是完全随机的,因此可以认为在任何反射方向上的分布都是一样的。
但是,入射光线的角度很重要,漫反射光照符合兰伯特定律(Lambert's law): 反射光线的强度与表面法线和光源方向之间夹角的余弦值成正比。
在这里插入图片描述
其中,n^ 是表面法线,l^ 是指向光源的单位矢量,Mdiffuse 是材质的漫反射颜色,Clight是光源颜色。需要注意的是,我们需要防止法线和光源方向点乘的结果为负值,为此,我们使用取最大值的函数来将其截取到0,这可以防止物体被从后面来的光源照亮。

高光反射

这里的高光反射是一种经验模型,也就是说,它并不完全符合真实世界中的高光反射现象。计算高光反射需要知道的信息比较多:表面法线 n、视角方向 v、光源方向 l、反射方向 r。
在这里插入图片描述
在这四个矢量中,我们实际上只需要知道其中3个矢量即可,而第四个矢量——反射方向可以通过其他信息计算得到:
在这里插入图片描述
这样,我们就可以利用Phong 模型来计算高光反射的部分:
在这里插入图片描述
其中,Mgloss是材质的光泽度(gloss) ,也被称为反光度(shininess)。它用于控制高光区域的“亮点”有多宽,Mgloss 越大,亮点就越小。Mspecular 是材质的高光反射颜色,它用于控制该材质对于高光反射的强度和颜色。Clight 则是光源的颜色和强度。同样,这里也需要防止 v * r 的结果为负数。
和上述的 Phong 模型相比,Blinn 提出了一个简单的修改方法来得到类似的效果。它的基本思想是,避免计算反射方向。为此,Blinn 模型引入了一个新的矢量 h,它是通过对 v 和 l 取平均后再归一化得到的。
在这里插入图片描述
然后,使用 n 和 h 之间的夹角进行计算,而非 v 和 r 之间的夹角:
在这里插入图片描述
在这里插入图片描述
在硬件实现时,如果摄像机和光源距离模型足够远的话,Blinn 模型会快于 Phong 模型,这是因为,此时可以认为 v 和 l 都是定值,因此 h 将是一个常量。但是,当 v 或者 l 不是定值时,Phong 模型可能反而更快一些。
需要这两种光照模型都是经验模型,它们并不完全完全符合真实世界中的高光反射现象。

逐顶点还是逐像素

我们通常在实现上述的光照模型时有两种选择:

  • 在片元着色器中计算,也被称为逐像素光照(per-pixel lighting)。在逐像素光照中,我们会以每个像素为基础,得到它的法线,然后进行光照模型的计算。这种在面片之间对顶点法线进行插值的技术被称为Phong 着色(Phong shading),也被称为Phong插值或法线插值着色技术。
  • 在顶点着色器中计算,被称为逐顶点光照(per-vertex lighting),也被称为高洛德着色(Gouraud shading)。在逐顶点光照中,我们在每个顶点上计算光照,然后会在渲染图元内部进行线性插值,最后输出成像素颜色。
  • 由于顶点数目往往远小于像素数目,因此逐顶点光照的计算量往往要小于逐像素光照。但是,由于逐顶点光照依赖于线性插值来得到像素光照,因此,当光照模型中有非线性的计算(例如计算高光反射时)时,逐顶点光照就会出问题。

6.3 Unity 中的环境光与自发光

Unity 场景中环境光可以在 window -> Rending -> Ligthing 中设置
在这里插入图片描述
具体光线设置可直接参考 Unity 官方手册
另外要在 Unity 中实现自发光也非常简单,我们只需要在片元着色器输出最后的颜色之前,把材质的自发光颜色添加到输出颜色上即可。

6.4 在 Unity Shader 中实现漫反射光照模型

逐顶点光照

Shader "Chapter 6/Diffuse Vertex Level"
{
    Properties
    {
        // 定义漫反射颜色,默认为白色
        _diffuse ("Diffuse", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        Pass
        {
            // 只有设置正确的光照模式,才能得到 Unity 的内置光照变量,比如 _LightColor0
            Tags { "LightMode"="ForwardBase" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            // 为了使用 Unity 内置的一些变量(比如 _LightColor0),必须包含相应 Unity 内置文件
            #include "UnityLightingCommon.cginc"

            fixed4 _diffuse;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                fixed3 color : COLOR;
            };

            v2f vert (a2v v)
            {
                v2f o;
                // 坐标转换
                o.vertex = UnityObjectToClipPos(v.vertex);
                
                // 获取环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                // 转换法线向量至世界坐标系
                fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                // 场景中只有一个光源且是平行光时,光源方向可以由 _WorldSpaceLightPos0 得到,当有多个光源时无法这样使用
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                // saturate 函数用于将结果截取至 [0,1]
                fixed3 diffuse = _LightColor0.rgb * _diffuse.rgb * saturate(dot(worldNormal, worldLight));
                // 将漫反射颜色与环境光叠加,作为返回结果
                o.color = ambient + diffuse;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(i.color, 1.0);
            }
            ENDCG
        }
    }
    Fallback "Diffuse"
}

逐像素光照

Shader "Chapter 6/Diffuse Frag Level"
{
    Properties
    {
        // 定义漫反射颜色,默认为白色
        _diffuse ("Diffuse", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        Pass
        {
            // 只有设置正确的光照模式,才能得到 Unity 的内置光照变量,比如 _LightColor0
            Tags { "LightMode"="ForwardBase" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            // 为了使用 Unity 内置的一些变量(比如 _LightColor0),必须包含相应 Unity 内置文件
            #include "UnityLightingCommon.cginc"

            fixed4 _diffuse;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
            };

            v2f vert (a2v v)
            {
                // 顶点着色器只负责进行坐标转换
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 颜色计算移动至片元着色器中进行
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse = _LightColor0.rgb * _diffuse.rgb * saturate(dot(i.worldNormal, worldLight));
                fixed3 color = ambient + diffuse;
                return fixed4(color, 1.0);
            }
            ENDCG
        }
    }
    Fallback "Diffuse"
}

半兰伯特模型

无论是使用逐顶点还是逐像素,都会有一个问题:在光照无法到达的区域,模型的外观通常是全黑的,没有任何明暗变化,这会使模型的背光区域看起来就像一个平面一样,失去了模型细节表现。为此,有一种改善技术被提出来,这就是半兰伯特(Half Lambert)光照模型。
在这里插入图片描述
可以看出,与原兰伯特模型相比,半兰伯特光照模型没有使用 max 操作来防止和的点积为负值,而是对其结果进行了一个倍的缩放再加上一个大小的偏移。绝大多数情况下,和的值均为0.5,即公式为:
在这里插入图片描述
通过这样的方式,我们可以把 n*l 的结果范围从[−1, 1]映射到[0, 1]范围内。也就是说,对于模型的背光面,在原兰伯特光照模型中点积结果将映射到同一个值,即0值处;而在半兰伯特模型中,背光面也可以有明暗变化,不同的点积结果会映射到不同的值上。需要注意的是,半兰伯特是没有任何物理依据的,它仅仅是一个视觉加强技术。
下面是半兰伯特模型的逐顶点实现:

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Chapter 6/Diffuse Half Lambert"
{
    Properties
    {
        _diffuse ("Diffuse", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        Pass
        {
            Tags { "LightMode"="ForwardBase" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"

            fixed4 _diffuse;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                fixed3 color : COLOR;
            };

            v2f vert (a2v v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                // 半兰伯特模型算法
                fixed3 halfLambert = dot(worldNormal, worldLight) * 0.5 + 0.5;
                fixed3 diffuse = _LightColor0.rgb * _diffuse.rgb * halfLambert;
                o.color = ambient + diffuse;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(i.color, 1.0);
            }
            ENDCG
        }
    }
    Fallback "Diffuse"
}

下面是逐顶点漫反射光照、逐像素漫反射光照和半兰伯特光照的对比效果:
在这里插入图片描述

6.5 Unity Shader 实现高光反射光照模型

逐顶点光照

Shader "Chapter 6/Specular Vertex Level"
{
    Properties
    {
        // 定义漫反射颜色,默认为白色
        _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
        // 高光反射颜色
        _Specular ("Specular", Color) = (1, 1, 1, 1)
        // 用于控制高光区域大小
        _Gloss ("Gloss", Range(8.0, 256)) = 20
    }

    SubShader
    {
        Pass
        {
            // 只有设置正确的光照模式,才能得到 Unity 的内置光照变量,比如 _LightColor0
            Tags { "LightMode"="ForwardBase" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            // 为了使用 Unity 内置的一些变量(比如 _LightColor0),必须包含相应 Unity 内置文件
            #include "UnityLightingCommon.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                fixed3 color : COLOR;
            };

            v2f vert (a2v v)
            {
                v2f o;
                // 坐标转换
                o.vertex = UnityObjectToClipPos(v.vertex);
                
                // 环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                /*漫反射*/
                fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));

                /*高光反射*/
                // 函数 reflect 可直接根据入射光角度与法线向量计算出反射方向
                fixed3 reflectDir = normalize(reflect(-worldLight, worldNormal));
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);

                // 叠加环境光、漫反射、高光反射,作为返回结果
                o.color = ambient + diffuse + specular;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(i.color, 1.0);
            }
            ENDCG
        }
    }
    Fallback "Specular"
}

逐像素光照

Shader "Chapter 6/Specular Frag Level"
{
    Properties
    {
        // 定义漫反射颜色,默认为白色
        _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
        // 高光反射颜色
        _Specular ("Specular", Color) = (1, 1, 1, 1)
        // 用于控制高光区域大小
        _Gloss ("Gloss", Range(8.0, 256)) = 20
    }

    SubShader
    {
        Pass
        {
            // 只有设置正确的光照模式,才能得到 Unity 的内置光照变量,比如 _LightColor0
            Tags { "LightMode"="ForwardBase" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            // 为了使用 Unity 内置的一些变量(比如 _LightColor0),必须包含相应 Unity 内置文件
            #include "UnityLightingCommon.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                fixed3 worldNormal : TEXCOORD0;
                fixed3 worldPos : TEXCOORD1;
            };

            v2f vert (a2v v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                /*漫反射*/
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(i.worldNormal, worldLight));

                /*高光反射*/
                // 函数 reflect 可直接根据入射光角度与法线向量计算出反射方向
                fixed3 reflectDir = normalize(reflect(-worldLight, i.worldNormal));
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);

                // 叠加环境光、漫反射、高光反射,作为返回结果
                fixed3 color = ambient + diffuse + specular;
                return fixed4(color, 1.0);
            }
            ENDCG
        }
    }
    Fallback "Specular"
}

Blinn-Phong光照模型的逐像素实现

Shader "Chapter 6/Specular Blinn-Phong"
{
    Properties
    {
        // 定义漫反射颜色,默认为白色
        _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
        // 高光反射颜色
        _Specular ("Specular", Color) = (1, 1, 1, 1)
        // 用于控制高光区域大小
        _Gloss ("Gloss", Range(8.0, 256)) = 20
    }

    SubShader
    {
        Pass
        {
            // 只有设置正确的光照模式,才能得到 Unity 的内置光照变量,比如 _LightColor0
            Tags { "LightMode"="ForwardBase" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            // 为了使用 Unity 内置的一些变量(比如 _LightColor0),必须包含相应 Unity 内置文件
            #include "UnityLightingCommon.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                fixed3 worldNormal : TEXCOORD0;
                fixed3 worldPos : TEXCOORD1;
            };

            v2f vert (a2v v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                /*漫反射*/
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(i.worldNormal, worldLight));

                /*高光反射*/
                // 函数 reflect 可直接根据入射光角度与法线向量计算出反射方向
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
                // Blinn-Phong 模型算法
                fixed3 halfDir = normalize(worldLight + viewDir);
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(halfDir, i.worldNormal)), _Gloss);

                // 叠加环境光、漫反射、高光反射,作为返回结果
                fixed3 color = ambient + diffuse + specular;
                return fixed4(color, 1.0);
            }
            ENDCG
        }
    }
    Fallback "Specular"
}

下面是以上三种实现(从左到右)的对比效果图:
在这里插入图片描述

  • 按逐像素的方式处理光照可以得到比逐顶点更加平滑的高光效果
  • Blinn-Phong光照模型的高光反射部分看起来更大、更亮一些。在实际渲染中,绝大多数情况我们都会选择Blinn-Phong光照模型。

6.6 使用 Unity 内置函数

函数详见 UnityCG.cginc中源码,此处省略。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript while 循环

文章目录JavaScript while 循环while 循环do/while 循环比较 for 和 while笔记列表JavaScript while 循环 只要指定条件为 true,循环就可以一直执行代码块。 while 循环 while 循环会在指定条件为真时循环执行代码块。 语法 while (条件) {需要执行的代码 }本例中…

Redis内部的阻塞式操作以及应对方法

Redis之所以被广泛应用,很重要的一个原因就是它支持高性能访问,也正因为这样,我们必须要重视所有可能影响Redis性能的因素,不仅要知道具体的机制,尽可能避免异常的情况出现,还要提前准备好应对异常的方案。…

MySQL进阶篇之索引2

02、索引 前四节内容:https://blog.csdn.net/kuaixiao0217/article/details/128753999 2.5、SQL性能分析 2.5.1、查看执行频次 1、SQL执行频率 MySQL客户端连接成功后,通过show [session|global] status命令可以提供服务器状态信息。 通过如下指令…

Computer architecture Cyber security Quantum computing交友

如果您也是computer architecture方向的博士硕士,希望交个朋友,欢迎后台私信。 当然,如果您也是 Cyber SecurityQuantum ComputingHigh Performance Computing 方向的博士硕士,想要交流,也可以私信。

学习记录669@项目管理之项目合同管理

有效合同原则 有效合同应具备以下特点: (1)签订合同的当事人应当具有相应的民事权利能力和民事行为能力。 (2)意思表示真实。 (3)不违反法律或社会公共利益 与有效合同相对应,需要避免无效合同。无效合同通常需具备下列任一情形: (1)一方以欺诈、胁迫的手段订立合…

【模拟CMOS集成电路】电路失调与CMRR—— 随机失调与系统失调分析(1)

电路失调与CMRR—— 随机失调与系统失调分析(1)前言1.1失调1.2失调电路模型1.2.1随机失调电路模型(1)电阻失配(2)跨导失配(3)电流镜的随机失调1.2.2系统失调前言 本文主要内容是失调…

深入剖析JVM垃圾收集器

文章目录前言1、新生代垃圾收集器1.1、Serial1.2、ParNew1.3、Parallel Scavenge2、老年代垃圾收集器2.1、Serial Old2.2、Parallel Old2.3、CMS(Concurrent Mark Sweep)3、全堆垃圾收集器3.1、Garbage First(G1)前言 参考资料&am…

ConfigurationProperties将配置绑定到bean的过程分析

概述 ConfigurationProperties是一个大家常用的注解。有一些系统配置,经常放在yml中,然后通过spring注入到bean中。 一般这些配置都是通过在spring生命周期的某一个环节,将属性注入进去的。 ConfigurationProperties就是利用了org.springf…

AC500 基于 Profinet 通讯连接变频器

硬件连接 使用 PM583-ETH 作为 Profinet 通讯的主站,ACS800 变频器 RETA-02 作为 Profinet 通讯的从站 2 ABB 变频器设置 以安装有 RETA-02 总线适配器的 ACS800 变频器为例,参照下表进行参数设定。详 细内容请参考变频器手册和 RETA-02 用户手册。表中…

Python 超强命令行解析工具 argparse !

在工作中,我们经常需要从命令行当中解析出指定的参数,而 Python 也提供了相应的标准库来做这件事情,比如 sys, optparse, getopt, argparse。这里面功能最强大的莫过于 argparse,下面就来看看它用法。import argparse# 使用 argpa…

计算机视觉OpenCv学习系列:第七部分、图像操作-3

第七部分、图像操作-3第一节、图像统计信息1.像素值统计2.函数支持说明3.代码练习与测试第二节、图像直方图1.图像直方图定义2.直方图函数3.代码练习与测试第三节、图像直方图均衡化1.直方图均衡化2.直方图均衡化函数3.代码练习与测试学习参考第一节、图像统计信息 1.像素值统…

零基础学JavaWeb开发(二十一)之 spring框架(4)

3、AOP详解 3.1、Aop常用术语 1.连接点(Join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。类中的哪些方法可以被增强,这些…

详解动态规划01背包问题--JavaScript实现

对其他动态规划问题感兴趣的,也可以查看详解动态规划最少硬币找零问题--JavaScript实现详解动态规划最长公共子序列--JavaScript实现一开始在接触动态规划的时候,可能会云里雾里,似乎能理解思路,但是又无法准确地表述或者把代码写…

车辆占用应急车道识别抓拍系统 opencv

车辆占用应急车道识别抓拍系统通过opencvpython人工智能识别技术,对高速公路应急车道进行不间断实时监测,当监测到应急车道上有车辆违规占用时,立即告警提醒后台人员及时处理避。OpenCV的全称是Open Source Computer Vision Library&#xff…

【18】C语言 | 数组详解

目录 1、数组的格式 2、下列有什么区别 3、维数组的使用 4、*p 和 int* p arr 的含义 5、二维数组:打印一个二维数组 6、二维数组在数组中的存储 7、数组作为函数参数 8、数组名是数组首元素的地址 1、数组的格式 数组是一组相同类型元素的集合。 数组的创…

20230123英语学习

Interesting Studies to Spark Your Interest in the Research Field 科研也可以很有趣!盘点那些好玩的研究 When it comes to picking studies worth reading, what scientists deem an interesting science article might be perceived differently by a person…

【Datewhale一起吃瓜 Task2】啃瓜第三章

文章目录线性模型关键:找到合适的w和b如何找到合适的 w和b?偏导为什么可以?推广线性模型 任务:找出一条线能够对数据进行划分或预测趋势 关键:找到合适的w和b 更适合于连续性的数值,如果数据是离散的如色…

AcWing 1020. 潜水员(二维费用背包)

一、问题 二、思路 这道题其实很容易看出是一个二维费用背包的变形,如果我们将氧气看作体积,将氮气看作价值的话,这道题就变成了从iii个物品里面选,体积至少为mmm,价值至少为nnn的条件下,所携带的物品的最…

Maplab:一个用于视觉惯性建图和定位研究的开源框架

摘要 鲁棒且精确的视觉惯性估计是当今机器人领域的重要挑战。能够用先验地图(prior map)进行定位(localize)并获得准确且无漂移的姿态估计,可以推动该系统的适应性。然而,目前大多数可用的解决方案都集中在单次使用,缺乏定位能力或端到端流水…

Java基本类型和包装类什么情况下判断相等(“==“或“equals“)?

[1] 先讨论一个面试题 int a 1; Integer b 1; Integer c new Integer(1); Integer d Integer.valueOf(1); int e d; int f d.intValue();请问以下式子的值?为什么? a b // true a c // true b c // false[2] ""与"equals"…