什么是Shader
即着色器, 仅仅是渲染流水线中的一个环节
1.GPU流水线上一些可高度编程的阶段,而由着色器编译的代码可以在GPU上运行
2.有一些特定类型的着色器。eg:顶点、片元着色器
3.依靠着色器我们可以控制流水线中的渲染细节
什么是渲染流水线
定义: 是显示芯片内部处理图形信号相互独立的的并行处理单元
工作任务: 计算机需要从一系列的顶点数据、纹理等信息出发,把这些信息转换成一张人脸可以看到的图像。由CPU、GPU共同完成。
三个阶段: 应用阶段、几何阶段、光栅化阶段
阶段 | 实现 | 任务 | 输出 |
---|---|---|---|
应用阶段 | CPU负责实现 | 1.把数据加载到显存中1 2设置渲染状态2 3.调用DrawCall3 |
渲染所需的几何信息 渲染图元 |
几何阶段 | GPU 处理所有与绘制的几何相关的事情 |
1.把顶点坐标变换到屏幕空间 2.交给光栅化器进行处理 进行逐顶点、逐多边形操作 |
屏幕空间的二维顶点坐标、每个顶点对应的深度值、着色等信息 |
光栅化阶段 | GPU | 决定每个渲染图元的哪些像素应该被绘制在屏幕上 | 渲染最终的图像 |
流水线阶段 | 定义 | 输入 | 输出 | 特点 | 任务 |
---|---|---|---|---|---|
顶点数据 | 由应用阶段加载到显存中,由Draw Call指定 | 传递给Vertex shader | |||
顶点着色器 | 实现顶点的空间变换、顶点着色 | CPU | 后续阶段所需的数据 | 顶点之间相互独立 | 坐标变换、逐顶点光照 |
曲面细分着色器 4 | 用于细分图元 | pach的顶点数量 | 曲面更加平滑细密 | 改变顶点与三角网格的数量–>插入新的顶点 | |
几何着色器5 | 逐图元的着色、产生更多图元 | 一系列顶点组成的图元 | 顶点–数量发生变换 | 能够在GPU上创建数据 | 根据运行环境产生合适分辨率的图形 |
裁剪 | 图元 | 图元 | 将不在摄像机视野内的顶点裁剪,并剔除某些三角图元的面片 | ||
屏幕映射 | 三维坐标转换到二维坐标(x,y) | 坐标:三维 | 坐标:二维 | 决定了顶点对应屏幕上哪个像素、距离 | 把每个图元的x,y坐标转换到屏幕坐标系下 |
三角形设置 | 计算三角网格表示数据的过程 | 三角网格每条边的两端点 | 边界像素的坐标信息 | 计算光栅化一个三角网格所需的信息 | |
三角形遍历 | 找到哪些像素被三角网格覆盖的过程 | 上个阶段的计算结果 | 得到一个片元序列6 | 对覆盖区域的像素进行插值 | 检查每个像素是否被一个三角网格所覆盖 |
片元着色器 | 顶点信息插值的结果 | 一个或多个颜色值 | 仅影响单个片元 | 完成渲染技术7、效果 | |
逐片元操作 | 片元 | 颜色缓冲区 | 对像素产生影响 | 经过测试8,决定每个片元的可见性问题 | |
屏幕图像 |
4.什么是Shader Lab?
Unity Shader 是Unity为开发者提供的高层级的渲染抽象层。ShaderLab 是Unity提供的编写Unity Shader的一种说明性语言。用语义来描述文件的结构,包含了渲染所需的数据。
5.Unity Shader的结构
Properties语义块的作用仅仅是为了让这些属性可以出现在材质面板中。
Unity Shader文件可以包含多个SubShader,但至少要有一个。
Unity会自动选择第一个能够在目标平台上运行的subshader,如果不支持则会使用Fallback指定的UnityShader
Shader "Name" //UnityShader的名字 也是索引的路径 可在Name中添加(‘/’)控制面板中出现的位置
{
Properties //包含了一系列的属性 名字
{
//声明一个Color类型的属性
_Color("Color Tint", Color) = (1.0,1.0,1.0,1.0) //白色
/*属性名字:下划线开始. 某些有特殊要求。 eg:_Color
显示的名称:在材质面板上可以看到名字--随便取:eg:Color Tint
类型:属性指定的类型。eg:Color
默认值:属性对应的默认值,第一次把shader赋给某个材质时,在材质面板上显示的默认值。eg:(1.0,1.0,1.0,1.0)
*/
}
SubShader
{
Tags{} //标签 可选 -- 也可在pass中设定
[RenderSetup] //状态可选
//至少要有一个pass
UsePass "ShaderLearn/Chapter12/GuassianShader/GAUSSIAN_BLUR_VERTICAL" //复用其他Pass
GrabPass {//抓取屏幕并将结果存储到一张纹理中,用于后续Pass处理
"_RefractionTex"
}
Pass{ //渲染通道必须要有一个,一个Pass占一个CG,过多会造成渲染性能下降
[Name] //Pass名称 大写。通过名称其他的Shader可以调用该Pass
Tags{}
[RenderSetup]
}
}
Fallback "name" / Fallback Off //若以上SubShader在该显卡上不能运行执行name /关闭Fallback
}
属性类型 | 默认值的定义语法 | 属性 | 例子 | CG变量类型9 |
---|---|---|---|---|
Int | number | 数字 | _Int(“Int”, Int) = 2 | |
Float10 | number | 数字 | _Float(“Float”, Float) = 2 | float,half,fixed |
Range(min,max) | number | 数字 | _Range(“Range”, Range(0,1)) = 0.5 | float,half,fixed |
Color | (number,number,number,number) | 四维向量 | _Color(“Color Tint”, Color) = (1.0,1.0,1.0,1.0) | float4,half4,fixed4 |
Vector | (number,number,number,number) | 四维向量 | _Vector(“Vector”, Vector) = (1.0,1.0,1.0,1.0) | float4,half4,fixed4 |
2D | “defauttexture”{} | 纹理类型11 | _2D(“2D”, 2D) = “white”{} | sampler2D |
Cube | “defauttexture”{} | 纹理类型 | _Cube(“Cube”, Cube) = “white”{} | samplerCube |
3D | “defauttexture”{} | 纹理类型 | _3D(“3D”, 3D) = “black”{} | sampler3D |
bump | 内置的法线纹理 | 对应了模型自带的法线信息 |
【Tags】SubShader标签
subshader的标签是一个键值对(Key - Value)
标签类型 | 说明 | 例子 |
---|---|---|
Queue | 控制渲染顺序,指定该物体属于哪一个渲染队列。 可以保证所有透明物体后渲染 |
Tags{“Queue” = “Transparent”} |
RenderType | 对着色器分类 | Tags{“RenderType” = “Opaque”} |
DisableBatching | 是否对该SubShader使用批处理 | Tags{“DisableBatching” = “True”} |
ForceNoShadowCasting | 控制使用该SubShader的物体是否会投射阴影 | Tags{“ForceNoShadowCasting” = “True”} |
IgnoreProjector | 为True是,该SubShader不会受Projector的影响,用于半透明物体 | Tags{“IgnoreProjector” = “True”} |
CanUseSpriteAtlas | 该SubShader用于Sprite时,设置为False | Tags{“CanUseSpriteAtlas” = “False”} |
PreviewType | 材质面板预览材质,可设置为plane、skybox等 | Tags{“PreviewType” = “Plane”} |
—>以上标签只适用与SubShader
渲染队列 | 队列索引号 | 描述 | 适用 | 例子 |
---|---|---|---|---|
Background | 1000 | 第一个被渲染的优先于其他队列 | 渲染那些需要绘制在背景上的物体 天空盒子 |
Tags{“Queue” = “Background”} |
Geometry | 2000 | 默认的渲染队列 | 不透明物体 | Tags{“Queue” = “Geometry”} |
AlphaTest | 2450 | 所有不透明物体渲染之后再渲染它们会更加高效 | 需要透明度测试的物体 | Tags{“Queue” = “AlphaTest”} |
Transparent | 3000 | 在Geometry与AlphaTest之后,再按从后往前的顺序进行渲染 | 使用了透明度混合的物体、关闭深度写入的Shader | Tags{“Queue” = “Transparent”} Pass{ZWrite Off} |
Overlay | 4000 | 实现叠加效果 | 任何需要在最后渲染的物体 | Tags{“Queue” = “Overlay”} |
【Tags】Pass标签
标签类型 | 说明 | 例子 |
---|---|---|
LightMode | 定义该Pass渲染路径 | Tags{"LightMode " = “ForwardBase”} |
RequireOptions | 满足某些条件才渲染该Pass。SoftVegetation | Tags{“RequireOptions” = “SoftVegetation”} |
SoftVegetation: Render this pass only if Soft Vegetation is on in the Quality window.
【LightMode 支持的渲染路径】
标签 | 描述 | 限制 |
---|---|---|
Always | 无论哪种渲染路径,该Pass总会被渲染,但不计算任何光照 | |
ForwardBase | 计算环境光、最重要的平行光、逐顶点/SH光源、Lightmaps | 前向渲染 |
ForwardAdd | 计算额外的逐像素光源,每个Pass对应一个光源 | 前向渲染 |
Deferred | 渲染G缓冲 | 延迟渲染 |
ShadowCaster | 把物体的深度信息渲染到阴影映射纹理或一张深度纹理中 | |
PrepassBase | 渲染法线和高光反射的指数部分 | 遗留的延迟渲染 |
PrepassFinal | 合并纹理、光照和自发光来渲染得到最后的颜色 | 遗留的延迟渲染 |
Vertex、VertexLMRGBM、VertexLM | 遗留的顶点照模渲染 |
【渲染状态】
状态名称 | 设置指令 | 解释 |
---|---|---|
Cull | Cull Back/Front/Off | 设置剔除模式;剔除背面/正面/关闭 只渲染前面/后面/全都渲染 |
ZTest | ZTest Less Greater/LEqual/GEqual/Equal/NotEqual/Always | 设置深度测试时使用的函数 |
ZWrite | ZWrite On/Off | 开启/关闭深度写入 |
Blend | Blend SrcFactor DstFactor | 开启并设置混合模式 |
Offset | Offset OffsetFactor, OffsetUnits | 设置Z缓冲区深度偏移 |
ColorMask | ColorMask RGB /A / 0/ any combination of R, G, B, A | 设置颜色通道蒙版,0关闭颜色通道的渲染 |
6.Unity Shader的形式
Create | 特点 | 劣势 | 例子 | |
---|---|---|---|---|
表面着色器 | Surface Shader 包含标准光照 | 代码量少 | 渲染代价大 | #pragma surface surf lambert |
顶点/片元着色器 | Unit Shader 无光照 | 灵活性高,可控制渲染的实现细节 | 复杂 | #pragma vertex vert #pragma fragment frag |
标准着色器 | Standard Shader | 表面的升级版,PBR技术 | ||
后期屏幕渲染特效 | Image Effect Shader | 屏幕后处理效果 | Graphics.Blit(scr,RT1,mat) ZWrite Off ZTest Always | |
计算着色器12 | Compute Shader | 大量数学计算 | 传输速率慢 CPU->GPU->CPU->GPU |
#pragma kernel CSMain |
固定函数 | 已被抛弃 |
7.坐标空间–顶点变换
定义 | 原点 | 坐标 | 顶点变换 | 维数 | |
---|---|---|---|---|---|
模型空间 | 与某个模型或者对象有关 | 模型的重心 | 顶点着色器访问到的顶点坐标 | 三维空间 | |
世界空间 | 最大最外层的坐标系 | 游戏空间的中心 | 模型的位置若无父节点,则为世界坐标 | 模型变换 | |
摄像机/观察空间 | 渲染游戏所使用的视角 | 摄像机位于原点 | 观察变换 | ||
齐次裁剪空间 | 能够方便地对渲染图元进行裁剪13 | 裁剪/投影矩阵14 | 四维空间 | ||
屏幕空间 | 显示的屏幕 | 屏幕左下角 | 归一化的设备坐标NDC | 屏幕映射 | 二维空间 |
切线空间 | 二维空间 |
7.法线变换
8.Unity Shader的内置变量
1.变换矩阵
变量名 | 描述 | 矩阵 | 曾用名 | 用法 |
---|---|---|---|---|
UnityObjectToClipPos | 将顶点从模型空间->裁剪空间 | 模型 . 观察 . 投影矩阵 | mul(UNITY_MATRIX_MVP,*) | UnityObjectToClipPos(*) |
UNITY_MAXTRIX_MV | 将顶点从模型空间->观察空间 | 模型 . 观察 | UNITY_MAXTRIX_MV | |
UNITY_MAXTRIX_V | 将顶点从世界空间->观察空间 | 观察矩阵 | UNITY_MAXTRIX_V | |
UNITY_MAXTRIX_P | 将顶点从观察空间->裁剪空间 | 投影矩阵 | UNITY_MAXTRIX_P | |
UNITY_MAXTRIX_VP | 将顶点从观察空间->裁剪空间 | 观察 . 投影矩阵 | UNITY_MAXTRIX_VP | |
UNITY_MAXTRIX_T_MV | UNITY_MAXTRIX_MV的转置 | UNITY_MAXTRIX_T_MV | ||
UNITY_MAXTRIX_T_MV | 法线从模型空间->观察空间 | UNITY_MAXTRIX_MV的逆转置 | UNITY_MAXTRIX_T_MV | |
unity_ObjectToWorld | 顶点从模型空间->世界空间 | 模型矩阵 | _Object2World | |
unityWorldToObject | 顶点从世界空间->模型空间 | _Object2World 的逆矩阵 | _World2Object |
2.Unity内置的摄像机和屏幕参数
变量名 | 类型 | 描述 | 曾用名 | 解析 | 用法 |
---|---|---|---|---|---|
_WorldSpaceCameraPos | float3 | 该摄像机在世界空间中的位置 | |||
_ProjectionParams | float4 | x=1.0/-1,y=Near,z=Far,w=1+1/Far | Near:近裁剪平面 Far:远裁剪平面 |
||
_ScreenParams | float4 | x=width,y=height,z=1+1/width,w=1+1/height | width:摄像机的渲染目标的像素宽度 Height:摄像机的渲染目标的像素高度 |
||
_ZBufferParams | float4 | x=1-Far/Near,y=Far/Near,z=x/Far,w=y/Far | 用于线性化Z缓存中的深度值 | ||
unity_OrthoParams | float4 | x=width,y=heght,z无定义,w=1(正交)/0(透视) | width:正交投影摄像机的宽度 height::正交投影摄像机的高度 |
||
unity_CameraProjection | float4x4 | 摄像机的投影矩阵 | |||
unity_CameraInvProjection | float4x4 | 摄像机的投影矩阵的逆矩阵 | |||
unity_CameraWorldClipPlanes[6] | float4 | 摄像机的6个裁剪平面在世界空间下的等式顺序:左右下上近远裁剪平面 |
3.Unity 内置包含文件unity的安装路径下CGIncludes
文件名 | 描述 |
---|---|
UnityCG.cginc | 包含了最常使用的帮助函数、宏和结构体等 |
UnityShaderVariables.cginc | 在编译UnityShader时自动包含。内置的全局变量ps:UNITY_MAXTIX_MVP(UnityObjectToClipPos) 访问事件、光照、雾化和环境光 |
Lighting.cginc | 包含了各种内置的光照模型,surface shader 会自动包含 |
HLSLSupport.cginc | 在编译UnityShader时自动包含。声明了很多跨平台编译的宏和定义 |
UnityStandardBRDF.cginc | 实现基于物理的渲染 |
UnityStandardCore.cginc |
4.UnityCG.cgin中一些常用的结构体
名称 | 描述 | 包含的变量 | 结构体 |
---|---|---|---|
appdata_base | 用于顶点着色器的输入 | 顶点位置、顶点法线、第一组纹理坐标 | struct appdata_base { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID}; |
appdata_tan | 用于顶点着色器的输入 | 顶点位置、顶点切线、顶点法线、第一组纹理坐标 | struct appdata_tan { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID}; |
appdata_full | 用于顶点着色器的输入 | 顶点位置、顶点切线、顶点法线、多组纹理坐标、顶点颜色 | struct appdata_full { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 texcoord1 : TEXCOORD1; float4 texcoord2 : TEXCOORD2; float4 texcoord3 : TEXCOORD3; fixed4 color : COLOR; UNITY_VERTEX_INPUT_INSTANCE_ID}; |
appdata_img | 用于顶点着色器的输入 | 顶点位置、第一组纹理坐标 | struct appdata_img{ float4 vertex : POSITION; half2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID}; |
v2f_img | 用于顶点着色器的输出 | 裁剪空间中的位置、纹理坐标 | struct v2f_img{ float4 pos : SV_POSITION; half2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO}; |
5.UnityCG.cginc中一些常用的帮助函数
函数名 | 描述 | 限制 | 实现 |
---|---|---|---|
float3 UnityWorldSpaceViewDir(float3 worldPos) | 输入一个模型空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向 | return _WorldSpaceCameraPos.xyz - worldPos; | |
float3 ObjSpaceViewDir(float4 v) | 输入一个模型空间中的顶点位置,返回模型空间中从该点到摄像机的观察方向 | float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz; return objSpaceCameraPos - v.xyz; |
|
float3 UnityWorldSpaceLightDir(float3 worldPos) WorldSpaceLightDir(float4 vertex) |
输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向 | 前向渲染 | return _WorldSpaceLightPos0.xyz - worldPos * _WorldSpaceLightPos0.w; |
float3 ObjSpaceLightDir(float4 v) | 输入一个模型空间中的顶点位置,返回模型空间中从该点到光源的光照方向 | 前向渲染 | float3 objSpaceLightPos = mul(unity_WorldToObject, _WorldSpaceLightPos0).xyz; return objSpaceLightPos.xyz - v.xyz * _WorldSpaceLightPos0.w; |
float3 UnityObjectToWorldNormal(float3 normal) | 把法线方向从模型空间转换到世界空间中 | return normalize(mul(norm, (float3x3)unity_WorldToObject)); | |
float3 UnityObjectToWorldDir(float3 dir) | 把方向矢量从模型空间转换到世界空间中 | return normalize(mul((float3x3)unity_ObjectToWorld, dir)); | |
float3 UnityWorldToObjectDir(float3 dir) | 把方向矢量从世界空间转换到模型空间中 | return normalize(mul((float3x3)unity_WorldToObject, dir)); | |
float3 Shade4PointLights(…) | 计算4个点光源的光照。前向使用这个函数计算逐顶点光照 | 前向渲染 |
9.渲染路径
决定了光照是如何应用到UnityShader中。一般一个项目只使用一种渲染路径,如果使用多条渲染路径,需要在摄像机下设置以覆盖Project Setting中的设置。
渲染路径 | 原理 | 处理光照方式15 | 判断规则 | Pass | 缺陷 |
---|---|---|---|---|---|
前向渲染路径 | 1.渲染该对象的渲染图元 2.计算两个缓冲区的信息:颜色缓冲区,深度缓冲区 |
逐顶点 逐像素 球谐函数SH |
1.最亮的平行光–逐像素处理 2.渲染模式为Not Important–逐顶点/SH处理 3.渲染模式为Important–逐像素 4.以上小于设定的值更多光源按逐像素方式 |
1.Base Pass 2.Additional Pass |
有大量实时光源时,渲染性能降低 |
延迟渲染路径 | 1.仅计算哪些片元是可见的–信息存储到G缓冲区 2.利用G缓冲中片元信息–计算真正的光照 |
逐像素 | 与光源的数目无关,与屏幕空间的大小有关 | 1.渲染G缓冲 2.计算真正的光照模型 |
1.不支持真正的抗锯齿 2.不能处理半透明 3.对显卡有要求 |
顶点照模渲染路径 | 已废弃 |
1.前向渲染的两种Pass
实现光照效果 | 渲染设置 | 光照计算 | 执行次数 | |
---|---|---|---|---|
Base Pass | 光照纹理、自发光、环境光、阴影 | Tags{“LightMode”=“ForwardBase”} #pragma multi_compile_fwdbase} |
一个逐像素的平行光以及所有逐顶点和SH光源 | 一次 |
Additional Pass | 默认不支持阴影可用命令开启 #pragma multi_compile_fwdadd_fulls_shadows |
Tags{“LightMode”=“ForwardAdd”} Blend One One #pragma multi_compile_fwdadd |
其他影响该物体的逐像素每个光源执行一次Pass | 多次 |
2.内置光照变量
名称 | 类型 | 描述 | 渲染路径使用 | Pass限制 |
---|---|---|---|---|
_LightColor0 | float4 | 该Pass处理的逐像素光源的颜色 | 前向 | |
_WorldSpaceLightPos0 | float4 | xyz分量是处理的逐像素光源的位置 平行光 w==0,其他光源w == 1 |
前向、延迟 | |
_LightMatrix0 | float4x4 | 从世界空间到光源空间的变换矩阵,可用于采样cookie和光强衰减纹理 | 前向 | |
unity_4LightPosX0、unity_4LightPosY0、unity_4LightPosZ0 | float4 | 前4个非重要的点光源在世界空间中的位置 | 前向 | Base Pass |
unity_4LightAtten0 | float4 | 前4个非重要的点光源的衰减因子 | 前向 | Base Pass |
unity_LightColor | half4[4] | 前4个非重要的点光源的颜色 | 前向 | Base Pass |
_LightColor | float4 | 光源颜色 | 延迟 |
3.渲染纹理
UnityShader 入门精要 作者github
彩图
4.Unity内置的时间变量
名称 | 类型 | 描述 | 分量 |
---|---|---|---|
_Time | float4 | t是自该场景加载开始所经过的时间 | (t/20,t,2t,3t) |
_SinTime | float4 | t是时间的正弦值 | (t/8,t/4,t/2,t) |
_CosTime | float4 | t是时间的余弦值 | (t/8,t/4,t/2,t) |
unity_DeltaTime | float4 | dt是时间增量 | (dt,1/dt,smoothDt,1/smoothDt) |
1.所有渲染需要的数据都要从硬盘中加载到系统内存中。
2.网格和纹理等数据又被加载到显卡的存储空间–显存中 <== 显卡对于显存的访问速度更快。
3.某些不需要的数据可以从RAM中移除 <==硬盘加载到RAM的过程耗时。 ↩︎
定义了场景中的网格是怎么被渲染的。eg:使用哪个顶点着色器/片元着色器、光源属性、材质等
如果没有更改渲染状态,所有的网格都将使用同一种渲染状态。
↩︎
DrawCall 就是一个命令。它的发起方:CPU,接收方:GPU。这个命令仅仅会指向一个需要被渲染的图元列表,而不会包含任何材质信息。 ↩︎
细分着色器介绍 ↩︎
几何着色器介绍 ↩︎
片元并不是真正意义上的像素,而是包含了许多状态的集合。状态包括:它的屏幕坐标、深度信息,以及其他从几何阶段输出的顶点信息,法线、纹理坐标等。 ↩︎
纹理采样:
1.在顶点着色器阶段输出每个顶点对应的纹理坐标
2.经过光栅化阶段对三角网格的3个顶点对应的纹理坐标进行插值
3.得到其覆盖的片元纹理坐标。 ↩︎
主要任务:1.决定每个片元的可见性
2.若一个片元通过了所有的测试,就需要把这个片元的颜色值与已经在缓冲区的颜色进行合并。
模板测试:
↩︎
CG代码块中访问属性 。uniform关键字:CG中修饰变量和参数的一种修饰,仅仅用于提供关于该变量的初始值是如何指定和存储相关信息。 ↩︎
内置的纹理名称:white、black、gray、bump等。花括号 原本是用于指定一些纹理属性。后来被移除了。 ↩︎
Compute Shader ↩︎
视锥体决定了哪些部分剔除,裁剪。
视锥体是空间中的一块区域六面体组成的裁剪平面,决定了摄像机能看到的空间。两种类型:
正交投影 :所有网格大小都一样,保持了物体的距离和角度 |视锥体为长方体型
透视投影:模拟人眼看世界的方式 |视锥体为金字塔型 ↩︎
投影矩阵的目的:1.为投影做准备。2.对x、y、z分量进行缩放 ↩︎
决定一个光源使用哪种处理模式取决于它的类型和渲染模型。
光源类型:该光源是平行光还是其他类型的光源
光源的渲染模式:该光源是否是重要的(Important or Not Important) ↩︎