您的位置:首页 > 移动开发 > Unity3D

Unity3d shader编程 VertexLit渲染路径

2015-07-07 14:56 543 查看
此文仅供参考使用。this is reference not a manual!

所以知识点比较零碎,如果有时间我会整理一下概念,组织一下逻辑,让弱基础的读者理解。

老生重提,学过shader编程的同学应该知道,一个特效的形成是由3部分组成(像魔戒三部曲一样)。物体材质+光源+视摄像机共同渲染的结果。物体材质是我们可以编程的如何接收光,反射,折射等,这一部分涉及物理光学(突然好高大上),计算机靠数学函数模拟光照的特征,计算出光照强度颜色等,最终反映到屏幕上被肉眼接收。那摄像机有vertexlit,forward,deferred三种模式干嘛? 其实摄像机就是统一规定屏幕内的物体都是以什么方式被渲染的,VertexLit顶点方式则全部用物体材质中的vertex path渲染路径去刻画每一个物体,如果(当前显示)摄像机用forward模式,则查找物体材质shader程序中forward base/forward add path去刻画物体,如果找不到则还是用vertex path去刻画。如果(当前显示)摄像机用deferred模式,则查找物体材质shader程序中PrepassBase/PrepassFinal path(这里不是deferred开头额。)方法去刻画物体,找不到则寻找forward base/forward add path去刻画物体,再找不到则使用最低级的vertex path去渲染,再找不到?有个FallBack “Diffuse”就是最终使用unity系统默认渲染方法来渲染..您就甭管了…

所以摄像机的渲染模式就像一个总开关… 而材质的渲染路径path就是总开关下的各种串并联电路,决定哪种渲染方式合适,而光源有两种光照vertex/pixel和材质渲染路径共同决定如何显示,总不能光源是vertex顶点的,而要求材质渲染用deferred的逐像素点渲染吧?这时候就会自动调整到适合光源的vertex path路径下渲染。。 而vertex顶点渲染硬件开销小..废话么,都不是每个像素点运算的,只是顶点插值出来的均值,所以游戏中主要光源应该用pixel逐像素点刻画,而次要光源(啥叫次要,比如太阳下的小星星,你就自己琢磨吧)就可直接设置成vertex模式的,强制材质物体在使用该光源时使用vertex path渲染来减少运算开销,增加帧率!有舍必有得嘛。

物体材质+光源+视摄像机的关系全部说完,接下来是正文..序言很长,但必须理清!如果不理解可看完正文回头来看这段解释,深度理解三者关系,才能在写代码时心中有丘壑。

VertexLit渲染路径

顶点照明就是通过计算顶点颜色和光照插值放入fragment shader中进行渲染,因为是线性插值,不涉及每个像素点的编程,所以vertex lit是最基础的渲染模式(路径)。广泛适用于硬件设施有限,或者性能低下的设备,比如手机…

在unity的shader lab编程环境中,目前已经知道的存取光源的变量有如下几个。

(1)float4 _WorldSpaceLightPos0矢量,和它相对应的是一个 float4 _LightColor0。这是一个世界坐标中的光源的位置或者光照射方向矢量。取决于变量最后一个参数例如: _WorldSpaceLightPos0.w

如果w值为0则说明向量是光照方向(平行光),否则为世界坐标系下的灯光位置,球形点光源(w为光照距离?)

<\version=1.1>测试结果:该光源信息变量在shader pass 中LightMode = Vertex并且camera渲染模式是vertexlit时不起作用,虽然拿得到数据,不过是无效的上次光照遗留数据!camera渲染模式是Forward,Deferred模式时正常工作 <\version=1.1>

(2)float4 unity_4LightPosX0, float4 unity_4LightPosY0, float4 unity_4LightPosZ0,根据UnityCG.cginc中的说明,这三个4元变量代表4个光源的x,y,z的坐标(结构组织为下)

float4 float4 float4

4元素 4元素 4元素

x y z x y z x y z x y z

和它对应的是float4 unity_4LightAtten0,表示的是4个光源的衰减,float4 unity_LightColor[4]是对应光源的颜色。

<\version=1.1>测试结果:该光源信息变量在shader pass 中LightMode = Vertex并且camera渲染模式是vertexlit时不起作用,虽然拿得到数据,不过是无效的上次光照遗留数据!camera渲染模式是Forward,Deferred模式时正常工作 <\version=1.1>

(3)float4 unity_LightPosition[4],表示4个点光源的光源位置或者平行光的方向矢量。如果unity_LightPosition[index].w为0,则表明这是个平行光。和它对应的是float4 unity_LightColor[4],存储了光源的颜色; float4 unity_LightAtten[4],存储了光源的衰减

<\version=1.1>测试结果:该光源信息变量在shader pass 中LightMode = Vertex时任意camera渲染模式,VertexLit,ForWard,Deferred都会及时跟新这个光源信息变量,并且平行光在该变量内存中靠前,比点光源优先处理,意思就是平行光比点光源要重要!) <\version=1.1>

<\version=1.1>上述情况都是shader pass 中LightMode = Vertex并且,光源的光照特性也为Vertex(光源一共有两个选项,一个是顶点,一个是像素Pixel),如果修改光照特性为Pixel,上述情况不变,因为Pixel是Vertex的高级版本光源,向下兼容vertex光照的特性 <\version=1.1>

注意上述的变量都是unity3d shader lab的内置环境变量,全局都可获取!不用申明

例如

Shader "Lighting/VertexLit/Lab1/unity_4LightPosX0.x0"{
Properties{
_Color ("Base Color",Color)=(1,1,1,1)   //这里没有分号;是因为这是给Unity解析用的就像xml解析一样?unity自动帮你设置变量和界面。
}
SubShader{
Pass{ //整个感觉就像xml一样....直到真正的cg语言代码处
Tags{ "LightMode"="Vertex" }
CGPROGRAM   //声明开始cg代码
#progma vertex vert  //指定vertex shader入口函数(main)为vert
#progma fragment frag //指定fragment shader入口函数(main)为frag
#include "UnityCG.cginc" //包含unity环境文件,内置函数,变量等,与unity外部程序交互
#include "Lighting.cginc" //包含灯光环境文件,获取程序内放置的光源和光源相关函数等
uniform float4 _Color;
struct vertOut{
float4 pos:SV_POSITION; //定义vertex shader输出变量 :POSITION一样,如果不懂请   学完cg语言在反过来看此文,概念不清就如雾里探花。
float4 color:COLOR; //cg语言定义vertex shader输出变量如上
}
vertOut vert(appdata_base v) //跟一般cg语言不同的是 我们这里用appdata_base来代替通常使用的 in float4 vertexIn:POSITION或者 float4 texCord1:TEXCORD0等外部输入变量
{
vertOut o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
o.color = unity_4LightPosX0[0];
return o; //vertex shader的main函数返回 (cg语言的语义绑定,return也好,显示声明out也好都是表示输出)
}
float4 frag(verOut i):COLOR //语义绑定可放在函数后面表输出类型反馈
{
return i.color;
}
ENDCG  //声明结束cg代码
}
}
}


上述代码中 o.color = unity_4LightPosX0[0]; 语句中unity_4LightPosX0[0]是环境变量,这就是为什么我们要#include “UnityCG.cginc”这样环境中就包含了unity内置的变量了

<\version=1.1> 后续对文章的修改 2015/7/8
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: