UnityShader快速上手指南(三)
简介
这一篇还是一些基本的shader操作:裁剪、透明和法向量的应用
(纠结了很久写不写这些,因为代码很简单,主要是些概念上的东西)
先来看下大概的效果图:(从左到右依次是裁剪,透明,加了法向量的透明)
(好奇怪,为啥我字那么多,提示我少于150字)
裁剪
代码
Shader "LT/Lesson3_Cull"
{
Properties
{
_Color ("Color", Color) = (1, 1, 1, 1)
}
SubShader
{
Pass
{
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float4 _Color;
appdata_base vert ( appdata_base input)
{
input.texcoord = input.vertex ;
input.vertex = mul(UNITY_MATRIX_MVP, input.vertex );
return input;
}
fixed4 frag (appdata_base input) : COLOR
{
if(input.texcoord.y < 0) {
discard;
}
return _Color;
}
ENDCG
}
}
}
代码的基本格式我就不介绍了,不熟的请看教程一
这里引入了一个新的东西: Cull Off
裁剪简单的可以分为三种裁剪:擦除裁剪(discard),正面裁剪(Front)和背面裁剪(Back)
这里的Cull Off代表关闭unity自带的背面裁剪(因为如果不写的话默认为Cull Back)
Cull Off 关闭裁剪
Cull Back 背面裁剪(默认)
Cull Front 正面裁剪
然后关于这个面的正反的界定,是通过法线来完成的,法线向量>0则为正
Cull Back 和 Cull Front Unity替我们完成了,如果需要简单的裁掉正面和反面的话直接使用预制的就行了
(Q:如果我想同时裁正面和反面怎么处理? A:如果你要同时裁掉正面和反面,你的模型就不用显示了好嘛)
这里我想通过模型的坐标位置来裁面,所以关闭了Unity的自动裁剪
然后就是把顶点信息缓存下来:
input.texcoord = input.vertex ;
为了方便(同时也能提高性能,由于GPU是频繁调用这些函数,所以不管什么空间啊,计算啊都能省就省),我直接将数据存在了input对象中,然后又将input返回给frag使用(这里随便选一个不用的字段用来缓存我们的位置信息就行了,注意vertex是要使用的,所以vertex不能用来缓存这个信息)
然后在frag中判断我们缓存的坐标信息,满足条件就discard掉
if(input.texcoord.y < 0) {
discard;
}
这里的discard相当于强行中断该次渲染,也可以说成取消渲染,这样就完成了我们的裁剪功能了
顺带一提,discard很消耗性能的,所以能不用还是就不用了(何况这里还多了一步if判断语句),需要指定裁剪还是改模型来的高效,当然如果需要动态裁剪就需要这样的代码了
透明
还是先来代码
代码
Shader "LT/Lesson3_Transparent"
{
Properties
{
_Color ("Color", Color) = (1, 1, 1, 0.5)
}
SubShader
{
Tags { "Queue" = "Transparent" }
Pass
{
ZWrite Off
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float4 _Color;
appdata_base vert ( appdata_base input)
{
input.vertex = mul(UNITY_MATRIX_MVP, input.vertex );
return input;
}
fixed4 frag (appdata_base input) : COLOR
{
return _Color;
}
ENDCG
}
}
}
恩...这里呢代码的内容比较少,就是直接把外面设置的颜色应用到物体上就完了
但是多了
Tags { "Queue" = "Transparent" }
ZWrite Off
Blend One One
这三个东西
**Tags { "Queue" = "Transparent" } **
先来第一个Tags { "Queue" = "Transparent" }
大家可能看到有个Transparent会想要写透明是不是必须要这句话,其实不然,这行代码只是指定一个渲染顺序而已,一般情况下是具体情况具体分析,比如你希望这个shader是渲染背景物体的时候,你可以设置为
"Queue" = "Background",需要时物体的时候设置为“Geometry”,其实对应下来的就是一个数值,这个数值越小,越先渲染,然后从我们的渲染顺序可以理解,先渲染的自然在背后了
下面列举下常用的值对应的名字
"Background"。值为1000。比如用于天空盒。
"Geometry"。值为2000。大部分物体在这个队列。不透明的物体也在这里。这个队列内部的物体的渲染顺序会有进一步的优化(应该是从近到远,early-z test可以剔除不需经过FS处理的片元)。其他队列的物体都是按空间位置的从远到近进行渲染。
"AlphaTest"。值为2450。已进行AlphaTest的物体在这个队列。
"Transparent"。值为3000。透明物体。
"Overlay"。值为4000。比如镜头光晕。
还有就是,用户可以定义任意值,比如"Queue"="Geometry+10"
**ZWrite Off **
再来ZWriter Off,这句命令表示不写入深度缓存
呃~~~,然后我们继续来科普概念吧(由于语文不好,后面一大段话是从别的网站复制的)
(1)什么是深度?
深度其实就是该像素点在3d世界中距离摄象机的距离,深度值(Z值)越大,则离摄像机越远。
(2)什么是深度缓存?
深度缓存中存储着每个像素点(绘制在屏幕上的)的深度值!如果启用了深度缓冲区,在绘制每个像素之前,OpenGL会把它的深度值和已经存储在这个像素的深度值进行比较。新像素深度值<原先像素深度值,则新像素值会取代原先的;反之,新像素值被遮挡,其颜色值和深度将被丢弃,最终屏幕显示的就是深度缓存中深度对应的像素点的颜色!(深度主要起的是比较的作用)
(3)什么是深度测试?
在深度测试中,默认情况是将要绘制的新像素的z值与深度缓冲区中对应位置的z值进行比较,如果比深度缓存中的值小,那么用新像素的颜色值更新深度缓存中对应像素的颜色值。
(4)为什么需要深度?
在不使用深度测试的时候,如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这样的效果并不是我们所希望的。而有了深度缓冲以后,绘制物体的顺序就不那么重要了,都能按照远近(Z值)正常显示,这很关键。(越后绘制的东西,距离相机就越近)
那么,在unity中,如果知道了渲染队列,ZWrite,ZTest,如何确定哪个物体先显示呢?
首先,unity先将渲染队列中较前的进行渲染,然后再执行ZWrite,ZTest
ZWrite可以取的值为:On/Off,默认值为On,代表是否要将像素的深度写入深度缓存中
ZTest可以取的值为:Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never/Off,默认值为LEqual,代表如何将像素的颜色写入深度缓存中,例如当取默认值的情况下,如果将要绘制的新像素的z值小于等于深度缓存中的值,则将用新像素的颜色值更新深度缓存中对应像素的颜色值。需要注意的是,当ZTest取值为Off时,表示的是关闭深度测试,等价于取值为Always,而不是Never!Always指的是直接将当前像素颜色(不是深度)写进颜色缓冲区中;而Never指的是不要将当前像素颜色写进颜色缓冲区中,相当于消失。
因为ZWrite默认值为On,ZTest默认值为LEqual,所以这很好地解释了为什么在unity中,距离相机近的东西会阻挡住距离相机远的东西。如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这时我们可以通过修改ZWrite和ZTest来改变物体的遮挡关系!
恩,好,介绍完了深度这个玩意儿咯, 那来解释下我们为啥要关掉了(其实不关掉也可以,但是关掉GPU可以少做一步操作啊,提高性能性能性能性能性能性能,所以能关就关吧),因为我们要写的是透明啊,不管先后顺序的,透明都可以看得到 - -
Blend One One
最后是Blend One One,这是个大概念,这个命令是写透明shader所必须的,因为它定义了透明的模式
然而,这玩意儿很简单的,命令是
Blend SrcFactor DstFactor
然后这个Factor 支持:
One
值为1,使用此设置来让源或是目标颜色完全的通过。
Zero
值为0,使用此设置来删除源或目标值。
SrcColor
此阶段的值是乘以源颜色的值。
SrcAlpha
此阶段的值是乘以源alpha的值。
DstColor
此阶段的值是乘以帧缓冲区源颜色的值。
DstAlpha
此阶段的值是乘以帧缓冲区源alpha的值。
OneMinusSrcColor
此阶段的值是乘以(1 - source color)
OneMinusSrcAlpha
此阶段的值是乘以(1 - source alpha)
OneMinusDstColor
此阶段的值是乘以(1 - destination color)
OneMinusDstAlpha
此阶段的值是乘以(1 - destination alpha)
然后下面是常用的搭配:
Blend SrcAlpha OneMinusSrcAlpha // Alpha blending alpha混合
Blend One One // Additive 相加混合
Blend One OneMinusDstColor // Soft Additive 柔和相加混合
Blend DstColor Zero // Multiplicative 相乘混合
Blend DstColor SrcColor // 2x Multiplicative 2倍相乘混合
具体效果,大家可以自己改代码看结果,这里就不多说了
带法向量计算的透明
代码
Shader "LT/Lesson3_Silhouette"
{
Properties
{
_Color ("Color", Color) = (1, 1, 1, 0.5)
}
SubShader
{
Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float4 _Color;
appdata_base vert ( appdata_base input)
{
fixed3 tempNormal = normalize(mul(fixed4(input.normal, 0.0), _World2Object).xyz);
fixed3 tempViewDir = normalize(_WorldSpaceCameraPos - mul(_Object2World, input.vertex).xyz);
input.vertex = mul(UNITY_MATRIX_MVP, input.vertex );
input.normal.x = min(1.0, _Color.a / abs(dot(tempNormal, tempViewDir)));
return input;
}
fixed4 frag (appdata_base input) : COLOR
{
return float4(float3(_Color.x,_Color.y,_Color.z), input.normal.x);
}
ENDCG
}
}
}
这里没啥新东西,但是代码上把法向量用起来了(原理主要是通过法向量和摄像机朝向算出一个新的透明度用来替换而已)
解释一下吧:
fixed3 tempNormal = normalize(mul(fixed4(input.normal, 0.0), _World2Object).xyz);
// 计算unity坐标系下的法向量
fixed3 tempViewDir = normalize(_WorldSpaceCameraPos - mul(_Object2World, input.vertex).xyz);
// 计算unity坐标系啊的摄像机的向量
input.normal.x = min(1.0, _Color.a / abs(dot(tempNormal, tempViewDir)));
// 将两个向量点乘然后换算给设定颜色的alpha通道,并缓存起来
// 至于为啥要点乘,然后用Color.a来除,这个是算法问题啦:
// a = min(1, a/ |V·N|),公式是书上来的,数学问题了,不做赘述
return float4(float3(_Color.x,_Color.y,_Color.z), input.normal.x);
// 使用设置的颜色的rgb值和算出来的新的alpha值
由于个人很喜欢这个效果,所以再来次效果展示
这样是不是有一点简单的立体效果咯捏(这不是光照,真的光照的反射啥的下一篇教程讲)
总结
本篇教程的东西都很基础,但是在以后写shader的过程中会用的很平凡,所以还是单独拿出来讲了一下,与我们的快速上手指南其实有点背道而驰 o(╯□╰)o ,但是为了后面不会看不懂,大家还是多自己写写熟悉一下,比如使用discard和Cull配合两个Pass写一个正反面渲染不同颜色的shader,利用前面讲的SinTime和法向量啥的写一个动态变化效果
还是那句话,又不懂得,QQ:821580467
UnityShader快速上手指南(三)的更多相关文章
- UnityShader快速上手指南(二)
简介 前一篇介绍了如果编写最基本的shader,接下来本文将会简单的深入一下,我们先来看下效果吧 呃,gif效果不好,实际效果是很平滑的动态过渡 实现思路 1.首先我们要实现一个彩色方块 2.让色彩动 ...
- UnityShader快速上手指南(一)
简介 引言 其实网上有很多shader教程,但是大概看了下,也不知是网上各位大神已经脱离了代码层面的高度还是啥原因.貌似没有找到从代码方面作为入门讲解的,导致了shader对于苦逼程序员入门有一定要求 ...
- UnityShader快速上手指南(四)
简介 由于其他项目中断了几天更新,继续~~ 这一篇主要是讲光照的(包含漫反射和高光以及多光源的处理) 还是先来看看具体效果(多光源后面单独展示) 有了基本的光照处理之后越来越有立体感了有不有 ╮(╯▽ ...
- Rancher 快速上手指南操作(1)
Rancher 快速上手指南操作(1)该指南知道用户如何快速的部署Rancher Server 管理容器.前提是假设你的机器已经安装好docker了.1 确认 docker 的版本,下面是 ubunt ...
- [转]Rancher 快速上手指南操作(1)
本文转自:http://www.cppblog.com/zhiyewang/archive/2016/03/17/213053.aspx Rancher 快速上手指南操作(1)该指南知道用户如何快速的 ...
- Markdown快速上手指南
Markdown快速上手指南 1.Markdown介绍 markdown可以实现快速html文档编辑,格式优没,并且不需要使用html元素. markdown采用普通文本的形式,例如读书笔记等易于使用 ...
- Mac快速上手指南
上周刚入手了2017版MacBookPro,预装macOS High Sierra.第一次接触Mac系统,经过一周的使用,简单总结下与Windows相比最常用的功能,快速上手. 1.Mac键盘实现Ho ...
- Github Action 快速上手指南
前言 各位读者,新年快乐,我是过了年匆忙赶回上海努力搬砖的蛮三刀. Github之前更新了一个Action功能(应该是很久以前了),可以实现很多自动化操作.用来替代用户自己设置的自动化脚本(比如:钩子 ...
- IDEA 快速上手指南(全配置)(Day_23)
Idea快速入门指南 1.安装 1.1.安装 我们使用的是2017.3.4版本: 双击打开, 选择一个目录,最好不要中文和空格: 然后选择桌面快捷方式,请选择64位: 然后选择安装: 开始安装: 然后 ...
随机推荐
- C#中操作xml文件(插入节点、修改、删除)
已知有一个xml文件(bookstore.xml)如下: <?xml version="1.0" encoding="gb2312"?> <b ...
- u3d动态加入模型
楼层一层一层的加,把模型分开,弄成prefab放到Resourse文件夹里,在代码里用Instantiate(Resources.Load("模型名字") as GameObjec ...
- PowerShell定时记录操作系统行为
作为系统管理员,有些时候是需要记录系统中的其他用户的一些操作行为的,例如:当系统管理员怀疑系统存在漏洞,且已经有被植入后门或者创建隐藏账户时,就需要对曾经登陆的用户进行监控,保存其打开或者操作过的文件 ...
- SAP ECC PP 配置文档
SAP ECC 6.0 Configuration Document Production Planning & Control (PP) 1. General Settings 1.1 Ma ...
- Android M Permission 学习笔记
Android应用权限简要介绍 一个Android应用默认情况下是不拥有任何权限的, 这即是说, 在默认情况下, 一个应用是没有权利去进行一些可能会造成不好影响的操作的. 这些不好的影响可能是对其它应 ...
- 纯CSS3实现3D特效的iPhone 6动画
iPhone 6发布不久,屌丝怎能买得起,不过作为程序员,今天看到一个用纯CSS3绘制的iPhone 6,由于CSS3特性的运用,带有点3D的动画特效,大家可以先来看看在线演示效果. 在线演示 ...
- Could not find the Visual SourceSafe Internet Web Service connection information for the specified database Would you like to launch the Visual sourceSafe connection wizard?
今天同事遇到个奇怪问题,以前也遇到过,不过重新绑定一下就OK了,不知道为什么今天不行了. 错误提示:===============================================Cou ...
- android xml解析添加到listview中的问题
一个问题不知什么原因,代码: public class OtherActivity extends ListActivity { @Override protected void onCreate(B ...
- java之对象转型2
public class TestCasting2{ public static void main(String args[]){ TestCasting2 test2= new TestCasti ...
- iTunes Connect突然登录不了的原因
突然使用开发者账号登录不了iTunes Connect了,提示:Your Apple ID or password was entered incorrectly. 这是由于iTunes Connec ...