我的ShaderLab学习

1, 一个shader 至少要有一个subshader 或者fallback, 一个subshader 至少要有一个pass,  一个subshader 可以有多个pass

2, FallBack Off 表示如果没有支持的subShader 就不管了

3, Cull 表示剔除, 

4, 声明了  sampler2D _MainTex.  且要用到TRANSFORM_TEX() 函数 就必须声明 float4 _MainTex_ST,   这个代表的就是下图中的这个纹理的变化

5, 偏远着色器中如果只是返回half4 的话, 方法需要声明如下  half4 frag(v2f data):SV_Target{} 奇怪,后面的SV_Target 的意思就是标明这个返回值是一个颜色值,  所以似乎也可以用Color 代替          #pragma 和#include  语句最后不带分号

6, 如果是透明材质的话,  似乎必须要加上混合设置,  Blend  之类的,  alpha混合的计算方式是,      srcColor * k+ (1-k)*destColor     srcColor 指的是当前需要被绘制的颜色, destColor 指的是当前帧缓冲内已经存在的颜色

7, TRANSFORM_TEX(textcoord, _maintex) 这个的意义是, 在材质面板可以设置这个, 对会uv 进行一些变换, 所以需要加上这个方法, 不然的话,其实这个uv是可以直接用的

8, UnityObjectToClipPos 方法是将物体模型本地空间的位置, 转换成  经过MVP 变换之后的位置, M 的意思是本地坐标转换成世界坐标, V 是世界坐标转换成观察坐标, P 是将观察坐标转换成  投影坐标

9,tex2D 这个的意思就是, 从纹理中提取位于uv坐标的像素, 

10, mul 函数的意思就是对矩阵进行乘法

11, vert 函数中传入的顶点的normal 变量的值是(x,y,z)(x,y,z的取值在  -1 到1) 之间, 如果需要转换成颜色的话, 就需要  normal*0.5+0.5  这个返回

12, _Time.x 可以获取到当前时间, 所以可以利用这个来做shader 的动画

13, Tiling 的意思就是缩小这张贴图, 然后配合贴图的repeat 属性, 将贴图铺满到模型上。 例如铺瓷砖,地面等等

14, DecodeLightmap()  函数是用于将外部的LightMap  跟本身进行叠加的函数, 效果就是类似于, LightMap 烘培, 具体请看  UnityCG.cginc

15, unity  shaderlab 有三种编写形式,   1, surface shader,  2 vertex shader and  fragment shader  3, fixed function shader

16, pass 通道里面 fixed  function shader    直接写一个color(1,0,0,1)     就是固定了红色  如果是 -一个在properties 中赋值的变量例如, _Color("main color", color)=(1,1,1,1)    然后使用的时候可以直接 color[_color]  注意这里是中括号了, 

17, diffuse  自身的反射光, 意思其实就是自身本身的颜色, ambient  指的是环境光, 例如周围放很多个红色的灯泡, 那么可以认为环境光是红色, specular  高光, 可以认为是照射光, Shininess   可以认为是照射光的强度, Emission 的意思是自发光

18, fixed function shader 其实就是, 提供了固定的一些函数, 可以共开发者调用, 自己不能实现任何计算, 唯一能做的就是开启某些函数, 然后传递某些参数就好了,   一些内置的函数如下,   Unity表示, 这些内置的函数时可以运行在几乎所有显卡上的, 

Diffuse[_color]  表示自身颜色, Ambient[_color] 表示的是环境光的颜色, Specular [_color] 表示的是高光的颜色, 其实可以认为就是照射光, Shininess[_value]  表示的是高光照射的强度, Emission[_color] 表示的是自发光的颜色,  光照需要配置  Lighting on 指令,   Specular 需要配合 SeparateSpecular on 指令,, SetTexture[_maintex]{combine texture * primary double} 这个是给材质设置纹理,  在原像素的基础上乘以uv 对应的像素,   然后乘以2,   primary 表示的是处理了顶点光照后的效果,   previous  表示的当当前的像素,  例如应用了两个纹理,  在第二个纹理 调用  combine texture  * previous  表示的是当前UV 对应的像素  乘以之前的所有操作之后的像素,, 这种settexture  调用的数量是有限的, 但是最少也可以2张。 Combine texture*primary,  texture  逗号后面的第二个参数表示的是最终应用的alpha值, 这里的意思就是, 最终的alpha值直接取 纹理的alpha值,, constantColor[_color]  然后最后用的时候就用constant 就好了

19,每个像素的灰度值  可以用以下方式计算Gray=R*0.3+G*0.59+B*0.11

20, 方阵的行可以被解释为坐标轴的基向量例如

21, 矩阵M的标准伴随矩阵adj M定义为,M 的代数余子式矩阵的转置矩阵,    矩阵的逆矩阵等于 矩阵的矩阵的标准伴随矩阵  除以矩阵的行列式

22, 正交矩阵的定义就是矩阵的逆等于矩阵的转置,

23 , 矩阵的行列式其实就是为了计算, 矩阵的行或者列是否存在某一行或者某一列可以完全被其他剩下的行或者列表示, 如果可以的话, 那么表示这一行或者列其实是没有意义的, 那么此方程组表示的解将会是无数个

24,一个矩阵是正交矩阵的条件是, 这个矩阵的每一行互相垂直, 且, 每一行向量的模都是1

25, surface shader  表示对一张纹理的uv信息命名必须是uv 开头,且后面跟纹理名字一致, 如纹理名称是_mainTex 那么总的命名就是uv_mainTex

26, half  数据类型就是占2个字节长度的浮点数, 相当于半个float

27, cg语言中的in  代表只输入, out 只输出, inout 既输入又返回,实际意思是如果只是out的话, 表示接收的参数就是实际的参数, 但是必须被重新赋值,  inout的话, 就可以直接修改属性, 或者重新赋值都OK , 都会改变传入的参数。  至于in, 似乎写与不写没有区别

28, Unity 有一点比较奇怪的是, 当相机没有任何操作, 完全跟世界坐标系一致的时候, 从世界坐标转为相机坐标的矩阵竟然会对Z取反.  难道是因为相机坐标系是右手坐标系跟Unity的世界坐标系相反? 网上在解释openGL 的相机投影矩阵的时候, 倒是有这样说的, 

29, unity 标准的相机投影矩阵是,

[

1/tan(fov/2)*aspect,0,0,0,

0, 1/tan(fov/2),0,0,

0,0, -(f+n)/(f-n), -2fn/(f-n),0,

0,0,-1,0

]

30,  之所以会就是因为28, 所以  当z等于-near 的时候, 会得到-1, -far的时候得到1,    apsect 默认的时候就是屏幕的比例

31, 单个光源的光照公式是   color= Cspec+ Cdiff+Cambi   其中spec 表示高光, diff 表示漫反射, ambi  表示环境光

32, 多个光源的光照公式是,color= 光照1+光照2+。。。。。一直累加就好了

33,Phong模型 镜面反射公式, Cspec= Math.pow(math.max((R*v),0),  镜面反射指数    )*k*   光源颜色,        R是反射向量, V 是视角向量, 都是从模型上的点为起点,    blinnPhong模型镜面反射公式  Cspec= Math.pow(math.max(H*n,0),镜面反射指数)*k*光源颜色。   镜面反射指数控制的是, 光圈的大小, k控制的是光圈的强度。  H,n 一个是表面的法向量, 一个是入射向量(指向光源)和视角向量的中间向量

34, 环境光公式 Camb=  环境光颜色*本身颜色

35, 漫反射公式 Cdiff=  math.max(N*I, 0)*光源颜色* 本身颜色

36, 雾的公式, 可以直接用计算光照后的物体表面颜色, 到  雾的颜色的根据距离计算的线性插值,  距离可以使用球形或者直接用基于摄像机坐标系的Z坐标都可以,   然后当距离小于某个数值的时候系数是0, 也就是忽略雾的效果, 当距离大于某个值的时候系数是1, 也就是完全雾化, 公式如下   Cfog= Clit +f(  fog- Clit)  f 就是距离系数, fog表示雾的颜色, clit 表示物体原本颜色, Cfog表示雾化后的颜色

37, 双缓存技术, 就是使用两个帧缓存,因为游戏可以在任何时候获取当前要显示的图像, 为了避免在本帧图像还没有没设置完成的时候就被展示, 所以可以是使用两个帧缓存, 显示器任何时候获取到的都是已经设置完毕的那个帧缓存, 然后每次写入的都是另一个帧缓存, 当写入完成之后, 就会切换,

38, fixed 是定点数, 用于表示颜色的时候已经完全足够

39, cg语言中, array 也是值类型的  例如 

float arr[2]={1,1};
      float arr3[2]=arr;
      arr3[0]=0;  最后也会发现arr3[0]=0, 而arr[0]=1

40, cg profile 的意思是, cg的一个功能子集, 意思其实就是对于某些设备,某些环境下, 兵不会完全支持CG的所有功能, 而是只支持其中的一部分

41, cg中的基本数据类型, 就是, float, half, fixed, int, bool, sampler*

42, #define 宏似乎就是完全替换   例如        #define MYDEFINE   col=float4(pos.xy,0,1);    那么使用MYDEFINE 编译就是完全替换成   col=float4(pos.xy,0,1); 

43, float2x4 表示的是一个2行4列的矩阵, 如果需要获取第一行就是  例如 float2x4 mat={1,0,0,1,0,0,1,1};,   float4 color = mat[0] 0 就表示第一行 获取的也就是1,0,0,1  这个

44, 创建数组,  float arr[5]={1,1,1,1,1}   这样的写法, 不可以把数组直接赋值给向量

45, switch case 是不被支持的, 即使不报错, 功能也不正常, if  else 是支持的

46, for循环, do while 和while 循环都是支持的, 写法也是一样的 但是一个循环迭代的次数只能小于1024次, 也就是最多1023次,  但是可以写两个循环, 哈哈哈, 每个1023次是可以的

47, Unity  对变化的执行顺序是先缩放, 然后按照Z,X,Y 轴顺序旋转(从物体本地坐标系变化到世界坐标系的旋转执行顺序), 然后才是平移。。  所以最终的变化矩阵是

M平移*My旋转*Mx旋转*Mz旋转*M缩放   这个是从本地坐标转世界坐标的变换矩阵

48, Unity中对矩阵和向量的乘法是, 向量采用了列向量操作。。   直接使用Matrix4x4  * 一个向量就好了。。。验证似乎发现, unity   transform.localtoworldmatrix  是没有包含平移的

49, 计算变换矩阵, 的方法可以是, 计算本地坐标系的一个点变换到世界坐标系之后的点的矩阵, 或者是计算本地坐标系的三个轴变换到世界坐标系的三个轴的变化矩阵, 结果一样

50, 一个使用in  修饰的没有被赋值过的float4  默认是1,1,1,1;

51,shaderlab中也有uniform变量跟openGL 一样, 是由外部进行赋值的, 一般是代码中, 

51, shaderlab中默认的矩阵乘向量是使用 列向量, 所以使用mul的时候 是矩阵在前, 向量在后

52, _WorldSpaceLightPos0 这个内置变量表示的就是当前顶点程序中的顶点指向灯光的向量,  以顶点为起点

53, _LightColor0表示的就是灯光的颜色

54, CG reflect(I,N)  用于求反射向量, 要注意的是这里的I 不是从顶点指向入射光, 而直接就是入射光的方向

55, 从顶点程序不可以直接传 normal语义, 但是直接改成任何一个支持float3 的向量的语义就好了,例如Color,哈哈

56, 处理点光源, 需要设置Tag{“LightMode”=“ForwardAdd”}

57, 默认情况下, 点光源只有在延迟渲染下才可以投射阴影, 但是在5.x之后, 即使在前照渲染下也可以了, 前提是给需要接收阴影的平面使用standard  材质

58, 给材质加上一个通道,。  设置  tags{“LightMode”=“ShadowCaster”} 这个物体就可以被光源照射产生阴影了, 然后可以在例如地面上展示, 这种设置会对方向光和点光源都生效, 在老版本上可能会只对方向光有效, 要注意要生成阴影, 光源必须也要设置可以投射阴影的, 所以有三个条件, 一个光源, 一个产生阴影的物体, 一个接收阴影的物体

59, 要想接收阴影,  首先 v2f 中声明 LIGHTING_COORDS(0,1),然后在顶点程序中 调用TRANSFER_VERTEX_TO_FRAGMENT(v)  然后在片段程序中  计算float atten = LIGHT_ATTENUATION(o)  将atten  乘以Color 的rgb 分量, 然后返回就好了, 还要加入一个预编译指令,    #pragma multi_compile_fwdbase,   引入autolight.cginc 就好了

60, 每次pass 都会计算出一个颜色值, 所以如果有多个通道的话, 需要设置  blend,  表示后面计算出来的颜色跟前面颜色缓冲区的颜色如何叠加

61, 如果要计算方向光的阴影, 那应该是在forwardbase 的lightmode的模式下,    计算点光源, 就在forwardadd  的lightmode下

62,如果一个变量被设置为color语义的话, 那么分量都会被限制为0到1

63,光照贴图默认的名字叫做unity_Lightmap

64, shader 中加入对lightmap的支持的方式如下:

首先vert(appdata_full v)  这个要使用appdata_full  然后texcoord1 就是这个物体在lightmap中的UV,     然后在fragment中得到光照贴图的像素,  tex2d(unity_Lightmap,  光照贴图uv)    得到一个像素值color. 然后调用decodeLightmap(color) 返回一个rgb   然后对其他处理得到的颜色值的rgb  *  这个光照得到最后得到的rgb就好了

65  colormask属性可以让开发人员指定输出通道, 例如R, G,B,A 或者0,  0 的话表示不输出到任何通道,  也就不会擦除原先帧缓存中的像素信息,    但是会输入深度, 所以可以用于做镂空效果

66, 做模糊处理可以使用ddx和ddy函数.  但是要求在target 3.0平台上

67, 帧深度缓存的默认值就是1, 所以如果是ztest greater的话 在没有任何物体阻挡他的时候, 就是不展示的

68, cube3维纹理采样. 就不是用2d坐标UV 进行采样了 而是利用反射向量

64, camera.rendertocubemap,    将相机拍到的时间渲染进cubemap

65  cg中的矩阵是, 按照一行一行填充的, 所以1,2,3,4,5,6,7,8,9  直接按顺序填充进去的话就成了

[1,2,3,

4,5,6,

7,8,9]

66, 如果要给某个物体的材质切换什么颜色啥的, 最好使用 MaterialPropertyBlock  , 而不是直接material  设置。   性能会好很多

67, frame debugger 可以调试当前场景的渲染信息

68, openGL和DirectX  的屏幕坐标系是不一样的, OpenGL原点是左下角,  DirectX原点 是左上角

69, 切空间, 是由顶点在模型空间的法线, 切线以及由法线和切线的 叉乘确定的新的坐标空间,  一般法线贴图会采用这个空间来存储,, 切线对应x, 法线对应z, 

70, clip(float4)  函数,   传入的浮点向量中只要一个分量<0 这个片段就会被丢弃

71, 使用texCube函数  对立方体纹理进行采样, 

72, 菲涅尔近似等式, 用于渲染折射现象  菲涅尔系数=  F+ (1-F)*(1- v.n)的5次方,  v是视角方向, n是法向,。F 是一个系数  这个用于计算  lerp(diffuse, reflection, 菲涅尔系数)

73, renderTexture  可以拿来做镜子的效果

74, OnRenderImage(RenderTexture src, RenderTexture dest)  用于做屏幕后期处理,  一般是通过  Graphics.Blit(Texture src, RenderTexture dest, Material mat, int pass=-1)  进行采样处理,  src 纹理会被传递给Shader  中名为_MainTex  的纹理属性,   pass =-1 则会依次调用shader 中的所有pass, 否则  只调用给定索引的pass。 默认情况下, OnRenderImage 会在不透明物体和透明物体都被渲染之后执行, 但是如果我们只想对不透明物体产生影响的话, 那么可以通过ImageEffectOpaque 这个属性进行控制, 屏幕后期处理的原理就是在绘制好之后, 创建一个四边形面片,  然后对四边形面片应用我们创建的后期处理的shader, 然后将绘制好的图片传入给_MainTex 参数, 进行处理。 

75, 卷积操作其实就是对每一个像素, 都取他周围指定数量的像素一起, 然后对每一个不同位置的像素, 进行不同的权重处理, 得到一个新的像素值, 

76, camera.depthTextureMode 是设置相机在渲染的时候保存的深度贴图是怎么样的, 可以是纯深度贴图,也可以是深度加法线的贴图,  这个东西一般用于做后期处理的时候, 获取屏幕上 每个像素的深度和法线信息

77, DecodeDepthNormal  对深度法线贴图的某个位置, 解码获取对应的深度和法线

78, 不透明物体的绘制顺序是从前往后所有overdraw比较少, 而透明物体为了保证渲染效果是从后往前渲染, 所以overdraw 会多一些

79, 低精度的浮点数计算速度会更快, 尽可能不要在不同精度的浮点数之间转换

80, 如果一个材质有多通道,那么是对一个模型的每一个顶点都应用某一个通道渲染完之后, 再对模型的每一个顶点应用第二个通道

81, 模板缓冲发生在alpha测试之后, 深度测试之前,    模板缓冲区可以为每一个像素设置一个模板值, 然后将每一个待渲染的像素的模板值跟缓冲区的模板值, 进行指定的函数操作, 如果测试通过, 或者不通过之后, 再执行某一些操作。 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值