Chapter10 高级纹理——Shader入门精要学习笔记

Chapter10 高级纹理

  • 一、立方体纹理
    • 1.基本概念
      • ①组成
      • ②采样
    • 2.天空盒子 Sky Box
    • 3.环境映射
      • 三种方法
        • ①特殊布局的纹理创建
        • ②手动创建Cubemap——老方法
        • ③脚本生成
    • 4.反射
    • 5.折射
    • 6.菲涅尔反射
  • 二、渲染
    • 1.镜子效果
    • 2.玻璃效果
    • 3.渲染纹理 vs GrabPass
  • 三、程序纹理
    • 1.简单程序纹理
    • 2.Unity中的程序材质

一、立方体纹理

1.基本概念

  • 立方体映射是环境映射的一种实现方式,可以让物体反射出周围的环境

①组成

  • 立方体纹理由6张图像组成,对应立方体6个面(左手坐标系)
    • 正面 (Front):沿着 +Z 轴观察
    • 背面 (Back):沿着 -Z 轴观察
    • 左面 (Left):沿着 -X 轴观察
    • 右面 (Right):沿着 +X 轴观察
    • 上面 (Top):沿着 +Y 轴观察
    • 下面 (Bottom):沿着 -Y 轴观察

②采样

  • 立方体纹理需要提供 三维纹理坐标 ,表示世界空间下的3D方向
  • 这个方向矢量从立方体中心出发,延伸并与立方体的一个面相交,采样结果由交点处的图像数据决定

2.天空盒子 Sky Box

  • 一个盒子,用来 模拟环境,整个场景被包围在一个立方体内
  • 这个立方体每个面使用的技术就是 立方体纹理映射技术
    在这里插入图片描述
  • 要把六张纹理的 Wrap Mode 设置为 Clamp
  • Tint Color 控制材质的整体颜色
  • Exposure 调整天空盒的亮度
  • Rotation 调整天空盒沿 +y 方向的旋转角度

3.环境映射

  • 可以模拟物体表面的 反射和折射效果 (金属、玻璃等质感的材质)

三种方法

①特殊布局的纹理创建

使用一张HDR图像(类似立方体展开图的交叉布局、全景布局等),把该纹理的 Texture Type 设置为 Cubemap 即可

②手动创建Cubemap——老方法

创建一个 Cubemap ,然后把6张纹理拖拽到面板中

③脚本生成

利用 Camera.RenderToCubemap 函数来实现(可以把任意位置观察到的场景图像存储到6张图像中,创建Cubemap)

4.反射

  • 金属镀层效果
  • 通过 入射光线的方向和表面法线方向 来计算 反射方向 ,再利用反射方向对立方体纹理采样即可
  • _ReflectColor 用于控制反射颜色; _ReflectAmount 用于控制材质反射程度;_Cubemap 用于模拟反射的环境纹理
 Properties{_Color ("Color Tint", Color) = (1,1,1,1)_ReflectColor ("Reflect Color", Color) = (1,1,1,1)_ReflectAmount ("Reflect Amount", Range(0,1)) = 1_Cubemap ("Reflection Cubemap", Cube) = "_Skybox"{}}
  • 在 v2f 结构体中定义了需要用于计算反射方向的 worldPos、worldNormal、worldViewDir 以及存储反射方向的 worldRefl
struct a2v{float4 vertex :POSITION;float3 normal : NORMAL;
};
struct v2f{float4 pos : SV_POSITION;float3 worldPos : TEXCOORD0;float3 worldNormal : TEXCOORD1;float3 worldViewDir : TEXCOORD2;fixed3 worldRefl : TEXCOORD3;SHADOW_COORD(4)
};
  • 在顶点着色器中计算反射方向,用了CG的 reflect 函数
  • 物体反射到摄像机的光线方向,可以由光路可逆原则来反向求得——可以计算 o.worldViewDir 视角方向 关于顶点法线的反射方向来求得入射光线方向
 v2f vert(a2v v){v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(_Object2World, v.vertex).xyz;o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);//计算世界空间下的反射方向o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);TRANSFER_SHADOW(o);return o;}
  • 对立方体纹理采样需要用到 CG的 texCUBE 函数
  • 使用 _ReflectAmount 来混合漫反射颜色和反射颜色
fixed4 frag(v2f i) : SV_Target{fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed3 worldViewDir = normalize(i.worldViewDir);fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0, dot(worldNormal,worldLightDir));fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb * _ReflectColor.rgb;UNITY_LIGHT_ATTENTION(atten, i, i.worldPos);fixed3 color = ambient + lerp(diffuse, reflection, _ReflectAmount) * atten;return fixed4(color, 1.0);
}
  • 把 Cubemap_0 拖进 Reflection map中
    在这里插入图片描述
    在这里插入图片描述

5.折射

  • 给定入射角时,可以使用 斯涅尔定律 来计算反射角
    • 当光从介质1沿着和表面法线夹角为 θ 1 θ_{1} θ1 的方向斜射入介质2时,可以用如下公式计算得到折射光线与法线的夹角 θ 2 θ_{2} θ2
    • η 1 s i n θ 1 η_{1} sinθ_{1} η1sinθ1 = η 2 s i n θ 2 η_{2} sinθ_{2} η2sinθ2
    • η 1 η_{1} η1 η 2 η_{2} η2 为两介质的折射率(真空一般为1,玻璃一般为1.5)
      在这里插入图片描述
  • _RefractColor、_RefractAmount 与反射属性相似, _RefractRatio 表示该属性不同介质的透射比(入射光线所在介质的折射率与折射光线所在介质折射率的比值),以此来计算折射方向
Properties{_Color ("Color Tint", Color) = (1,1,1,1)_RefractColor ("Refraction Color", Color) = (1,1,1,1)_RefractAmount ("Refraction Amount", Range(0, 1)) = 1_RefractRatio ("Refraction Ratio", Range(0.1, 1)) = 0.5_Cubemap ("Refraction Cubemap", Cube) = "_Skybox"{}
}
  • 使用CG中的 refract函数来计算折射方向,第一个参数为 入射光线方向(必须归一化后的矢量),第二个为 表面法线(必须归一化后的矢量),第三个是两个介质的折射率比值
v2f vert(a2v v)
{v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);o.worldPos = mul(_Object2World, v.vertex).xyz;o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);//计算世界空间下的折射方向o.worldRefr = refract(-normalize(o.worldViewDir), normalize(o.worldNormal), _RefractRatio);TRANSFER_SHADOW(o);return o;
}
 fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldPos = normalize(i.worldPos);fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed3 worldViewDir = normalize(i.worldViewDir);fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0,dot(worldNormal, worldLightDir));fixed3 refraction = texCUBE(_Cubemap, i.worldRefr).rgb * _RefractColor.rgb;UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);fixed3 color = ambient + lerp(diffuse, refraction, _RefractAmount)*atten;return fixed4(color,1.0);}

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

6.菲涅尔反射

  • 描述了一种光学现象,光照到物体表面时,一部分发生反射,一部分进入物体内部发生折射或者散射
  • 许多车漆、水面等材质的渲染中,会使用菲涅尔反射来模拟更加真实的效果
  • Schlick 菲涅尔近似等式
    • F s c h l i c k ( v ⋅ n ) = F 0 + ( 1 − F 0 ) ( 1 − v ⋅ n ) 5 F_{schlick}( v \cdot n) = F_{0} + (1 - F_{0})(1 - v \cdot n)^{5} Fschlick(vn)=F0+(1F0)(1vn)5
    • F 0 F_{0} F0 为反射系数,用于控制菲涅尔反射的强度
    • v 是视角方向,n 是表面法线
  • 声明了用于调整菲涅尔反射的属性以及使用的Cubemap
Properties
{_Color ("Color Tint", Color) = (1,1,1,1)_FresnelScale ("Fresnel Scale", Range(0,1)) = 0.5_Cubemap ("Reflection Cubemap", Cube) = "_Skybox"{}
}
  • 在顶点着色器中计算法线、视角方向以及反射方向
v2f vert(a2v v)
{v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);o.worldPos = mul(_Object2World, v.vertex).xyz;o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);TRANSFER_SHADOW(o);return o;
}
  • 在片元着色器中计算菲涅尔反射,并使用结果指混合漫反射光照和反射光照
fixed4 frag(v2f i):SV_Target 
{//fixed3 worldPos = normalize(i.worldPos);fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed3 worldViewDir = normalize(i.worldViewDir);fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb;fixed fresnel = _FresnelScale + (1 - _FresnelScale) * pow(1-dot(worldNormal,worldViewDir),5);fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0,dot(worldNormal,worldLightDir));fixed3 color = ambient + lerp(diffuse, reflection, saturate(fresnel)) * atten;return fixed4(color,1.0);
}
  • _FresnelScale 调为1时,物体将完全反射图像,调为0时,则是一个具有边缘光照效果的漫反射物体
    在这里插入图片描述
    在这里插入图片描述
    +

二、渲染

  • 渲染纹理(Render Texture)是 Unity 中一种特殊的纹理类型,它允许我们将场景渲染到一张纹理上,而不是直接显示在屏幕上

1.镜子效果

  • 创建一个Render Texture 作为渲染纹理
  • 创建一个渲染摄像机,将摄像机的 Render Target 设为 Render Texture(要将摄像机绕y轴旋转180°
  • 声明一个纹理属性,对应了由镜子摄像机渲染得到的渲染纹理
Properties {_MainTex ("Main Tex", 2D) = "white" {}
}
  • 在顶点着色器中计算纹理坐标
  • 因为镜子是左右翻转的,所以需要翻转x坐标
v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.texcoord;// Mirror needs to filp xo.uv.x = 1 - o.uv.x;return o;
}
  • 在片元着色器中对渲染纹理进行采样输出
fixed4 frag(v2f i) : SV_Target {return tex2D(_MainTex, i.uv);
}

在这里插入图片描述

2.玻璃效果

  • 还可以通过在Shader中使用一种特殊的Pass来完成获取屏幕图像的目的 —— GrabPass
  • GrabPass可以实现类似于玻璃等透明材质的模拟(可以使用法线模拟折射效果)
  • 使用时要注意渲染队列
  • _MainTex是玻璃的材质纹理,_BumpMap是法线纹理,_Cubemap是模拟反射的环境纹理,_Distortion控制折射时图像的扭曲程度,_RefractAmount控制折射程度
Properties
{_MainTex ("Main Tex", 2D) = "white"{}_BumpMap ("Normal Map", 2D) = "white"{}_Cubemap ("Environment Cubemap", Cube) = "_Skybox"{}_Distortion ("Distortion", Range(0, 100)) = 100_RefractAmount ("Refract Amount", Range(0.0, 1.0)) = 1.0
}
  • 定义相应的渲染队列,并使用GrabPass来获取屏幕图像
SubShader
{Tags { "Queue"="Transparent" "RenderType"="Opaque" }GrabPass {"_RefractionTex"}
  • _RefractionTex 和_RefractionTex_TexelSize,后者可以让我们得到该纹理的纹素大小,我们需要在对屏幕图像的采样坐标进行偏移时使用该变量
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float4 _BumpMap_ST;
samplerCUBE _Cubemap;
float _Distortion;
fixed _RefractAmount;
sampler2D _RefractionTex;
float4 _RefractionTex_TexelSize;
  • 在顶点着色器中,使用内置的 ComputeGrabScreenPos 函数来得到对应被抓取屏幕图像的采样坐标
  • o.uv 存储了 _MainTex 和 _BumpTex 的采样坐标
  • 计算顶点对应的从切线空间到世界空间的变换矩阵 TBN → \rightarrow 需要在片元着色器中把法线方向从切线方向(由法线采样纹理得)变换到世界空间下,以便对Cubemap进行采样。把TBN变换矩阵的每一行存储在 TtoW0、TtoW1、TtoW2 的xyz分量中,w存储世界空间下的顶点坐标
v2f vert (a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.scrPos = ComputeGrabScreenPos(o.pos);o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);o.uv.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;  fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);  fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);  fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; 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);  return o;
}
  • 在片元着色器中,首先通过TtoW0等获得顶点的世界坐标
  • fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
    • 对法线纹理进行采样,得到切线空间下的法线方向
  • 使用bump 与 _Distortion、_RefractionTex_TexelSize 来对屏幕图像的采样坐标进行偏移 → \rightarrow 模拟折射效果
    • _Distortio值越大,偏移越大,玻璃背后物体形变越大
    • 选择使用切线空间下的法线方向来偏移 是因为该空间下的法线可以反映顶点局部空间下的法线方向
  • 再对scrPos 透视除法 i.scrPos.xy/i.scrPos.w 得到真正屏幕坐标,再使用该坐标对抓取的屏幕图像进行采样,模拟折射的颜色
  • 把法线从切线空间变换到世界空间 half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)),以此得到反射方向(光路可逆)
  • 用反射方向对Cubemap进行采样 texCUBE(_Cubemap, reflDir).rgb ,并与主纹理颜色 texColor.rgb 相乘后得到反射颜色
  • 最终用 _RefractAmount 对反射 reflCol * (1 - _RefractAmount) 和折射颜色 refrCol * _RefractAmount 进行混合,得到最终的输出颜色
fixed4 frag (v2f i) : SV_Target {		float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));// Get the normal in tangent spacefixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));	// Compute the offset in tangent spacefloat2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;fixed3 refrCol = tex2D(_RefractionTex, i.scrPos.xy/i.scrPos.w).rgb;// Convert the normal to world spacebump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));fixed3 reflDir = reflect(-worldViewDir, bump);fixed4 texColor = tex2D(_MainTex, i.uv.xy);fixed3 reflCol = texCUBE(_Cubemap, reflDir).rgb * texColor.rgb;fixed3 finalColor = reflCol * (1 - _RefractAmount) + refrCol * _RefractAmount;return fixed4(finalColor, 1);
}

在这里插入图片描述

3.渲染纹理 vs GrabPass

  • 渲染纹理:
    • 需要创建一个 额外的摄像机 和一个 渲染纹理资源
    • 可以自定义渲染纹理的分辨率和属性
    • 效率更高,尤其是在移动设备上
  • GrabPass:
    • 实现简单,只需在着色器中 添加 GrabPass 命令
    • 可以获取当前屏幕的图像,无需创建额外的摄像机
    • 效率较低,尤其是在高分辨率屏幕上
    • 所有使用 GrabPass 的物体都会 使用同一张屏幕图像
    • 在移动设备上,GrabPass 虽然不会重新渲染场景,但往往需要CPU直接读取后备缓冲(back buffer),破坏了CPU和GPU的并行性
  • 命令缓冲(Command Buffers)
    • 可以实现类似抓屏的效果,并在不透明物体 渲染后对图像进行额外的操作,例如模糊、颜色调整等
    • 效率更高,功能更强大,但使用起来也更复杂

三、程序纹理

  • 指用计算机生成的图像,可以使用各种参数来控制纹理的外观

1.简单程序纹理

[ExecuteInEditMode] //为了让该脚本可以在编辑器模式下运行
public class ProceduralTextureGeneration : MonoBehaviour
{public Material material = null;#region Material properties//纹理的大小(数值通常是2的整数幂)[SerializeField, SetProperty("textureWidth")]private int m_textureWidth = 512;public int textureWidth{get{return m_textureWidth;}set{m_textureWidth = value;_UpdateMaterial();}}//纹理的背景颜色[SerializeField, SetProperty("backgroundColor")]private Color m_backgroundColor = Color.white;public Color backgroundColor{get{return m_backgroundColor;}set{m_backgroundColor = value;_UpdateMaterial();}}//圆点的颜色[SerializeField, SetProperty("circleColor")]private Color m_circleColor = Color.yellow;public Color circleColor{get{return m_circleColor;}set{m_circleColor = value;_UpdateMaterial();}}//模糊因子——模糊圆形边界[SerializeField, SetProperty("blurFactor")]private float m_blurFactor = 2.0f;public float blurFactor{get{return m_blurFactor;}set{m_blurFactor = value;_UpdateMaterial();}}#endregionprivate Texture2D m_generatedTexture = null; //保存生成的程序纹理private void Start(){if(material == null){Renderer renderer = GetComponent<Renderer>();if(renderer == null){Debug.LogWarning("Cannot find a renderer.");return;}material = renderer.sharedMaterial;}_UpdateMaterial();}private void _UpdateMaterial(){if (material != null){m_generatedTexture = _GenerateProceduralTexture();material.SetTexture("_MainTex", m_generatedTexture); //把生成的纹理赋值给材质,material中需要有一个名为_MainTex 的纹理属性}}private Color _MixColor(Color color0, Color color1, float mixFactor){Color mixColor = Color.white;mixColor.r = Mathf.Lerp(color0.r, color1.r, mixFactor);mixColor.g = Mathf.Lerp(color0.g, color1.g, mixFactor);mixColor.b = Mathf.Lerp(color0.b, color1.b, mixFactor);mixColor.a = Mathf.Lerp(color0.a, color1.a, mixFactor);return mixColor;}private Texture2D _GenerateProceduralTexture(){Texture2D proceduralTexture = new Texture2D(textureWidth, textureWidth);// 定义圆之间的间距float circleInterval = textureWidth / 4.0f;// 定义圆的半径float radius = textureWidth / 10.0f;//定义模糊系数float edgeBlur = 1.0f / blurFactor;for (int w = 0; w < textureWidth; w++){for (int h = 0; h < textureWidth; h++){//使用背景颜色初始化Color pixel = backgroundColor;// 依次画9个圆for (int i = 0; i < 3; i++){for (int j = 0; j < 3; j++){// 计算当前所绘制的圆心位置Vector2 circleCenter = new Vector2(circleInterval * (i + 1), circleInterval * (j + 1));// 计算当前像素与圆心的距离float dist = Vector2.Distance(new Vector2(w, h), circleCenter) - radius;// 模糊圆的边界Color color = _MixColor(circleColor, new Color(pixel.r, pixel.g, pixel.b, 0.0f), Mathf.SmoothStep(0f, 1.0f, dist * edgeBlur));// 混合颜色pixel = _MixColor(pixel, color, color.a);}}proceduralTexture.SetPixel(w, h, pixel);}}proceduralTexture.Apply();return proceduralTexture;}
}

在这里插入图片描述

2.Unity中的程序材质

  • 程序材质使用的纹理是程序纹理,在 Substance Designer 生成
  • 自由度高
  • 可与 Shader 配合:可以实现更加复杂的视觉效果

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis Plus 自动填充注解 @TableField(fill = FieldFill.INSERT_UPDATE)

第一步&#xff1a;在需要自动填充的位置加上注解 通过在创建时间和修改时间上添加 fill 填充字段 进行自动填充 第二步&#xff1a;要想实现自动填充还需要实现MetaObjectHandler接口&#xff0c;在这里实现自动填充的逻辑 Component public class MyMetaObjectHandler …

Cmake静态库与动态库的构建与使用

项目目录 各个文件 myhell.h // // Created by glt on 2024/7/3. //#ifndef MY_PRO_HELLO_H #define MY_PRO_HELLO_H#include <iostream>void HelloFunc();#endif //MY_PRO_HELLO_Hhello.cpp // // Created by glt on 2024/7/3. // #include "myhello.h"voi…

《数据结构与算法基础 by王卓老师》学习笔记——2.5线性表的链式表示与实现1

1.链式表示 2.链表举例 3.链式存储的相关术语 4.三个讨论题

文本分析-使用Python做词频统计分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

【Python机器学习】模型评估与改进——带交叉验证的网格搜索

虽然将数据划分为训练集、验证集、测试集的方法是可行的&#xff0c;也相对常用&#xff0c;但这种方法对数据的划分相当敏感&#xff0c;为了得到对泛化性能的更好估计&#xff0c;我们可以使用交叉验证来评估每种参数组合的性能&#xff0c;而不是仅将数据单次划分为训练集与…

【简单讲解下npm常用命令】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

最靓丽的C++开源通知弹框SnoreToasts自动监听软件及网页通知

SnoreToasts&#xff0c;作为一款轻量级的C开源项目&#xff0c;为开发者提供了一个便捷的方式来在Windows操作系统上展示通知弹框&#xff08;Toast Notifications&#xff09;。 特点与优势 轻量级&#xff1a;SnoreToasts采用了简洁的代码设计&#xff0c;避免了不必要的依…

昇思25天学习打卡营第3天|yulang

今天主要学习03-张量Tensor&#xff0c;主要包含了处理创建张量、张量的属性、张量索引和张量运算&#xff0c;稀疏张量&#xff0c;有点看不太懂&#xff0c;感觉要开始入门到放弃了&#xff1f;张量在构建和训练深度学习模型中的实际应用&#xff0c;如卷积神经网络。 张量&a…

2024 AIGC 技术创新应用研讨会暨数字造型设计师高级研修班通知

尊敬的老师、领导您好! 为深入响应国家关于教育综合改革的战略部署&#xff0c;深化职业教育、高等教育改革&#xff0c;发挥企业主体重要作用&#xff0c;促进人才培养供给侧和产业需求侧结构要素全方位融合&#xff0c;充分把握人工智能创意式生成(AIGC)技术在教育领域的发展…

如何使用代理 IP 防止多个 Facebook 帐户关联 - 最佳实践

在社交媒体被广泛应用的今天&#xff0c;Facebook作为全球最大的社交网络平台之一&#xff0c;面临着很多挑战&#xff0c;其中之一就是用户行为的管理和安全。 为了防止多个账户之间的关联和滥用&#xff0c;Facebook需要采取一系列措施&#xff0c;其中包括使用静态住宅代理…

web自动化(三)鼠标操作键盘

selenuim 键盘操作 import timefrom selenium.webdriver.common.keys import Keys from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait from selen…

【LeetCode的使用方法】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 🔮LeetCode的使用方法 🔮LeetCode 是一个在线编程平台,广泛…

Transformation(转换)开发-switch/case组件

一、switch/case组件-条件判断 体育老师要做一件非常重要的事情&#xff1a;判断学生是男孩还是女孩、或者是蜘蛛&#xff0c;然后让他们各自到指定的队伍中 体育老师做的事情&#xff0c;我们同样也会在Kettle中会经常用来。在Kettle中&#xff0c;switch/case组件可以来做类似…

【Linux】多线程(一万六千字)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 文章目录 前言 线程的概念 线程的理解(Linux系统为例) 在Linux系统里如何保证让正文部分的代码可以并发的去跑呢&#xff1f; 为什么要有多进程呢&#xff1f; 为…

Jedis、Lettuce、RedisTemplate连接中间件

jedis就像jdbc一样&#xff0c;用于两个端直接的连接。 1.创建Spring项目 这里不过多赘述... 2.导入连接工具jedis 在pom文件中导入jedis的依赖。 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version&…

IO多路复用学习

Linux中的I/O多路复用 相关基础概念 在学习I/O多路复用之前&#xff0c;先学习一些相关的基础概念&#xff0c;便于理解。 内核缓冲区和用户缓冲区 &#x1f62e; CPU 上会运行两种程序&#xff0c;一种是操作系统的内核程序&#xff08;也称为系统程序&#xff09;&#x…

Redis持久化详解

【关闭文件、AOF 刷盘、释放内存这三个任务都有各自的任务队列】所以不是单线程 Redis有两种持久化方案&#xff1a; RDB持久化 AOF持久化 基于Redis集群解决单机Redis存在的问题 【Redis是单进程的】 【也有人做分布式section】 【主从集群中多个从就是做负载均衡的】 …

浅谈如何在linux上部署java环境

文章目录 一、部署环境1.1、JDK1.2、Tomcat1.3、MySQL 二、将自己写的的程序部署到云服务器上 一、部署环境 为了在linux上部署 Java web 程序&#xff0c;需要安装一下环境。 1.1、JDK 直接使用 yum 命令安装 openjdk。我们 windows系统上 下载的是 oracle 官方的 jdk。而 …

uniapp uniCloud云开发

uniCloud概述 uniCloud 是 DCloud 联合阿里云、腾讯云、支付宝云&#xff0c;为开发者提供的基于 serverless 模式和 js 编程的云开发平台。 uniCloud 的 web控制台地址&#xff1a;https://unicloud.dcloud.net.cn 文档&#xff1a;https://doc.dcloud.net.cn/uniCloud/ un…

python 第6册 辅助excel 002 批量创建非空白的 Excel 文件

---用教授的方式学习 此案例主要通过使用 while 循环以及 openpyxl. load_workbook()方法和 Workbook 的 save()方法&#xff0c;从而实现在当前目录中根据已经存在的Excel 文件批量创建多个非空白的Excel 文件。当运行此案例的Python 代码&#xff08;A002.py 文件&#xff0…