Shader杂记

1.凹凸映射和纹理映射有什么不同?

  ”它们的不同之处在于——凹凸映射是一种负责光方向的纹理映射。

2.Shader的基本结构:

【【补充 *******************************************************************************
Shader
这是shader的根命令
SubShader
这个是子着色器,一个Shader里面可以有多个SubShader
Properties
属性块
常用属性
语法	说明
name(“display name”,Range(min,max)=number)	定义一个范围值
name(“display name”,Color=(number,number,number,number)	定义颜色,number取0~1
name(“display name”,2D)=”name”{option}	定义2D纹理,缺省值:”white”,”black”,”gray”,”bump”
name(“display name”,Rect)=”name”{option}	定义矩形纹理(非2的n次幂),缺省值为2D纹理属性
name(“display name”,Cube)=”name”{option}	定义立方体纹理,缺省值同位2D纹理
name(“display name”,Float)=number	定义一个浮点数
name(“display name”,Vector)=(number,number,number,number)	定义四维向量
纹理属性选项(即2D等属性的{option})
选项名称	说明
TexGen	自动生成纹理坐标时的模式,可以为:ObjectLiner、EyeLinear、SphereMap、CubeMap、CubeNormal
LightmapMode	光照贴图模式,如果给出这个选项,纹理会被渲染器的光线贴图所影响,即纹理不能被应用在材质中,而是使用渲染器中的设定
Tags
Queue 队列标签
Tags {“Queue”=”Transparent”}

队列名称	说明
Background	后台,这个渲染队列在所有渲染队列之前渲染,被用于天空盒之类的对象(1000)
Geometry	几何体,这个是默认队列,被用于大多数对象,不透明的几何体使用这个队列(2000)
Transparent	透明,在几何体队列之后渲染,采用由后到前的次序,任何采用alpha混合的对象(不对深度缓冲产生写操作的着色器)应该在这里渲染(如玻璃,粒子等)(3000)
Overlay	覆盖,这个渲染队列用于实现叠加效果,任何需要最后渲染的对象应该放置在此处(如镜头光晕)(4000)
IgnoreProjector 忽略投影标签
Pass
每个通道都能使几何体被渲染一次,一个Subshader里面可以有多个Pass
两个特殊通道

通道名称	语法	说明
UsePass	UsePass “Shader/Name”	插入所有来自给定着色器中的给定名字的通道,Shader为着色器的名字,Name是通道的名字
GrabPass	GrabPass{[“纹理名”]}	捕获屏幕到一个纹理,该纹理通常使用在靠后的通道中,”纹理名”是可选的
UsePass例子:
UsePass “Specular/BASE”
Name “MyPassName”
使用Specular/BASE这个Pass,并在当前shader中重命名为MyPassName使用
所有通道名字都是大写开头,因此UsePass必须使用大写开头的名字来书写索引

GrabPass捕获当前屏幕内容到一个纹理中,纹理能在后续通道中通过_GrabTexture进行访问

通道渲染设置命令

命令	说明
Material{材质块}	定义一个使用顶点光照管线的材质
Lighting 开关状态	开启或关闭顶点光照。开关状态值为On或Off
Cull 裁剪模式	设置裁剪模式,裁剪模式有Back、Front、Off
ZTest 测试模式	设置深度测试模式。测试模式有Less、Greater、LEqual、GEqual、Equal、NotEqual、Always
ZWrite 开关状态	开启或关闭深度缓冲,开关值为On或Off
Fog{雾块}	设置雾参数
AlphaTest 测试模式< alpha测试值 >	开启alpha测试,测试模式有Less、Greater、LEqual、GEqual、Equal、NotEqual、Always
Blend 混合模式	设置alpha混合模式,混合模式有SourceBlendMode、DestBlendMode
Color <颜色>	设置当顶点光照关闭时使用的颜色
ColorMask 颜色值	设置颜色遮罩,颜色值可以使用RGB或A或0或任何R、G、B、A的组合,设置为0将关闭所有颜色通道的渲染
Offset 偏移因子,偏移单位	设置深度偏移,这个命令仅接受常数参数
SeparateSpecular 开关状态	开启或关闭顶点光照相关的镜面高光颜色。开关状态的值为On或Off
ColorMaterial 颜色集	当计算顶点光照时使用顶点颜色,颜色集可以是AmbientAndDiffuse,也可以是Emission
SetTexture
设置纹理,格式为SetTexture [纹理属性名] {纹理块}
混合
混合是用来制作透明物体的

常用混合只能在RGBA模式下进行,物体的绘制顺序会影响到OpenGL的混合处理

Blend常用语法如下:
Blend Off
关闭混合
Blend 源因子 目标因子
配置并开启混合,计算产生的颜色和源因子相乘,颜色缓冲中的颜色和目标因子相乘,然后两个颜色相加
Blend 源因子 目标因子,源因子A 目标因子A
源因子,目标因子和上面相同,但是源因子A,目标因子A这些因子使用alpha通道进行混合
BlendOp 操作
不是将加入的颜色混合在一起,而是对他们做一些操作,主要操作指令有Min(最小值)、Max(最大值)、Sub(求和)、RevSub
关于混合因子

OpenGL红宝书上的解释为:

源因子:就是当前的贴图,或光照计算后生成的颜色值

目标因子:就是显示器中的帧缓存的图

常用混合因子(对源因子和目标因子都有效)如下:

混合因子	说明
One	值为1,使用此设置来让源或是目标颜色完全地通过
Zero	值为0,使用此设置来删除源或目标值
SrcColor	此阶段的值是乘以源颜色的值
SrcAlpha	此阶段的值是乘以源alpha的值
DstColor	此阶段的值是乘以帧缓冲区目标颜色的值
DstAlpha	此阶段的值是乘以帧缓冲区目标alpha的值
OneMinusSrcColor	此阶段的值是乘以(1-源颜色)
OneMinusSrcAlpha	此阶段的值是乘以(1-源alpha)
OneMinusDstColor	此阶段的值是乘以(1-目标颜色)
OneMinusDstAlpha	此阶段的值是乘以(1-目标alpha)

以下是常见的混合类型:

Blend SrcAlpha OneMinusSrcAlpha //混合
Blend One One //混合相加
Blend One OneMinusDstColor //柔和相加混合
Blend DstColor Zero //相乘混合
Blend DstColor SrcColor //2倍相乘混合
通道标签
通道标签只能在通道(而不是子着色器)中使用

LightMode
光照模式标签,它定义了光照管线中的通道的角色。比较少用,大多数情况下需要和光照进行互动的着色器会被写成表面着色器
常用光照模式标签表如下:

标签	说明
Always	总是渲染,没有光照应用
ForwardBase	环境光,主要的定向光,顶点/SH光被应用
ForwardAdd	附加的逐像素光照被应用。每个光照1个通道
PrepassBase	渲染法线/镜面指数
PrepassFinal	使用纹理,光照和自发光混合出最终的颜色
Vertex	当物体没有光照映射使用顶点光照渲染,所有顶点光照被应用
VertexLMRGBM	当物体有光照映射时使用顶点光照渲染,在平台上光照映射是RGBM编码
VertexLM	当物体有光照映射时使用顶点光照渲染,在平台上光照映射是double-LDR编码(移动平台,以及老师CPU)
ShadowCaster	将物体当做阴影产生者来渲染
ShadowCollector	为了正向渲染路径将对象的阴影收集到屏幕空间缓冲区中

RequireOptions
当某些额外条件满足时,该通道才会被渲染,它的值是SoftVegetation,需要在Quality Settings中开启SoftVegetation才渲染通道
Fallback
降级,如果没有子着色器能使用,将运行降级着色器,用法如下:
Fallback “着色器名” //回归到指定着色器
Fallback Off //不降级,也不会出现任何出错报警,没有子着色器也会继续运行
Category
分类是渲染命令的逻辑组,大多数情况下用于继承渲染状态
#pragma surface 表面函数 光照模式 [可选参数]
表面函数
表明那些CG函数中有表面着色器的代码,这个函数的格式如下:
void surf(Input IN,inout SurfaceOutpur o)

光照模式
在光照模式中使用,内置的光照模式有Lamberr(漫反射)和BlinnPhong(高光)

可选参数
可选参数列表如下:

可选参数	说明
alpha	Alpha混合模式,使用它可以写出用以渲染半透明效果的着色器
alphatest:VariableName	Alpha测试模式,使用它可以写出镂空效果的着色器。楼口大小的变量(VariableName)是一个float型的变量
vertex:VertexFunction	自定义的顶点函数,VertexFunction为函数名
finalcolor:ColorFunction	自定义的最终颜色函数,ColorFunction为函数名
exclude_path:prepass或exclude_path:forward	使用指定的渲染路径,不需要生成通道
addshadow	添加阴影投射并且集合通道,通常用于自定义顶点的修改,使阴影也能投射在任何过程的顶点动画上
dualforward	在正向(forward)渲染路径中使用双重光照贴图(dual lightmap)
fullforwardsshadows	在正向(forward)渲染路径中支持所有阴影类型
decal:add	添加贴花着色器
decal:blend	混合半透明的贴花着色器
softvegetation	使表面着色器仅能在Soft Vegetation打开时进行渲染
noambient	不使用任何环境光照(ambient lighting)或者球面调和光照(spherical harmonics lights)
novertexlights	在正向渲染(Forward rending)中不使用球面调和光照(spherical harmonics lights)或每顶点光照(per-vertex lights)
nolightmap	在这个着色器上禁用光照贴图(lightmap)
nodirlightmap	在这个着色器上禁用方向光照贴图(directional lightmap)
noworwardadd	禁用正向渲染添加通道,这会使这个着色器支持一个完整的方向光和所有逐顶点/SH计算的光照
approxview	当着色器有需要的时候,计算每个顶点,而不是每个像素的方向,这样更快,但是当摄像机接近表面时,视图方向不完全正确
halfasview	在光照函数中传递进来的是half-direction向量,而不是视图方向向量,Half-direction计算且将每个顶点标准化,这样更快,但不完全正确

标准的表面着色器输出结构体如下:
struct SurfaceOutput {
half3 Albedo; //反射光颜色
half3 Normal; //法线
half3 Emission; //自发光,用于增强物体自身的亮度,使之看起来好像可以自己发光
half Specular; //镜面高光
half Gloss; //光泽度
half Alpha; //透明度
};

表面着色器的输入结构体Input包含着所有着色器所需要的纹理坐标和附加值
纹理坐标必须在纹理名称前面加上”uv”,或者以”uv2”作为头命名来使用第二个纹理坐标集
附加值按需要加入Input中,常用附加值如下所示:

附加值	说明
float3 viewDir	视图方向,为了计算视差、边缘光照等效果,Input需要包含视图方向
float4 with COLOR semantic	每个顶点颜色的插值
float4 screenPos	屏幕空间中的位置,为了获得反射效果,需要包含屏幕坐标
float3 worldPos	世界坐标
float3 worldRefl	世界空间中的反射向量。如果表面着色器不写入法线(o.Normal)参数,将包含这个参数
float3 worldNormal	世界空间中的法线向量。如果表面着色器不写入法线(o.Normal)参数,将包含这个参数
float3 worldRefl;INTERNAL_DATA	内部数据。如果表面着色器写入了o.Normal,将包含世界反射向量。为了得到基于每个像素的法线贴图的反射向量需要使用世界反射向量(WorldReflection(IN,o.Normal))
float3 wroldNormal;INTERNAL_DATA	内部数据。如果表面着色器写入了o.Normal,将包含世界法线向量。为了得到基于每个像素的法线贴图的法线向量需要使用世界反射向量(WorldReflection(IN,o.Normal))
RenderType
在一个子着色器的Tags中可以设置RenderType,格式如:
Tags {“RenderType” = “Opaque”}
而RenderType的参数如下所示:

Opaque: 用于大多数着色器(法线着色器、自发光着色器、反射着色器以及地形的着色器)。
Transparent:用于半透明着色器(透明着色器、粒子着色器、字体着色器、地形额外通道的着色器)。
TransparentCutout: 蒙皮透明着色器(Transparent Cutout,两个通道的植被着色器)。
Background: Skybox shaders. 天空盒着色器。
Overlay: GUITexture, Halo, Flare shaders. 光晕着色器、闪光着色器。
TreeOpaque: terrain engine tree bark. 地形引擎中的树皮。
TreeTransparentCutout: terrain engine tree leaves. 地形引擎中的树叶。
TreeBillboard: terrain engine billboarded trees. 地形引擎中的广告牌树。
Grass: terrain engine grass. 地形引擎中的草。
GrassBillboard: terrain engine billboarded grass. 地形引擎何中的广告牌草。
顶点片元着色器
顶点片元着色器不使用灯光交互,实际着色器代码用CG或HLSL语言编写,嵌入在着色器的通道块中,常用编译指令表如下所示:

编译指令	说明
pragma vertex	声明以name为名字的函数是顶点程序
pragma fragment	声明以name为名字的函数是片元程序
pragma fragmentoption	添加选项到编译的OpenGL片元程序,通过OpenGL的ARB_fragment_program可以查询到所允许的规范的选项列表,这个指令对顶点程序或者不是以OpenGL为编译目标的程序无效
pragma target	着色器目标编译
pragma only_renderers	仅用给定的渲染器编译着色器。默认情况下用所有的渲染器都编译着色器。当选择多个渲染器时用空格隔开
pragma exclude_renderers	不用给定的渲染器编译着色器。默认情况下用所有的渲染器都编译着色器。当选择多个渲染器时用空格隔开
pragma glsl	用桌面OpenGL平台编译着色器时,将Cg/HLSL转换成GLSL而不是默认的ARB顶点片元着色器

在only_renderers和exclude_renderers中的渲染器如下:

渲染器	渲染器指令代码
Direct3D 9	d3d9
OpenGL	opengl
OpenGL ES 2.0	gles
Xbox 360	xbox360
PlayStation 3	ps3
Flash	flash

使用方法:#pragma only_renderers opengl

注意:每个顶点片元着色器必须包含一个顶点程序或者片元程序(或两者兼有),因此需要一个#pragma vertex命令或者#pragma fragment命令(或两者兼有)

顶点结构成员
成员	说明
float4 vertex	顶点位置
float3 normal	顶点法线
float4 texcoord	第一UV坐标
float4 texcoord1	第二UV坐标
float4 tangent	切线向量(用在法线贴图中)
float4 color	每个顶点(per-vertex)颜色

************************************************************************************】】

Blend介绍:

混色,根据目前已经画好的颜色,与正在计算的颜色的透明度(Alpha), 混合为两种颜色,作为新的颜色输出

https://blog.csdn.net/m0_37884055/article/details/83316747

https://blog.csdn.net/ecidevilin/article/details/52864349

// 源颜色可以理解为shader本身计算出来的颜色 目标颜色可以理解为背景颜色

1.Blend SrcAlpha OneMinusSrcAlpha  源颜色 x 源通道  +  目标颜色 x(1 - 源通道)          

  A * alpha + B*(1-alpha)

这就是我们常用的 alpha blending ,效果比较接近源颜色,可以深一些

2.Blend One One //additive  :源颜色 + 目标颜色  正常的叠加模式 

A + B

这种模式,是叠加模式,颜色只会比目标颜色亮,很难降低颜色,但是它可以不用通道,黑色就可以替代通道颜色

3.Blend SrcAlpha One //additive blending  源颜色 x 源通道   +  目标颜色   带通道的叠加模式(常用的ADD模式)

A*alpha + B

跟第2种比较接近,但是他需要alpha通道,如果黑白图,可以将黑白图的R通道取出来作为alpha通道,但是记得修改颜色和强度的时候,想办法避免就可以了



4.Blend OneMinusDstColor One //soft additive  源颜色 x (1-目标颜色)  +  目标颜色   

A * (1-B) +B

这种也是add模式,相对温柔一点,只认黑白图,不用管通道


5.Blend DstColor Zero //multiplicative  源颜色 x 目标颜色 + 0(目标颜色 x 0) 

A * B+0


6.Blend DstColor SrcColor //2x multiplicative  源颜色 x 目标颜色 + 目标颜色 x 源颜色     正片叠底的效果

A*B + A *B



7.Blend Zero SrcAlpha //multiplicative blending for attenuation by the fragment's alpha    0(源颜色 x 0)+目标颜色 x 源通道 

下面为各种效果的大致效果



选项代号

与之等价的代码

One

值为1,使用此因子来让帧缓冲区源颜色或是目标颜色完全的通过。1

Zero

值为0,使用此因子来删除帧缓冲区源颜色或目标颜色的值。0

SrcColor

使用此因子为将当前值乘以帧缓冲区源颜色的值 A

SrcAlpha

使用此因子为将当前值乘以帧缓冲区源颜色Alpha的值。A*alpha

DstColor

 使用此因子为将当前值乘以帧缓冲区目标颜色的值。B

DstAlpha

 使用此因子为将当前值乘以帧缓冲区目标颜色Alpha分量的值。B*alpha

OneMinusSrcColor

 使用此因子为将当前值乘以(1 -帧缓冲区源颜色值) 1- A

OneMinusSrcAlpha

 使用此因子为将当前值乘以(1 -帧缓冲区源颜色Alpha分量的值) 1-A*lpha

OneMinusDstColor

使用此因子为将当前值乘以(1 –目标颜色值) 1-B
OneMinusDstAlpha

使用此因子为将当前值乘以(1 –目标Alpha分量的值) 1- B*alpha

向量减法:

https://blog.csdn.net/popy007//article/list/2?  //关于向量系列文章

意义是从一个点移动另一个点。

    public Transform start;
    public Transform end;
    void Update ()
    {
        Vector3 dir = (end.position- start.position).normalized;
        start.transform.position = start.transform.position + dir * 0.5f;
    }

点乘:

点乘的计算:

目的是计算向量之间的角度。 

描述: 一个向量在另一个向量的投影。点乘得到的是弧度值。如果想得到角度需要转。

一个手电筒照射两个向量

一个向量绕某一个轴旋转angle角度:

 angle= Vector2.Doc(V1, V2);

 Vector2 newVec = Quaternion.AngleAxis(angle, Vector3.back) 

叉乘:

这个是数学上的叉乘右手的,但是Unity使用的是左手坐标系。

 a×b=|a||b|sinθ   

Vector3.Cross(Vector3a,Vector3b)得到值类型是Vector3,也就是垂直于向量a和b的向量。

表述一个向量在另一个向量的哪个方位。

计算出的点乘结果>0,则和z轴同向,顺时针旋转,否则逆时针旋转。

游戏应用:

AI和逃跑角色 面对面的判定:逃避者朝向的反向和AI角色的朝向必须大约在20度范围内,才认为是面对着。

叉乘的应用:

案例一:方向盘

 //计算方向盘中心点到触控点的向量
    Vector3 currVec;
    //触控点的向量
    Vector3 wheelPos;
    //后一次的操作点
    Vector3 oldVec;
    //方向盘
    public RectTransform wheelObj; 
    private void Update()
    {
        RotateWheel(wheelObj.position);
    }
    void RotateWheel(Vector3 pos)
    {
        //计算触控点的位置
        Vector3 vecWord = Vector3.zero;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(wheelObj, Input.mousePosition, Camera.main, out vecWord);
        wheelPos = vecWord;

        //计算方向盘中心点到触控点的向量
        currVec = pos - wheelPos;
        //计算前后两次操作时向量的 法向量
        Vector3 normalVec = Vector3.Cross(currVec, oldVec);
        //计算两个向量的夹角
        float vecAngle = Vector2.Angle(currVec, oldVec);

        //使用“右手定则”可知,当大拇指方向指向我们时,四指方向为逆时针方向
        //当大拇指方向远离我们时,四指方向为顺时针方向
        //这里叉乘后的法向量平行于z轴,所以用法向量的z分量的正负判断法向量方向
        if (normalVec.z > 0)//和z轴同向,则顺时针转
        {
            wheelObj.transform.Rotate(Vector3.forward, -vecAngle*50);//顺时针转
        }
        else if (normalVec.z < 0)//和z轴反向,则逆时针转
        {
            wheelObj.transform.Rotate(Vector3.forward, vecAngle* 50);//逆时针转
        }
        oldVec = currVec;//赋值
    }
确定	取消 

案例2:使用叉乘计算角度,使得小车永远沿着自己画的线内部行走:

                Vector3 vec = current - (Vector3)listVecTest[count];

                    //取屏幕的原点的Y向量作为参照向量,计算画的线的前后两帧连线和参照向量的夹角。
                    Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector2(0,0));
                    worldPos = new Vector3(worldPos.x, worldPos.y,0);
                    Vector3 vecStart = new Vector3(worldPos.x, worldPos.y, 0)- new Vector3( worldPos.x,  worldPos.y+5, 0);

                    Debug.DrawLine(current, (Vector3)listVecTest[count], Color.green, 5);
                    Debug.DrawLine(new Vector3(worldPos.x, worldPos.y, 0), new Vector3(worldPos.x, worldPos.y + 5, 0), Color.red, 5);

                    Vector3  crossVec= Vector3.Cross(vec, vecStart);
                    float angle  =   Vector3.Angle(vec, vecStart);
                    if (crossVec.z > 0)//右手法则,z>0,顺时针旋转
                    {  
                        Debug.Log("Clockwise Angle  " + angle);
                        playerTest.transform.eulerAngles = new Vector3(0, 0, 90 - angle);
                    }
                    else if (crossVec.z == 0)
                    {
                        Debug.Log("  Angle "+ angle);//+90   或者  -90
                        if (angle == 90)
                        {
                            playerTest.transform.eulerAngles = new Vector3(0, 0, 90);
                        }
                        else if (angle == 180)
                        {
                            playerTest.transform.eulerAngles = new Vector3(0, 0, -90);
                        }
                    }
                    else if (crossVec.z < 0)
                    {
                        Debug.Log("Antclockwise  Angle   " + angle);   //   angle+ 90
                        playerTest.transform.eulerAngles = new Vector3(0, 0, angle + 90);
                    }

案例3:导弹跟踪

    public Transform player;
    public Transform missile;
    private Vector3 missileDir;    //导弹的速度向量
    public float missileRate=0.02f;
    private void Update()
    {
        missileDir = player.position - missile.position;
        missileDir = missileDir.normalized;

        Vector3 normalVec = Vector3.Cross(missileDir,missile.up);
        float vecAngle = Vector2.Angle(missileDir,missile.up);
        if (normalVec.z > 0)//顺时针
        {
            missile.transform.Rotate(Vector3.forward, -vecAngle);//顺时针转
        }
        else if (normalVec.z < 0)
        {
            missile.transform.Rotate(Vector3.forward, vecAngle );//逆时针转
        }

        missileDir *= missileRate;
        missile.position += missileDir;
    }

固定流水管线: 

  • 局部坐标是对象相对于局部原点的坐标,也是对象开始的坐标。
  • 将局部坐标转换为世界坐标,世界坐标是作为一个更大空间范围的坐标系。这些坐标是相对于世界原点的。
  • 接下来我们将世界坐标转换为观察坐标,观察坐标是指以摄像机或观察者的角度观察的坐标。
  • 在将坐标处理到观察坐标之后,我们需要将其投影到裁剪坐标上。裁剪坐标是在1.0到1.0范围内判断哪些顶点将会出现在屏幕上的。
  • 最后,我们需要将裁剪坐标转换为屏幕坐标,我们将这一过程称为视口变换(Viewport Transform)。视口变换将位于1.0到1.0范围内的坐标转换到由视口函数所定义的坐标范围内。转换的坐标将会送到光栅器中,由光栅器将其转化为片段。

3.在电脑端的shader是这样写的:

uniform sampler2D texture;
uniform vec2 sizeInfo;
varying mediump vec2 texcoord;
const vec2 src_size = vec2 (1.0 / sizeInfo.x, 1.0 / sizeInfo.y);
但是部署到手机端的时候,就报错。正确的写法是将const去掉。

这个问题是const的问题,在着色器编译的时候,sizeInfo并没有确定,并不能设置为const对象,所以在手机端的时候就会报错,但是在电脑端因为版本优化的问题则不会报错。

【Unity Shaders】Mobile Shader Adjustment —— 为手机定制Shader
https://blog.csdn.net/weixin_34365635/article/details/85701742

如果不在tags里写入"LightMode"="ForwardBase"    灯光的向量取值会出错.......md查了几个小时才查出来.

4.UnityShader 浮雕凹凸贴图BumpMap与法线贴图NormalMap的原理及其区别:

https://blog.csdn.net/anypkv/article/details/7313995

https://blog.csdn.net/e295166319/article/details/80372843

浮雕贴图:

法线贴图:

 

 

5.编译指令的一般格式如下:

#pragma surface surfaceFunction lightModel [optionalparams]//可选参数
#pragma surface surf Phong

 6. Unity3D光照前置知识——Rendering Paths(渲染路径)及LightMode(光照模式)译解

 <1. https://blog.csdn.net/kevlis/article/details/53006708

不同的游戏内容,平台硬件有不同的表现效果,可以在playersetting或者camera中设置LightMode。如果目标平台不支持,则会过度到低保证LightMode。

Deferred Shading Rendering Path:

【Shading的时机不是发生在第一个Pass的Vertex和Pixel/Fragment函数内,而是存在延迟,直到第二Pass的时候才执行】

性能较高,移动端基本不用(限制太多),所有的光源都是(逐像素)光照,性能开销与光源数量成正比。

缺点在于,其不能真正的支持抗锯齿以及半透明物体(半透明物体是用 Forward Rendering 渲染路径)。同时也不支持Unity3D中的Mesh Renderer组件的Receive Shadows功能。

Forward Rendering Rendering Path:

Forward: 默认情况下,只有少数最亮的光源得以成为Per-Pixel光源。其他的光源则视为Per-Vertex。

HDR: 通常拍的照片要么太亮,要么太暗,所以需要拍多张照片,通过压缩亮度混合,来实现效果。这个压缩的技术就是HDR.

7.学习shader之前必须知道的东西——OpenGL的固定功能管线

http://imgtec.eetrend.com/d6-imgtec/blog/2018-11/19250.html

8.基本的概念

渲染:就是将三维物体或三维场景的描述转化为一幅二维图像,生成的二维图像能很好的反应三维物体或三维场景。过程:几何变换、光栅化、着色。

顶点渲染单元(Vertex Shader):根据 描述3D图形外观的三角形顶点的数据,来确定3D图形的形状及位置关系; 作几何变换、生成3D图像的骨架。

光栅化: 显示的图像是由像素组成的,将顶点渲染生成的3D图像骨架的一系列三角形(数据)通过一定的算法转换到相应屏幕上的像素点的过程就是光栅化,把一个离散信号转换为模拟信号的过程。

像素渲染:光照、光线追踪、纹理帖图、像素着色。 也就是对每个像素进行计算,从而确定每个像素的最终颜色。最后由ROP(光栅化引擎)完成像素的输出,1帧渲染完毕后,被送到显存帧缓冲区;然后经由D/A转换输出到显示器上。

逐顶点光照:在vetext shader中计算每个顶点的光照颜色而的。该过程将为每个顶点计算一次光照颜色,然后在通过顶点在多边形所覆盖的区域对像素颜色进行线性插值。现实中,光照值取决于光线角度,表面法线,和观察点。【这个渲染路径不支持大多数的逐像素效果:阴影,法线贴图,光照缓存,和高细节的镜面高光不被支持。】

9. 注意顶点法向量和顶点坐标从objectSpace变换到worldSpace

https://blog.csdn.net/yuchenwuhen/article/details/70941443

模型物体空间的顶点坐标-->世界空间的顶点坐标,用的矩阵是wordMartrix,但是模型空间下的顶点法向量-->世界空间的顶点法向量则用的是wordMartrix矩阵的转置矩阵的逆矩阵。因为法向量经过缩放变换之后,不再垂直于变换之前的面

注:平移和选择变换并不会改变法向量与线段的垂直关系。

10. 从视点坐标空间到屏幕坐标空间 (先投影再裁剪)

 详细介绍Unity中相机的投影矩阵  https://blog.csdn.net/mao_xiao_feng/article/details/52268944?locationNum=2 

向量和矩阵相关运算:https://blog.csdn.net/popy007//article/list/2?

   <1. 用透视变换矩阵把顶点从视锥体中变换到裁剪空间的 CVV 中; 【投影】
   <2. 在 CVV 进行图元裁剪; 
   <3. 屏幕映射:将经过前述过程得到的坐标映射到屏幕坐标系上。

    因为在不规则的体(viewing frustum)中进行裁剪并非易事,所以经过图形学前辈们的精心分析,裁剪被安排到一个单位立方体中进行,该立方体的对角顶点分别是 (-1,-1,-1)和(1,1,1),通常称这个单位立方体为规范立方体。

第1份图是看xz视图,从上往下看,第2图是看yz视图

11. Z Buffer 与 Z 值 

其中存放的是视点到每个像素所对应的空间点的距离衡量,称之为 Z 值 或者深度值

如图:线段 AE 是某三角面片的两个顶点,投影到屏幕空间对应到 像素 1 和像素 5;光栅化时,需要对像素 2、3、4 进行属性插值,从视点引射线 到空间线段上的交点分别为 B、C、D。从图中可以看出,点 B、C、D 并不是均分布在空间线段上的,而且如果离视点越远,这种差异就越发突出。即,投影面上相等的步长,在空间中对应的步长会随着离视点距离的增加而变长。所以如果对内部像素点的 Z 值进行线性插值,得到的 Z 值并不能反应真实的空间点的深度关系。Z 值的不准确,会导致物体显示顺序的错乱,例如,在游戏中常会看 到远处的一些面片相互交叠。 

Z buffer精度:16  24 位 32位,如果拥有 32 位的 Z buffer,则 Z 精度 (Z-precision)则不是一个问题。

Z 精度之所以重要,是因为 Z 值决定了物体之间的相互遮挡关系,如果没有足够的精度,则两个相距很近的物体将会出现随机遮挡的现象,这种现象通常称 为”Z-fighting”

12. 模板缓冲(Stencil Buffer)

通常附加在额外的buff中,例如:16位的z buffer后加1位的stencil buffer[2和字节],或者24位的z buffer加上4位的stencil buffer

作用是用来做标记的buffer, 例如在一个像素的stencil  buffer中存放1,则表明该像素对应的3d空间点处于阴影中。

13. 帧缓冲器(Frame Buffer)

 

猜你喜欢

转载自blog.csdn.net/qq_35433081/article/details/90713239
今日推荐