一切混乱开端的透明效果——ShaderCp8
——20.8.18
Unity中,通常用两种方法来实现透明效果 1)透明度测试 2)透明度混合 这两个分别是什么呢
1.透明度测试指的只要不符合条件(即在物体颜色中的alpha通道的值小于某一个阈值)对应片元会被直接舍弃。(该片元不会对颜色缓冲有任何影响)否则就按照不透明物体处理。进行深度测试和深度写入。特点:不关闭深度写入 没法做到半透明要么不透明要么全透明
2.透明度混合指的是使用当前片元透明度为混合因子于已经储存的在颜色缓存中的颜色进行混合。要关闭深度写入不关闭深度测试。通过深度测试能够正确的确定非透明物体于透明物体之间的覆盖关系。 特点:关闭深度写入 做到半透明
在我们对上面两个定义进行下一步解读之前先回顾两个概念 深度写入以及深度测试 两者发生的过程是在GPU渲染的时候发生的,即下面这张图的关系
深度测试就是通过摄像机与该片元的距离(也就是深度)于之前存在深度缓存区的深度值进行比较 对应的条件来决定是否舍弃该片元 ZTest
深度写入则是是否要将深度测试的结果覆盖到深度缓存区中 因为半透明物体的存在是不可以作为深度的标准来舍弃因为半透明物体与其他物体是叠加的关系的 ZWrite
接着我们就可以引入一个新的重要性的问题 就是渲染顺序 这是在Tags中的一个元素 “Queue”
因为我们对半透明物体关闭了深度写入的操作 则对我们的渲染顺序有一定的要求也就是在关闭了深度写入的条件下渲染顺序的正确与否便是十分重要因为会引发两个问题 1)对非透明物体与半透明物体之间 因为关闭了深度写入,当半透明物体先渲染由于深度缓存为空则非透明物体直接覆盖 2)半透明物体与半透明物体之间 渲染顺序如果与深度一致(由近到远)则导致看上去位置相反
常用方法:1.先渲染所有不透明物体开启深度测试与写入(“Queue”=“Geometry”) 2.把半透明物体由远到近顺序渲染 并开启深度测试关闭写入(“Queue”=“AlphaTest“)
但依旧还是有问题所以才叫做混乱的开端 因为存在重叠现象一个物体有两个渲染顺序(每个像素都有深度,逐像素去遍历无法选取) 便采取分割网格 并且务必使用凸面体 需要具体问题具体分析
下面就是久违的ShaderLab部分了,我的想法是坚决不做搬运工,下面的部分直接选取部分代码说自己的理解 还是要自己敲一遍 最后再上源码 虽然上面部分就是书上的用我的理解包括一些大佬的理解顺序也很像书上的顺序 就是慢慢改进吧 嘿嘿
一、透明度测试
void Clip(x) x:float4,float3,flaot2,float
void Clip(float4 x)
{
if(any(x < 0))
discard;
}
参数x是裁剪时所使用的标量或矢量
如果给定参数的任何一个分量是负数则直接舍弃该像素
Tags { "RenderType"="TransparentCutOut" "Queue"="AlphaTest" "IgnoreProjector"="True" }
样例给的要点主要有要在SubShader中设置”Queue“为了透明度测试 ”IgnoreProjector“为了设置不受到投影器的影响
clip(texColor.a - _Cutoff);
内部参数为原图像的透明度减去_Cutoff(为能接受的阈值) 当这个值小于0则直接discard
源码:
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' Shader "Unlit/8-1AlphaTest"
{
Properties
{
_Color("Color", Color) = (1,1,1,1)
_MainTex ("Texture", 2D) = "white" {}
_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5
}
SubShader
{
Tags { "RenderType"="TransparentCutOut" "Queue"="AlphaTest" "IgnoreProjector"="True" }
Pass
{
Tags{ "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "UnityCG.cginc" struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
}; struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
}; sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
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.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);
fixed3 albedo = texColor.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0 * albedo * saturate(dot(worldNormal, worldLightDir));
return fixed4(diffuse + ambient, 1.0);
}
ENDCG
}
}FallBack "Transparent/Cutout/VertexLit"
}
二、透明度混合
说到混合就要讲混合指令Blend
采用的是以下的公式 源颜色就是该片元的颜色 目标颜色就是颜色缓存的颜色
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
要关闭深度写入 同时开启混合(设置的时候即开启)如果不打开blend默认是关闭的就以深度测试的结构决定直接覆盖A=1(?没找到依据但实验结果如此)
源码:
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' Shader "Unlit/8-2AlphaBlend"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
_AlphaScale ("AlphaScale", Range(0,1)) = 1
}
SubShader
{
Tags { "RenderType"="Transparent" "IgnoreProjector"="True" "Queue"="Transparent" }
Pass
{
Tags { "LightMode"="ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "UnityCG.cginc" struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
}; struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
}; sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
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);
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.rgb * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal, worldLightDir));
return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
}
ENDCG
}
}FallBack "Transparent/VertexLit"
}
三、开启深度写入的半透明
我们可以看一下上面这个图可以发现这个图全露出就是当模型存在互相交叉的时候会得到这样错误的效果 本质的原因就是没有打开深度写入导致的单物体内部错误 那有什么解决方方能就是用双Pass 第一个Pass把最前面的输出片元的深度值通过比较后存入深度缓存中但不输出颜色 第二个Pass再关闭深度写入 可以直接和正确的比较直接discard
ColorMask 0 | RGB | G |
设置颜色通道的写掩码就是指定输出的颜色通道 0就是不输出
源码:
Shader "Unlit/8-3AlphaBlendZWrite"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
_AlphaScale ("AlphaScale", Range(0, 1)) = 1
}
SubShader
{
Tags { "RenderType"="Transparent" "IgnoreProjector"="True" "Queue"="Transparent" } Pass{
ZWrite On
ColorMask 0
} Pass
{
Tags { "LightMode"="ForwardBase" }
ZWrite Off
//Alpha Blend
Blend SrcAlpha OneMinusSrcAlpha
//Soft Additive
//Blend OneMinusDstColor One
//Multiply
//Blend DstColor Zero
//Multiply 2X
//Blend DstColor SrcColor
//Darken
//BlendOp min
//Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "UnityCG.cginc" struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
}; struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
}; sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
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);
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.rgb * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal, worldLightDir));
return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
}
ENDCG
}
}FallBack "Diffuse"
}
这张图有一点奇怪就是存在投影。可以看Cp9的半透明投影部分主要是FallBack设置。
四、双面渲染的透明效果
这个是最后的内容啦 加加油 也就是剔除渲染图元的关系默认的情况下为了节约资源只渲染证明不渲染背面我们则需要用指令打开
Cull off | back | Front
设置back不渲染back 设置off就是都渲染
那么对应的透明度测试的双目渲染我直接放图代码便是在以上基础上在Pass里面添加以上指令
可以明显对比
然后就是透明度混合的双目渲染 比上述的麻烦了一点就是双Pass 先渲染背面后渲染正面因为从视角看上去避免了之前说的半透明物体与半透明物体之间因为渲染顺序的导致的问题可以直接比较一下 毕竟图形学是效果的学科看看啥效果就知道了
可以很明显看出第二个比第一个有了对面的背面(奇妙的比喻)也就是双目渲染 第三个则是渲染顺序相反背面先渲染 摄像机进入物体能看到颜色鲜艳的正面
最后最后留个小坑就是BlendOp 我也没太看懂可能需要具体例子才会用吧 只有一些效果
谢谢你看到最后 cheers!
ps.刚刚看完Shader入门Cp8记录记录一些细碎的知识点以及相关深度研究学习
一切混乱开端的透明效果——ShaderCp8的更多相关文章
- Unity Shader入门精要学习笔记 - 第8章 透明效果
转载自 冯乐乐的 <Unity Shader入门精要> 透明是游戏中经常要使用的一种效果.在实时渲染中要实现透明效果,通常会在渲染模型时控制它的透明通道.当开启透明混合后,当一个物体被渲染 ...
- Android课程---Android设置透明效果的三种方法(转)
1.使用Android系统自带的透明效果资源 <Button android:background="@android:color/transparent"/> ...
- Unity3D ShaderLab 使用alpha参数创建透明效果
Unity3D ShaderLab 使用alpha参数创建透明效果 其实Unity为了方便我们的工作,为我们内置了很多参数.比如马上用到的透明功能. 准备场景新建Shader Material ,一张 ...
- 用CSS实现Firefox 和IE 都支持的Alpha透明效果
有的时候,为了实现一些特殊效果,需要将页面元素变透明,本文介绍的就是用 CSS 实现 Firefox 和 IE 都支持的 Alpha 透明效果.CSS: filter:alpha(opacity=50 ...
- 一些有用的 Emacs 配置(窗口快速切换、一键透明效果、任意位置删除整行等)
本篇文章记录的是一些有用的 Emacs 配置,有些是自己原创,有些是借鉴别人(能记起来出处的我放了链接). 规定:C 代表 Ctrl,M 代表 Alt. 1.设置一次跳跃 n 行的快捷键 按 C-M- ...
- Css实现透明效果,兼容IE8
Css实现透明效果,兼容IE8 >>>>>>>>>>>>>>>>>>>>> ...
- CentOS下Qt窗口透明效果失效,成黑色背景的问题
一.问题 Linux系统下Qt窗口的透明效果成了黑色,但同样的代码在windows机子上有透明效果,主要是修改系统的配置,仅在centos6.3及其以上版本实验过.其他系统可以相应配置. 二.问题运行 ...
- QT下的几种透明效果(三种方法:调色板,透明度属性,自绘)
1.窗口整体透明,但是窗体上的控件不透明. 通过设置窗体的背景色来实现,将背景色设置为全透. QPalette pal = palette(); pal.setColor(QPalette: ...
- android:android:background="#00000000",透明效果
ImageButton中设置 android:background="#00000000",可以达到透明效果 具体的源码 管理-->文件中的 viewpager0829.ra ...
- Windows窗体透明效果
虚拟机里的win7也想实现透明效果, 使用vitrite这个免费软件就可以了.
随机推荐
- 深入理解JVM 学习笔记2
Java内存区域 在执行java程序的过程中JVM会把它管理的内存划分为多个不同的数据区域. 根据<Java 虚拟机规范 SE7版>的规定,Java 虚拟机所管理的内存将会包括以下几个运行 ...
- windows下搭建nrf52832nordic_ble_sniffer_3.0+wireshark抓包环境
准备工具 pythone3.7安装包 https://www.python.org/ftp/python/3.7.7/python-3.7.7-amd64.exe Wireshark-win64-3. ...
- jdbc中druid连接池遇到的问题和jdbcTemplate
无效的源发行版11 这是jdk版本不一致,去项目结构里排查一下 严重: init datasource error com.mysql.jdbc.exceptions.jdbc4.MySQLNonTr ...
- 抽取JDBC工具类:JDBCUtils
目的:简化书写 分析: 驱动注册,连接对象创建,其中包括输入驱动,数据库的地址,以及用户名和密码,每次编写代码都需要重复编写,如果每次使用的都是同一个账户的同一个数据库,代码的重复读很高,甚至 ...
- Windows 11安装etcd
一.从官方网站找到Windows版的安装包下载 https://etcd.io/ 把etcd的压缩包解压到D:/soft/etcd文件夹下,首先运行etcd.exe,这是启动etcd服务的,接着就可以 ...
- 51电子-STC89C51开发板:安装驱动
全部内容请点击目录列表查看: 51电子-STC89C51开发板:<目录> --------------------------- 正文开始 ---------------------- ...
- git 问题解决
1. fatal: the remote end hung up unexpectedly git config --global http.postBuffer 104857600 其他方案: gi ...
- 【二】python学习总结
一i.python概念 python是一种解释型语言,速度比java慢 二.运算符和格式输出.导入 1.Python3 运算符 | 菜鸟教程 (runoob.com) 2.格式输出 % 和.form ...
- mysql表关联更新
UPDATE enterprise_test t1, enterprise_development_relation t2 SET t1.development_area_id = t2.develo ...
- PCB Layout之EMMC_Flash走线总结@@@
PCB Layout之EMMC_Flash走线总结 1,数据线DATA[0-7]走线要(基本)等长(含芯片内部线长),线要短,线间距控制3W原则,参考面要完整(参考面下面最好不要走其它高速信号线),阻 ...