目录
扫描二维码关注公众号,回复:
15235785 查看本文章
3ColAmbient代码实现
定义参数面板
Properties {
_Occlusion ("环境光贴图" , 2D) = "white" {}
_EnvUpCol ("朝上环境色", Color) = (1.0,1.0,1.0,1.0)
_EnvSideCol("侧边环境色" , Color) = (0.5,0.5,0.5,1.0)
_EnvDownCol("朝下环境色" , Color) = (0.0,0.0,0.0,1.0)
}
输入结构
struct VertexInput {
float4 vertex : POSITION; //将模型顶点信息输入进来
float3 normal : NORMAL; //将模型法线信息输入进来
float2 uv0 : TEXCOORD0; //将模型UV信息输入进来 0通道 共4通道
// 要用到贴图就要用到UV
};
输出结构
// 把顶点信息做一个变换
struct VertexOutput {
float4 pos : SV_POSITION; // 由模型顶点信息换算来的顶点屏幕位置
float3 nDirWS : TEXCOORD0; //由模型法线信息换算来的世界空间法线信息
float2 uv : TEXCOORD1 ; //追加UV信息用用于像素shader采样贴图
};
顶点Shader
// 顶点shader和像素shader实际上是两个函数 中间土黄色的名字是函数名
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0; //新建一个输出结构
o.pos = UnityObjectToClipPos( v.vertex ); //变换顶点信息 并将其塞给输出结构 模型空间转换到相机裁剪空间
o.nDirWS = UnityObjectToWorldNormal(v.normal); //变换法线信息 并将其塞给输出结构 模型空间下的法线信息转换到世界空间法线信息 这里需要注意大小写
o.uv = v.uv0; //图森破
return o; //将输出结构 输出
}
像素shader
// 可以把float4理解为输出的一个RGBA的颜色信息
// 输出结构>>>像素
float4 frag(VertexOutput i) : COLOR {
// 准备向量
float3 nDir = i.nDirWS;
// 计算各部分遮罩
float upMask = max(0.0,nDir.g); //顶部遮罩就等于法线的绿通道也就是nDir.g
float downMask = max(0.0, -nDir.g);
float sideMask = 1.0 -upMask - downMask;
// 混合环境色
float3 envCol = _EnvUpCol*upMask + _EnvSideCol*sideMask + _EnvDownCol*downMask;
// 采样Occlusion 贴图
float3 Occlusion = tex2D(_Occlusion,i.uv); //采样贴图的方法是tex2D 前面是所用的到的纹理,后面是UV
// 计算环境光光照
float3 envLighting = envCol * Occlusion;
return float4(envLighting ,1.0);
}
Unity自带投影ShaderForge实现
Unity内置投影代码调用方法
必须包含的库文件
#include "AutoLight.cginc" //使用unity投影必须包含这两个库文件
#include "Lighting.cginc" //同上
在输入结构中Unity已经封装好的输出结构内容。括号中的参入,如(0, 1);0,1分别代表占用了TEXCOORD1和TEXCOORD2;如果有占用需要增加或减少。LIGHTING_COORDS
// 把顶点信息做一个变换
struct VertexOutput {
float4 pos : SV_POSITION;
LIGHTING_COORDS(0, 1) //投影用坐标信息 Unity已封装 不用管技术细节
};
顶点Shader中必须调用Unity封装好的方法:TRANSFER_VERTEX_TO_FRAGMENT(o)
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.pos = UnityObjectToClipPos( v.vertex );
TRANSFER_VERTEX_TO_FRAGMENT(o) //Unity封装 不用管技术细节
return o;
}
像素Shader中获取投影信息同样通过Unity提供的方法:LIGHT_ATTENUATION(i)
然后将投影作为结果输出
float4 frag(VertexOutput i) : COLOR {
float shadow = LIGHT_ATTENUATION(i); //同样Unity封装好的函数 可取出投影
return float4(shadow , shadow , shadow , 1.0);
}
OldSchoolPlus
了解一下环境光
依靠阳光或者灯光提供亮度的地方就是反射。环境光就是反射的意思,比方说地面、墙壁有太阳光照着地面时就会天亮、地面也明亮,没有太阳光的时候就会天黑地面也会漆黑这叫靠阳光提供亮度这就是环境光。环境光(汉语词汇)_百度百科 (baidu.com)
简化理解光照构成
OldSchoolPlus构成
连连看实现
代码实现 (作业版)
面板参数
Properties {
_BaseColor ("BaseColor" , Color) = (0.5,0.5,0.5,1)
_SpecualStrength ("SpecualStrength" , Range(0.0 , 90.0)) = 0.0
_DirectionalLightCol ("DirLightCol" , Color) = (1.0,1.0,1.0,1.0)
_DirLightColStrength ("DirLightColStrength" , Range(0.0 , 20.0)) = 1.0
_EnvUpCol ("EnvUpCol" , Color) = (0.45,0.7,0.8,1.0)
_EnvDownCol ("EnvDownCol" , Color) = (0.6,0.6,0.5,1.0)
_EnvSideCol ("EnvSideCol" , Color) = (0.5,0.6,0.5,1.0)
_EnvColorStrength ("EnvColorStrength" , Range(0.0,10.0)) = 1.0
_AmbientOcclusion ("AO" , 2D) = "white"{}
}
库文件
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "Lighting.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
顶点Shader
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0; //新建一个输出结构
o.pos = UnityObjectToClipPos( v.vertex ); //变换顶点信息 并将其塞给输出结构 模型空间转换到相机裁剪空间
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
o.nDirWS = UnityObjectToWorldNormal(v.normal); //变换法线信息 并将其塞给输出结构 模型空间下的法线信息转换到世界空间法线信息 这里需要注意大小写
o.uv = v.uv0; //图森破
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o; //将输出结构 输出
}
像素Shader
float4 frag(VertexOutput i) : COLOR {
float attenuation = LIGHT_ATTENUATION(i); //拿遮挡阴影
// 准备向量
float3 nDir = i.nDirWS;
float3 LightingDir = normalize(_WorldSpaceLightPos0.xyz);
float3 ViewDir = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
// 计算Lambert
float nDotl = dot(nDir , LightingDir);
float Lambert = max(0 , nDotl);
float3 CLambert =_BaseColor*Lambert;
// 计算Phone
// float3 newLDir = -1*LightingDir;
float3 nDotv = max(0 , dot( nDir , reflect(-LightingDir , nDir)));
float PowerPhone = pow(nDotv , _SpecualStrength);
// float3 CL_A_PPone = CLambert + PowerPhone;
// 环境光以及其强度再混合遮挡阴影
float3 DirectionCon = _DirectionalLightCol*_DirLightColStrength;
float3 CL_Add_P_M_Dir = (CLambert+PowerPhone)*DirectionCon;
float3 LL =CL_Add_P_M_Dir;
float3 LL_M_LAtten = LL*attenuation;
// 获取三色环境光
float upMask = max(0.0,nDir.g); //顶部遮罩就等于法线的绿通道也就是nDir.g
float downMask = max(0.0, -nDir.g);
float sideMask = 1.0 -upMask - downMask;
float3 envCol = _EnvUpCol*upMask + _EnvSideCol*sideMask + _EnvDownCol*downMask;
float3 envColStrength = envCol*_EnvColorStrength;
float3 Env_M_Base = envColStrength*_BaseColor;
float3 EE = Env_M_Base;
float3 Occlusion = tex2D(_AmbientOcclusion , i.uv);
float3 AO_M_EE = Occlusion*EE;
// 加上光源和环境
float3 DL_Add_Env = LL_M_LAtten+AO_M_EE;
return float4(DL_Add_Env,1.0);
}