《Unity Shader 入门精要》笔记07

透明效果

  • 为什么渲染顺序很重要
  • Unity Shader的渲染顺序
  • 透明度测试
  • 透明度混合
  • 开启深度写入的半透明效果
  • ShaderLab 的混合命令
    • 混合等式和参数
    • 混合操作
    • 常见的混合类型
  • 双面渲染的透明效果
    • 透明度测试的双面渲染
    • 透明度混合的双面渲染

Unity中通常使用两种方法来实现透明效果:第一种是试用透明度测试(Alpha Test),这种方法其实无法得到真正的半透明效果;另一种是透明度混合(Alpha Blending)

由于深度缓冲的存在,可以让不透明物体不考虑他们渲染顺序也能得到正确的排序效果。但是实现透明效果需要关闭深度写入(ZWrite)

透明度测试不需要关闭深度写入,它和其他不透明物体最大的不同就是他会根据透明度来舍弃一些片元。原理简单但是很极端,要么完全透明,看不到,要么完全不透明。

透明度混合需要关闭深度写入,不关闭深度测试。
对于透明度混合来说,深度缓冲是只读的。
可以得到真正的半透明效果。
会使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲区中的颜色值进行混合,得到新的颜色。

为什么渲染顺序很重要

比如渲染距离较远的一个不透明物体和距离较近的一个半透明物体,如果先渲染半透明的物体,不透明物体会直接覆盖颜色,出现视觉错误。

两个半透明物体也是需要顺序的。如果两个半透明物体A较近 B较远,如果先渲染A在渲染B,混合结果也会反过来,得到错误的半透明结构。

但总有一些情况很特殊 比如循环重叠 或者深度相同,为了减少错误排序的情况,尽可能拆分子模型或者让模型是凸面体。

扩展博文:图形学基础|深度缓冲

Unity Shader的渲染顺序

Unity内部使用了一系列整数索引来表示每个渲染队列,且索引号越小表示越早被渲染。

名称队列索引号描述
Background1000这个渲染队列会在任何其他队列之前被渲染,我们通常使用该队列来渲染那些需要绘制在背景上的物体
Geometry2000默认的渲染队列,大多数物体都使用这个队列。不透明物体使用这个队列
AlphaTest2450需要透明度测试的物体使用这个队列。在Unity 5中它从Geometry队列中被单独分出来,这是因为在所有不透明物体渲染之后再渲染他们会更加高效。
Transparent3000这个队列中的物体会在所有Geometry和AlphaTest物体渲染后,再按从后往前的顺序进行渲染。任何使用了透明度混合(例如关闭了深度写入的Shader)的物体都应该使用该队列
Overlay4000该队列用于实现一些叠加效果。任何需要在最后渲染的物体都应该使用该队列。

想通过透明度测试实现透明效果,应包含类似代码:

SubShader {Tags{ "Queue" = "AlphaTest"}Pass{...}
}

想通过透明度混合实现透明效果,应包含类似代码:

SubShader {Tags{ "Queue" = "Transparent"}Pass{ZWrite Off//关闭深度写入...}
}

透明度测试

通常会在片元着色器中进行透明度测试
clip是Cg中的一个函数
函数:void clip(float4 x) | void clip(float3 x) | void clip(float2 x) | void clip(float1 x) | void clip(float x)
参数:裁剪时使用的标量或矢量条件
描述:如果给定参数的任何一个分量是负数,就会舍弃当前像素的输出颜色。

Shader "Custom/AlphaTestShader"
{Properties{_Color ("Main Tint", Color) = (1,1,1,1)_MainTex ("Main Tex", 2D) = "white" {}_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5//决定调用clip进行透明度测试时使用的判断条件 范围0-1}SubShader{Pass{//通常使用了透明度测试的shader都应该在subshader中设置这三个标签//设置队列为透明度测试  shader不会受到投影器的影响 rendertype标签可以让Unity把这个shader归入提前定义的组Tags{"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"}CGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;float _Cutoff;struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;float2 uv : TEXCOORD2;};v2f vert(a2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);return o;}fixed4 frag(v2f i) : SV_Target{fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed4 texColor = tex2D(_MainTex,i.uv);clip(texColor.a - _Cutoff);//相当于↓//if ((texColor.a - _Cutoff) < 0.0)//{//    discard//}fixed3 albedo = texColor.rgb * _Color.rgb;fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir));return fixed4(ambient + diffuse,1.0);}ENDCG}}FallBack "Transparent/Cutout/VertexLit"
}

透明度混合

为了进行混合,我们需要使用Unity提供的混合命令——Blend。Blend是Unity提供的设置混合模式的命令。混合时使用的函数就是由该指令决定的

语义描述
Blend Off关闭混合
Blend SrcFactor DstFactor开启混合,并设置混合因子。源颜色(该片元产生的颜色)会乘以SrcFactor,而目标颜色(已经存在于颜色缓存的颜色)会乘以DstFactor,然后把两者相加后再存入颜色缓冲中。
Blend SrcFactor DstFactor, SrcFactorA DstFactorA和上面几乎一样,只是使用不同的因子来混合透明通道
BlendOp BlendOperation并非是吧源颜色和目标颜色简单相加后混合,而是使用BlendOperation对它们进行其他操作

只有开启混合模式之后,设置片元的透明通道才有意义,而Unity在我们使用Blend命令式会自动帮我们打开。
我们会把源颜色的混合因子SrcFactor设为SrcAlpha,而目标颜色的混合因子DstFactor设为OneMinusSrcAlpha
混合后新颜色 = ArcAlpha x SrcColor + (1 - SrcAlpha) x 混合前颜色

Shader "Custom/AlphaBlendShader"
{Properties{_Color ("Main Tint", Color) = (1,1,1,1)_MainTex ("Main Tex", 2D) = "white" {}_AlphaScale("Alpha Scale", Range(0,1)) = 1}SubShader{Pass{Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}ZWrite Off//关闭深度写入Blend SrcAlpha OneMinusSrcAlpha//将源颜色的混合因子设为SrcAlpha 目标颜色的混合因子设为OneMinusSrcAlphaCGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;fixed _AlphaScale;struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;float2 uv : TEXCOORD2;};v2f vert(a2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);return o;}fixed4 frag(v2f i) : SV_Target{fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed4 texColor = tex2D(_MainTex,i.uv);fixed3 albedo = texColor.rgb * _Color.rgb;fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir));return fixed4(ambient + diffuse,texColor.a * _AlphaScale);//设置透明通道}ENDCG}}FallBack "Transparent/VertexLit"
}

开启深度写入的半透明效果

在面对复杂遮挡关系的模型师,会有各种因为排序错误而产生的透明效果。这都是因为关闭了深度写入而造成的。

一种解决方法是使用两个Pass来渲染模型
第一个Pass开启深度写入,但不输出颜色,目的仅仅是为了把该模型的深度值写入深度缓存中
第二个Pass进行正常的透明度混合,由于上一个Pass已经得到了逐像素的正确的深度信息,该Pass就可以按照像素级别的深度排序结果进行透明渲染。
但缺点是,多使用一个Pass会对性能造成一定的影响。

Pass { //新增 PassZWrite On //开启深度写入ColorMask 0 //Pass不写入任何颜色通道,即不输出任何颜色。
}

这个新增Pass的目的仅为了把模型的深度信息写入深度缓冲中,从而剔除模型中被自身遮挡的片元。

ColorMask用于设置颜色通道的写掩码(write mask)

ColorMask RGB | A | 0 | 任何其他的RGB的组合

ShaderLab 的混合命令

混合是如何实现的:

当片元着色器产生一个颜色的时候,可以选择与颜色缓存中的颜色进行混合。这样混合就和两个操作数有关:源颜色(source colo)目标颜色(destination color)。源颜色S,指的是由片元着色器产生的颜色;目标颜色D,指的是从颜色缓冲中读取到的颜色值。对它们进行混合后得到的输出颜色O,会重新写入到颜色缓冲中。需要注意的是源颜色目标颜色和输出颜色都包含了RGBA四个通道的值。

混合等式和参数

混合是一个逐片元操作,是不可编程但可高度配置的。

ShaderLab中设置混合因子的命令

命令描述
Blend SrcFactor DstFactor开启混合,并设置混合因子。源颜色(该片元产生的颜色)会乘以SrcFactor,而目标颜色(已经存在于颜色缓存的颜色)会乘以DstFactor,然后把两者相加后在存入颜色缓冲中
Blend SrcFactor DstFactor, SrcFactorA DstFactorA和上面几乎一样,只是使用不同的因子来混合透明通道

加法混合公式
O(rgb) = SrcFactor x S(rgb) + DstFactor x D(rgb)
O(a) = SrcFactor x S(a) + DstFactorA x D(a)

ShaderLab中的混合因子

参数描述
One因子为1
Zero因子为0
SrcColor因子为源颜色值。当用于混合RGB的混合等式时,使用SrcColor的RGB分量作为混合因子;当用于混合A的混合等式时,使用SrcColor的A分量作为混合因子
SrcAlpha因子为源颜色的透明度值(A通道)
DstColor因子为目标颜色值。当用于混合RGB的混合等式时,使用DstColor的RGB分量作为混合因子;当用于混合A的混合等式时,使用DstColor的A分量作为混合因子
DestAlpha因子为目标颜色的透明度值(A通道)
OneMinusSrcColor因子为(1-源颜色)。当用于混合RGB的混合等式时,使用结果的RGB分量作为混合因子;当用于混合A的混合等式时,使用结果的A分量作为混合因子
OneMinusSrcAlpha因子为(1-源颜色的透明度值)
OneMinusDstColor因子为(1-目标颜色)。当用于混合RGB的混合等式时,使用结果的RGB分量作为混合因子;当用于混合A的混合等式时,使用结果的A分量作为混合因子
OneMinusDstAlpha因子为(1-目标颜色的透明度值)

例如:想要在混合后,输出颜色的透明度值就是源颜色的透明度
Blend SrcAlpha OneMinusSrcAlpha, One Zero(代入公式前面x1后面x0 就是源颜色)

混合操作

BlendOp BlendOperation

ShaderLab中的混合操作

操作描述
Add将源和目标相加。
Sub从源减去目标。
RevSub从目标减去源。
Min使用源和目标中的较小者。
Max使用源和目标中的较大者。
其他逻辑操作仅在Direct11.1中支持

常见的混合类型

//正常(Normal),即透明度混合
Blend SrcAlpha OneMinusSrcAlpha//柔和相加(Soft Additive)
Blend OneMinusDstColor One//正片叠底(Multiply),即相乘
Blend DstColor Zero//两倍相乘(2x Multiply)
Blend DstColor SrcColor//变暗(Darken)
BlendOp Win
Blend One One//变亮(Lighten)
BlendOp Max
Blend One One//滤色(Screen)
Blend OneMinusDstColor One//等同于
Blend One OneMinusSrcColor//线性减淡(Linear Dodge)
Blend One One

虽然有些混合模式并没有设置混合操作的种类,但是他们默认就是使用加法操作,相当于设置了BlendOp Add

Shader "Unity Shaders Book/Chapter 8/Blend Operations 1" {Properties {_Color ("Color Tint", Color) = (1, 1, 1, 1)_MainTex ("Main Tex", 2D) = "white" {}_AlphaScale ("Alpha Scale", Range(0, 1)) = 1}SubShader {Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}Pass {Tags { "LightMode"="ForwardBase" }ZWrite Off//			// Normal
//			Blend SrcAlpha OneMinusSrcAlpha
//			
//			// Soft Additive
//			Blend OneMinusDstColor One
//			
//			// MultiplyBlend DstColor Zero
//			
//			// 2x Multiply
//			Blend DstColor SrcColor
//			
//			// Darken
//			BlendOp Min
//			Blend One One	// When using Min operation, these factors are ignored
//			
//			//  Lighten
//			BlendOp Max
//			Blend One One // When using Max operation, these factors are ignored
//			
//			// Screen
//			Blend OneMinusDstColor One// Or
//			Blend One OneMinusSrcColor
//			
//			// Linear DodgeBlend One OneCGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;fixed _AlphaScale;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;};struct v2f {float4 pos : SV_POSITION;float2 uv : TEXCOORD0;};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);return o;}fixed4 frag(v2f i) : SV_Target {				fixed4 texColor = tex2D(_MainTex, i.uv);return fixed4(texColor.rgb * _Color.rgb, texColor.a * _AlphaScale);}ENDCG}} FallBack "Transparent/VertexLit"
}

双面渲染的透明效果

使用 Cull 指令来控制需要剔除哪个面得渲染图元

Untiy中Cull指令的语法:Cull Back | Front | Off

Back:是默认状态。背对着摄像机的图元不会被渲染。
Front:朝向摄像机的渲染图元不会被渲染。
Off:关闭剔除功能,渲染所有图元,通常不关闭。

透明度测试的双面渲染

在这里插入图片描述
只需在Pass中添加一句Cull Off

透明度混合的双面渲染

因为关闭了深度写入,需要谨慎控制渲染顺序。但如直接关闭剔除功能,那我们就无法保证同一个物体的正面和背面的渲染顺序,就有可能得到错误的半透明效果。
对此我们选择把双面渲染顺序的工作分成两个Pass——第一个Pass只渲染背面,第二个Pass只渲染正面。由于Unity会顺序执行SubShader中的各个Pass,因此可以保证背面总是在正面之前被渲染,借此用来保证正确的深度渲染关系。

Shader "Custom/AlphaTestBothSidedShader"
{Properties{_Color ("Main Tint", Color) = (1,1,1,1)_MainTex ("Main Tex", 2D) = "white" {}_AlphaScale("Alpha Scale", Range(0,1)) = 1}SubShader{Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}Pass{Tags{ "LightMode" = "ForwardBase"}Cull FrontZWrite Off//关闭深度写入Blend SrcAlpha OneMinusSrcAlpha//将源颜色的混合因子设为SrcAlpha 目标颜色的混合因子设为OneMinusSrcAlphaCGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;fixed _AlphaScale;struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;float2 uv : TEXCOORD2;};v2f vert(a2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);return o;}fixed4 frag(v2f i) : SV_Target{fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed4 texColor = tex2D(_MainTex,i.uv);fixed3 albedo = texColor.rgb * _Color.rgb;fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir));return fixed4(ambient + diffuse,texColor.a * _AlphaScale);//设置透明通道}ENDCG}Pass{Tags{ "LightMode" = "ForwardBase"}Cull BackZWrite Off//关闭深度写入Blend SrcAlpha OneMinusSrcAlpha//将源颜色的混合因子设为SrcAlpha 目标颜色的混合因子设为OneMinusSrcAlphaCGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;fixed _AlphaScale;struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;float2 uv : TEXCOORD2;};v2f vert(a2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);return o;}fixed4 frag(v2f i) : SV_Target{fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed4 texColor = tex2D(_MainTex,i.uv);fixed3 albedo = texColor.rgb * _Color.rgb;fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir));return fixed4(ambient + diffuse,texColor.a * _AlphaScale);//设置透明通道}ENDCG}}FallBack "Transparent/VertexLit"
}

只是把Pass复制了两份 然后第一个写的Cull Back 第二个是Cull Front

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

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

相关文章

openGauss学习笔记-99 openGauss 数据库管理-管理数据库安全-客户端接入认证之配置文件参考

文章目录 openGauss学习笔记-99 openGauss 数据库管理-管理数据库安全-客户端接入认证之配置文件参考99.1 参数说明99.2 认证方式 openGauss学习笔记-99 openGauss 数据库管理-管理数据库安全-客户端接入认证之配置文件参考 99.1 参数说明 表 1 参数说明 参数名称描述取值范…

swift ui 布局 ——Stack(HStack、VStack、ZStack)

一、HStack 水平布局 将其子视图排列在水平线上 import Foundation import SwiftUI struct MyView: View {var body: some View {HStack{Text("text")Image("yuyin").resizable().frame(width: 102,height: 80)}} } 默认子视图是水平中心对齐的,可添加al…

python+django高校教室资源预约管理系统lqg8u

技术栈 后端&#xff1a;pythondjango 前端&#xff1a;vueCSSJavaScriptjQueryelementui 开发语言&#xff1a;Python 框架&#xff1a;django/flask Python版本&#xff1a;python3.7.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyChar…

Go语言入门心法(五): 函数

一: go语言函数认知 Go语言入门心法(一): 基础语法 Go语言入门心法(二): 结构体 Go语言入门心法(三): 接口 忙着去耍帅,后期补上..........

集合的进阶

不可变集合 创建不可变的集合 在创建了之后集合的长度内容都不可以变化 静态集合的创建在list &#xff0c;set &#xff0c;map接口当中都可以获取不可变集合 方法名称说明static list of(E …elements)创建一个具有指定元素集合list集合对象staticlist of(E…elements)创…

掌握Python爬虫实现网站关键词扩展提升曝光率

目录 一、关键词优化的重要性 二、关键词优化的基本方法 1、选择与网站内容相关的关键词 2、控制关键词的密度和分布 3、关键词的层次布局 三、Python爬虫实现网站关键词扩展 1、确定目标网站 2、分析目标网站的HTML结构 3、编写Python爬虫代码 4、分析爬取到的关键词…

BSPHP 未授权访问 信息泄露

漏洞描述 BSPHP 存在未授权访问 泄露用户 IP 和 账户名信息 漏洞复现 访问url&#xff1a; 构造payload访问&#xff1a; /admin/index.php?madmin&clog&atable_json&jsonget&soso_ok1&tuser_login_log&page1&limit10&bsphptime16004073…

25栈和队列-理解栈和队列

目录 LeetCode之路——232. 用栈实现队列 分析&#xff1a; LeetCode之路——225. 用队列实现栈 分析&#xff1a; 栈&#xff08;Stack&#xff09;和队列&#xff08;Queue&#xff09;是两种基本的数据结构&#xff0c;它们在计算机科学中用于不同的目的。以下是它们的定…

【windows下docker安装rocketMQ】

namesrv和broker安装就不说了&#xff0c;见如下博客 https://blog.csdn.net/Wonderful1025/article/details/107244434/ 安装rocketMQ-console docker run -d -e "JAVA_OPTS-Drocketmq.config.namesrvAddr192.168.65.2:9876 -Drocketmq.config.isVIPChannelfalse"…

12.SpringBoot之RestTemplate的使用

SpringBoot之RestTemplate的使用 初识RestTemplate RestTemplate是Spring框架提供用于调用Rest接口的一个应用&#xff0c;它简化了与http服务通信方式。RestTemplate统一Restfull调用的标准&#xff0c;封装HTTP链接&#xff0c;只要需提供URL及返回值类型即可完成调用。相比…

Spark中的Driver、Executor、Stage、TaskSet、DAGScheduler等介绍

工作流程&#xff1a; Driver 创建 SparkSession 并将应用程序转化为执行计划&#xff0c;将作业划分为多个 Stage&#xff0c;并创建相应的 TaskSet。Driver 将 TaskSet 发送给 TaskScheduler 进行调度和执行。TaskScheduler 根据资源情况将任务分发给可用的 Executor 进程执…

DAE转换GLB格式

1、DAE模型介绍 DAEA&#xff08;Deep Attentive and Ensemble Autoencoder&#xff09;模型是一种用于无监督学习的深度学习模型&#xff0c;由华为公司提出。DAEA模型结合了自编码器和深度注意力机制&#xff0c;能够对高维数据进行降维和特征提取&#xff0c;并且在处理大规…

博图数值按照特定格式(“T000000”)转换成字符串

一、前言 1.string to dint物流输送线往往需要通过扫码器读取托盘条码&#xff0c;一维码或者二维码​。 读取的数据需要解析才能正常使用。两种方式读取的数据直接是字符串&#xff0c;但当设备与上位机通信时&#xff0c; 字符串数据量太大&#xff0c;故可以通过算法转换成…

Ceph分布式存储的简单介绍与Ceph集群的部署搭建

文章目录 1. 存储的概述1.1 单机存储设备1.1.1 DAS&#xff08;直接附加存储&#xff09;1.1.2 NAS&#xff08;网络附加存储&#xff09;1.1.3 SAN&#xff08;存储区域网络&#xff09; 1.2 单机存储的缺陷1.3 分布式存储&#xff08;软件定义的存储 SDS&#xff09;1.4 分布…

unity ugui text 超链接和下划线,支持部分富文本格式

unity版本&#xff1a;2021.3.6f1 局限性&#xff1a; 1.测试发现不能使用 size 富文本标签, 2.同一文本不能设置不同颜色的超链接文本 其它&#xff1a;代码中注释掉使用innerTextColor的地方&#xff0c;可以使用富文本设置超链接颜色&#xff0c; 但是下划线是文本本身颜色 …

windows部署django服务器

windows部署django服务器 1、安装IIS1.1 控制面板-----程序----程序和功能----启用或关闭windows功能1.2安装IIS服务器&#xff0c;完成后&#xff0c;重新进入&#xff0c;把CGI安装进系统 2、安装python与虚拟环境2.1 安装python2.2 安装virtualenv虚拟环境2.3 创建一个虚拟环…

求二叉树的高度——函数递归的思想

二叉树的高度&#xff1a;左右两个数最高的那个的1 int TreeHight(BTNode* root) {if (root NULL){return 0;}int lefhightTreeHight(root->left);int righthight TreeHight(root->right);return lefhight > righthight ? TreeHight(root->left) 1 : TreeHight…

想要精通算法和SQL的成长之路 - 连续的子数组和

想要精通算法和SQL的成长之路 - 连续的子数组和 前言一. 连续的子数组和1.1 最原始的前缀和1.2 前缀和 哈希表 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 连续的子数组和 原题链接 1.1 最原始的前缀和 如果这道题目&#xff0c;用前缀和来算&#xff0c;我们的思路…

雷电模拟器上使用第一个frida(三)简单的使用实例

经过前两篇 雷电模拟器上使用第一个frida&#xff08;一&#xff09;之安装-CSDN博客雷电模拟器上使用第一个frida&#xff08;二&#xff09;之su超级权限-CSDN博客 本篇开始记录如何使用frida进行hook。 一、先让手机模拟器端的frida server运行起来 虽然是让手机模拟器端…

Rust 流程控制

开发中最常见的用来控制执行流的结构是判断和循环。 判断 Rust 中的 if 表达式允许根据条件执行不同的代码分支&#xff0c;提供一个条件并表示 “如果条件满足&#xff0c;运行这段代码&#xff1b;如果条件不满足&#xff0c;不运行这段代码。” 需要注意的是&#xff0c;…