unity渲染场景流程
大概流程
渲染管线使用物体队列调用多个渲染通道->渲染通道遍历物体队列调用Shader中的某个Pass->Pass中通过Shader执行物体渲染过程
为了区分,把 RenderPipeline 称为 渲染管线, ShaderPipeline 称为着色管线,RenderPass 称为渲染通道,ShaderPass 称为着色通道
渲染管线的大致流程
// 这个就是渲染管线,不同的管线有不同的实现代码,这里描述的是内置渲染管线
void Pipeline:Render(RenderContext context)
{
for (var camera in camearas)
{
Render(context,camera);
}
}
void Pipeline:Render(RenderContext context,Camera camera)
{
CullResult cull = CullResults.Cull(context);// 剔除掉不会渲染的物体
context.SetupCameraProperties(camera); // 设置矩阵及其他属性
var buffer = new CommandBuffer(); // 创建命令缓冲
buffer.ClearRenderTarget(); // 清除渲染目标
context.ExecuteCommandBuffer(buffer); // 执行命令缓冲,没有立即执行,只是拷贝到内部缓冲区
buffer.Release();
// 现在主流有2种渲染路径:前向渲染和延迟渲染
// 不同的渲染路径会使用不同的 shader 代码,因此在立项时就要确定好采用哪种渲染路径
// 一般手机用前向渲染,通用性更好,PC或VR等性能好的用延迟渲染,具有更好的光影表现
// 参考 教程\图形学\渲染管线\延迟渲染 VS 前向渲染.pdf
// 参考 Unity User Manual (2019.4 LTS)/图形/Render pipelines/内置渲染管线/Extending the Built-in Render Pipeline with Command Buffers
// 不同的路径有不同实现代码,通过组合不同的物体队列和着色通道来渲染物体
//
if ( m_useForward )
{
// 前向渲染
// 渲染不透明物体然后渲染透明物体
// 指定使用材质上的哪个Pass,物体材质上可以有多个 SubShader 代表不同的显卡平台,每个SubShader上有多个Pass
// 每个Pass代表不同参数下如何渲染物体,当我们渲染一个队列的物体时要指定用哪个Pass
// 初始化所有灯光
setupFirstLight();
// 渲染不透明物体
{
// 前向渲染当重要光源超过1个时会用到多个Pass
// 第1次设置第1个重要光源和其他不重要光源,然后调用材质中的 ForwardBase Pass
var drawSettings = new DrawRendererSettings(camera, new ShaderPassName("ForwardBase"));
// 指定排序方式,不透明物体按离摄像机从近到远排序,这样远的物体如果被覆盖,在深度测试时就被pass掉,提高效率
drawSettings.sorting.flags = SortFlags.CommandOpaque;
// drawSettings.SetOverrideMaterial(errMaterial); // 可以通过该函数覆盖所有物体渲染时的材质
// 指定不透明物体队列
var filterSettings = new FilterRenderersSettings(){
renderQueueRange=RenderQueueRange.opaque};
// 使用 ForwardBase 着色器通道渲染不透明物体,FrameDebugger中看到的是 A ForwardBase, B ForwardBase
conext.DrawRenderers(cull.visibleRenderers, ref drawSettings, filterSettings);
// 然后对剩下的重要光源每次设置1个,然后调用材质中的 ForwardAdd Pass ,
// 为什么使用不同的Pass 呢,因为第1次Pass还有其它光源
// 后面的Pass有点不一样,是设置好所有Pass,然后再遍历物体
for ( int i=1; i<m_importLights.Length; i++ )
{
drawSettings.SetShaderPassName(i-1,new ShaderPassName("ForwardAdd"));
}
// 设置好所有Pass后再一次性遍历,所以在 FrameDebugger中看到的是 A ForwardAdd, A ForwardAdd, B ForwardAdd, B ForwardAdd
conext.DrawRenderers(cull.visibleRenderers, ref drawSettings, filterSettings);
}
contex.DrawSkyBox(); // 画天空盒,没有立即执行,只是提交了个命令到内部缓冲区
// 渲染半透明物体
{
// 透明物体队列物体按离摄像头从远到近排序,这样才能正确显示
drawSettings.sorting.flags