Sharder学习 2
在看shader入门精要。
第五章 shader学习之旅
如何使用属性
Shader "Book/Chapter 5/Simple Shader" {
Properties {
_Color ("Color Tint", Color) = (1.0,1.0,1.0,1.0)
}
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//定义一个与属性名称和类型都匹配的变量
fixed4 _Color; // 前面要加uniform?
struct a2v {...};
struct v2f{...};
v2f vert(a2v v) : SV_POSITION {
...
}
fixed4 frag(v2f i) : SV_Target {
fixed3 c = i.color;
c *= _Color.rgb;
return fixed4(c, 1.0);
}
ENDCG
}
}
}
强大的援手:Unity提供的内置文件和变量
内置包含文件
CGPROGRAM
#include "UnityCG.cginc"
ENDCG
可以在 http://unity3d.com/cn/get-unity/download/archive
unity程序目录下,CGIncludes 也包含了相关文件。
Unity提供的CG/HLSL语义
更具体内容看DirectX相关文档。
从应用阶段传递模型数据给顶点着色器时Unity支持的常用语义
POSITION | 模型空间中顶点位置,通常是float4类型 |
---|---|
NORMAL | 顶点法线,float3 |
TANGENT | 顶点切线,float4 |
TEXCOORDn | 该顶点的纹理坐标,float2 or float4 |
COLOR | 顶点颜色,fixed4 or float4 |
从顶点着色器阶段到片元着色器阶段的语义
SV_POSITION | 裁剪空间中的顶点坐标, |
---|---|
COLOR0 | 顶点颜色 |
COLOR1 | 顶点颜色 |
TEXCOORD0~7 | 纹理坐标 |
Debug
使用假彩色
Visual Studio
帧调试器
第六章 Unity中的基础光照
光源
自发光,环境光
辐照度(irradiance) 对于平行光,它的辐照度是垂直于光的单位面积上单位时间内穿过的能量。
吸收和散射
折射、透射、反射
高光反射(specular)
漫反射(diffuse)
着色(shading)
BRDF(Bidirectional Reflectance Distribution Function)光照模型
大多使用一个数学公式表示,并且提供了一些参数来调整光照能量分布。它可以给出在某个出射方向上的光照能量分布。
标准光照模型
把进入摄像机的光线分为4个部分,每个部分使用一种方法来计算它的贡献度。
- 自发光(emissive)部分。往往不会照亮周围物体。
- 高光反射(specular)部分。
- 漫反射(diffuse)。
- 环境光(ambient)。unity shader可以通过UNITY_LIGHTMODEL_AMBIENT得到环境光的颜色和强度信息。
基于基本的光照模型的数学公式。可以选择:在片元着色器中计算,也叫逐像素光照(per-pixel lighting);在顶点着色器中计算,也叫逐顶点光照(per-vertex lighting)。
在UnityShader中实现漫反射光照模型
逐顶点光照
SubShader {
Pass {
Tags {"LightMode"="ForwardBase"}
LightMode标签是Pass标签中的一种,它用于定义该Pass在Unity的光照流水线中的角色,通过这个操作,我们才能得到一些Unity的内置光照变量。
实践:逐顶点光照
v2f vert(a2v v) {
v2f o;
// transform the vertex from object space to projection space
o.pos = mul (UNITY_MATRI_MVP, v.vertex);
// get ambient term
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//transform the normal from object space to world space
fixed3 worldNormal = normalize(mul(v.normal, (float3x3)_World2Object));
//get the light direction in world space
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//compute diffuse term
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));
o.color = ambient + diffuse;
return o;
}
顶点着色器最基本任务是把顶点位置从模型空间转换到裁剪空间中,因此我们需要使用Unity内置的模型 * 世界 * 投影矩阵 UNITY_MATRIX_MVP 来完成这样的坐标变换。通过Unity的内置变量UINTY_LIGHTMODEL_AMBIENT得到环境光部分。
_Diffuse 材质的漫反射颜色
v.normal顶点法线
内置变量_LightColor0,该Pass处理的光源的颜色和强度信息(注意,需要定义合适的LightMode标签)
_WorldSpaceLightPos0光源方向
实践:逐像素光照
//顶点着色器的输出结构体
struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
}
//顶点着色器不需要计算光照模型,只需要把世界空间下的法线传递给片元着色器
v2f vert(a2v v) {
//transform the vertex from object space to projection space
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//transform the normal from object space to world space
o.worldNormal = mul(v.normal, (float3x3)_World2Object);
return o;
}
//片元着色器需要计算漫反射光照模型
fixed4 frag(v2f i) : SV_Target {
// get ambient term
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//get the normal in world space
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//compute diffuse term
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
fixed3 color = ambient + diffuse;
return fixed4(color,1.0);
}
目前,逐像素漫反射光照的问题是,在光照无法到达的区域,模型的外观通常是全黑的,没有任何明暗变化。改善技术,下面的。