在看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); }
目前,逐像素漫反射光照的问题是,在光照无法到达的区域,模型的外观通常是全黑的,没有任何明暗变化。改善技术,下面的。