找回密码
 立即注册
查看: 286|回复: 0

URP源码笔记-渲染器(Renderer)

[复制链接]
发表于 2023-3-4 13:49 | 显示全部楼层 |阅读模式
Renderer的创建

依稀还记得上个文章的一个方法叫:RenderSingleCamera
RenderSingleCamera(ScriptableRenderContext context, CameraData cameraData, bool anyPostProcessingEnabled)
Unity里面的渲染,是以相机为单位的。而各个相机会在不同的情景有不一样的表现,这时候就需要单独设置相机的参数。 在RenderSingleCamera方法中,调用了InitializeCameraData方法初始化了这些参数。 在UniversalRenderPipelineCore.cs中定义了CameraData,里面包含一个ScriptableRenderer
//UniversalRenderPipelineCore.cs
public struct CameraData
{
    Matrix4x4 m_ViewMatrix;
    Matrix4x4 m_ProjectionMatrix;

    //Camera实例
    public Camera camera;
    //各种相机参数
    public CameraRenderType renderType;
    public RenderTexture targetTexture;
    public RenderTextureDescriptor cameraTargetDescriptor;
    internal Rect pixelRect;
    ...略

    //!!!这里定义了ScriptableRenderer
    public ScriptableRenderer renderer;
}在InitializeAdditionalCameraData中,为CameraData的renderer赋值
static void InitializeAdditionalCameraData(Camera camera, UniversalAdditionalCameraData additionalCameraData, bool resolveFinalTarget, ref CameraData cameraData)
{
    bool isSceneViewCamera = cameraData.isSceneViewCamera;
    if (isSceneViewCamera)
    {
        cameraData.renderer = asset.scriptableRenderer;
    }
    else if (additionalCameraData != null)
    {
        cameraData.renderer = additionalCameraData.scriptableRenderer;
    }
    else
    {
        cameraData.renderer = asset.scriptableRenderer;
    }
}pipeline asset中获取scriptableRenderer
public ScriptableRenderer scriptableRenderer
{
    get
    {
        if (scriptableRendererData.isInvalidated || m_Renderers[m_DefaultRendererIndex] == null)
        {
            DestroyRenderer(ref m_Renderers[m_DefaultRendererIndex]);
            m_Renderers[m_DefaultRendererIndex] = scriptableRendererData.InternalCreateRenderer();
        }

        return m_Renderers[m_DefaultRendererIndex];
    }
}在UniversalRenderPipeline的代码中是这么获取Renderer的,实际上ScriptableRenderer是个抽象类,URP只是其中的一种实现。然后自定义管线也是同样的方式去处理。
SRP的几个重要class



URP类中的render调用流程



Setup,SetupLights,SetupCullingParameters,FinishRendering这几个是虚函数,定制管线的时候需要自定义,例如:URP就有自己的实现。
ScriptableRenderer里面的Execute方法

先说说ScriptableRenderer中我认为比较重要的变量个方法吧:

  • m_ActiveRenderPassQueue

    • 保存着当前的所有ScriptableRenderPass
    • EnqueuePass方法:添加pass
    • ExecuteBlock方法:一个block是有范围的,根据blockRanges里面的下标范围,从m_ActiveRenderPassQueue中取出pass,并执行

  • BlockIndex

    • 有四种,BeforeRendering, MainRenderingOpaque, MainRenderingTransparent, AfterRendering
    • 根据

  • 执行RenderPassBlock的顺序,如果有在framedebug中查看,可以对比下看看

    • ExecuteBlock(RenderPassBlock.BeforeRendering
    • ExecuteBlock(RenderPassBlock.MainRenderingOpaque
    • ExecuteBlock(RenderPassBlock.MainRenderingTransparent
    • ExecuteBlock(RenderPassBlock.AfterRendering

  • m_RendererFeatures

    • RenderData中的Feature填入到m_RendererFeatures

public void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
    CommandBuffer cmd = CommandBufferPool.Get();
    // 开始渲染,调用pass的OnCameraSetup,收集指令然后发送。
    InternalStartRendering(context, ref renderingData);

    // 清理渲染状态,如禁用一些关键字,后续根据pass需要开启
    ClearRenderingState(cmd);
    // 设置_Time,_SinTime,_CosTime,unity_DeltaTime,_TimeParameters的值
    SetShaderTimeValues(cmd, time, deltaTime, smoothDeltaTime);
    context.ExecuteCommandBuffer(cmd);
    cmd.Clear();

    // 对render pass做排序
    SortStable(m_ActiveRenderPassQueue);
    //根据hash值把合并pass
    SetupNativeRenderPassFrameData(cameraData, useRenderPassEnabled);

    //填充rendersBlocks
    using var renderBlocks = new RenderBlocks(m_ActiveRenderPassQueue);
    //初始化光照
    SetupLights(context, ref renderingData);

    ExecuteBlock(RenderPassBlock.BeforeRendering, in renderBlocks, context, ref renderingData);
    //设置摄像机的shader变量
    SetPerCameraShaderVariables(cmd, ref cameraData);
    SetShaderTimeValues(cmd, time, deltaTime, smoothDeltaTime);

    context.ExecuteCommandBuffer(cmd);
    cmd.Clear();

    // 渲染不透明物体
    ExecuteBlock(RenderPassBlock.MainRenderingOpaque, in renderBlocks, context, ref renderingData);
    // 渲染透明物体
    ExecuteBlock(RenderPassBlock.MainRenderingTransparent, in renderBlocks, context, ref renderingData);
    // 绘制Gizmos
    DrawGizmos(context, camera, GizmoSubset.PreImageEffects);
    // 渲染之后,后处理or播视频
    ExecuteBlock(RenderPassBlock.AfterRendering, in renderBlocks, context, ref renderingData);

    DrawWireOverlay(context, camera);
    DrawGizmos(context, camera, GizmoSubset.PostImageEffects);
    //finishRendering事件
    InternalFinishRendering(context, cameraData.resolveFinalTarget);

    //清理,下次render再次setup
    for (int i = 0; i < m_ActiveRenderPassQueue.Count; ++i)
    {
        m_ActiveRenderPassQueue.m_ColorAttachmentIndices.Dispose();
        m_ActiveRenderPassQueue.m_InputAttachmentIndices.Dispose();
    }

    //发送指令到context
    context.ExecuteCommandBuffer(cmd);
    CommandBufferPool.Release(cmd);
}添加和执行pass

添加pass:EnqueuePass方法。在URP中,setup的添加URP实现的pass。renderfeature里面也会加入相应的pass
public void EnqueuePass(ScriptableRenderPass pass)
{
    m_ActiveRenderPassQueue.Add(pass);
    if (disableNativeRenderPassInFeatures) pass.useNativeRenderPass = false;
}用到的pass会存储m_ActiveRenderPassQueue,然后Execute方法中会new一个RenderBlocks,来组织pass。


执行pass:ExecuteBlock->ExecuteRenderPass
void ExecuteRenderPass(ScriptableRenderContext context, ScriptableRenderPass renderPass,
            ref RenderingData renderingData)
{
    ref CameraData cameraData = ref renderingData.cameraData;
    CommandBuffer cmd = CommandBufferPool.Get();

    //调用pass的Configure,进行一些配置,如attachment
    renderPass.Configure(cmd, cameraData.cameraTargetDescriptor);

    //配置color,depth RT,里面调用的是SetRenderTarget->CoreUtils.SetRenderTarget
    SetRenderPassAttachments(cmd, renderPass, ref cameraData);
    context.ExecuteCommandBuffer(cmd);
    CommandBufferPool.Release(cmd);

    //执行pass
    renderPass.Execute(context, ref renderingData);
}pass相关



ScriptableRenderPass是一个abstract class,一个pass实现需要继承它并且实现具体逻辑。 从构造函数,可以知道相关渲染数据:
public ScriptableRenderPass()
{
    renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
    //颜色缓冲
    m_ColorAttachments = new RenderTargetIdentifier[] { BuiltinRenderTextureType.CameraTarget, 0, 0, 0, 0, 0, 0, 0 };
    m_InputAttachments = new RenderTargetIdentifier[] { -1, -1, -1, -1, -1, -1, -1, -1 };
    m_InputAttachmentIsTransient = new bool[] { false, false, false, false, false, false, false, false };
    //深度缓冲
    m_DepthAttachment = BuiltinRenderTextureType.CameraTarget;
    m_ColorStoreActions = new RenderBufferStoreAction[] { RenderBufferStoreAction.Store, 0, 0, 0, 0, 0, 0, 0 };
    m_DepthStoreAction = RenderBufferStoreAction.Store;
    m_OverriddenColorStoreActions = new bool[] { false, false, false, false, false, false, false, false };
    m_OverriddenDepthStoreAction = false;
    //缓冲清理标记,Color, Depth,Stencil
    m_ClearFlag = ClearFlag.None;
    m_ClearColor = Color.black;
    overrideCameraTarget = false;
    isBlitRenderPass = false;
    profilingSampler = new ProfilingSampler($"Unnamed_{nameof(ScriptableRenderPass)}");
    useNativeRenderPass = true;
    renderTargetWidth = -1;
    renderTargetHeight = -1;
    renderTargetSampleCount = -1;
    renderPassQueueIndex = -1;
    renderTargetFormat = new GraphicsFormat[]
    {
        GraphicsFormat.None, GraphicsFormat.None, GraphicsFormat.None,
        GraphicsFormat.None, GraphicsFormat.None, GraphicsFormat.None, GraphicsFormat.None, GraphicsFormat.None
    };
    depthOnly = false;
}方法:


  • ConfigureInput

    • 配置input(None,Depth,Normal,Color,Motion)

  • ConfigureTarget

    • 配置当前pass的render targets,如ColorAttachment、DepthAttachment

  • ConfigureClear

    • 配置clearFlag和clearColor

  • OnCameraSetup (虚函数)

    • 渲染一个camera之前的回调

  • Configure (虚函数)

    • 定制pass可以自定义里面的configure逻辑

  • OnCameraCleanup (虚函数)

    • 事件回调

  • OnFinishCameraStackRendering (虚函数)

    • 事件回调

  • Execute (抽象函数)

    • pass的execute逻辑

  • CreateDrawingSettings

    • 根据当前渲染状态创建绘制设置

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-16 14:41 , Processed in 0.089750 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表