在Unity中实现透明效果的方式有两种,其一是透明度测试,其二是透明度混合。
在之前的Shader中我们并没有关心过物体渲染顺序的问题。这是因为深度缓冲的存在。当渲染一个片元时,需要把它的深度值与已经存在于深度缓冲中的值进行比较,如果它的深度值更大,说明有物体挡住了它,这个片元就不应该被渲染到屏幕上;反之,这个片元就会覆盖掉颜色缓冲中的像素值,它的深度值也会更新到深度缓冲中。也就是说,有深度缓冲在,即便我们先渲染了前面的物体A,再渲染了后面的物体B,也不用担心B会覆盖掉A。因为已经在深度缓冲中判断出B在A的后面。
那么进行透明度混合时为什么要关闭深度写入呢?对于一个半透明物体来讲,其后面的物体应该是可以透过它看到的。但如果开启了深度写入,距离摄像机更近的透明物体的深度就会覆盖掉后面的物体。从而后面物体的表面将会被剔除,我们也就无法通过透明物体观察到后面的物体了。
一旦关闭了深度写入,事情就会变得复杂起来。

比如上面这两个物体,A是半透明物体,B是不透明物体。
那么如果是两个半透明物体又会怎样呢?下图中A和B都是半透明物体。

渲染引擎在渲染前一般会先对物体进行排序。先渲染所有不透明物体,并开启它们的深度测试和深度写入。然后再把半透明物体按从后往前的顺序进行渲染,并开启深度测试,关闭深度写入。尽管如此,仍然会有些不理想的情况:

像上面几种无法得到正确排序顺序的情况,就只能将物体进行拆分或是让透明通道更加柔和,让穿插不是这么明显。
Unity为了解决渲染顺序的问题,提供了渲染队列这一解决方案。我们可以在SubShader的Tags中决定模型使用哪个渲染队列。

接下来我们实现透明度测试效果。首先将之前的纹理采样的Shader复制过来。这里不考虑高光,所以将计算高光的部分删掉
Shader "Unlit/AlphaTest"
{
Properties
{
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Gloss("Gloss",Range(1,256)) = 20
_MainTex("MainTex",2D) = "white" {}
}
SubShader
{
Tags
{
"LightMode"="ForwardBase"
}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _Diffuse;
float _Gloss;
sampler2D _MainTex;
float4 _MainTex_ST;
struct v2f
{
float4 vertex: SV_POSITION;
fixed3 worldNormal: TEXCOORD0;
float2 uv:TEXCOORD1;
};
v2f vert(appdata_base v)
{
v2f o;
// 将顶点坐标从物体空间转换到裁剪空间
o.vertex = UnityObjectToClipPos(v.vertex);
// 将法线从物体空间转换到世界空间
o.worldNormal = UnityObjectToWorldNormal(v.normal);
// 计算uv坐标
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
}
fixed4 frag(v2f i):SV_Target
{
// 获取归一化的光源方向
const fixed3 worldLight = normalize(_WorldSpaceLightPos0);
const fixed3 albedo = tex2D(_MainTex,i.uv).rgb;
// 环境光
const fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
// 计算漫反射
const fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * (0.5*dot(i.worldNormal, worldLight)+0.5);
fixed3 color = ambient + diffuse;
return fixed4(color, 1);
}
ENDCG
}
}
}
首先定义一个属性作为透明度测试时的判断条件,并在CG中定义与之匹配的变量
_Cutoff("Alpha Cutoff",Range(0,1)) = 0.5
在Tags中将渲染队列设置为「AlphaTest」,并忽略投影器的影响
Tags
{
"Queue"="AlphaTest"
"IgnoreProjector"="True"
}
最后在片元着色器中根据纹理的alpha通道的值进行剔除
fixed4 frag(v2f i):SV_Target
{
// 获取归一化的光源方向
const fixed3 worldLight = normalize(_WorldSpaceLightPos0);
const fixed4 texColor = tex2D(_MainTex,i.uv);
// 根据条件剔除
if(texColor.a - _Cutoff < 0)
{
discard;
}
// 环境光
const fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
// 计算漫反射
const fixed3 diffuse = _LightColor0.rgb * texColor.rgb * _Diffuse.rgb * (0.5*dot(i.worldNormal, worldLight)+0.5);
fixed3 color = ambient + diffuse;
return fixed4(color, 1);
}
找一张alpha值不同的图片作为纹理,得到如下效果

Unity提供了设置混合模式的命令——Blend。混合时使用的函数就由该指令决定。Unity提供的Blend指令如下

对于「Blend SrcFactor DstFactor」和「Blend SrcFactor DstFactor,SrcFactorA DstFactorA」两个命令,它们实际上表达的是两个混合公式
O
r
g
b
=
S
r
c
F
a
c
t
o
r
×
S
r
g
b
+
D
s
t
F
a
c
t
o
r
×
D
r
g
b
O_{rgb}=SrcFactor×S_{rgb}+DstFactor×D_{rgb}
Orgb=SrcFactor×Srgb+DstFactor×Drgb
O
a
=
S
r
c
F
a
c
t
o
r
A
×
S
a
+
D
s
t
F
a
c
t
o
r
A
×
D
a
O_{a}=SrcFactorA×S_{a}+DstFactorA×D_{a}
Oa=SrcFactorA×Sa+DstFactorA×Da
其中
O
r
g
b
、
O
a
O_{rgb}、O_{a}
Orgb、Oa代表混合后的rgb通道和a通道,
S
r
g
b
、
S
a
S_{rgb}、S_{a}
Srgb、Sa代表源颜色通道,
D
r
g
b
、
D
a
D_{rgb}、D_{a}
Drgb、Da代表目标颜色通道。第一个命令只提供了两个因子,意味着rgb通道和a通道的混合因子都是SrcFactor和DstFactor。
那么这些混合因子可以有哪些值呢?

另外,前面的公式将源颜色和目标颜色与混合因子的乘积相加得出最终结果。我们当然也可以自定义其他的混合操作。「BlendOP BlendOperation」的作用就是如此。Unity提供的混合操作如下

下面列出了常见的混合类型,类似于PS中对应的混合效果
// 正常(Normal),即透明度混合
Blend SrcAlpha OneMinusSrcAlpha
// 柔和相加(Soft Additive)
Blend OneMinusDstColor One
// 正片叠底(Multiply),即相乘
Blend DstColor Zero
// 两倍相乘(2x Multiply)
Blend DstColor SrcColor
// 变暗(Darken)
BlendOp Min
Blend One One
// 变亮(Lighten)
BlendOp Max
Blend One One
// 滤色(Screen)
Blend OneMinusDstColor One
// 等同于
Blend One OneMinusSrcColor
// 线性减淡(Linear Dodge)
Blend One One
接下来我们尝试实现透明度混合。依然是基于之前的纹理采样的Shader进行修改。
首先定义一个属性用来控制整体的透明度,并在CG中声明对应变量
_AlphaScale("Alpha Scale",Range(0,1)) = 1
在Tags中指定渲染队列,忽略投影器影响,将「RenderType」设置为「Transparent」
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
}
在Pass通道中,将光照模式设置为前项渲染路径,关闭深度写入,并设置混合模式
Tags{ "LightMode"="ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
最后设置片元着色器返回值中的透明通道
fixed4 frag(v2f i):SV_Target
{
const fixed3 worldLight = normalize(_WorldSpaceLightPos0);
const fixed4 texColor = tex2D(_MainTex,i.uv);
const fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
const fixed3 diffuse = _LightColor0.rgb * texColor.rgb * _Diffuse.rgb * (0.5*dot(i.worldNormal, worldLight)+0.5);
fixed3 color = ambient + diffuse;
// 修改返回值中的透明通道
return fixed4(color, texColor.a * _AlphaScale);
}
效果如下

但假如我们换一个模型,就会发现这样做有些许问题

很明显,当模型网格相互交叉时,会得到错误的半透明效果。这是因为我们关闭了深度写入,无法对模型进行像素级别的深度排序。解决方案是增加一个Pass通道,在新的Pass通道中开启深度写入,但不输出颜色。这样就会先把模型的深度值写入缓冲中。当第二个Pass再进行透明度混合时,由于上一个Pass已经获得了逐像素的正确深度信息,因而该Pass就可以按照深度排序结果进行透明渲染。当然,这样做的缺点也很明显:多使用了一个Pass会对性能造成影响。
// 新增一个Pass
Pass
{
ZWrite On
// 不写入任何颜色通道
ColorMask 0
}
效果如下

ruby调试器不会在我在与执行开始时不同的文件中设置的断点处停止。例如,考虑这两个文件,foo.rb:#foo.rbclassFoodefbarputs"baz"endend和main.rb:#main.rbrequire'./foo'Foo.new.bar我使用ruby-rdebug.\main.rb开始调试。现在,当我尝试使用b./foo.rb:4在另一个文件的特定行上设置断点时,我收到消息Setbreakpoint1atfoo.rb:4,但是当我cont时,程序执行到最后,调试器永远不会停止。但是,如果我在main.rb中的一行上打断,例如b./main.rb:3,或者一个方法,
今天我在我的Rails控制台中尝试了一些东西,这发生了,2.0.0p247:009>Date.today-29.days=>Fri,07Feb20142.0.0p247:010>Date.today-29.days=>Thu,09Jan2014我很困惑。我可以看到我缺少一些基本的东西。但这让我印象深刻!谁能解释为什么会这样? 最佳答案 实际发生的是这样的:Date.today(-29.days)#=>Fri,07Feb2014today有一个名为start的可选参数,默认为Date::ITALY。Anoptionalargument
视频教程:https://www.bilibili.com/video/BV1WJ411778C/?spm_id_from=333.999.0.0&vd_source=4a4c35da6aef7094d5990c213c39aa09使用素材(推荐使用GitZipforgithub下载):https://github.com/zheyuanzhou/Youtube-Unity-Tutorial/tree/master/EP45_Health%20Bar/Sprites效果如下图所示:首先在场景中创建一个新的Canvas,并命名为HeathBar,并创建三个Image作为前者的子物体,分别命名为
我需要从此图像中删除白色背景并使背景透明。所以它只是导出为png的透明背景上的黑色勾号。例如转动进入有什么想法吗? 最佳答案 convertimage.png-matte-fillnone-fuzz1%-opaquewhiteresult.png用透明替换任何白色。模糊选项包括几乎是白色的任何东西。 关于ruby-RMagick从图像中删除白色背景并使其透明,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.c
一、如何实现透明效果在Unity中实现透明效果的方式有两种,其一是透明度测试,其二是透明度混合。透明度测试:这种方式不需要关闭深度写入,且实现机制非常简单粗暴。只要一个片元的透明度不满足条件(比如小于某个值),则该片元会被直接舍弃,否则就按照不透明物体的处理方式来处理。它产生的效果要么是完全不透明,要么是完全透明,并不是真正的半透明效果。透明度混合:这种方式会使用当前片元的透明度作为混合因子,与颜色缓冲中的颜色进行混合。这就需要关闭深度写入。而关闭深度写入意味着我们需要非常小心物体的渲染顺序,否则可能出现渲染问题。为什么要关注渲染顺序在之前的Shader中我们并没有关心过物体渲染顺序的问题。这
在Ruby1.9中你可以有Fixnum,Float,和Symbol未卡住或卡住的值:irb(main):001:0>a=[17,42.0,:foo];a.map(&:frozen?)=>[false,false,false]irb(main):002:0>a.each(&:freeze);a.map(&:frozen?)=>[true,true,true]我了解卡住字符串、数组或其他可变数据类型的实用性。然而,据我所知,Fixnum,Symbol,和Float实例从一开始就是不可变的。是否有任何理由卡住它们(或者Ruby不会报告它们的任何原因frozen?请注意,在Ruby2.0中Fi
我想在保持文本/图像不透明的同时使我的容器背景透明。只能使用HTML做到这一点吗?这是我的代码:看答案我看到了您的问题,如果我正确理解您,我想我知道您可以做什么。我注意到的一件事是,在我进一步走之前,看起来您正在使用引导程序代码。如果您更改了可能与此相关的CSS样式表,则可能会更好,更有效,也可能不会破坏整体代码的其他元素,但是让我们看看我的解决方案是否对您有效。基本上您想做的是:1)在您的HTML中编写一个“样式”标签,然后在其中放入样式(CSS)属性(您可以将其放入HTML代码的标题中以更好地跟踪它)。2)使用提供背景颜色的“RGBA”格式,并将其不透明度为“0”作为代码段的第四值。因此,
往期周报汇总地址:嵌入式周报-uCOS&uCGUI&emWin&embOS&TouchGFX&ThreadX-硬汉嵌入式论坛-PoweredbyDiscuz! 祝大家开工大吉视频版:https://www.bilibili.com/video/BV1GT411o7zr1、ThreadX老大离开微软,开发的第5代RTOS系统PX5RTOS正式上线最早是看到IAR的一条消息,全面支持PX5RTOS,然后就进一步上他们的官方下载白皮书了解相关消息当看到这两个名字时,很熟悉,这不就是ThreadX的老大BillLamie。 经过信息检索,应该是实锤了,领英上已经更新了他的工作经历: 然后再结合Azur
我需要当mouseentercurrentdiv将一些文本附加到div但有时效果不好有时显示有时没有这里是fiddleexample代码:$(document).ready(function(){varthmb_wrap=$('.thm-img');varthumb=$('.thm-imgimg');varouter=$('.mn-img');varfull=$('.mn-imgimg').length;varsc_height=$(outer).height();thmb_wrap.one('mouseenter',function(){varcur_im=$('.thm-imgim
有没有办法用three.js做Lithophane效果.目前我尝试了不同的透明度和不透明度的Material,但都没有成功。Lith(Three.js)varcontainer,scene,camera,renderer,controls,stats;varclock=newTHREE.Clock();varcube;init();animate();functioninit(){//SCENEscene=newTHREE.Scene();//CAMERAvarSCREEN_WIDTH=window.innerWidth,SCREEN_HEIGHT=window.innerHeight