5.透明效果

实时渲染中要实现透明效果,通常会在渲染模型时控制它的透明通道(Alpha channel)

当一个物体被渲染到屏幕上时,每个片元除了颜色和深度值之外,它还有另一个属性—透明度。

当透明度为1时,表示该像素是完全不透明的,当为0时,表示该像素完全不会显示

Unity中实现透明效果有两种方法:

  • 透明度测试(Alpah Test):但无法得到真正的半透明效果
  • 透明度混合(Alpha Blending)

对于不透明物体,不考虑它们的渲染顺序也能得到正确的排序效果,这是深度缓冲的(depth buffer,也被称为z-buffer)的存在。

在实时渲染中,深度缓冲是用于可见性问题的,它可以绝定哪个物体的哪些部分会被渲染到前面,而哪些物体会被其他物体遮挡。

基本思想为为:根据深度缓冲中的值来判断该片元距离摄像机的距离,当渲染一个片元时,需要把它的深度值和已经存在于深度缓冲中的值进行比较(如果开启了深度测试),如果它的值距离摄像机更远,那么说明这个片元不该被渲染到屏幕上(有物体挡住了它);否则,这个片元因该覆盖掉此时颜色缓冲中的像素值,并把它的深度值更新到深度缓冲中(如果开启了深度写入)。

使用深度缓冲,可以不关心不透明物体的渲染顺序。但如果要实现透明效果,使用透明度混合时,就要关闭深度写入

透明度测试:

  • 只要一个片元的透明度不满足条件(通常是小于某个阈值),那么它对应的片元就会被舍弃。
  • 舍弃的片元不再进行任何处理,也不会对颜色缓冲产生任何影响
  • 否则就会按照普通的不透明物体的处理方式来处理它,进行深度测试,深度写入等
  • 不需要关闭深度写入,它和其他不透明物体最大的不同:它会根据透明度来舍弃一些片元。但是极端的,要么完全不透明,要么完全透明。

透明度混合:

  • 可以得到真正的半透明效果
  • 使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色
  • 需要关闭深度写入,所以要非常小心物体的渲染顺序。
  • 透明度混合只关闭深度写入,不关闭深度测试
  • 当使用透明度混合渲染一个片元时,还是会比较它的深度值与当前深度缓冲中的深度值,如果它的深度值距离摄像机更远,那么就不会再进行混合操作
  • 当一个不透明物体出现在在一个透明物体的前面,我们先渲染不透明物体
  • 而我们先渲染不透明物体,它任然可以正常的遮挡住透明物体
  • 也就是说透明度混合中,深度缓冲是只读的

一、为什么渲染顺序很重要

渲染引擎一般都会先对物体进行排序,再进行渲染。常用的方法:

(1)先渲染所以不透明物体,并开启它们的深度测试和深度写入

(2)把半透明物体按照它们的距离摄像机的远近进行排序,然后按照从后往前的顺序渲染这些半透明物体,并开启它们的深度测试,但关闭深度写入

二、Unity Shader的渲染顺序

为了解决渲染顺序的问题,Unity提供了渲染队列,这一解决方案。

可以用SubShader的Queue标签来决定模型将归于哪个渲染队列。

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

如果我们想要通过透明度测试实现透明效果,代码中应包含类似一下代码

SubShader {Tags { “Queue”=“AlphaTest” }Pass {...}
}

如果我们想要通过透明度混合来实现透明效果, 代码中应包含类似一下代码

SubShader {Tags { “Queue”=“TransParent” }Pass {ZWrite Off...}
}

其中 ZWrite Off用于关闭深度写入,这里把它写在Pass中。

也可以写在SubShader中,这意味着该SubShader下的所有Pass都会关闭深度写入

三、透明度测试

透明度测试:只要一个片元的透明度不满足条件(通常是小于某个阈值),那么它对应的片元就会被舍弃。被舍弃的片元将不会再进行任何处理,也不会对颜色缓冲产生任何影响;否则,就会按照普通的不透明物体的处理方式来处理它

通常,在片元着色器中使用Clip函数来进行透明度测试。

Clip函数定义:

函数:void Clip(float4 x);void Clip(float3 x);void Clip(float2 x);void Clip(float x);void Clip(float x);

参数:裁剪时使用的标量或矢量条件

描述:如果给定参数的任何一个分量时负数,就会舍弃当前像素的输出颜色。它等同于下面代码

void Clip(float4 x)
{if (any(x < 0))discard;
}


 

Shader "Shader/AlphaTest"
{Properties{_Color ("Main Tint", Color) = (1,1,1,1)_MainTex ("Texture", 2D) = "white" {}//_Cutoff参数用于决定我们调用clip进行透明度测试时使用的判断条件。_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5}SubShader{Tags { "Queue"="AlphaTest" // 透明度测试使用的渲染队列名为AlphaTest"IgnoreProjector"="True"//Shader不会受到投影器Projectors的影响"RenderType"="TransparentCutout" //RenderType标签用于着色器替换功能}Pass{Tags { "LightMode"="ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;float4 uv : TEXCOORD0;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;float2 uv : TEXCOORD2;};fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;fixed _Cutoff;v2f vert (appdata 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.uv, _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);//Alpha testclip(texColor.a - _Cutoff);fixed3 albedo =texColor.rgb * _Color.rgb;fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldLightDir, worldNormal));return fixed4(ambient + diffuse, 1.0);}ENDCG}}Fallback "Transparent/Cutout/VertexLit"
}

四、透明度混合

透明度混合:这种方法可以得到真正的半透明效果。它会使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。但是,透明度混合需要关闭深度写入,这使得我们要非常小心物体的渲染顺序。

Blend:Blend是Unity通过的设置混合模式的命令。要想实现半透明的效果就要把当前自身的颜色和已经存在于颜色缓冲中的颜色值进行混合,混合时使用的函数就是由该指令决定的。

 Blend SrcFactor DstFactor:

这个命令在设置混合因子的同时也开启了混合模式。只要开启混合之后,设置片元的透明通道才有意义,而Unity在我们使用Blend命令的时候就自动帮我们打开了。

如果模型没有任何透明效果,可能是因为没有在pass中使用Blend命令,一方面没有设置混合因子,另一方面没有打开混合模式。

把源颜色的混合因子SrcFactor设为SrcAlpha,而目标颜色的混合因子DstFactor设为OneMinusSrcAlpha。

混合后的新颜色为:
DstColor_{new}=SrcAlpha\times SrcColor+(1-SrcAlpha)\times DstColor_{old}

Shader "Shader/AlphaBlend"
{Properties{_Color ("Main Tint", Color) = (1,1,1,1)_MainTex ("Texture", 2D) = "white" {}_AlphaScale ("Alpha Scale", Range(0, 1)) = 1//在透明纹理的基础上控制整体的透明度}SubShader{Tags { "Queue"="Transparent" //Transparent"IgnoreProjector"="True"//Shader不会受到投影器Projectors的影响"RenderType"="Transparent" //RenderType标签用于着色器替换功能}Pass{Tags { "LightMode"="ForwardBase" }//前向渲染ZWrite Off//关闭深度写入Blend SrcAlpha OneMinusSrcAlpha//开启混合模式CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;float4 uv : TEXCOORD0;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;float2 uv : TEXCOORD2;};fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;fixed _AlphaScale;v2f vert (appdata 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.uv, _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.xyz * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldLightDir, worldNormal));return fixed4(ambient + diffuse, texColor.a * _AlphaScale);}ENDCG}}Fallback "Transparent/VertexLit"
}

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

当模型本身有复杂的遮挡关系或者包含了复杂的非凹凸网格的时候,就会有各种各样因为排序错误而产生的透明效果

使用两个Pass来渲染模型:

第一个Pass开启深度写入,但不输入颜色,它的目的仅仅是为了把该模型的深度值写入深度缓冲中;

第二个Pass进行正常的透明度混合,由于上一个Pass已经得到了逐像素的正确深度信息,该Pass进就可以按照下像素级别的深度排序结果进行渲染透明。

缺点是:多使用一个Pass会对性能造成一定的影响

Shader "Shader/AlphaBlendZWrite"
{Properties{_Color ("Main Tint", Color) = (1,1,1,1)_MainTex ("Texture", 2D) = "white" {}_AlphaScale ("Alpha Scale", Range(0, 1)) = 1//在透明纹理的基础上控制整体的透明度}SubShader{Tags { "Queue"="Transparent" //Transparent"IgnoreProjector"="True"//Shader不会受到投影器Projectors的影响"RenderType"="Transparent" //RenderType标签用于着色器替换功能}Pass{ZWrite On//开启深度写入ColorMask 0//ColorMask用于设置颜色通道的写掩码//语义://ColorMask RGB |A | 0 |其他任何R、G、B、A的组合//当ColorMask设置为0时,意味着该Pass不写入任何颜色通道,即不会输入任何颜色//这正是我们需要的——该Pass只需要写入深度缓存即可}Pass{Tags { "LightMode"="ForwardBase" }//前向渲染ZWrite Off//关闭深度写入Blend SrcAlpha OneMinusSrcAlpha//开启混合模式CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;float4 uv : TEXCOORD0;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;float2 uv : TEXCOORD2;};fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;fixed _AlphaScale;v2f vert (appdata 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.uv, _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.xyz * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldLightDir, worldNormal));return fixed4(ambient + diffuse, texColor.a * _AlphaScale);}ENDCG}}Fallback "Diffuse"
}

六、ShaderLab的混合命令

 混合是如何实现的:

当片元着色器产生一个颜色时,可以选择与颜色缓存中的颜色进行混合。这样一来混合就和两个操作有关:源颜色和目标颜色。

源颜色:用S表示。指由片元着色器产生的颜色值;

目标颜色:用D表示,指的是从颜色缓冲中读取到的颜色值。

输出颜色:对它们混合后得到的输出颜色用O表示,它会重新写入颜色缓冲区中。

注意:当我们谈及混合中的源颜色、目标颜色和输出颜色时,它们都包含了RGBA四个通道值,并非仅仅时RGB通道

如何开始混合: 

在Unity中,使用Blend(Blend Off命令除外)命令时,除了设置混合状态也开启了混合。但在其他图像API中要手动开启。如OpenGL中,我们要使用glEnable(GL_BLEND)来开启混合。但在Unity中,他已经在背后为我们做了这些工作

1.混合等式和参数

混合等式:用源颜色S和目标颜色D得到输出颜色O的等式。进行混合时,需要使用两个混合等式,一个用于混合RGB通道,一个用于混合A通道。当设置混合状态时,我们实际设置的就是混合等式中的操作和因子。

第一个命令指提供两个因子,使用同样的混合因子来混合RGB通道和A通道,即此时SrcFactorA将等于DStFactor。

使用这些因子进行加法混合时使用的混合公式:

O_{rgb}=SrcFactor\times S_{rgb}+DstFactor\times D_{rgb}

O_{a}=SrcFactorA\times S_{a}+DstFactorA\times D_{a}

混合因子有哪些值呢?

RGB通道的混合因子和A通道的混合因子都是一样的,有时我们希望可以使用不同的参数混合A通道,这时就可以利用Blend SrcFactor DstFactor, SrcFactorA  DstFactorA指令。

如:混合后,输出颜色的透明度值就是源颜色的透明度

Blend SrcAlphaA OneMinusSrcAlpha, One Zero

2.混合操作

BlendOp BlendOperation

 混合操作命令通常是与混合因子命令一起工作的。注意:当使用Min或Max混合操作时,混合因子不起作用,它们仅会判断原始的源颜色和目标颜色之间的比较结果

3.常见的混合类型

使用Min和Max混合操作时仍然设置了混合因子,但并不会对结果有任何影响 

七、双面渲染的透明效果

如果一个物体是透明的,意味着我们不仅可以透过它看其他物体的样子,也可以看到它内部的结构。但在现实的透明效果中,无论是透明度测试还是透明度混合,我们都无法观察到正方形内部以及其背面的形状,导致物体看起来好像只要半个。

默认情况下渲染引擎剔除物体背面的渲染图元,只渲染物体的正面。如果想要双面效果,可以使用Cull指令来控制需要剔除哪个面的渲染图元。

在unity中,Cull指令的语法如下:

Cull Back | Front | Off

Back:背对着摄像机的渲染图元就不会被渲染,这也是默认情况下的剔除状态;

Front:朝向摄像机的渲染图元不会被渲染;

Off:关闭剔除功能,所有图元都会被渲染,但需要渲染的图元会成倍增加,除特殊效果,一般是不会关闭的

1.透明度测试的双面渲染

如何使用透明测试实现双面渲染的效果。只需要在Pass的渲染设置中使用Cull指令来关闭剔除即可

2.透明度混合的双面渲染

把双面渲染的工作分成两个Pass——第一个Pass只渲染背面,第二个Pass只渲染正面,unity会顺序执行SubShader中的各个Pass,因此可以保证背面总是被渲染之前渲染,从而保证深度渲染关系正确

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

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

相关文章

Dvws靶场

文章目录 一、XXE外部实体注入二、No-SQL注入三、Insecure Direct Object Reference四、Mass Assignment五、Information Disclosure六、Command Injection七、SQL注入 一、XXE外部实体注入 访问http://192.168.92.6/dvwsuserservice?wsdl&#xff0c;发现一个SOAP服务。在SO…

MySQL 存储过程(二)

本篇继续介绍MySQL存储过程的相关内容。 目录 一、if语句 二、case 三、循环语句 while loop repeat 一、if语句 在存储过程中&#xff0c;可以使用if语句进行条件判断&#xff0c;其语法结构如下&#xff1a; if 判断语句 then 逻辑语句..... elseif 判断语句 then 逻…

【Linux取经路】初识信号

文章目录 一、人眼中的信号 VS 进程眼中的信号二、ctrlc 终止一个前台进程三、查看信号信息3.1 Core dump——核心转储功能验证 四、信号的处理方式五、ctrlc 被解释成2号信号验证5.1 signal——设置自定义捕捉方法 六、ctrlc 是如何变成信号的&#xff1f;七、异步、软中断八、…

【SQL边干边学系列】04中级问题(续)

文章目录 前言回顾中级问题25.高昂运费26.2015年的高昂运费27.高昂运维 - 使用between28.去年的高昂运费29.库存清单30.没有任何订单的客户31.没有任何订单的客户&#xff0c;员工ID为4 答案25.高昂运费26.2015年的高昂运费27.高昂运维 - 使用between28.去年的高昂运费29.库存清…

CVE-2022-4230

CVE-2022-4230 漏洞介绍 WP Statistics WordPress 插件13.2.9之前的版本不会转义参数&#xff0c;这可能允许经过身份验证的用户执行 SQL 注入攻击。默认情况下&#xff0c;具有管理选项功能 (admin) 的用户可以使用受影响的功能&#xff0c;但是该插件有一个设置允许低权限用…

DDMA信号处理以及数据处理的流程---DDMA原理介绍

Hello&#xff0c;大家好&#xff0c;我是Xiaojie&#xff0c;好久不见&#xff0c;欢迎大家能够和Xiaojie一起学习毫米波雷达知识&#xff0c;Xiaojie准备连载一个系列的文章—DDMA信号处理以及数据处理的流程&#xff0c;本系列文章将从目标生成、信号仿真、测距、测速、cfar…

vscode设置代码自动换行显示

☆ 问题描述 vscode设置代码自动换行显示 ★ 解决方案 ✅ 总结

每日两题 / 198. 打家劫舍 74. 搜索二维矩阵(LeetCode热题100)

198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; dp[i]表示考虑前i 1号房屋&#xff0c;能获取的最大金额。对于没一间房屋都有偷与不偷两种选择 如果偷&#xff0c;需要从dp[i - 2]转移&#xff0c;因为不能偷窃相邻房屋&#xff0c;dp[i] dp[i - 2] nums[i] 如果…

稍微学学react

文章开始前&#xff0c;先划划水~ 今日份开心&#xff1a; 今天看之前发布的按钮npm包下载量有162次&#xff0c;早知道好好做了 今日份不开心&#xff1a; 爬岗位看到一个整体都挺满意的岗位&#xff0c;公司位置和发展大方向都好喜欢&#xff01;&#xff01;&#xff01;…

【PL理论】(6) F#:标准库之列表(List)

​​​​​ &#x1f4ad; 写在前面&#xff1a;本章我们将介绍 F# 标准库的列表&#xff0c;我们将简单的先过一遍列表的一些常用操作&#xff0c;具体的讲解我们将放在后续章节。 目录 0x00 标准库&#xff1a;列表&#xff08;List&#xff09; 0x01 模式匹配与列表 0x…

14.8k Star!CrewAI:部署一支由你指挥的人工智能代理大军,股票分析、发布帖子、支持Ollama!

原文链接&#xff1a;&#xff08;更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号&#xff01;&#xff09; 14.8k Star&#xff01;CrewAI&#xff1a;部署一支由你指挥的人工智能代理大军&#xff0c;股票分析、发布帖子、支持Ollama&#xff01;…

计算机组成结构—多处理器

目录 一、SISD、SIMD、MIMD 和向量处理器 1. 费林分类法 2. SIMD 和向量处理器 二、硬件多线程 三、多核处理器和 SMP 1. 多核处理器 2. 共享内存多处理器&#xff08;SMP&#xff09; 3. MPP 和集群 一、SISD、SIMD、MIMD 和向量处理器 通过改进系统结构&#xff0c;可…

C++设计模式-外观模式,游戏引擎管理多个子系统,反汇编

运行在VS2022&#xff0c;x86&#xff0c;Debug下。 30. 外观模式 为子系统定义一组统一的接口&#xff0c;这个高级接口会让子系统更容易被使用。应用&#xff1a;如在游戏开发中&#xff0c;游戏引擎包含多个子系统&#xff0c;如物理、渲染、粒子、UI、音频等。可以使用外观…

图像算法---自动曝光AE

一&#xff0c;自动曝光AE 自动曝光&#xff08;AE&#xff0c;全称Auto Exposure&#xff09;是一种在摄影和摄像中广泛使用的技术&#xff0c;它允许相机或摄像机根据环境光线条件自动调整曝光参数&#xff0c;以获得清晰、亮度适中的图像或视频。以下是关于自动曝光AE的详细…

31|HTTP3:甩掉TCP、TLS 的包袱,构建高效网络

前面两篇文章我们分析了HTTP/1和HTTP/2&#xff0c;在HTTP/2出现之前&#xff0c;开发者需要采取很多变通的方式来解决HTTP/1所存在的问题&#xff0c;不过HTTP/2在2018年就开始得到了大规模的应用&#xff0c;HTTP/1中存在的一大堆缺陷都得到了解决。 HTTP/2的一个核心特性是…

优卡集团冲刺港股上市:90后创始团队孵化,IPO前突击大额分红

现年26岁的鲁圳&#xff0c;正在带领其6年以来的创业成果冲击资本市场。 近日&#xff0c;金融居间机构服务商优卡集团&#xff08;Yoc Group&#xff09;向港交所递交上市申请&#xff0c;民银资本为其独家保荐人。透过招股书可知&#xff0c;优卡集团成立于2018年&#xff0…

【CTF-Web】文件上传漏洞学习笔记(ctfshow题目)

文件上传 文章目录 文件上传What is Upload-File&#xff1f;Upload-File In CTFWeb151考点&#xff1a;前端校验解题&#xff1a; Web152考点&#xff1a;后端校验要严密解题&#xff1a; Web153考点&#xff1a;后端校验 配置文件介绍解题&#xff1a; Web154考点&#xff1a…

vcruntime140.dll找不到的正确处理方法,vcruntime140.dll是什么文件

vcruntime140.dll找不到的这个问题&#xff0c;相信不少人都有遇到吧&#xff1f;其实遇到了也不需要害怕&#xff0c;这只是一个很小的问题&#xff0c;我们完全可以自己快速修复。还有就是缺失这个vcruntime140.dll文件&#xff0c;你的一些程序是会打不开的&#xff0c;不用…

揭秘!2024版Camtasia永久免费,全新功能体验

在当今数字时代&#xff0c;视频已经成为了我们生活中不可或缺的一部分。无论是在工作中进行演示、培训&#xff0c;还是在生活中分享生活点滴&#xff0c;视频都扮演着重要的角色。而要想制作出高质量的视频&#xff0c;一款专业的录屏软件是必不可少的。今天&#xff0c;我就…

PHP函数大全之array_count_values()

array_count_values()函数是用于计算数组中每个值的出现次数的PHP函数&#xff0c;并返回一个关联数组&#xff0c;该数组的键表示原始数组中的唯一值&#xff0c;而键值表示该值在原始数组中的出现次数。 array_count_values()函数的一些注意事项&#xff1a; 该函数不区分大…