https://www.baidu.com/link?url=o85V5QLsraCjMOmzJc6081Z3bsQRw4_hjoPki5igyrvrJExygnt2Ex-_oGmH60-wm2VU53AsKInafwE2Z7NCB_&wd=&eqid=f46be4f400050577000000065d31d21e //shader学习链接
3D纹理:
只能脚本创建 opengl 3.0及以上才支持。
file:///D:/Unity5.6.6/Editor/Data/Documentation/en/Manual/SL-Material.html //unity APL
shader 1.0 灯光调节公式:
Ambient * Lighting Window’s Ambient Intensity setting + (Light Color * Diffuse + Light Color * Specular) + Emission
Ambient : 环境光 Specular 镜面反射 Emission: 自发光
SeparateSpecular 镜面照明不受纹理的影响。只有在使用照明时才有效果
Lighting Window’s Ambient Intensity setting :
进度条:
矩阵旋转注意事项 :
使用旋转后的UV进行纹理采样。
1. 物体平移到原点,否则会绕着原点旋转,应该移动到物体中心点,再进行旋转。
2.发生旋转
3.再把物体平移到原点的位置
例如: 要做一个旋转的进度圈。
让uv坐标绕z轴进行旋转。
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
//加到Image
Shader "Custom/Loading"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Speed ("Speed ",float) = 2
}
SubShader
{
// No culling or depth
//Cull Off ZWrite Off
ZTest Always
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float _Speed ;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
fixed4 frag (v2f i) : SV_Target
{
float2 tmpUV = i.uv ;
//先把UV中心点移动到原点
tmpUV -= float2(0.5,0.5) ;
//把四个中心点到顶点的距离(即<0.5f)>得改为0.5f,避免取到圆圈顶点之外得点
if(length(tmpUV)>0.5)
{
return fixed4(0,0,0,0) ;
}
float2 finalUV = 0 ;
float angle = _Time.x*_Speed ;
finalUV.x = tmpUV.x* cos(angle) -tmpUV.y*sin (angle) ;
finalUV.y = tmpUV.x *sin(angle) + tmpUV.y *cos(angle);
//又移回去
finalUV += float2(0.5 ,0.5) ;
fixed4 col = tex2D(_MainTex, finalUV);
return col;
}
ENDCG
}
}
}
描边:
方式一:渲染两次,两个pass,一个大一个小。
方式二:找到边缘
模糊:
获取场景渲染结束的最后一张图片: 对一个像素周围的四个点求一个平均。即对一个UV
Alpha测试:
shader1.0
因为没有采样函数,所以用过Alpha测试来做
应用:可以做图片的渐变消失
shader2.0
因为G-Buffer中没有像素点,所以直接显示的黑色。所以要使用Blend命令。
5. 模板测试:Stencil
5.1 作用:
一般用作每个像素掩码,来保存或者丢弃像素的作用。
0-255整数的8位掩码,
Comp: 引用值与缓冲区当前内容进行比较的函数。
Pass:模板测试和深度测试都通过了。默认:保持。
Fail: 模板测试未通过该如何处理缓冲区的内容。默认:保持。
ZFail: 模具测试通过,但是深度测试失败,该如何处理缓冲区的内容。默认:保持。
以上操作也可以使用和正面几何图形。
Comparison Operation:> >= < <= == != 模板测试总是通过 模板测试从不通过
Stencil Operation:
ShaderLab: Stencil file:///D:/unity2018insatll/Editor/Data/Documentation/en/Manual/SL-Stencil.html
符合条件的通过写入到G-Buffer中,不符合的丢弃。
G-Buffer中包含: RGBA 深度信息 模板信息
公式:输入的值和G-Buffer中的模板值做比较。
应用: 墙穿透效果:
Stencil {
Ref 2 //设置模板值等于2
Comp always //使模具测试始终通过。
Pass replace
}
<1. 设置前边物体,并且关闭深度缓存,防止前边物体挡住back物体。
<2. 设置中间物体,如果不等于2,则显示出来。否则丢弃掉像素。即被前边物体遮挡的区域就透明掉了。
<3. 设置后边物体, 如果和2相等时,则显示出来。
深度测试:
深度: 物体位置到相机水平线的投影。
深度缓存:新的像素和深度缓存中的深度做对比,如果小于深度缓存中的深度,则替换RGBA像素,且替换深度缓存中的深度值。
深度测试: ZWrite : 将要渲染的物体的Z值和G-buffer中的深度缓存值进行对比。
深度相同时,可以通过调整Offset来微调。强迫一个多边形在另一个上绘制,尽管它们实际上处于相同的位置.
Blend:
https://www.baidu.com/link?url=o85V5QLsraCjMOmzJc6081Z3bsQRw4_hjoPki5igyrvrJExygnt2Ex-_oGmH60-wm2VU53AsKInafwE2Z7NCB_&wd=&eqid=f46be4f400050577000000065d31d21e
Texture Type
选择适合的类型,Unity会为Unity Shader传递正确的纹理,并对一些纹理进行优化。
Defualt(默认纹理)
Normal map(法线纹理)
使用了法线纹理类型,Unity会根据不同平台对纹理进行压缩,如DXT5nm格式,通过UnpackNormal函数进行采样,见下面UnityCG.cginc中源码。这种压缩只用两个通道(原来三个),减少法线纹理占用的内存空间。
inline fixed3 UnpackNormalDXT5nm (fixed4 packednormal)
{
fixed3 normal;
normal.xy = packednormal.wy * 2 - 1;
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
return normal;
}
inline fixed3 UnpackNormal(fixed4 packednormal)
{
#if defined(UNITY_NO_DXT5nm)
return packednormal.xyz * 2 - 1;
#else
return UnpackNormalDXT5nm(packednormal);
#endif
}
Create from Grayscale
用于高度图生成法线纹理。这样就可以和切线空间下的法线纹理同等对待了。
- Bumpiness:控制凹凸程度
- Filtering:决定凹凸程度计算方式
- Smooth:生成平滑的法线纹理
- Sharp:使用Sobel滤波(一种边缘检测使用的滤波器)生成法线纹理
WrapMode
决定纹理坐标超过[0, 1]范围后将会被如何平铺(Tiling)。
渐变纹理应该选择Clamp(下右图)。因为Repeat(下左图)可能产生如下错误,大于1的值如1.01会采样为0.01,为黑色。
FilterMode
决定纹理拉伸时采样哪种滤波模式。
Point、Bilinear、Trilinear 最邻近插值法、双线性插值以及双三线性插值对比如下,效果依次提升,性能消耗同样增大。
图像插值就是当图像进行放大/缩小时,图像原有的像素数量不足以满足需求,例如从3X3的像素矩阵往4X4的像素矩阵变换的时候,就会出现像素值不知该如何填充的问题,而图像插值算法就是为了解决这个问题。
双线性过滤以pixel对应的纹理坐标为中心,采该纹理坐标周围4个texel的像素,再取平均,以平均值作为采样值。
双线性过滤像素之间的过渡更加平滑,但是它只作用于一个MipMap Level,它选取texel和pixel之间大小最接近的那一层MipMap进行采样。当和pixel大小匹配的texel大小在两层Mipmap level之间时,双线性过滤在有些情况效果就不太好。于是就有了三线性过滤。
三线性过滤以双线性过滤为基础。会对pixel大小与texel大小最接近的两层Mipmap level分别进行双线性过滤,然后再对两层得到的结果进生线性插值。
三线性过滤在一般情况下效果非常理想了。但是到目前为止,我们均是假设是texture投射到屏幕空间是各向同性的。但是当各向异性的情况时,效果仍然不理想,于是产生了Anisotropic Filtering(各向异性过滤)。
多级渐远纹理(mipmapping)
面板中Advanced->Generate Mip Maps默认开启。原理是提前用滤波处理得到更小的图形,每一层都是上一层图像降采样得到,以此类推,形成一个图像金字塔。在物体远离摄像机时,直接使用较小的纹理。缺点是通常会多占用33%的内存空间。
https://blog.csdn.net/candycat1992/article/details/17097907 【Unity Shaders】概述及Diffuse Shading介绍】
https://blog.csdn.net/candycat1992/article/details/39994049 初探Surface Shader背后的机制
第一章 漫反射
1.5 自定义漫反射
如果 你想在着色器代码里通过变量名来获得它的属性值,则必须创建与之对应的另一个变量。
#pragma surface 告诉编辑器使用哪个光照模型计算。
三种格式的光照模型函数:命名 Lighting+任何名字
● half4 LightingName (SurfaceOutput s, half3 lightDir, half atten){} 该函数用于不需要视角方向的前向着色。
● half4 LightingName (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten){} 该函数用于需要视角方向的前向着色。
● half4 LightingName_PrePass (SurfaceOutput s, half4 light){} 该函数用于需要使用延迟着色的项目
1.6 创建 Half Lambert 光照模型
Half Lambert : 用于在低光照区域照亮 物体的技术。它基本上提高了材质和物体表面周围的漫反射光照。用来防止某个物体的背光面 丢失形状并且显得太过平面化。没有物理原理,只是为了视觉增强。
左:半兰伯特模型 右:普通漫反射
Half Lambert 技术实现的原理:
把漫反射光照值的范围分成两半,然后加上0.5。基本 意思就是如果光照值是1,对半开后就是 0.5,然后再加 0.5 回去,将会再得到 1。如果你对 0 进行操作,那么你会得到 0.5,因此我们将 0 ~ 1 之间的所有值重新映射到区间 0.5 ~ 1。
1.7 创建渐变纹理来控制漫反射着色
—使用渐变纹理(ramp texture)来控 制漫反射光照的颜色。这允许你突出表面的颜色,来模拟更多的反射光照或者其他高级的 灯光设置.想要突出艺术画面,不需要真实物理模拟时使用。
tex2D 函数有两个参数,第一个参数是我们使用的纹理,第二个参数包含的是映射纹理的 UV 坐标。 ,tex2D 函数会去搜索(0,0)UV坐标处的纹理像素。
1.8 使用 2D 渐变纹理创建假的 BRDF
由光照函数BRDF【双向反射分布函数】提供的视角方向,观察方向指的是我们看向物体自身的方向。它是一个标注了方向的向量,这意味着我们可以将它和法线以及光照方向结合起来使用。这种视点向量可以为我们提供一种更先进 的纹理索引技术。
【双向反射分布函数】可以简单理解为入射光在不透明物体表面同时反射到观察方向 (观察者眼睛方向)和出射光两个方向。
当使用观察方向参数时,我们可以创建一个简单的衰减渲染效果。你可以使用这个参 数来制作任何不同类型的效果:一个透明的泡泡、边缘高光效果、盾牌效果,甚至可以制 作卡通边缘线效果。
使用纹理贴图制作特效
PC上都是按照最高精度float来计算,而在移动平台。fixed在比较旧的移动平台用,大多数都是把half和fixed当成同精度来处理。
注意: shader中的语法错误,定位行是40行,其错误可能在39行引起的下一行错误。
插值:
lerp(a,b,f)=(1-f )* a + b * f ;
f的取值范围是【0-1】。当f=1时,直接放回b, 当f=0时返回a , f=0.5时,返回(a+b)平均数。
返回的这个数是一个定值,应用时需要把上一次插值的结果作为下一次插值的a.
//transform.position = Vector3.Lerp(transform.position, end, 0.5f);
//Debug.Log(transform.position + " " + start + " " + end);
2.4 压缩和混合纹理贴图
原理是:利用插值从一个纹理图片插值到另一个纹理插值,使用第三张贴图的r来作为影响参数。
2.5 法线贴图
用途: 它是用来在不增加额外多边形的情况下 添加更多的细节。该技术的一个常见用途是通过一个高多边形模型或高度图形成法线贴图, 这样就显著地提高了低多边形模型的表现效果以及细节。
UnpackNormals() 函数(法线解压函数)来使用法线贴图
2.6 创建程序纹理贴图
概念:需要动态创建纹理或者在运行时修改它们的像素 值,这种情况通常被称为程序性的纹理效果。
创建流程: 需要在一个二维空间中创建一组像素然后将其应用到一个新的纹理上。再将创建 的新纹理传入到着色器中,使它们可以在着色器中进行计算。
应用:使用动态创建纹理贴图的 方式可以制造一种玩家和游戏环境之间的互动效果。也可以用它来制作一些贴花的效果, 或者创建一些可以在着色器函数中使用的程序化形状等。
2.7 Photoshop 色阶效果
色阶是表示图像亮度强弱的指数标准。
实现原理:
Shader "Custom/ColorStage" {
Properties {
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_inBlack("Input Black",Range(0,255)) = 0
_inGamma("Input Gamma",Range(0,2)) = 1.61
_inWhite("Input White",Range(0,255)) = 255
_outWhite("Out White",Range(0,255)) = 255
_outBlack("Out Black",Range(0,255)) = 0
}
SubShader{
Tags { "RenderType" = "Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
float _inBlack;
float _inGamma;
float _inWhite;
float _outWhite;
float _outBlack;
float outRPixel; //存储红色通道
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
float GetPixelLevel(float pixelColor)
{
float pixelResult;
// 因为tex2D() 函数所提供的颜色值范围是从0 到 1,所以我们需要将其重新映射至 0.0 到 255.0 的范围内
pixelResult = (pixelColor * 255.0);
//. 然后减去我们的输入值_inBlack,这样当我们将输入色阶的黑色滑块朝着255.0 滑动 时可以使所有像素变得更暗。
pixelResult = max(0, pixelResult - _inBlack);
//然后,当我们将输入色阶的白色滑块朝着0.0 滑动时,可以将所有像素变得更亮,并 对得到的结果求 _inGamma 次方
pixelResult = saturate(pow(pixelResult / (_inWhite - _inBlack), _inGamma));
// 最后,我们将新的像素值与_outWhite 减去_outBlack 的差相乘,然后将新的像素值 重新映射到 0.0 ~ 1.0 的范围内:
//我们使用_outWhite 和 _outBlack 再次修改像素值,这样你就可以对最小像素值 以及最大像素值有一个最终的全局控制了。
pixelResult = (pixelResult * (_outWhite - _outBlack) + _outBlack) / 255.0;
return pixelResult;
}
void surf (Input IN, inout SurfaceOutput o)
{
half4 c = tex2D(_MainTex, IN.uv_MainTex);
float outRPixel = GetPixelLevel(c.r);
float outGPixel = GetPixelLevel(c.g);
float outBPixel = GetPixelLevel(c.b);
o.Albedo = float3(outRPixel, outGPixel, outBPixel);
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
第 3 章 利用镜面反射让游戏闪耀起来
UnityCG.cginc 文件有Lambert 和 BlinnPhong 两种光照模型可以使用。
#pragma surface surf BlinnPhong 编译着色器 的时候,你就会告诉着色器使用UnityCG.cginc 文件中的BlinnPhong 光照函数。
#pragma surface surf Lambert.... 实现前边已经说过了。
3.3 创建Phong高光模型:
高光着色器:
告诉编辑器我们创建一个自定义的视点相关性着色器。注意和申明的语句一致。
6.2 使用Alpha参数创建透明效果
修改表面着色器的#pragma语句的参数:
用来告诉unity允许一个透明表面渲染到屏幕上,可以为内置的值赋值。 o.Alpha = c.b * _MyTransVal;
修改表面着色器的输出输出参数:标准的输入输出参数改为普通的输入输出
6.3 透明度裁剪着色器
使用一个值来简单的控制某些特定的像素不渲染到屏幕上,因此可以实现一个完全透明和不透明混合的着色器。网易观点:裁剪普遍情况下比半透耗。
Shader "91YGame/TransparentCutoff" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
//申明_Cutoff变量;
_Cutoff("Cutoff Value",Range(0.01,1))=0.5
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
//告诉着色器 我们需要的是一个裁剪类型的着色器;
CGPROGRAM
#pragma surface surf Lambert alphatest:_Cutoff
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.r;
}
ENDCG
}
FallBack "Diffuse"
}
透明度混合Blend:
将片段着色器中计算出来的颜色称之为 “源颜色”,帧缓存中对应的像素已经存在的颜色叫做“目标颜色”。混合操作就是将源颜色与目标颜色以一些选项进行结合。
通用公式: float4 result = SrcFactor * fragment_output + DstFactor * pixel_color;
Blend SrcAlpha OneMinusSrcAlpha //alpha blending
Blend One OneMinusSrcAlpha //premultiplied alpha blending
Blend One One //additive
Blend SrcAlpha One //additive blending
Blend OneMinusDstColor One //soft additive
Blend DstColor Zero //multiplicative
Blend DstColor SrcColor //2x multiplicative
Blend Zero SrcAlpha //multiplicative blending for attenuation by the fragment's alpha
(r,g,b) * a = (r*a , g*a , b*a)
(r,g,b) * (x,y,z) = (r*x , g*y , b*z)
(r,g,b) + (x,y,z) = (r+x , g+y , b+z)
(r,g,b) - (x,y,z) = (r-x , g-y , b-z)
混合操作的基本语法: Blend SrcFactor DstFactor
例如:
根据通用公式:下图
Blend SrcAlpha One
//源颜色(输出颜色) * 源透明值+目标因子(One) * 目标颜色(帧缓存中的颜色,一般是背景颜色)
《==》 (1,0,0)*1+(1,1,1)(0,0,0)=(0.5,0.5,0.5)
《shader入门精要》
Blend SrcFactor DstFactor: 稍微解释一下,这行指令意思就是将本 Shader 计算出的颜色值(源颜色值,即蓝色) * 源Alpha值(0.6) + 目标颜色值(可以理解为背景色) * (1-0.6),从而让蓝色方块展示出了40%的透明度。
6.4 通过渲染队列进行深度排序
https://blog.csdn.net/puppet_master/article/details/73478905 //学习链接
深度排序: 物体被渲染的先后顺序。利用层级方法来渲染你的物体,也就是利用Unity提供的内置标签。
渲染顺序: 其实前后无所谓的,因为即使是先渲染人模,再渲染栅栏,遮挡部分深度测试成功也会替代人模的部分,这样会造成OverDraw,所以Unity对于不透明物体一般采用从前向后的顺序,把遮挡的部分不用替代了。
初始:
给前边加上shader,设置成先渲染
Shader "Custom/Depth" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "Queue"="Geometry-20" } //设置渲染顺序,Geometry为2000,-20表示在所有几何体后面显示
ZWrite Off //告诉Unity我们想自己控制该对象的渲染顺序,而不写到深度缓冲中,我们想要重写对象的深度排序,并且我们将会为它指定一个新的渲染队列
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
Pass通道:
之前的shader中都只有一个Pass,也就是单通道渲染,这样的话如果要对同一个RenderTexture在不同的时刻进行不同的渲染效果输出就需要不停的更换shader。
所有需要Pass,根据需求设定通过哪个Pass来进行渲染,从而实现在不同的时候对使用同一个shader对同一个对象进行不同的效果处理。
物体边缘:
光向量和法向量求点积,得到的是光线的强度,即光线入眼的多少。
摄像机看到这个物体,物体的顶点法线和摄像机视角夹角是90度,越暗,用点积来达到这种类似于边缘查找的效果。
点积的结果越大,越暗, 即法向量和视向量>90度,则越暗。1减去结果作为系数乘以一个边缘光颜色就达到了边缘光的效果。
缺陷:边缘光效果只是在当前模型本身的光照计算时调整了边缘位置的颜色值,并没有达到真正的“描边”
描边 : 边缘泛光shader 2
描边效果:https://blog.csdn.net/puppet_master/article/details/54000951
一般都是在正常模型的渲染状态下,在模型外面扩展出一个描边的效果。既然要让模型的形状有所改变(向外拓一点),那么肯定就和vertex shader有关系了。而我们的描边效果,肯定就是要让模型更“胖”一点,能够把我们原来的大小包裹住;微观一点来看,一个面,如果我们让它向外拓展,而我们指的外,也就是这个面的法线所指向的方向,那么就让这个面朝着法线的方向平移一点;再微观一点来看,对于顶点来说,也就是我们的vertex shader真正要写的内容了,我们正常计算顶点的时候,传入的vertex会经过MVP变换,最终传递给fragment shader,那么我们就可以在这一步让顶点沿着法线的方向稍微平移一些。我们在描边后,描边这一次渲染的边缘其实是没有办法和我们正常的模型进行区分的,为了解决这个问题,就需要用两个Pass来渲染,第一个Pass渲染描边的效果,进行外拓,而第二个Pass进行原本效果的渲染,这样,后面显示的就是稍微“胖”一点的模型,然后正常的模型贴在上面,把中间的部分挡住,边缘挡不住就露出了描边的部分了。
1. 顶点信息基本应用------提取存储的顶点信息
2. 顶点信息进阶应用,顶点信息的应用
https://www.cnblogs.com/jaffhan/p/7358383.html
8.2 轻型着色器
1.用最少的数据达到相同的效果
<1 .计算精度优化。
float(32bits)
,half(16bits)
和fixed(11bits)
float
精度。 half精度
,必要时增加精度。 +-60000fixed
精度。光照、颜色 +-2应该使用哪种数据精度取决于平台和GPU::
float精度进行
计算,float/half/fixed
在底层是完全相同的。因此在Unity编辑器中(即使切换为移动平台),难以确定半/固定精度是否足够,因此请始终在目标设备上测试着色器以获得准确的结果。half精度
支持。通常更快,并且使用更少的功率来进行计算。Fixed
精度通常仅对较旧的移动GPU有效。fixed
内部处理成和half
精度完全一样。 <2 .把没用到的输入变量删掉
<3. 通过设置灯光的渲染模式 自动选择 逐像素渲染物体 逐顶点渲染物体