Shader 爱被打了一巴掌 2022-02-21 08:07 342阅读 0赞 ## 初始shader ## **Shader概述** * Shader(着色器)是给GPU执行的程序。 * Shader是运行在图形处理单元上,可以让开发人员直接操作图形硬件渲染功能。 * Shader能开发出很多好的效果:UV动画,水,雾等一些特效。(这些用程序开发出来比较困难,性能不好) * 渲染流水线,模型投影,定点着色器; * Shader主要有: 1. 固定管线着色器(慢慢会被淘汰掉) 2. 顶点Shader:干预模型形态的shader; 3. 像素shader:干预像素着色的shader; * 模型定点运算的时候,可以加入顶点shader来干预顶点的位置;顶点着色的时候,加入像素shader来干预像素上色。 **Shader Lab语法基础** 定义一个Shader,每一个着色程序都要有一个Shader Shader "name"\{// name Shader名称 //定义的一些属性,定义在这里的都会在属性查看器里面显示; \[Propeties\] //子着色器列表,一个Shader必须至少有一个子着色器; SubShaders:\{......\} //如果子着色器显卡不支持,就会降级,即Fallback操作; \[FallBack\] \} * **Properties****定义** 1:name(“display name”, type) = 值; name指的是属性的名字,Unity中用下划线开始\_Name; display name是在属性检查器的名字; type: 这个属性的类型 值: 只这个属性的默认值; 2: 类型: Float, Int, Color(num, num, num, num)(0 ~ 1) Vector(4维向量), Range(start, end) 2D: 2D纹理属性; Rect: 矩形纹理属性; Cube: 立方体纹理属性; 3D: 3D纹理属性; name(“displayname”, 2D) = “name” \{options\} 3: Options: 纹理属性选项 TexGen:纹理生成模式,纹理自动生成纹理坐标的模式;顶点shader将会忽略这个选项; ObjectLinear, EyeLinear, SphereMap, CubeReflect CubeNormal LightmapMod: 光照贴图模式如果设置这个选项,纹理会被渲染器的光线贴图所影响。 1: \_Range (“range value”, Range(0, 1)) = 0.3; // 定义一个范围 2: \_Color(“color”, Color) = (1, 1, 1, 1); // 定义一个颜色 3: \_FloatValue(“float value”, Float) = 1 // 定义一个浮点 4: \_MainTex (“Albedo”, Cube) = “skybox” \{ TexGen CubeReflect\} // 定义一个立方贴图纹理属性; * **SubShader** 1: SubShader \{\[Tags\], \[CommonState\], Pass \{\} \} 子着色器由 标签(Tags),通用状态,通道列表组成,它定义了一个渲染通道列表,并可选为所有通道初始化需要的通用状态; 2: SubShader渲染的时候,将优先渲染一个被每个通道所定义的对象。 3: 通道的类型: RegularPass, UsePass, GrabPass, 4: 在通道中定义状态同时对整个子着色器可见,那么所有的通道可以共享状态; SubShader { Tags {“Queue”, “Transparent” } Pass { Lighting Off // 关闭光照 .... } } * **Tags** 1: Tags \{“标签1” = “value1” “key2” = “value2”\} 2: 标签的类型: Queue tag 队列标签; RenderType tag 渲染类型标签; DisableBatching tag 禁用批处理标签; ForceNoShadowCasting Tag 强制不投阴影标签; IgnoreProjecttor 忽略投影标签; CanUseSpriteAtlas Tag,使用精灵图集标签; PreviewType Tag预览类型标签; * **Pass** 1: subshader 包装了一个渲染方案,这些方案由一个个通道(Pass)来执行的,SubShader可以包括很多通道块,每个Pass都能使几何体渲染一次; 2: Pass基本语法: Pass \{ \[Name and Tags\] \[RenderSetup\] \[Texture Setup\]\} Pass块的Name引用此Pass,可以在其它着色器的Pass块中引用它,减少重复操作,Name命令必须打大写; * **RegularPass** **渲染设置** 1: Lighting 光照: 开启关闭定点光照 On/Off 2: Material\{ 材质块\}: 材质,定义一个使用定点光照管线的材质; 3:ColorMaterial: 颜色集 计算定点光照的时使用顶点颜色; 4: SeparateSpecular: 开光状态 开启或关闭顶点光照相关的镜面高光颜色,On/Off; 5: Color 设置定点光照关闭时的所使用的颜色; 6: Fog\{ 雾块\}: 设置雾参数; 7: AlphaTest: Alpha测试 8: ZTest: 深度测试模式; 9: ZWrite: 深度写模式; 10: Blend: 混合模式 SourceBlendMode, DestBlendMode, AlphaSourcesBlendMode, AlphaDstBlendMode; 11: ColorMask 颜色遮罩: 设置颜色遮罩,颜色值可以由RGB或A或0或R,G,B,A的组合,设置为0关闭所有颜色通道渲染; 12: Offset偏移因子: 设置深度偏移; * **特殊通道****Pass** 1: UsePass: 插入所有来自其它着色器的给定名字的通道; UsePass ”Shader/Nmae”, Name为着色器通道; UsePass “Specular/BASE” // 插入Specular中为Bass的通道; 2: GrabPass \{\}: 一种特殊通道类型,他会捕获物体所在的位置的屏幕的内容,并写入一个纹理中,这个纹理能被用于后续通道中完成一些高级图像特效,后续通道可以使用 \_GrabTexture进行访问; 3: GrabPass\{“纹理名称”\} 捕获屏幕内容到指定纹理中,后续通道可以通过纹理名称来访问; * **Fallback** 1:降级: 定义在所有子着色器之后,如果没有任何子着色器能运行,则尝试降级; 2: Fallback “着色器名称”; 3: Fallback Off; 没有降级,并且不会打印任何警告; * **Category****分类** 1:分类是渲染命令的逻辑组。例如着色器可以有多个子着色器,他们都需要关闭雾效果,和混合 Shader “xxxx” { Categroy { Fog { Mode Off } SubShader {...} SubShader {...} } } ## 顶点片元shader ## * **空间坐标** 1. 物体空间: 3D物体自己的坐标空间一般设计时几何体以中心为原点,人物以双脚为原点; 2. 世界空间: 3D物体在场景中的世界坐标, 整个游戏场景的空间; 3. 摄像机空间: 以观察摄像机为原点的坐标系下的坐标空间; 4. 投影成像 3D坐标转换到屏幕空间; * **Unity坐标系转换** 1. transform.localToWorldMatrix 局部转世界的矩阵; 2. transfrom.worldToLocalMatrix 世界坐标转局部坐标矩阵; 3. MultiplyPoint, MultiplyPoint3x4 MultiplayVector 来进行坐标变换; 4. shader中 左乘unity\_World2Object矩阵来实现世界坐标转局部坐标变换; 5. shader中左乘unity\_Object2World矩阵来实现局部转世界的转换; 6. UNITY\_MATRIX\_MV 基本变换矩阵 x 摄像机矩阵; 7. UNITY\_MATRIX\_MVP 基本变换矩阵x摄像机矩阵x投影矩阵; 8. UNITY\_MATRIX\_V 摄像机矩阵; 9. UNITY\_MATRIX\_P 投影矩阵; 10. UNITY\_MATRIX\_VP摄像机矩阵x投影矩阵; 11. UNITY\_MATRIX\_T\_MV (基本变换矩阵 x 摄像机矩阵) 转置矩阵; 12. UNITY\_MATRIX\_IT\_MV(基本变换矩阵 x 摄像机矩阵) 的逆转置矩阵; 13. UNITY\_MATRIX\_TEXTURE0 纹理变化矩阵; ## GPU管道流水线 ## 1: 主要的运算在GPU上计算,CPU插入指令; 2: 大致流程: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTMxNjgyNA_size_16_color_FFFFFF_t_70][] * **顶点片元着色器** 1. 控制灵活,但不能参与光照计算; 2. 在着色器中插入Cg代码段,编写在CGPROGRAM 与 ENDCG之间; 3. 编译指令: (a) \#pragma控制 着色器代码编译; (b) \#pragma vertex name 将名称为name的函数编译为顶点着色器; (c) \#pragma fragment name 将名称为name的函数编译为片元着色器; 4. 参数和返回值有语义修饰 * **常用语义修饰** 1. **POSITION** : 位置 2. **TANGENT** : 切线 3. **NORMAL**: 法线 4. **TEXCOORD0**: 第一套纹理 5. **TEXCOORD1**: 第二套纹理 6. **TEXCOORD2**: 第三套纹理 7. **TEXCOORD3**: 第四套纹理 8. **COLOR**: 颜色 ## **Cg****基本语法** ## * **基本类型表达式** 1. 语法和C语言类是,有对应的编译器,程序是给显卡运行; 2. 可以从渲染流水线中获得对应的输入; 3. 指定的输出能流入下一个流水线模块; 4. 操作符号和C语言一样,可以使用 \+, -, \* / <, >, <=, >= 等运算; 5. Cg提供了float half double 浮点类型; 6. Cg 支持定点数 fixed来高效处理 某些小数; 7. Cg使用int来表示整数; 8. bool 数据类型来表示逻辑类型; 9. sampler\*,纹理对象的句柄, sampler/1D/2D/3D/CUBE/RECT 10. 内置向量数据类型: float4(float, float, float, float), 向量长度不能超过4; 11. 内置矩阵数据类型: float1x1 float2x3 float4x3 float4x4;不能超过4x4; 12. 数组类型float a\[10\]; 10个float, float4 b\[10\], 10个float4; 13. 语义绑定 float4 a : POSITION,返回值也可以语义绑定; * **结构体与语义** struct name { 类型 名字; // 尽量不要使用; 返回值 函数名称(参数) { // 如果成员函数里面使用,数据成员,该成员定义在函数前; } }; 如 struct v2f{ float2 uv : TEXCOORD0; float4 vertex : POSITION; }; **输入语义与输出语义:** 语义:一个阶段处理数据,然后传输给下一个阶段,那么每个阶段之间的接口; 例如:顶点处理器的输入数据是处于模型空间的顶点数据(位置,法向量),输出的是投影坐标和光照颜色;片段处理器要将 光照颜色做为输入;c/c++用指针,而cg通过语义绑定的形式; 输入语义: 绑定接收参数,从上一个流水线获得参数; 输出语义: 绑定输出参数到下一个流水线模块; 语义: 入口函数上有意义(顶点着色入口,像素着色入口),普通的函数无意义; **标准内置函数** 1:abs(num)绝对值; 2: 三角函数; 3: cross(a, b) 两个向量的叉积; 4: determinant(M)矩阵的行列式; 5: dot(a, b) 两个向量的点积; 6: floor(x)向下取整; 7: lerp(a, b, f), 在a, b之间线性插值; 8: log2(x) 基于2为底的x的对数; 9: mul(m, n): 矩阵x矩阵, 矩阵x向量, 向量x矩阵; 10: power(x, y) x的y次方; 11: radians(x) 度转弧度; 12: reflect(v, n) v 关于法线n的反射向量; 13: round(x) 靠近取整; 14: tex2D(smapler, x) 二维纹理查找 15: tex3Dproj(smapler, x) 投影三维纹理查找; 16: texCUBE 立方体贴图纹理查找; **Unity****自带函数** 1: 引用Unity自带的函数库: \#include “UnityCG.cginc” Unity-->Edit-->Data-->CGIncludes; 2: TRANSFORM\_TEX: 根据顶点的纹理坐标,计算出对应的纹理的真正的UV坐标; 3: 使用属性的变量: 在shader里面需要使用属性变量还需要在shader中定义一下这个变量的类型和名字; 名字要保持一致; 4: 外部修改shader的编辑器上的参数值; **float4 fixed4 \_Time** 1: float4是内置向量 (x, y, z, w); float4 a; 访问单独成员a.x, a.y, a.z, a.w; 2: fixed4 是内置向量(r, g, b, a); fixed4 c; color.r, color.g, color.b, color.a; 3: float3是内置向量(x, y, z); 4: fixed3 是内置向量(r, g, b); 5: float2 是内置向量(x, y); 6: \_Time: 自场景加载开始所经过的时间t,4个分量分别是 (t/20, t, t\*2, t\*3); 7: \_SinTime: t 是时间的正弦值,4个分量分别是 (t/8, t/4, t/2, t); 8: \_CosTime: t 是时间的余弦值,4个分量分别是 (t/8, t/4, t/2, t); 9: unity\_DeltaTime: dt 是时间增量,4个分量的值(dt, 1/dt, smoothDt, 1/smoothDt),平滑时间,防止时间间隔起伏太大; [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTMxNjgyNA_size_16_color_FFFFFF_t_70]: /images/20220221/a6b7b3af24d14ad2834247f1decdefb8.png
还没有评论,来说两句吧...