mesh render:根据物体样子给予皮肤和颜色
OpenGL和 DirectX:提供了渲染图形的许多接口,让处理更加简化
shader:一种渲染命令,由OpenGL和directX进行解析,来控制渲染各种图形
GLSL shader语言用于OpenGL
HLSL shader语言用于directX
英伟达CG编写shader可以在OpenGL和directX通用
Unity Shader的分类:
使用的是ShaderLab编写unity中的的shader
1 表面着色器 Surface Shader
2 顶点/片元着色器 Vertex/Fragment Shader
3 固定函数着色器 Fixed Function Shader
在unity中创建一个shader用vs编写:Shader "myShader"{ } 这里“”表示shader的名字,如果“siki/myshader”表示siki栏下面名为myshader。
如果只写了一个空shader那么unity不知道如何渲染,调用shader就会显示出紫色
在myshader{}中第一个是属性Properties{ }
这些属性中Range是对数进行限制,默认为6, 这里2D表示2D纹理,我们可以看到在inspector面板上显示出来了这些信息,我们可以在面板上修改这些属性,因此properties中的作用仅仅是在面板上显示出来这些属性
虽然在Properties中定义了但是在pass中要使用哪个还是再声明下,在属性中一行不加;在pass中要加分号
属性中color用了4个变量所以使用float4,当然使用float都可以用half或fiexed来代替。比如half4 _Color;
区别是使用float 用32位来存储用half使用16位存储从-6万到+6万,使用fixed使用11位存储,从-2到+2
shader中包含多个SubShader,但最少一个,unity会选用一个能够在目标平台上运行的subShader如果都不行,就使用Fallback语义指定的shader
每个图像都是由许多个三角面组成的,每个三角面由三个顶点组成
顶点函数:将顶点坐标从模型空间到剪裁空间的转换 格式:#pragma vertex vert
片元函数:确定每个像素的点的颜色 格式:#pragma fragment frag
结构体的定义:
这个a2v是自定义的名字,当传递多个数据的时候可以直接传递结构体
片元函数和顶点函数是如何传递数据的呢:
定义两个结构体v和f,在顶点函数参数传v返回f,在函数中变量赋值,在片元函数参数中传f进来
光照模型:是一个公式,使用这个公式可以计算某个点的光照效果
进入摄像机的光分为四类:
1 自发光
2 高光反射 specular
3 漫反射(diffuse)
4 环境光
渲染流水线的任务是:从一个3维场景出发,生成一个2维图像,由cpu和Gpu共同完成
渲染流程分为3个阶段:
应用阶段:准备场景数据,粗粒度剔除,输出渲染的几何信息,即渲染图元,在cpu上实现,这里又分为三个阶段,1,把数据加载到显存上,2,设置渲染状态。3,调用Draw Call
几何阶段:处理渲染图元,处理几何,在gpu上实现
光栅化阶段:渲染出最终图像,gpu上实现
渲染所需的数据会通过硬盘加载到内存中,网格纹理这些数据会又被加载到显存中,因为显卡对于显存的访问速度更快。
渲染状态:这些状态定义了场景中网格是怎样被渲染的,例如使用了那个顶点/片元着色器,光源属性,材质等
Draw Call:Cpu通过调用一个渲染命令来告诉Gpu,数据准备好,可以进行渲染,这个渲染命令就是Draw Call
顶点着色器:实现顶点的空间变换,顶点着色 曲面细分着色器:细分图元
裁剪:不在摄像机范围内的物体不需要被处理 屏幕映射:把图元的x,y坐标转换到屏幕坐标系下
三角形设置:计算三角网格表示数据的过程 片元着色器:
总结:如果问你3d流水线的流程或是渲染管线的工作原理?
答:渲染管线主要分为三个阶段:应用程序阶段、几何阶段、光栅阶段。应用程序阶段是Cpu和内存交互,顶点坐标、法向量、纹理坐标、纹理等数据作为源数据等待处理。几何阶段,负责顶点坐标变换、光照、裁剪、投影以及屏幕映射,gpu上实现。光栅化阶段,渲染出最终图像,gpu上实现。
1,cpu和gpu如何并行工作?
命令缓冲区包含一个命令队列,cpu添加命令,gpu读取
2,为什么Draw Call多了会影响帧率?
每次调用它之前,cpu需要检查渲染状态等,如果太多,cpu会把大量时间浪费在提交Draw Call上
3,如何减少Draw Call数量
批处理方法,把许多小的Draw Call合并成一个大的Draw Call,同时避免使用过多材质,尽量在不同网格之间只用同一材质
shader本身无法发生作用,必须和材质结合起来才能发生神奇的化学反应
shaderLab:自动封装了渲染的许多设置,让开发者编写shader更容易,也即编写shader的格式
世界空间:不解释
模型空间:局部空间,把世界空间看做模型空间的父空间系
模型变换(模型-世界变换)
模型变换的实质就是将模型上的顶点在模型空间中的描述,转换为在世界空间中的描述。假设有一个模型坐标系表示为矩阵 M(基于世界坐标系来描述),一个顶点在该模型坐标系上的坐标表示为列向量 D。 那么,该顶点在世界坐标系中的坐标 D‘,有如下变换关系:M·D = D’。M 也称为模型矩阵。模型矩阵本质上是一系列缩放、旋转和平移矩阵的复合矩阵。视图空间:
视图空间,也称为视点空间或摄像机空间或观察空间,从摄像机的角度来看,视图坐标系 x-轴和 y-轴的正方向分别指向摄像机右方和上方,而 z-轴的负方向则指向摄像机的镜头指向。
注意的是:观察空间和屏幕空间是不同的,从观察空间转到屏幕空间只需一个操作,就是投影
视图变换(世界-视图变换):将某个顶点在世界空间中的描述,转换为在视图空间中的描述。
模型视图矩阵(Model-View)
为了渲染一个模型,我们通常会先将它从模型空间变换到世界空间,然后再从世界空间变换到视图空间。这两个过程都有对应的变换矩阵:模型矩阵和视图矩阵。我们可以将这两个矩阵结合起来用一个复合矩阵来表示,这样的一个复合矩阵我们称为模型视图矩阵。通过模型视图矩阵,我们可以将模型上的顶点从模型空间直接变换到摄像机的视图空间
剪裁空间:在写shader的时候,出现的错误可能会在报错的那行的上面或者上上一行
漫反射的公式:
Shader "siki/myShader"{//两冒号是shader的名字
SubShader{
Pass{
Tags{"LightMode" = "ForwardBase" } //只有正确而定义了LightMode才能得到unity的内置光照变量
CGPROGRAM
#include "Lighting.cginc" //包含unity的内置文件,才可以使用unity的内置变量
#pragma vertex vert
#pragma fragment frag
struct a2v {
float4 vertex : POSITION;//告诉unity把模型空间下的顶点坐标给vertex
float3 normal:NORMAL; //取得法线
};
struct v2f {
float4 position:SV_POSITION;//把剪裁空间下的位置传给Position
fixed3 color : COLOR;//用于接收最后的漫反射光的颜色
};
v2f vert(a2v v) { //把结构体a2v传进来,v2f传出去
v2f f;
f.position = mul(UNITY_MATRIX_MVP,v.vertex);//mul()是计算两个矩阵和向量相乘,UNITY_MATRIX_MVP矩阵是把顶点坐标从模型空间转换到剪裁空间
fixed3 normalDir = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
//由于拿到的法线是世界坐标下的,所以要转到模型空间下,通过mul相乘,由于World2Object是世界空间转模型空间矩阵,所以要想从模型空间转世界,把
//两个参数互选下位置,由于矩阵是4x4,normal是float3所以要把矩阵强转为3x3,normalize是将向量单位化
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz); //平行光,所以光的位置就是光的方向
fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir),0);
//这里_LightColor0是取得平行光的颜色,dot是两个向量点积
f.color = diffuse;
return f;
}
fixed4 frag(v2f f): SV_Target {
return fixed4(f.color,1); //由于拿到的颜色是float3,所以最后一位在加上一个1
}
ENDCG
}
}
Fallback "VertexLit"
}
高光反射的公式:specular=直射光*pow(max(cos夹角,0),10) 夹角等于反射光的方向和相机和物体之间的连线方向的夹角
通过max(cos夹角,0)取正数,通过pow(,10)来将它乘以10次幂将曲线的陡度提起来
高光反射的效果:可以看到球体的上头有个亮点,这个亮点会随着视角的移动而移动,这就是高光反射
Lambert模型较好的表现了粗糙表面的光照现象,如墙壁,纸张等,但是在用于诸如金属等有光泽效果的材质上则会显得呆板,表现不出光泽,主要原因是Lambert光照模型没有考虑表现这些表面的镜面反射效果。
一个光滑物体被光照射时,可以从某个方向上看到很强的反射光,这是因为在接近镜面反射角的一个区域内,反射了入射光的全部或大部分光强,这种现象称为镜面发射。也可以理解为高光反射
故此,提出一个计算镜面反射光强的光照模型,称为Phong模型,认为镜面反射的光强与反射光线和视线的夹角相关。
BlinnPhong光照模型混合和了Lambert的漫反射和标准的高光,渲染有时比Phong高光更柔和、更平滑,此外它的处理速度相当快,因此成为许多CG软件中默认的光照渲染方法
上面的代码用到的一些系统函数:
写代码的时候要想把多行向右移动,选中代码,按Tab键即可