在看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);
}

目前,逐像素漫反射光照的问题是,在光照无法到达的区域,模型的外观通常是全黑的,没有任何明暗变化。改善技术,下面的。

半兰伯特模型(Half Lambert)

高光反射光照模型