Unity shader - 纹理采样

news2024/10/6 8:30:41

目录

1.什么是UV  

2.凹凸纹理

3.渐变纹理映射

4.遮罩纹理


1.什么是UV  

对于三维模型,有两个最重要的坐标系统,一是顶点的位置(X,Y,Z)坐标,另一个就是UV坐标。什么是UV?简单的说,就是贴图影射到模型表面的依据。 完整的说,其实应该是UVW(因为XYZ已经用过了,所以另选三个字母表示)。U和V分别是图片在显示器水平、垂直方向上的坐标,取值一般都是0~1,也 就是(水平方向的第U个像素/图片宽度,垂直方向的第V个像素/图片高度)。那W呢?贴图是二维的,何来三个坐标?嗯嗯,W的方向垂直于显示器表面,一般 用于程序贴图或者某些3D贴图技术(记住,确实有三维贴图这种概念!),对于游戏而言不常用到,所以一般我们就简称UV了。

定义纹理:

Properties
{
    // 主纹理
    _MaxTex ("_MaxTex",2d) = "white" {}
}

sampler2D _MaxTex;
float4 _MaxTex_ST;

_MainTex_ST:表示该纹理的偏移缩放属性,在属性面板上表现出tilling 和 offset ,float4 类型xy 存的是缩放  zw 存的是偏移

通过 _MainTex_ST 重新计算uv  texcord *_MainTex_ST.xy+_MainTex_ST.zw

 或者使用内置方法 TRANSFORM_TEX(uv,_MainTex)

tex2D(_MainTex,uv) 对_MainTex采样,得到该uv 坐标下的颜色

上完整代码:这里加了漫反射和高光的代码有不懂的可以看:漫反射,高光反射

Shader "Unlit/005"
{
    Properties
    {
        // 漫反射颜色
        _Diffuse ("Diffuse",Color) = (1,1,1,1)
        // 高光反射颜色值
        _Specular ("Specular",Color) = (1,1,1,1)
        // 高光反射值
        _Gloss ("_Gloss",range(1,100)) = 5
        // 主纹理
        _MaxTex ("_MaxTex",2d) = "white" {}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            sampler2D _MaxTex;
            float4 _MaxTex_ST;
            float4 _Specular;
            float4 _Diffuse;
            float _Gloss;
            
            struct v2f
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD1;
                float3 worldNormal : TEXCOORD0;
                float3 viewDir : TEXCOORD2;
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                // 将对象空间中的点变换到齐次坐标中的摄像机裁剪空间
                o.vertex = UnityObjectToClipPos(v.vertex);
                // 计算uv坐标
                o.uv = TRANSFORM_TEX(v.texcoord,_MaxTex);
                // o.uv = v.texcoord.xy * _MaxTex_ST.xy + _MaxTex_ST.zw;
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.viewDir = normalize(WorldSpaceViewDir(o.vertex));
                return o;   
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 纹理采样
                float3 texColor = tex2D(_MaxTex,i.uv);

                // 计算漫反射
                float3 diffuse = texColor * _LightColor0.rgb * _Diffuse.rgb * (dot(_WorldSpaceLightPos0.xyz,i.worldNormal) * 0.5 + 0.5);
                // 计算高光
                float3 halfVector = normalize(normalize(_WorldSpaceLightPos0.xyz) + i.viewDir);
                // 计算高光
                float3 specular = texColor * _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(halfVector,i.worldNormal)),_Gloss);
                
                return float4(diffuse + specular,1);
            }
            ENDCG
        }
    }
}

2.凹凸纹理

凹凸纹理的本质是通过一张存储了顶点法线坐标的图片,营造出一种凹凸的效果,模型本身并没有改变

为什么改变了法线就能营造出凹凸的结果,因为法线的作用就是就算光照,现实生活中,你看到的物体觉得很立体,就是因为光照到物体上产生了阴影,有明暗区分,所以觉得很立体,凹凸贴图通过改变法线,间接改变了光照的方向,和阴影产生的结果,让你看起来有种立体的感觉。

凹凸纹理 分为两种:

  • 高度贴图:高度贴图,存储的并不是顶点的法线,而是强度值,表示该像素的海拔高度,颜色越深,表示越往里凹,因为越凹越看不见,如上高度映射图,越白的地方高度越高,越黑的地方高度越低,需要根据灰度值,转到表面法线计算比较复杂,也不利于美术制作。

  • 法线贴图: 存储的就是顶点的法线坐标.

法线纹理中存储的是表面的法线方向。由于法线方向的各个分量范围在[ − 1 , 1 ] 之间,而像素的分量范围在[ 0 , 1 ] 之间,所以需要进行映射

pixel=normal∗0.5+0.5

所以,我们在Shader中对法线纹理进行纹理采样后,还要对结果进行一次逆映射,即

normal=pixel∗2−1

为什么法线贴图大部分都是浅蓝色呢?

浅蓝色表示改法线贴图存储的是切线空间下的法线,顶点的原始法线是(0,0,1),映射到像素上RGB(0.5,0.5,1),浅蓝色.

法线贴图有两种形式:

  • 模型空间下的法线坐标

  • 切线空间下的法线坐标

模型空间法线:

优点: 直接就能获取到模型的法线,不需要空间转换,因为所有的法线都是在同一坐标空间下,所以边角处通过线性插值得到的效果更加平滑.

缺点:因为 模型空间存储的是绝对法线,只适用于创建该法线的的模型,如果换个模型就得不到正确的结果,且无法进行uv偏移,

切线空间下法线

  • 自由度更高。
  • 切线空间下的法线纹理是相对的法线纹理,即使在不同网格上也可以得到合理的结果。
  • 可以进行uv 动画,可以通过移动一个纹理的uv坐标来实现凹凸移动的效果。
  • 可以重用法线纹理。
  • 可以压缩,切线空间下,z轴总是正方向的,可以同过xy推导出 z坐标 = sqrt(1-max(0,dot(xy,xy)))。

如何实现?

要计算光照,就要统一坐标空间,要么在切线空间,要么在世界空间。

切线空间: 在顶点中将 光源方向 和 视角方向 转换到切线空间然后在片元中计算光照模型

世界空间:法线转换到世界空间下,因为有时候我们需要用到世界空间下的法线坐标和光照方向比如对cubemap 进行环境采样,因为纹理坐标是逐像素的,所以要在片元着色器中进行采样然后进行一个矩阵变换,比上面多了一次矩阵运算。

我们先来实现以下 切线空间的纹理映射:

接下来需要将光源方向和视角方向变换到切线空间,要完成这步操作需要求出变换所需的旋转矩阵。我们已知的是变换后的三个向量:

  • b = (0,1,0)
  • t = (1,0,0)
  • n = (0,0,1)

假设变换前的三个向量为:

  • b′ = ( xb,yb,zb) 
  • t′ = (xt,yt, zt)
  • n′ = ( xn,yn,zn)

变换矩阵为 :

 可以求得 c1  = t′ , c2 = b′ , c3 = n′ 。

shader 代码:

// 求副切线向量 float3 biNormal = cross(normalize(v.normal),normalize(v.tangent.xyz))*v.tangent.w; // 求出旋转矩阵 float3x3 rotation = float3x3(v.tangent.xyz,biNormal,v.normal);

可以使用unity内置的自定义写法

TANGENT_SPACE_ROTATION

在 UnityCG.cginc中 实际上就是帮我们写了上面求出的切线空间旋转变换矩阵

Shader "Unlit/006"
{
    Properties
    {
        // 漫反射颜色
        _Diffuse ("Diffuse",Color) = (1,1,1,1)
        // 高光反射颜色值
        _Specular ("Specular",Color) = (1,1,1,1)
        // 高光反射值
        _Gloss ("_Gloss",range(1,100)) = 5
        // 主纹理
        _MaxTex ("MaxTex",2d) = "white" {}
        // 法线纹理
        _BumpMap ("Bump Map",2d) = "white" {}
        // 控制凹凸程度
        _BumpScale ("Bump Scale",float) = 1
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM 
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            sampler2D _MaxTex;
            float4 _MaxTex_ST;
            float4 _Specular;
            float4 _Diffuse;
            float _Gloss;
            
            sampler2D _BumpMap; 
            float4 _BumpMap_ST;
            float _BumpScale;
            
            struct v2f
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float2 normalUv : TEXCOORD1;
                float3 lightDir : TEXCOORD2;
                float3 viewDir : TEXCOORD3;
            };

            v2f vert (appdata_tan v)
            {
                v2f o;
                // 将对象空间中的点变换到齐次坐标中的摄像机裁剪空间
                o.vertex = UnityObjectToClipPos(v.vertex);
                // 计算uv坐标
                o.uv = TRANSFORM_TEX(v.texcoord,_MaxTex);
                o.normalUv = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
                
                // TANGENT_SPACE_ROTATION
                // 求副切线向量
	            float3 biNormal = cross(normalize(v.normal),normalize(v.tangent.xyz))*v.tangent.w;
	            // 求出旋转矩阵
            	float3x3 rotation = float3x3(v.tangent.xyz,biNormal,v.normal);
            	
            	// 求切线空间的光源方向
            	o.lightDir = normalize(mul(rotation,UnityWorldToObjectDir(_WorldSpaceLightPos0.xyz)));
            	// 切线空间视角方向
            	o.viewDir = normalize(mul(rotation,ObjSpaceLightDir(v.vertex)));
            	
                return o;   
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 主纹理采样
                fixed4 texColor = tex2D(_MaxTex,i.uv);
                // 法线贴图采样
                fixed4 packedNormal = tex2D(_BumpMap,i.normalUv);
                fixed3 tangentNormal;
                tangentNormal.xy = (packedNormal.xy * 2 - 1 ) * _BumpScale;
                tangentNormal.z = sqrt(1 - max(0,dot(tangentNormal.xy,tangentNormal.xy)));
                
                // 用内置方法 UnpackNormal 图片类型为NormalMap  
                //fixed3 tangentNormal = UnpackNormal(packedNormal);  
                // tangentNormal.xy *= _BumpScale;

                // 计算漫反射
                float3 diffuse = texColor.rgb * _LightColor0.rgb * _Diffuse.rgb * (dot(i.lightDir,tangentNormal) * 0.5 + 0.5);
                // 计算高光
                float3 halfVector = normalize(i.lightDir + i.viewDir);
                // 计算高光
                float3 specular = texColor.rgb * _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(halfVector,tangentNormal)),_Gloss);
                
                return float4(diffuse + specular,1);
            }
            ENDCG
        }
    }
}

给上主纹理贴图,和法线贴图,法线贴图可以用主纹理在PhotoShop中,滤镜->3D->生成法线贴图就制作好了,不过下项目中通常是美术给的

shader效果如下:左边是没用法线的,右边是加了法线纹理的可以看出加了法线纹理更有凹凸感

我们在用 世界空间纹理映射实现以下:

我们需要在顶点着色器中计算出从切线空间转换到世界空间的变换矩阵,但一个插值寄存器最多只能存储float4大小的变量,所以对于矩阵这种变量,我们需要定义三个float3类型的变量拆开存储。但为了充分利用插值寄存器的空间,我们将其定义为float4类型,多出来的一个维度可以用来存储世界空间下的顶点位置。uv变量也可以定义成float4类型,其中xy分量用来存储贴图纹理坐标,zw分量用来存储法线纹理坐标。

直接上代码了,都在代码里详细备注:

Shader "Unlit/007"
{
    Properties
    {
        // 漫反射颜色
        _Diffuse ("Diffuse",Color) = (1,1,1,1)
        // 高光反射颜色值
        _Specular ("Specular",Color) = (1,1,1,1)
        // 高光反射值
        _Gloss ("_Gloss",range(1,100)) = 5
        // 主纹理
        _MaxTex ("MaxTex",2d) = "white" {}
        // 法线纹理
        _BumpMap ("Bump Map",2d) = "white" {}
        // 控制凹凸程度
        _BumpScale ("Bump Scale",float) = 1
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM 
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            sampler2D _MaxTex;
            float4 _MaxTex_ST;
            float4 _Specular;
            float4 _Diffuse;
            float _Gloss;
            
            sampler2D _BumpMap; 
            float4 _BumpMap_ST;
            float _BumpScale;
            
            struct v2f
            {
                float4 vertex : POSITION;
                float4 uv : TEXCOORD0;
                float4 T2w0 : TEXCOORD1;
                float4 T2w1 : TEXCOORD2;
                float4 T2w2 : TEXCOORD3;
            };

            v2f vert (appdata_tan v)
            {
                v2f o;
                // 将对象空间中的点变换到齐次坐标中的摄像机裁剪空间
                o.vertex = UnityObjectToClipPos(v.vertex);
                // 计算uv坐标
                o.uv.xy = TRANSFORM_TEX(v.texcoord,_MaxTex);
                o.uv.zw = TRANSFORM_TEX(v.texcoord,_BumpMap);
                float2 normalUv = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
               
                fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
                fixed3 worldBiTangent = cross(worldTangent,worldNormal) * v.tangent.w;
            	fixed3 worldPos = UnityObjectToWorldDir(v.vertex.xyz);
            	
            	o.T2w0 = float4(worldTangent.x,worldBiTangent.x,worldNormal.x,worldPos.x); 
            	o.T2w1 = float4(worldTangent.y,worldBiTangent.y,worldNormal.y,worldPos.y); 
            	o.T2w2 = float4(worldTangent.z,worldBiTangent.z,worldNormal.z,worldPos.z); 
            	
                return o;   
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 主纹理采样
                fixed4 texColor = tex2D(_MaxTex,i.uv.xy);
                // 法线贴图采样
                fixed4 packedNormal = tex2D(_BumpMap,i.uv.zw);
                
                
                //fixed3 tangentNormal;
                //tangentNormal.xy = (packedNormal.xy * 2 - 1 ) * _BumpScale;
                //tangentNormal.z = sqrt(1 - max(0,dot(tangentNormal.xy,tangentNormal.xy)));
                
                // 用内置方法 UnpackNormal 图片类型为NormalMap  
                fixed3 tangentNormal = UnpackNormal(packedNormal);  
                tangentNormal.xy *= _BumpScale;
                
                // 将切线空间法线变换到世界空间
                fixed3 worldNormal = normalize(fixed3(dot(i.T2w0.xyz,tangentNormal),dot(i.T2w1.xyz,tangentNormal),dot(i.T2w2.xyz,tangentNormal)));

                // 计算漫反射
                float3 diffuse = texColor.rgb * _LightColor0.rgb * _Diffuse.rgb * (dot(_WorldSpaceLightPos0.xyz,worldNormal) * 0.5 + 0.5);
                // 计算高光
                float3 viewDir = _WorldSpaceCameraPos.xyz - float3(i.T2w0.z,i.T2w1.z,i.T2w2.z);
                float3 halfVector = normalize(_WorldSpaceLightPos0.xyz + viewDir);
                // 计算高光
                float3 specular = texColor.rgb * _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(halfVector,worldNormal)),_Gloss);
                
                return float4(diffuse + specular,1);
            }
            ENDCG
        }
    }
}

效果如下:分别为 无法线贴图,切线空间纹理映射,世界空间纹理映射

3.渐变纹理映射

纹理不止能用来定义一个物体的颜色,也可以用来存储任何表面的属性。一种常见的用法就是使用渐变纹理来控制漫反射光照的结果。使用一张从冷到暖的渐变图片用于纹理采样,并将采样结果用于计算漫反射模型。就可以得到一种插画风格的渲染效果,物体的轮廓线相比于传统的漫反射更加明显。很多卡通风格的渲染中都使用了这种技术。

Shader "Unlit/008"
{
    Properties
    {
        // 漫反射颜色
        _Diffuse ("Diffuse",Color) = (1,1,1,1)
        // 高光反射颜色值
        _Specular ("Specular",Color) = (1,1,1,1)
        // 高光反射值
        _Gloss ("_Gloss",range(1,100)) = 5
        // 主纹理
        _MaxTex ("_MaxTex",2d) = "white" {}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM 
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            sampler2D _MaxTex;
            float4 _MaxTex_ST;
            float4 _Specular;
            float4 _Diffuse;
            float _Gloss;
            
            struct v2f
            {
                float4 vertex : POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 viewDir : TEXCOORD2;
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                // 将对象空间中的点变换到齐次坐标中的摄像机裁剪空间
                o.vertex = UnityObjectToClipPos(v.vertex);
                // 计算uv坐标
                //o.uv = TRANSFORM_TEX(v.texcoord,_MaxTex);
                // o.uv = v.texcoord.xy * _MaxTex_ST.xy + _MaxTex_ST.zw;
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.viewDir = normalize(WorldSpaceViewDir(o.vertex));
                return o;   
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 半兰伯特漫反射
                float halfLambert = (dot(_WorldSpaceLightPos0.xyz,i.worldNormal) * 0.5 + 0.5);
                // 采样渐变纹理 使用半兰伯特做uv坐标
                float3 texColor = tex2D(_MaxTex,float2(halfLambert,halfLambert));
                float3 diffuse = texColor * _LightColor0.rgb * _Diffuse.rgb * texColor;
                // 计算高光
                float3 halfVector = normalize(normalize(_WorldSpaceLightPos0.xyz) + i.viewDir);
                // 计算高光
                float3 specular = texColor * _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(halfVector,i.worldNormal)),_Gloss);
                
                return float4(diffuse + specular,1);
            }
            ENDCG
        }
    }
}

效果:

4.遮罩纹理

在游戏中地形场景中,假设有草地和沙漠的接壤处,为了保护各自区域的反射值,我们就会用到了遮罩纹理,假设草地需要高光,沙漠不需要高光。

实现非常简单,就是增加一张遮罩纹理,需要高光的为白色,不需要的地方为黑色,因为白色的rgb值为 255/255 = 1。同常只需要一个通道就可以实现了,然后在计算高光的地方 乘上遮罩的采样值。

Shader "Unlit/009"
{
    Properties
    {
        // 漫反射颜色
        _Diffuse ("Diffuse",Color) = (1,1,1,1)
        // 高光反射颜色值
        _Specular ("Specular",Color) = (1,1,1,1)    
        // 高光反射值
        _Gloss ("_Gloss",range(1,100)) = 5
        // 主纹理
        _MaxTex ("_MaxTex",2d) = "white" {}
        // 高光遮罩纹理
        _SpecularMask ("Specular Mask",2d) =  "white" {}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM 
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            sampler2D _MaxTex;
            float4 _MaxTex_ST;
            sampler2D _SpecularMask;
            float4 _SpecularMask_ST;
            float4 _Specular;
            float4 _Diffuse;
            float _Gloss;
            
            struct v2f
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float2 maskUv : TEXCOORD1;
                float3 worldNormal : TEXCOORD2;
                float3 viewDir : TEXCOORD3;
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                // 将对象空间中的点变换到齐次坐标中的摄像机裁剪空间
                o.vertex = UnityObjectToClipPos(v.vertex);
                // 计算uv坐标
                o.uv = TRANSFORM_TEX(v.texcoord,_MaxTex);
                o.maskUv = TRANSFORM_TEX(v.texcoord,_SpecularMask);
                // o.uv = v.texcoord.xy * _MaxTex_ST.xy + _MaxTex_ST.zw;
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.viewDir = normalize(WorldSpaceViewDir(o.vertex));
                return o;   
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 texColor = tex2D(_MaxTex,i.uv);
                // 半兰伯特漫反射
                float halfLambert = (dot(_WorldSpaceLightPos0.xyz,i.worldNormal) * 0.5 + 0.5);
                // 采样渐变纹理 使用半兰伯特做uv坐标
                float3 diffuse = texColor * _LightColor0.rgb * _Diffuse.rgb * halfLambert;
                // 计算高光
                float3 halfVector = normalize(normalize(_WorldSpaceLightPos0.xyz) + i.viewDir);
                // 采样遮罩纹理
                float3 maskColor = tex2D(_SpecularMask,i.maskUv);
                // 计算高光
                float3 specular = texColor * _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(halfVector,i.worldNormal)),_Gloss) * maskColor;
                
                return float4(diffuse + specular,1);
            }
            ENDCG
        }
    }
}

地形图:      遮罩图: 

 效果如下:左边是不加遮罩纹理,右边是加了遮罩纹理。

可以看出,不加遮罩纹理两边都有高光。

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

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

相关文章

关于机器人精度的总结(重复精度和绝对精度区分)

ABB系列某款机器人精度参数表 机械臂是工业生产中的重要设备,在焊接码垛 以及 非 接触测量等 领域中有 着重要应 用。然而由于机械臂本体制造中存在机械制造公差装配误差导致的运动学参数误差以及电机转角与关节转角间减速比误差等,导致机械臂存在重复性定位精度较高(0.05 mm …

EMQ的介绍及整合SpringBoot的使用

首先先了解一下底层的协议: 1. MQTT MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅 (publish/subscribe)模式的"轻量级"通讯协议,该协议构建…

python实现递归算法解决年龄问题

一、问题描述 有5个人坐在一起,问第5个人多少岁,他说比第4个人大2岁。问第4个人多少岁,他说比第3个人大2岁。问第3人多少岁,他说比第2个人大2岁。问第2个人多少岁,他说比第1个人大2岁。最后问第1个人多少岁&#xff0…

ALLEGRO之SHAPE

ALLEGRO中的SHAPE菜单对应AD中的Polygon Pour,即铺铜操作。 1. Polygon:铺铜,在Options选择对应子层(例如Etch-Top),选择Dynamic copper(动态铺铜,会自动避让过孔,Static…

MIT 6.S081 教材第五章内容 -- 中断与设备驱动--上

MIT 6.S081 教材第五章内容 -- 中断与设备驱动--上 引言真实操作系统内存使用情况(上一节回顾)中断和设备驱动Interrupt硬件部分设备驱动概述在XV6中设置中断UART驱动的top部分UART驱动的bottom部分Interrupt相关的并发UART读取键盘输入Interrupt的演进小结代码:控制…

VanillaNet 原理与代码解读

paper:VanillaNet: the Power of Minimalism in Deep Learning official implementation: GitHub - huawei-noah/VanillaNet 存在的问题 虽然复杂网络的性能很好,但它们日益增加的复杂性给部署带来了挑战。例如,ResNets中的sh…

浏览器工作原理

浏览器(也称为网络浏览器或互联网浏览器)是安装在我们设备上的软件应用程序,使我们能够访问万维网。在阅读这篇文字时,你实际上正在使用一个浏览器。 有许多浏览器正在被使用,截至2022年,使用最多的是&…

为了找到好工作,花2个月时间整理了3.5W字的自动化测试面试题(答案+学习路线)!

从5月初开始找工作到现在,先后面试了阿里巴巴、字节跳动、网易、快手的测试开发岗。 大公司对于测试开发的要求相比来说高很多,要求掌握的知识点的广度和深度层次也比较高,遂整理了这两个月的面试题目文档供大家参考,同时也是为了…

基于java+swing+mysql商城购物系统

基于javaswingmysql商城购物系统 一、系统介绍二、功能展示1.项目骨架2.主界面3.用户登陆4.添加商品类别5、添加商品6、商品管理 四、其它1.其他系统实现五.获取源码 一、系统介绍 项目类型:Java SE项目 项目名称:商城购物系统 用户类型:双…

【C++学习】线程库 | IO流 | 空间配置器

🐱作者:一只大喵咪1201 🐱专栏:《C学习》 🔥格言:你只管努力,剩下的交给时间! 一、线程库 在C11之前,涉及到多线程问题,都是和平台相关的,比如w…

【Python爬虫开发基础⑥】计算机网络基础(Web和HTTP)

专栏:python网络爬虫从基础到实战 欢迎订阅!近期还会不断更新~ 另外:如果想要看更多的计算机网络知识,可以关注我的专栏:计算机网络 往期推荐: 【Python爬虫开发基础①】Python基础(变量及其命名…

【数据结构】特殊矩阵的压缩存储

🎇【数据结构】特殊矩阵的压缩存储🎇 🌈 自在飞花轻似梦,无边丝雨细如愁 🌈 🌟 正式开始学习数据结构啦~此专栏作为学习过程中的记录🌟 文章目录 🎇【数据结构】特殊矩阵的压缩存储&#x1f38…

C语言学习(二十六)---指针练习题(二)

在上节的内容中,我们进一步学习了有关指针的内容,并做了一些关于指针的题目,今天我们将继续练习一些指针的题目,以便大家更好的理解和掌握指针的知识,好了,话不多说,开整!&#xff0…

【c++11】 左值引用和右值引用

c11特性 右值引用左值引用和右值引用左值引用右值引用比较 右值引用的应用左值引用的短处右值引用解决问题移动构造 STL的改动move()函数结语 右值引用 c从出现就有着引用的语法,但是在c11后又新增了右值引用的新特性,以往所学的引用成了左值引用。非左…

代码随想录算法训练营第四十二天| 背包问题

标准背包问题 有n件物品和一个最多能背重量为w 的背包。 第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 举一个例子: 背包最大重量为4。 物品为: 重量价…

5.2.3目录与文件之权限意义

现在我们知道了Linux系统内文件的三种身份(拥有者、群组与其他人),知道每种身份都有三种权限(rwx), 已知道能够使用chown, chgrp, chmod去修改这些权限与属性,当然,利用ls -l去观察文…

《C++高级编程》读书笔记(十:揭秘继承技术)

1、参考引用 C高级编程(第4版,C17标准)马克葛瑞格尔 2、建议先看《21天学通C》 这本书入门,笔记链接如下 21天学通C读书笔记(文章链接汇总) 1. 使用继承构建类 1.1 扩展类 当使用 C 编写类定义时&#xf…

WMS中Choreographer 配合 VSYNC 中断信号

WMS中Choreographer 配合 VSYNC 中断信号 1、了解SurfaceFlinger中VSYNC信号刷新2、Choreographer 舞蹈编导2.1 Choreographer初始化2.2 FrameHandler中处理任务2.3 FrameDisplayEventReceiver初始化3.4 简易流程图 3、ViewRootImpl中scheduleTraversals3.1 postCallback 通过n…

java——IO与NIO

文章目录 1. 传统IO模型字节流字符流 2. NIO模型 Java中的IO(输入输出)是用于在程序中读取和写入数据的一种机制。Java提供了两种不同的IO模型:传统的IO模型和NIO(New IO)模型。 1. 传统IO模型 在传统的IO模型中&…

WPF本地化/国际化,多语言切换

之前写过winformwinform使用本地化,中英文切换_winform 中英文切换_故里2130的博客-CSDN博客 基本的技术差不多,但是后来又发现了一个ResXManager工具,可以更好方便快捷的使用。 首先下载,网络不好的话,去官网下载&a…