Unity SRP自定义渲染管线 -- 1.Custom Pipeline

该篇是对Catlike Coding这篇文章的概要总结,本人能力有限,如果有不正确的地方欢迎指正  https://catlikecoding.com/unity/tutorials/scriptable-render-pipeline/custom-pipeline/

通过这篇文章,你将学习到

  • Create a pipeline asset and instance. 创建一个渲染管线资源和实例
  • Cull, filter, sort, render.   剪裁,过滤,排序和渲染
  • Keep memory clean.   内存清理优化
  • Provide a good editing experience.  更好的编辑器用户体验

This tutorial is made with Unity 2018.3.0f2.  这篇文章的实现基于Unity 2018.3.0f2版本,是在Unity中实现一个自定义渲染管线教程系列的第一篇。

1.创建一个管线

在Unity2018之前,Unity中有Foward 和 Deferred 两种渲染管线,渲染管线中你可以操控的部分和内容非常少。在Unity2018中,提供了可编程渲染管线(SRP),有了它,我们可以自定义管线中的很多内容,虽然大多数步骤是Unity中已经封装好的功能(比如Culling裁剪)。在2018中,SRP还处于preview阶段,但是目前的版本提供的功能和稳定性足以让我们实现自定义渲染管线。

1.1项目设置

创建一个标准3D项目,移除掉PackageManager中除Package Manager UI外的所有其他内容。

 将Unity2018默认的Gamma空间改成线性空间(Edit / Project Settings / Player  -- Color Space in the Other Settingssection to Linear

创建一些测试用的简单材质资源:

  • 默认的standard 材质,Rendering Mode 为opaque
  • 默认的standard 材质, Rendering Mode 为Transparent 
  • Unlit/Color shader,   Rendering Mode 为opaque
  • Unlit/Color shader,   Rendering Mode 为Transparent 

2.渲染管线资源(Pipeline Asset)

Unity默认使用的是传统的前向渲染管线,如果要使用我们自定义的,需要在Edit / Project Settings / Graphics中设置

想要设置我们自定义的RenderPipelineAsset,我们需要先为我们的自定义渲染管线创建一个RenderPipelineAsset。它继承于RenderPipelineAsset,我们把自定义的渲染管线命名为MyPipline,所以对应的管线资源文件就命名为MyPipelineAsset。我们需要使用UnityEngine.Experimental.Rendering命名空间,因为该功能还在preview阶段,以后如果正式版本发布的话可能需要更改成对应的命名空间

RenderPipelineAsset的主要目的是帮助Unity创建一个渲染管线实例,RenderPipelineAsset自身其实就是存储各渲染管线的配置。我们可以通过overriding the InternalCreatePipeline 方法来创建一个渲染管线实例,因为我们现在还没定义自己的渲染管线,所以现在先返回个Null。

 用CreateAssetMenu函数来使得在编辑器中可以创建我们的管线

创建出我们自己的管线资源:

将创建好的管线Asset赋值到SRP Setting

创建一个实现了IRenderPipeline接口的类,命名为MyPipeline,它将是用于渲染过程的实例

 为了方便,我们直接继承RenderPipeline类,它是Unity总已经实现IRenderPipeline接口基本功能的类

 现在,我们将之前InternalCreatePipeline函数中返回Null部分的代码替换成创建我们自定义好的MyPipeline类

2.渲染

pipeline每帧渲染,Unity做的事就是使用context和active状态的camera作为参数,调用pipeline中的render函数,进行渲染。这个过程对game 窗口,scene窗口和材质预览窗口都是一样的。我们现在要做的就是正确的设置好各参数,用正确的顺序绘制出应该被渲染的东西。

2.1 Context(上下文)

RenderPipeline需要实现Render这个方法,它的第一个参数是Context,一个Context是一个ScriptableRenderContext结构体,作用是对Native code的桥接。该函数的第二个参数是一个camera数组。

  基类RenderPipeline的RenderPipeline.Render函数并没有实际绘制任何东西,只是检查了管线中的物体是否合法用于渲染,如果不是的话会抛出异常。我们调用积累中的这个函数来保持这个检查功能。

我们可以调用command是去控制渲染状态和绘制各种东西,其中最简单的一个例子就是绘制天空盒,我们调用DrawSkyBox函数完成这个功能。该函数需要传入一个摄像机作为参数,为求简便我们使用Camera数组中的第一个。

调用了这个函数我们还是看不到任何东西,这是因为我们这是把command传入了buffer,实际起效需要我们通过submit函数submit 这些commands。

这回我们能在game视图中看到skybox了,我们也能在frame debugger中看到。

 2.2 Cameras

场景中可能存在多个摄像机需要挨个渲染,我们可以为单个摄像机写一个render函数,在我们目前要实现的渲染管线中,主要关注这个函数就可以了。

想要正确的渲染Skybox和整个场景,我们需要通过Camera的位置和视角设置MVP矩阵,Unity Shader中unity_MatrixVP 就是这个矩阵。我们需要将Camera中的配置信息通过SetupCameraProperties函数写入Context中。

2.3 Command Buffers

Context 直到我们Submit才会进行实际的渲染,在这之前,我们需要配置它并且将comands加入其中等之后执行。一些任务比如绘制Skybox有专门的函数实现,但是很多commands都是用command buffer来完成。

command buffer在UnityEngine.Rendering命名空间中,它是在srp功能之前就有的功能,我们在绘制Skybox之前创建一个command buffer。

ExecuteCommandBuffer函数将command传入context的内部,等待submit后执行

command buffer会消耗unity native层的内存资源,当我们不再需要它的时候要立刻释放掉。Release函数可以完成这个功能。

执行一个空的command buffer没有意义,我们加入command buffer是为了清除render target去保证之前渲染的东西不会影响到目前。我们向buffer中加入一个clear command通过调用ClearRenderTarget函数,它包括三个参数,第一个参数是否清除depth ,第二个参数是否清除color,第三个参数是将缓冲区清除成什么颜色。

在frame debugger中我肯能够看到command buffer执行的结果,清除了Z缓冲和stencil缓冲。 

通过Camera中的clear flags和background color参数,我们可以清除掉这个函数的硬编码,直接使用配置好的信息 

给Command Buffer设置一个名字,在这里我们将其设置成camera的name,在frame debugger中就可以看到这个相应信息。 

2.4 Culling

我们目前只渲染了Skybox还没有渲染场景中的物体,在渲染物体之前,我们需要先通过摄像机的视椎体对物体进行裁剪剔除,只渲染那些被我们看见,应该被渲染的物体。

通过ScriptableCullingParameters结构体和 CullResults.GetCullingParameters 函数,我们可以针对某个Camera得到裁剪的配置信息。

优化一下,可以判断一下Camera 设置是否valid,如果不是的话,该函数会返回false,直接不渲染东西return掉。

得到裁剪的配置信息后,通弄过CullResults.Cull 函数可以得到最终的裁剪结果 

2.5 Drawing

有了场景中的可视信息后,我们可以通过DrawRenderers函数进行下一步的渲染。该函数用剪裁后的cull.visibleRenderers和

DrawRendererSettings and FilterRenderersSettings配置信息进行渲染。

到现在我们还是看不到任何物体,这是因为我们需要设置 FilterRenderersSettings信息,通过置为true,可以渲染everything。·

通过设置DrawRendererSettings信息,我们设置用于渲染的shader pass,在这里我们使用SRPDefaultUnlit Shader Pass。

到这步在场景中我们就可以看到不透明的物体了 

在frame debugger中可以看到透明物体也被渲染了,但是在game视图中没看到,这是因为渲染顺序的问题,透明物体渲染时不会写入深度缓冲,应该在最后再渲染。当透明物体被渲染后,再渲染skybox就会导致透明物体渲染不正确。 

要解决这个问题,我们需要调整渲染顺序,先只渲染不透明物体。 

 之后渲染skybox,最后再渲染透明物体

 现在不透明物体,透明物体和skybox都可以正常渲染了。

 我们先渲染不透明物体,后渲染skybox的原因是因为不透明物体一定在skybox之前,会挡住skybox,这样的话就可以减少over draw。同样的原理,也可以用于不透明物体之间的遮挡,我们可以先对不透明物体进行排序,明确前后关系后按顺序渲染,这样被挡住物体的部分就不会参与渲染,可以增加渲染效率。

通过设置SortFlags.CommonOpaque,可以从前向后的顺序渲染不透明物体

为了渲染透明物体,我们要将渲染顺序改回从后到前,通过设置SortFlags.CommonTransparent,可以实现该功能

 现在,我们的自定义渲染管线可以正确的渲染不透明和透明物体了。

3.Polishing

能够正确的渲染只是渲染管线一小部分功能,我们还要考虑很多其他东西,比如内存的分配,和Editor是否结合的更好等等问题。

3.1 Memory Allocations

不要每帧都创建CullResults结构体,因为它里面有3个List,都需要分配内存

去掉Camera.name的调用,每次调用这个,都会新生成一个string,消耗内存

缓存command Buffer,不要每帧都分配,使用clear进行重置 

3.2 Frame Debugger Sampling

通过BeginSample 和 EndSample,我们可以控制frame debugger中显示的层级,便于调试

3.3 Rendering the Default Pipeline

因为我们自定义的这个渲染管线只支持unlit shaders,当物体使用其他shader的时候就渲染不出来了。我们可以使用一个Unity的error shader,当物体不能正确渲染的时候可以显示其形状,通过使用DrawDefaultPipeline函数来实现这个功能。

 我们使用Unity默认的ForwardBase pass,我们不用考虑剪裁排序这些,因为他们本来就不该被正确的渲染出来

因为我们的管线不支持ForwardBase,所以这些物体渲染的并不正确,我们用Unity中的ErrorShader生成一个material,用于渲染,渲染结果就是粉粉的我们熟悉的那种效果了。

目前是只有使用了ForwardPass的shader会得到这种效果,我们通过设置drawSettings,可以将Unity中其他shader pass加入其中。

3.4 Conditional Code Execution

通过Conditional功能,我们可以控制函数只在development版本和Editor中编译运行,在正式build版本中会被删掉不进行编译

3.5 UI in Scene Window

我们不用做任何处理,就可以在game视图中正确显示UI,这些Unity已经为我们做好了。但是想在Scene视图中看到UI,我们需要调用ScriptableRenderContext.EmitWorldGeometryForSceneView函数。但是要注意的是调用这个函数会导致UI在game视图中再渲染一遍,所以我们要根据CameraType.SceneView区分是否是在scene视图中,并且用#if UNITY_EDITOR来保证只在Editor模式下编译这段代码。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246256.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GPU Gems2 - 7 带位移映射的细分表面自适应镶嵌

文章参照该文 https://zhuanlan.zhihu.com/p/38411575 【章节概览】 这章介绍了如何使用可选的位移贴图(Displacement Mapping)执行Catmull-Clark细分曲面(Catmull-Clark Subdivision Surfaces)的视图相关的自适应镶嵌&#xff0…

GPU Gems2 - 8 使用距离函数的逐像素位移贴图

【章节概览】 距离贴图(distance map)是一种在像素着色器中给对象添加小范围位移映射的技术。这章中详细介绍了使用距离函数的逐像素位移贴图(Per-Pixel Displacement Mapping with Distance Functions)技术。 【核心要点】 这章中…

GPU Gems2 - 9 S.T.A.L.K.E.R.中的延迟着色(Deferred Shading in S.T.A.L.K.E.R.)

关于延迟着色的详细技术及最新渲染管线技术可以参考我的这篇文章: https://blog.csdn.net/yinfourever/article/details/90263638 【章节概览】 本章是对《S.T.A.L.K.E.R.》中所用渲染器的几乎两年的研究和开发的事后剖析。该渲染器完全基于延迟着色(De…

GPU Gems2 - 10 动态辐照度环境映射实时计算

【章节概览】 环境映射(Environment Maps)是常用的基于图像的渲染技术,用来表现以空间上不变的球面函数。本章描述了一种完全GPU加速的方法,来生成一个环境映射在图形上特别有趣的类型——辐照度环境映射(Irradiance …

GPU Gems2 - 11 近似的双向纹理函数(Approximate Bidirectional Texture Functions)

【章节概览】 本章介绍的内容关于如何较容易地采集和渲染的真实材质,如布料、羊毛和皮革等的技术。这些材质难以用早先的技术渲染,它们基本来与兼得的纹理映射。本章的目标是在采集上花费少量的努力,在渲染上花费少量的技术,但是仍…

GPU Gems2 - 12 基于贴面的纹理映射(Tile-Based Texture Mapping)

本文内容摘自https://zhuanlan.zhihu.com/p/38411575 【章节概览】 这章介绍了一个基于贴面的纹理映射(Tile-Based Texture Mapping)系统,用来从一组贴面生成一个大的虚拟纹理。 【核心要点】 使用纹理贴面(Texture Tiling&#…

一些图形学中的数学应用

包围体是一个简单的几何空间,里面包含着复杂形状的物体。为物体添加包围体的目的是快速的进行碰撞检测或者进行精确的碰撞检测之前进行过滤(即当包围体碰撞,才进行精确碰撞检测和处理)。包围体类型包括球体、轴对齐包围盒&#xf…

GPU Gems2 - 13 动态环境光遮蔽与间接光照(Dynamic Ambient Occlusion and Indirect Lighting)

本文摘自https://zhuanlan.zhihu.com/p/38411575 【章节概览】 这章在讲大家很熟知的环境光遮蔽(Ambient Occlusion , AO)。 文中的描述是,介绍了一种用于计算散射光传递的新技术,并演示如何用它来计算运动场景中的全局光照。主要…

解析Monte-Carlo算法(基本原理,理论基础,应用实践)

转载自https://www.cnblogs.com/leoo2sk/archive/2009/05/29/1491526.html 引言 最近在和同学讨论研究Six Sigma(六西格玛)软件开发方法及CMMI相关问题时,遇到了需要使用Monte-Carlo算法模拟分布未知的多元一次概率密度分布问题。于是花了几天…

Unity SRP自定义渲染管线 -- 3.Lights

Lights Single-Pass Forward Rendering 实现 diffuse shading.支持 directional(方向光), point(点光源), and spotlights(聚光灯).每帧可允许最多16个可见光参与渲染每个物体可以最多由4个像素光和4个顶…

Faceware 面部捕捉在Unity中的应用

官网软件下载:https://www.facewaretech.com/ 官网教程:http://support.facewaretech.com/ 官网素材下载:https://www.facewaretech.com/learn/free-assets Faceware Analyzer Faceware Retargeter(Maya) Unity 真…

Tone mapping进化论

转载自 https://zhuanlan.zhihu.com/p/21983679 这几年,随着拍摄设备、渲染方法和显示设备的发展,HDR慢慢会成为标配。照相机和摄像机可以捕捉到HDR的影响,渲染过程中可以产生HDR的画面。这些内容如果需要显示到LDR的设备上,就需…

坐标变换过程(vertex transformation)

原文:https://blog.csdn.net/wangdingqiaoit/article/details/51594408 在上面的图中,注意,OpenGL只定义了裁剪坐标系、规范化设备坐标系和屏幕坐标系,而局部坐标系(模型坐标系)、世界坐标系和照相机坐标系都是为了方便用户设计而…

三灯布光法

原文:https://zhuanlan.zhihu.com/p/62307736?utm_sourcewechat_session&utm_mediumsocial&utm_oi919394520523739136 如果将视频影像比喻成一幅画,光线就是画笔,光影造就了影像画面的立体感。本期圈圈就给大家简单介绍一下视频影像…

齐次坐标

本文是一些关于齐次坐标知识的整合。 https://www.sohu.com/a/258317807_100007727 http://www.songho.ca/math/homogeneous/homogeneous.html https://blog.csdn.net/VenoBling/article/details/87794400 https://www.cnblogs.com/csyisong/archive/2008/12/09/1351372.ht…

Unity SRP自定义渲染管线 -- 4.Spotlight Shadows

英文原文:https://catlikecoding.com/unity/tutorials/scriptable-render-pipeline/spotlight-shadows/ 渲染并且读取纹理从光空间(光源角度)渲染为阴影投射(shadow casters)添加一个着色器pass采样阴影贴图支持软阴影…

Unity SRP自定义渲染管线 -- 5.Directional Shadows

原文:https://catlikecoding.com/unity/tutorials/scriptable-render-pipeline/directional-shadows/ 支持多个方向光阴影控制阴影距离定义独立的主光源渲染和采样级联阴影(cascaded shadow map)使用球形剔除1. Shadows for Directional Lig…

浅析Unity中的Enlighten与混合光照

原文https://www.cnblogs.com/murongxiaopifu/p/8553367.html 0x00 前言 在Unity的5.6版本之前的5.x中,主要使用了Geomerics公司的Enlighten【1】来提供实时全局照明以及烘焙全局照明,在5.6之后Unity引入了新的Lightmapper——Progressive来提供烘焙全…

聊聊LightProbe原理实现以及对LightProbe数据的修改

原文链接https://www.cnblogs.com/murongxiaopifu/p/8997720.html 0x00 前言 最近工作比较忙,所以文章已经很久没有更新了。这篇小文的主题也是在出差的高铁上想到,因为最近和一些朋友聊天,发现他们中很多人的项目中都使用了多个实时光源。…

3D游戏的照明设计理论,第3部分:三点照明法的异端与误区

https://zhuanlan.zhihu.com/p/87997570 这是有关如何处理游戏照明的系列文章的一部分。第一部分是关于灯具,第二部分是关于光的形式材料。 在第一部分中,我们首先从文化角度考虑了灯光-灯光在整个历史上对不同的人意味着不同的事物,并且在照…