各种shader 小问题请咨询扣扣:2540,33230
Fragment Shader的效果要好于vertex shader,前者基于面,然后逐像素处理对象,后者基于顶点来处理对象,缺点就是前者计算相对复杂,会多耗费一些资源。
首先对应着vertex shader(看之前的博客),来看一下Fragment的漫反射的效果。
Fragment Shader的主要计算在Frag方法里计算,Vert方法主要起传递数据的作用,而vertex shader主要在Vert方法里计算。
Shader "Custom/FragmentShader" {
SubShader {
PASS{
tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f{
float4 pos:POSITION;
float3 normal1:TEXCOORD0;
float4 vertex1:TEXCOORD1;
};
v2f vert(appdata_base v){
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.normal1=v.normal;
o.vertex1=v.vertex;
return o;
}
float4 frag(v2f IN):COLOR{
float4 col= UNITY_LIGHTMODEL_AMBIENT;
float3 N=UnityObjectToWorldNormal(IN.normal1);
float3 L=normalize(WorldSpaceLightDir(IN.vertex1));
float diffuseScale=saturate(dot(N,L));
col+=_LightColor0*diffuseScale;
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
2、将上面代码稍微修改一下,即在frag方法里增加Phong的计算就可以得到Phong的效果,原理请看上篇博文。具体代码如下:
properties{
_SpecularColor("SpecularColor",color)=(1,1,1,1)
_Shininess("Shininess",range(1,8))=4
}
SubShader {
PASS{
tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
float4 _SpecularColor;
float _Shininess;
struct v2f{
float4 pos:POSITION;
float3 normal1:TEXCOORD0;
float4 vertex1:TEXCOORD1;
};
v2f vert(appdata_base v){
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.normal1=v.normal;
o.vertex1=v.vertex;
return o;
}
float4 frag(v2f IN):COLOR{
float4 col= UNITY_LIGHTMODEL_AMBIENT;
float3 N=UnityObjectToWorldNormal(IN.normal1);
float3 L=normalize(WorldSpaceLightDir(IN.vertex1));
float diffuseScale=saturate(dot(N,L));
col+=_LightColor0*diffuseScale;
//Phong运算
float3 V=normalize(WorldSpaceViewDir(IN.vertex1));
float3 R=2*dot(N,L)*N-L;
float specularScale=saturate(dot(R,V));
col+=_SpecularColor*pow(specularScale,_Shininess);
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
3、同样的,在Phong效果的基础上,再修改一下,即可以得到BlinnPong的效果。
Shader "Custom/FragmentShader" {
properties{
_SpecularColor("SpecularColor",color)=(1,1,1,1)
_Shininess("Shininess",range(1,8))=4
}
SubShader {
PASS{
tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
float4 _SpecularColor;
float _Shininess;
struct v2f{
float4 pos:POSITION;
float3 normal1:TEXCOORD0;
float4 vertex1:TEXCOORD1;
};
v2f vert(appdata_base v){
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.normal1=v.normal;
o.vertex1=v.vertex;
return o;
}
float4 frag(v2f IN):COLOR{
float4 col= UNITY_LIGHTMODEL_AMBIENT;
float3 N=UnityObjectToWorldNormal(IN.normal1);
float3 L=normalize(WorldSpaceLightDir(IN.vertex1));
float diffuseScale=saturate(dot(N,L));
col+=_LightColor0*diffuseScale;
//Phong运算
//float3 V=normalize(WorldSpaceViewDir(IN.vertex1));
//float3 R=2*dot(N,L)*N-L;
//float specularScale=saturate(dot(R,V));
//col+=_SpecularColor*pow(specularScale,_Shininess);
//BlinnPhong运算
float3 V=normalize(WorldSpaceViewDir(IN.vertex1));
float3 H=normalize(V+L);
float specularScale=saturate(dot(H,V));
col+=_SpecularColor*pow(specularScale,_Shininess);
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
4、从上面的代码,可以看到,上面并没有阴影的描述,所以需要增加一个阴影,这个阴影用光照深度来描述(atten),将上面的代码再修改一下
Shader "Custom/FragmentShader" {
properties{
_SpecularColor("SpecularColor",color)=(1,1,1,1)
_Shininess("Shininess",range(1,8))=4
}
SubShader {
PASS{
tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
float4 _SpecularColor;
float _Shininess;
struct v2f{
float4 pos:POSITION;
float3 normal1:TEXCOORD0;
float4 vertex1:TEXCOORD1;
LIGHTING_COORDS(2,3)
};
v2f vert(appdata_base v){
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.normal1=v.normal;
o.vertex1=v.vertex;
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
}
float4 frag(v2f IN):COLOR{
float4 col= UNITY_LIGHTMODEL_AMBIENT;
float3 N=UnityObjectToWorldNormal(IN.normal1);
float3 L=normalize(WorldSpaceLightDir(IN.vertex1));
float diffuseScale=saturate(dot(N,L));
col+=_LightColor0*diffuseScale;
//Phong运算
//float3 V=normalize(WorldSpaceViewDir(IN.vertex1));
//float3 R=2*dot(N,L)*N-L;
//float specularScale=saturate(dot(R,V));
//col+=_SpecularColor*pow(specularScale,_Shininess);
//BlinnPhong运算
float3 V=normalize(WorldSpaceViewDir(IN.vertex1));
float3 H=normalize(V+L);
float specularScale=saturate(dot(H,V));
col+=_SpecularColor*pow(specularScale,_Shininess);
//增加阴影
float atten=LIGHT_ATTENUATION(IN);
col.rgb*=atten;
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
阴影效果如下:
从上面的效果可以看出,背面比较黑,如果想背面也显示不那么黑,就可以用Half Lambert光照模型
Shader "Custom/Shader" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
}
SubShader {
pass{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "UnityCG.cginc"
struct v2f {
float4 pos:SV_POSITION;
float3 V:Texcoord0;
float3 N:Texcoord1;
};
fixed4 _Color;
v2f vert(appdata_base v){
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.N=v.normal;
o.V=WorldSpaceLightDir( v.vertex);
return o;
}
float frag(v2f IN):color {
float4 col;
float diff=dot(IN.N,IN.V)*0.5+0.5;
col=_LightColor0*diff;
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
渐变纹理(摘自http://blog.csdn.net/u013354943/article/details/52788010)
Shader "LT/RampTexture"
{
Properties
{
_Color("Color Tint",Color) = (1,1,1,1)
_RampTex("Ramp Tex",2D) = "white" {} //渐变纹理
_Specular("Specular",Color) = (1,1,1,1)
_Gloss("Gloss",Range(8.0,256)) = 20
}
SubShader
{
Pass
{
Tags { "LightMode"="ForwardBase" }//定义该Pass在光照流水线中的角色光照模式注意要设置为Forward
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _RampTex;
fixed4 _Specular;
float4 _RampTex_ST;
float _Gloss;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldNormal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.uv, _RampTex); //内置的宏计算平铺和偏移位置
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 worldNormal =normalize(i.worldNormal);
fixed3 worldLightDir =normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz ;
//法线和方向和光照方向的点积做一次0.5倍的缩放和一个0.5大小的偏移来计算兰伯特部分halfLambert,得到结果在【0,1】之间
fixed halfLambert = 0.5 *dot(worldNormal,worldLightDir) +0.5;
//用halfLambert构建一个纹理坐标,并对这个纹理坐标对_RampTex进行采样。
//由于_RampTex实际是一个一维纹理(纵轴方向上颜色不变),所以纹理坐标的UV方向我们都使用了halfLambert,
fixed3 diffuseColor = tex2D(_RampTex, fixed2(halfLambert,halfLambert)).rgb * _Color.rgb;
//漫反射颜色 = 渐变纹理采样得到的颜色 * 材质颜色
fixed3 diffuse = _LightColor0 * diffuseColor ;
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfDir = normalize(worldLightDir + viewDir);
fixed3 specular = _LightColor0.rbg * _Specular.rgb *pow(max(0,dot (worldNormal,halfDir)),_Gloss);
fixed4 col = fixed4( diffuse+ specular + ambient,1.0);
return col;
}
ENDCG
}
}
Fallback "Specular"
}