这是对unity shader语法的快速入门、复习 主要参考链接:
Lesson 1 渲染管线
此部分可以参考我之前的文章:百人计划学习 图形 1.1 渲染流水线 主要分清楚顶点着色器、片段着色器阶段的输入和输出,以及这两个阶段是做什么的
Lesson 2 Shader的基本结构
Shader "Custom/ShaderLearning"
{
Properties {
_MainTex("Main Tex",2D) = "white"
}
SubShader{
Tags{"LightMode" = "ForwardBase"}
Pass{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
sampler2D _MainTex;
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag(v2f i) :SV_Target {
fixed4 color = tex2D(_MainTex,i.uv);
color *= fixed4(i.uv.x,i.uv.y,0,1);
return color;
}
ENDCG
}
}
FallBack "Diffuse"
}
解析一下上面的各部分:
properties属性部分
Properties {
_Tex("Tex", 2D) = "white" {}
_Intensity("Intensity", Range(0, 20)) = 2
_MainTex("Main Tex",2D) = "white"
}
- Subshader,定义了一系列pass以及可选状态,pass是子着色器
- Fallback,告诉unity,如果上面所有的subshader在这块显卡上都不执行,那么使用这个最低级的shader
Lesson 3 纹理输入
将带有透明通道的PNG图片渲染出来 如果没有设置透明通道,会出现以下情况
注意:在属性区块内被定义的数据在CGPROGRAM内被使用之前都要预定义一遍,不然会报错。在CGPROGRAM内加入纹理的定义:
sampler2D _Tex;
float4 _Tex_ST;
float _Intensity;
要返回纹理,片段着色器应该写为:
fixed4 frag(v2f i) :SV_Target {
return tex2D(_MainTex,i.uv);
}
设置透明度, 使用Alpha Blend : Blend SrcAlpha OneMinusSrcAlpha OutColor = SrcColor * ScrAlpha + DstColor * (1 - SrcAlpha) 代码如下:
Shader "Custom/TextureShader"
{
Properties {
_MainTex ("Main Tex", 2D) = "white"
}
SubShader{
Tags{"LightMode" = "ForwardBase"}
Tags{"Queue" = "Transparent"}
Pass{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
#include "Lighting.cginc"
struct a2v{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag(v2f i) :SV_Target {
return tex2D(_MainTex,i.uv);
}
ENDCG
}
}
FallBack "Diffuse"
}
Lesson 4 屏幕后处理效果
-
在颜色缓冲区的内容真正被喷到屏幕上之前,我们仍然有机会更改其中的内容。而unity也为我们考虑到了这一点,因此它提供了一个叫OnRenderImage的函数,这是个monobehaviour事件。 -
Called after scene rendering is complete to allow post-processing of the image, -
Blit 将 dest 设置为渲染目标,在材质上设置 source _MainTex 属性, 并绘制全屏四边形。所以在material上要设置 _MainTex
- 完整shader是lesson1中的代码
- 下面的脚本添加到camera中
using UnityEngine;
[ExecuteInEditMode]
public class PostEffects : MonoBehaviour
{
public Material material;
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
Graphics.Blit(source,destination,material);
}
}
Lesson 5 扭曲效果制作
需要添加位移图、和扭曲强度参数 位移图红色作为uv的x值,所以取到红色就是向右移动 绿色同理,向上移动
这里实现的是动态扭曲的效果,有两点需要注意 一是_Time的使用, 二十disp*2 -1 将范围划到(-1,1)中uv值就随着时间的推移而改变,我们在对位移图进行采样的时候,uv值就已经改变过了 会重复的原因是tex2D的原因,最终会把纹理uv的值映射到0-1中(没有完全明白)
float4 frag(v2f i) :SV_Target {
float2 distuv = float2(i.uv.x + _Time.x ,i.uv.y + _Time.x*2);
float2 disp = tex2D(_DisplaceTex,distuv).xy;
disp = ((disp*2) - 1) * _Magnitude;
float4 color = tex2D(_MainTex,i.uv + disp);
return color;
}
Lesson 6 小练习
小练习1 实现两个图片的替换 添加两个参数:
- _SubTex (“Sub Tex”,2D) = “white” {}
- _Between (“Tween”,Range(0,1)) = 0
在frag shader里
fixed4 frag(v2f i) :SV_Target {
return tex2D(_MainTex,i.uv)*(1-_Between) + tex2D(_SubTex,i.uv)*(_Between);
}
2.设置灰度值并乘以自定义颜色 使用明亮度(luminance)公式来算出一个明亮度值,然后将红绿蓝通道都设置为明亮度值,透明度通道则用对图片采样获得的透明度,最终获得灰度效果 luminance = 0.2125 * Red + 0.07154 * Green + 0.0721 * Blue
fixed4 frag(v2f i) :SV_Target {
fixed4 colorVal = tex2D(_MainTex,i.uv)*(1-_Between) + tex2D(_SubTex,i.uv)*(_Between);
fixed luminance = 0.2125 * colorVal.r + 0.07154 * colorVal.g + 0.0721 * colorVal.b;
return fixed4(luminance,luminance,luminance,tex2D(_MainTex,i.uv).a);
}
Lesson 7 替换渲染及矩阵转换
- 我们可以通过定义一系列的子shader(SubShader)来让相机根据不同的对象进行不同的渲染方法,这种渲染被称之为替换渲染。
- 当Unity需要渲染一个网格时,它会在shader的SubShader列表里面,查找第一个可供目前显卡上运行的SubShader来进行渲染
待更
|