Unity引擎源码解析(伪) - 8 数据流的渲染流水线

由于Unity的渲染器十分复杂,整个渲染循环分支又多,所以本篇只关注渲染主线的数据流水线,即 网格数据流。

Unity的核心渲染组件是 MeshFilterMeshRenderer,前者给后者提供网格数据,后者是单个对象的渲染逻辑。

//在类初始化时自动调用
void MeshFilter::InitializeClass()
{
    RegisterAllowNameConversion(TypeOf<MeshFilter>()->GetName(), "m_LodMesh", "m_Mesh");
    REGISTER_MESSAGE_VOID(kDidAddComponent, OnDidAddMesh); //注册事件,当有组件添加时触发
}
void MeshFilter::OnDidAddMesh()
{
    AssignMeshToRenderer();
}
void MeshFilter::AssignMeshToRenderer()
{
    if (GetGameObjectPtr())
    {
        //当有网格组件添加时,就把网格设置过去
        MeshRenderer* renderer = QueryComponent<MeshRenderer>();
        if (renderer && renderer->GetSharedMesh() != m_Mesh)
            renderer->SetSharedMesh(m_Mesh);

        SendMessage(kMeshFilterChanged);
    }
}
//所以网格的源数据就存在 MeshRenderer 的 m_Mesh 这个字段中
void MeshRenderer::SetSharedMesh(PPtr<Mesh> mesh)
{
    SET_CACHED_SURFACE_AREA_DIRTY();
    m_Mesh = mesh; // PPtr<Mesh> m_Mesh;
    UpdateCachedMesh();
}
//又做了一次更新,将 m_Mesh 转存在了 m_CachedMesh 中
void MeshRenderer::UpdateCachedMesh()
{
    Mesh* mesh = m_Mesh;
    if (mesh != m_CachedMesh)
    {
        ...
        m_CachedMesh = mesh;
...
    UpdateLocalAABB();
}

MeshRenderer 中也有一个关键的初始化函数 InitializeClass

void MeshRenderer::InitializeClass()
{
    ...
    RegisterPrepareRenderNodesCallback(kRendererMesh, PrepareMeshRenderNodes<false>, PrepareMeshRenderNodes<true>);
    GetRendererUpdateManager().RegisterDispatchUpdate(kRendererMesh, TransformChangeSystemMask(0), DispatchUpdate, PrepareDispatchUpdate, PrepareSingleRendererUpdate, FinalizeUpdate);
}

template<bool kExecuteMultiThreaded>
static void PrepareMeshRenderNodes(RenderNodeQueuePrepareThreadContext& perThreadContext)

这里将 PrepareMeshRenderNodes 函数注册到了一个集中的位置,且类型是 kRendererMesh 这个枚举。这个函数至关重要,后面会讲。

渲染循环的入口点:

LRESULT CALLBACK PlayerMainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_ERASEBKGND:
            // do not erase background
            return 1;
        case WM_PAINT:
            // redraw screen only when we're paused
            if (gInitialized && (kPlayerPaused == GetPlayerPause()))
            {
                if (!g_ShowingSplashScreen)
                {
                    GfxDevice& device = GetGfxDevice();
                    device.BeginFrame();
                    if (device.IsValidState())
                    {
                        GetRenderManager().RenderOffscreenCameras();
                        GetRenderManager().RenderCameras();
#if ENABLE_UNITYGUI
                        GetGUIManager().Repaint(0);
#endif
                        Cursors::RenderSoftwareCursor();
                    }
                    device.EndFrame();
                    device.PresentFrame();
                }
                else
                {
                    DrawSplashScreen(!IsSplashScreenFadeComplete());
                }
            }
            ValidateRect(hWnd, NULL);
            return 0;
           ...
    }
    ...
    return DefWindowProcW(hWnd, message, wParam, lParam);
}

在 Windows 系统中渲染循环是在窗口消息 WM_PAINT 触发时执行的。其他的如 Android 或 IOS 各不相同,由各自系统决定。GetRenderManager() 返回的就是总的渲染管理器,它触发了两个渲染操作 RenderOffscreenCameras() 、RenderCameras(),光看名字就能猜到,一个从屏幕之外的相机渲染,一个是真正主屏幕相机。

那么什么事屏幕之外呢?查询 RenderManager 这个类发现两个成员变量 m_Cameras, m_OffScreenCameras

typedef std::list<PPtr<Camera>> CameraContainer;
CameraContainer m_Cameras, m_OffScreenCameras; //两组相机
//添加相机
void RenderManager::AddCamera(Camera *c)
{
    Assert(c != NULL);
    PPtr<Camera> cam(c);
    ...
    m_Cameras.remove(cam);
    m_OffScreenCameras.remove(cam);
    //判断相机是否有 TargetTexture 来选择加入哪一个相机组
    CameraContainer &queue = (c->GetTargetTexture() == NULL) ? m_Cameras : m_OffScreenCameras;
    ...
    queue.push_back(c);
}

在Unity中相机组件如果设置的有 TargetTexture 那么它就只渲染到该纹理中,不会渲染到屏幕上,这就是它为啥分开渲染的原因了。

接着回到正题 在函数 RenderManager::RenderCameras(...)

void RenderManager::RenderCameras(...)
{
    ...
    RendererScene& scene = GetRendererScene(); //渲染场景
    ...
    CameraStackArray cameraStacks;
    FindCameraStacks(m_Cameras, cameraStacks);
    while (currentRenderPass < totalRenderPasses)
    {
        ...
        // Render each camera stack
        for (size_t ist = 0, nst = cameraStacks.size(); ist != nst; ++ist)
        {
            const CameraStack& stack = cameraStacks[ist];
            CameraStackRenderingState stackState;
            m_CurrentCameraStackState = &stackState;
            stackState.BeginRenderingStack(stack, ist == 0);
            // Render each camera in the stack
            for (size_t icam = 0, ncam = stack.m_Cameras.size(); icam != ncam; ++icam)
            {
                Camera* cam = stack.m_Cameras[icam];
                if (!ShouldRenderScreenCamera(cam, displayId))
                    continue;

                PROFILER_AUTO_GFX(gCameraRenderManagerProfile, cam);
                scene.BeginCameraRender();//渲染场景做准备工作
                stackState.SetCurrentCamera(cam);
                m_CurrentCamera = cam;
                DoRenderScreenCamera(cam, preImageEffectsPerCameraCall, postImageEffectsPerCameraCall); //渲染
                scene.EndCameraRender();//进行剔除操作的时候会禁止修改渲染对象列表,将添加和移除操作进行缓存。这里将缓存的操作队列依次处理
            }
            ...
        }
        ...
    }
...
}

这里出现了一个重要类 RendererScene,所有拥有渲染组件的对象都会将自己关联到一个统一的地方,进行统一管理。

class MeshRenderer : public Renderer
//当组件设置为激活时触发
void Renderer::SetEnabled(bool newEnabled)
{
    if (m_Enabled == newEnabled)
        return;

    m_Enabled = newEnabled;
    SetDirty();
    UpdateRenderer();
}

class EXPORT_COREMODULE Renderer : public Unity::Component, public BaseRenderer

void Renderer::UpdateRenderer()
{
    bool shouldBeInScene = ShouldBeInScene();
    if (IsInScene() == shouldBeInScene)
        return;

    if (shouldBeInScene)
        AddToScene();
    else
        RemoveFromScene();
}
//将该组件添加进 RendererScene
void Renderer::AddToScene()
{
    Assert(!IsInScene());
    Assert(!IsVisibleInScene());
    RendererScene& scene = GetRendererScene();
    m_SceneHandle = scene.AddRenderer(this);
    ...
}

所以在渲染组件被激活时添加到 RendererScene 中,而失活时就又被移除。添加进场景的组件被处理成 SceneNode

dynamic_array<SceneNode> m_RendererNodes;

struct SceneNode
{
    ...
    BaseRenderer*   renderer; //渲染组件用基类存储
    UInt32          layer;
    ...
};

再回到渲染管理器中主线 DoRenderScreenCamera(cam, preImageEffectsPerCameraCall, postImageEffectsPerCameraCall);

static void DoRenderScreenCamera(Camera* cam, RenderManager::PostPerCameraFunctor preImageEffectsPerCameraCall, RenderManager::PostPerCameraFunctor postImageEffectsPerCameraCall)
{
    ...
    {
        CullResults cullResults;
        if (cam->GetEnabled())
        {
            cam->Cull(cullResults); //第一步 剔除
        }
        if (cam->GetEnabled())
        {
            ...
            //第二步 渲染
            cam->Render(cullResults, GetDefaultPassContext(), Camera::kRenderFlagSetRenderTarget, preImageEffectsPerCameraCall, postImageEffectsPerCameraCall);
        }
    }
...
}

剔除

在相机类中进行剔除,把结果存在 CullResults 中。剔除操作十分复杂,不在当前文章的讨论范围,这里只找几个关键的点:

void Camera::Cull(CullResults& results, CullingOptions cullingOptions)
{
    CameraCullingParameters parameters(*this, kCullFlagNeedsLighting | kCullFlagNeedsReflectionProbes | cullingOptions);
    if (GetUseOcclusionCulling())
        parameters.cullingOptions |= kCullFlagOcclusionCull;

    CustomCull(parameters, results);
}
void Camera::CustomCull(const CameraCullingParameters& parameters, CullResults& results, bool sendOnPreCullMessage)
{
    ...
    m_IsCulling = true;
    ...
    PrepareCullingParameters(parameters, CalculateRenderingPath(), results); //获取剔除参数
    ...
    //获取所有的渲染节点数据,会从 RendererScene 中拿到所有的可渲染的 SceneNode 集合
    PrepareCullingParametersRendererArrays(cullingCameraParameters.cameraProperties.coreCameraValues, results);
    //开始剔除
    CullScene(results);
    results.isValid = true;
    m_IsCulling = false;
}

CullResults 是整个流程的数据传递核心:

struct CullResults : public NonCopyable
{
    ...
    //剔除后的将要被用于渲染的信息
    CullingOutput           sceneCullingOutput;
    ...
    //保存要触发 OnWillRenderObject 函数的对象集合
    BaseRendererArray       needsCullCallback; //全部集中一起保存的
    BaseRendererArray       rendererCullCallbacks[kRendererTypeCount]; //按类型保存的
    
    //剔除前的保存的所有的参数,内部保存有从 RendererScene 获取到的 SceneNode 集合
    SceneCullingParameters sceneCullParameters; //如下
    ...
    SharedRendererScene* sharedRendererScene;

    const SharedRendererScene* GetOrCreateSharedRendererScene();
    void DestroySharedRendererScene();
    ...
};
struct SceneCullingParameters : CullingParameters
{
    ...
    //当前渲染场景的所有已经添加进来的节点,并非最后用于渲染的节点。用于剔除的输入参数
    RendererCullData *renderers; //如下
    int              totalRendererListsCount;
    ...
    int             renderPath; //渲染路径类型。前向渲染、延迟渲染 等
    ...
};
//场景渲染节点二次封装
struct RendererCullData
{
    const AABB*      bounds;
    const SceneNode* nodes;
    size_t           rendererCount;
};

渲染

现在通过渲染的网格数据去寻找整个渲染的一条线

void Camera::Render(CullResults& cullResults, ShaderPassContext& passContext, RenderFlag renderFlags, RenderManager::PostPerCameraFunctor preImageEffectsPerCameraCall, RenderManager::PostPerCameraFunctor postImageEffectsPerCameraCall)
{
    //往下走
    Render(cullResults, passContext, NULL, renderFlags, preImageEffectsPerCameraCall, postImageEffectsPerCameraCall);
}
void Camera::Render(CullResults& cullResults, ShaderPassContext& passContext, const CameraRenderingParams* params, RenderFlag renderFlags, RenderManager::PostPerCameraFunctor preImageEffectsPerCameraCall, RenderManager::PostPerCameraFunctor postImageEffectsPerCameraCall)
{
    //默认的渲染函数处理
    DefaultPerformRenderFunction& renderFunctionObj = DefaultPerformRenderFunction::Instance();
    //往下走
    CustomRender(cullResults, passContext, params, renderFlags, &renderFunctionObj, preImageEffectsPerCameraCall, postImageEffectsPerCameraCall);
}
void Camera::CustomRender(CullResults& cullResults, ShaderPassContext& passContext, const CameraRenderingParams* params, RenderFlag renderFlags, PerformRenderFunction* renderFunctionObj, RenderManager::PostPerCameraFunctor preImageEffectsPerCameraCall, RenderManager::PostPerCameraFunctor postImageEffectsPerCameraCall)
{
    ...
    //根据剔除后的数据,构造一个 SharedRendererScene 对象
    const SharedRendererScene* sharedRendererScene = cullResults.GetOrCreateSharedRendererScene();
    ...
    DoRender(cullResults, renderFlags, renderFunctionObj); //渲染所有的几何体
    ...
    CleanupAfterRendering(&cullResults);
}
《1》构造 SharedRendererScene

struct CullResults 内部有字段 SharedRendererScene* sharedRendererScene;

const SharedRendererScene* CullResults::GetOrCreateSharedRendererScene()
{
    PROFILER_AUTO(gCreateSharedRendererScene);
    __FAKEABLE_METHOD__(CullResults, GetOrCreateSharedRendererScene, ());
    if (sharedRendererScene == NULL)
    {
        CullResults& cullResults = *this;
        //new一个新的 SharedRendererScene
        sharedRendererScene = UNITY_NEW(SharedRendererScene, kMemTempJobAlloc)(kMemTempJobAlloc);
        //提取一个渲染队列用于后续的数据
        ExtractSceneRenderNodeQueue(cullResults, kDefaultSceneExtractionFlags, sharedRendererScene->queue);
        ...
    }
    return sharedRendererScene;
}
bool ExtractSceneRenderNodeQueue(const CullResults& cullResults, ExtractionFlags flags, RenderNodeQueue& outputQueue)
{
    JobBatchDispatcher dispatcher;
    const UInt32 customCullNodes = GetCustomCullResultNodeCount(cullResults.sceneCustomCullResults);
    RenderNodeQueuePrepareContext* context = BeginRenderQueueExtraction(outputQueue, cullResults.sceneCullingOutput, cullResults.sceneCullParameters.renderers, cullResults.sceneCullParameters.lodDataArrays, customCullNodes, flags, dispatcher);
    //往下走
    return EndRenderQueueExtraction(context, cullResults.sceneCustomCullResults, dispatcher);
}
bool EndRenderQueueExtraction(RenderNodeQueuePrepareContext* context, const dynamic_array<CustomCullResult*>& customCullResults, JobBatchDispatcher& dispatcher)
{
    ...
    QueuePrepareIntegrateMainThreadObjects(*context); //走
    ...
    return result && (outputQueueFinalSize != outputQueueInitialSize);
}
static void QueuePrepareIntegrateMainThreadObjects(RenderNodeQueuePrepareContext& sharedContext)
{
    PrepareRenderNodes* renderNodeCallbacks[kMaxRenderTypeCount];
    FillPrepareNodeCallbacks(renderNodeCallbacks, true); //获取各个渲染类型的回调
    int contextCount = sharedContext.perThreadContextCount;
    int maxObjectCount = sharedContext.outputQueue->GetRenderNodesCount();
    for (int i = 0; i < contextCount; i++)
    {
        RenderNodeQueuePrepareThreadContext& threadContext = sharedContext.perThreadContexts[i];
        threadContext.outputIndex = maxObjectCount;
        int objCount = threadContext.mainThreadObjects.size();
        for (int obj = 0; obj < objCount; obj++)
        {
            RenderNodeQueuePrepareThreadContext::MainThreadIntegrationInfo& objInfo = threadContext.mainThreadObjects[obj];
            ...
            while (threadContext.inputIndex < threadContext.visibleRenderers.size)
            {
                BaseRenderer* renderer = GetRendererAtIndex(threadContext, threadContext.inputIndex);
                RendererType type = renderer->GetRendererType();
                renderNodeCallbacks[type](threadContext); //执行各个渲染数据,获取每个渲染节点的包装数据
            }
        }
        maxObjectCount = threadContext.outputIndex;
    }
    sharedContext.outputQueue->SetRenderNodesCount(maxObjectCount);
}
//查找各个mesh组件中的回调
static void FillPrepareNodeCallbacks(PrepareRenderNodes** callbacks, bool runOnMainThread)
{
    for (UInt32 i = 0; i != kMaxRenderTypeCount; i++)
    {
        if (gRenderNodeCallbacks[i].prepareRenderNodesMainThread != NULL)
        {
            if (runOnMainThread)
                callbacks[i] = gRenderNodeCallbacks[i].prepareRenderNodesMainThread;
            else
                callbacks[i] = gRenderNodeCallbacks[i].prepareRenderNodesJob;
        }
        ...
    }
}

之前有提到在 MeshRenderer 初始化时注册了一个关键函数 PrepareMeshRenderNodes(...) 用于处理自己类型的网格数据,将 SceneNode 包装为 RenderNode

RenderNodeQueue 这个类型是用于存放 RenderNode 的集合,所以构造 SharedRendererScene 的最终目的是为了得到 RenderNodeQueue 这个可渲染的数据集。

template<bool kExecuteMultiThreaded>
static void PrepareMeshRenderNodes(RenderNodeQueuePrepareThreadContext& perThreadContext)
{
    const IndexList visibleList = perThreadContext.visibleRenderers;
    //关键位置,之前获取到的所有的场景节点
    const SceneNode* sceneNodes = perThreadContext.rendererCullData.nodes;
    ...
    //遍历场景节点
    for (; perThreadContext.inputIndex < visibleList.size; perThreadContext.inputIndex++)
    {
        UInt32 index = perThreadContext.inputIndex;
        int renderIndex = visibleList[index];
        const SceneNode& sceneNode = sceneNodes[renderIndex]; //单个场景节点
        MeshRenderer* renderer = static_cast<MeshRenderer*>(sceneNode.renderer);//得到渲染网格组件
        if (kRendererMesh != renderer->GetRendererType())
            break;
        if (sceneNode.disable)
            continue;
        //取到用于渲染的网格数据。
        //Mesh* GetMeshUsedForRendering() const { return m_CachedMesh; }
        //m_CachedMesh 就是之前处理过的的网格数据字段
        Mesh* mesh = renderer->GetMeshUsedForRendering();
        if (!mesh)
            continue;
        ...
        RenderNode& node = perThreadContext.outputNodes[outputIndex]; //取一个空的渲染节点
        renderer->CheckIsTransformInfoUpToDate(!kExecuteMultiThreaded);
        //填充一些数据
        Renderer::FlattenBasicData(*renderer, CalculateLODFade(lodDataArrays, sceneNode), sceneNode.lodIndexMask, allocator, node);
        ...
        node.smallMeshIndex = mesh->GetInternalMeshID();
        //rendererSpecificData 是处理后的网格数据
        node.rendererSpecificData = allocator.Allocate<MeshRenderingData>();
        MeshRenderingData& renderingData = *(MeshRenderingData*)node.rendererSpecificData;
        //填充网格数据 rendererSpecificData
        renderingData.Init(mesh, additionalVertexStreams, enlightenVertexStream);//跳转
        ...
        //关键位置,用于最终渲染的工具函数,存在渲染节点 node 中
        node.executeCallback = DrawUtil::DrawMeshRawFromNodeQueue;
        node.cleanupCallback = DrawUtil::CleanupDrawMeshRawFromNodeQueue;
        outputIndex++;
    }
    perThreadContext.outputIndex = outputIndex;
}
//网格数据填充
inline void MeshRenderingData::Init(Mesh* mesh, Mesh* additionalVertexStreamsMesh, Mesh* enlightenVertexStreamMesh)
{
    m_PrimaryMeshData = mesh->AcquireSharedMeshData(); //底层网格数据
    m_PrimaryVertexFormat = mesh->GetMeshVertexFormat();
    ...
}

接回上面的函数位置 FillPrepareNodeCallbacks() QueuePrepareIntegrateMainThreadObjects(...) 执行时就会触发 MeshRenderer 中的 PrepareMeshRenderNodes 函数。

获取两个关键数据 RenderNodeQueue 和 渲染工具函数 executeCallback

RenderNodeQueue 会存在 CullResults SharedRendererScene 的成员变量 RenderNodeQueue queue; 中。

《2》DoRender 渲染几何体
void Camera::DoRender(CullResults& cullResults, RenderFlag renderFlags, PerformRenderFunction* renderFunctionObj)
{
    ...
    PreMultiCustomRender(cullResults, renderFlags, true);//再做一个数据中转
    MultiCustomRender(cullResults, &renderFunctionObj, 1, true);
    PostMultiCustomRender(renderFlags, true);
}
void Camera::PreMultiCustomRender(CullResults& cullResults, RenderFlag renderFlags, bool bSkipMarkers /*= false*/)
{
    ...
    InitializeRenderLoopContext(this, *cullResults.sharedRendererScene, m_RenderLoop);
    ...
}
void InitializeRenderLoopContext(Camera* camera, const SharedRendererScene& rendererScene, RenderLoop* renderLoop)
{
    AssertMsg(renderLoop->m_Context == NULL, "Recursive initialization of the renderloop context. This will leak a lot of memory.");
    renderLoop->m_Context = UNITY_NEW(RenderLoopContext, kMemTempJobAlloc)(kMemTempJobAlloc);
    const_cast<SharedRendererScene&>(rendererScene).AddRef();
    renderLoop->m_Context->m_Camera = camera;
    renderLoop->m_Context->m_RenderLoop = renderLoop;
    renderLoop->m_Context->m_Scene = &rendererScene;
    renderLoop->m_Context->m_Queue = &rendererScene.queue; //关键数据 渲染数据集合
    renderLoop->m_Context->m_CommandBufferQueue = &rendererScene.commandBufferQueue;
    renderLoop->m_Context->m_TargetType = GetCurrentCameraStackState().GetTarget();
}

不得不承认 Unity 真是能弯弯绕啊,渲染之前还又拿了个 m_RenderLoop、m_Context 做个周转。Camera 在构建时就构造了 RenderLoop 用于渲染处理。

Camera::Camera(MemLabelId label, ObjectCreationMode mode)
{
    m_RenderLoop = CreateRenderLoop(*this);
    ...
}
struct RenderLoop
{
public:
    RenderLoop(Camera& camera);
    ~RenderLoop();
    void PrepareFrame(bool renderingShaderReplace);
public:
    RenderLoopContext*          m_Context;
    ImageFilters                m_ImageFilters;
};
struct RenderLoopContext : public ThreadSharedObject<RenderLoopContext>
{
    RenderLoopContext(MemLabelId memLabel);
    ~RenderLoopContext();
    Camera*         m_Camera;
    ShadowJobData   m_ShadowCullData;
    SceneCullingParameters m_ShadowSceneCullParameters;
    ...
    const SharedRendererScene*  m_Scene;
    const RenderNodeQueue*      m_Queue; //渲染节点集合
    ...
    RenderLoop*     m_RenderLoop;
};

所以下一步会将渲染逻辑移交到 RenderLoop 中做。

void Camera::MultiCustomRender(CullResults& cullResults, PerformRenderFunction* const* renderFunctionObjects, size_t count, bool bSkipMarkers /*= false*/)
{
    ...
    for (size_t i = 0; i < count; i++)
    {
#if ENABLE_ASSERTIONS
        if (renderFunctionObjects[i] == &DefaultPerformRenderFunction::Instance())
        {
            defaultRenderCount++;
        }
#endif
        (*renderFunctionObjects[i])(this, static_cast<RenderingPath>(cullResults.sceneCullParameters.renderPath), &cullResults);
    }
    ...
}

PerformRenderFunction* const* renderFunctionObjects 这里又根据传入的函数来做处理,查找内部默认的处理函数吧,回到前面

void Camera::Render(CullResults& cullResults, ShaderPassContext& passContext, const CameraRenderingParams* params, RenderFlag renderFlags, RenderManager::PostPerCameraFunctor preImageEffectsPerCameraCall, RenderManager::PostPerCameraFunctor postImageEffectsPerCameraCall)
{
    //默认的渲染函数处理
    DefaultPerformRenderFunction& renderFunctionObj = DefaultPerformRenderFunction::Instance();
    ...
}

class DefaultPerformRenderFunction : public PerformRenderFunction
{
public:
    virtual void operator()(Camera* camera, RenderingPath renderPath, CullResults* cullResults)
    {
        if (camera && cullResults)
            DoRenderLoop(*camera->m_RenderLoop, renderPath, *cullResults, *camera->m_ShadowCache); //渲染循环
    }
    ...
};
//渲染循环
void DoRenderLoop(
    RenderLoop& loop,
    RenderingPath renderPath,
    CullResults& cullResults,
    ShadowMapCache& shadowCache)
{
    ...
    {
        PROFILER_AUTO_GFX(gRenderOpaque, &camera);
        //根据渲染路径找到对应的渲染逻辑,暂且走 前向渲染路径的处理方式 DoForwardShaderRenderLoop
        if (renderPath == kRenderPathPrePass)
        {
            RenderObjectDataContainer remainingObjects(kMemTempAlloc);
            DoPrePassRenderLoop(*loop.m_Context, loop.m_Context->m_OpaqueObjects, remainingObjects, cullResults, rtDepth, rtDepthNormals, &prepassDepthWasCopied);
            RenderRemainingObjectsThatCantHandleDeferred(renderPath, *loop.m_Context, cullResults, prepassDepthWasCopied, rtDepth, rtDepthNormals, remainingObjects);
        }
        else if (renderPath == kRenderPathDeferred)
        {
            RenderObjectDataContainer remainingObjects(kMemTempJobAlloc);
            DoDeferredRenderLoop(*loop.m_Context, loop.m_Context->m_OpaqueObjects, remainingObjects, cullResults, rtDepth, rtDepthNormals, &prepassDepthWasCopied);
            RenderRemainingObjectsThatCantHandleDeferred(renderPath, *loop.m_Context, cullResults, prepassDepthWasCopied, rtDepth, rtDepthNormals, remainingObjects);
        }
        else
        {
            DoForwardShaderRenderLoop(*loop.m_Context, loop.m_Context->m_OpaqueObjects, cullResults, true, false, true);
        }
    }
    ...
}
void DoForwardShaderRenderLoop(
    const RenderLoopContext& ctx,
    RenderObjectDataContainer& objects,
    const CullResults& cullResults,
    bool opaque,
    bool disableDynamicBatching,
    bool clearFrameBuffer,
    Camera::RenderFlag cameraRenderFlag)
    {
        ...
        //渲染 走
        renderLoop->PerformRendering(renderPassDataSortFence, mainDirShadowLight, ctx.m_ShadowCullData, disableDynamicBatching, clearFrameBuffer, opaque, cameraRenderFlag);
    }

void ForwardShaderRenderLoop::PerformRendering(JobFence& renderPassDataSortFence, const ActiveLight* mainDirShadowLight, const ShadowJobData& shadowCullData, bool disableDynamicBatching, bool clearFrameBuffer, bool opaque, Camera::RenderFlag cameraRenderFlag)
{
    ...
    //开启渲染任务 走
    StartRenderJobs(renderPassDataSortFence, opaque, mixShadowMaskAndRealtimeShadow, defaultPassContext);
    ...
    CleanupAfterRendering();
}
void ForwardShaderRenderLoop::StartRenderJobs(JobFence& renderPassDataSortFence, bool opaque, bool mixShadowmaskAndRealtimeShadow, ShaderPassContext& passContext)
{
    ...
    //走
    device.ExecuteAsync(numJobs, ForwardRenderLoopJob, (GfxDeviceAsyncCommand::ArgScratch**)splitHeaders, this, assignProjectorQueueFence);
    ClearFenceWithoutSync(assignProjectorQueueFence);
    ...
}
static void ForwardRenderLoopJob(GfxDeviceAsyncCommand::ArgScratch* scratch, const GfxDeviceAsyncCommand::Arg* arg)
{
    ...
    const RenderNodeQueue& queue = *renderLoop.m_Context->m_Queue;
    RenderLoopStats stats;
    //这里又把 RenderNodeQueue 传进了 BatchRenderer 这个类中
    BatchRenderer batchRenderer(stats, queue, renderLoop.m_EnableDynamicBatching, renderLoop.m_EnableInstancing, false);
    ...
    //循环渲染单个节点
    for (size_t renderPassIndex = scratchHeader.startNode; renderPassIndex < scratchHeader.endNode; ++renderPassIndex)
    {
        ...
        const RenderNode& node = queue.GetNode(roDataH.nodeIndex);
        ...
        //渲染逻辑再次移交到 BatchRenderer 中
        batchRenderer.RenderSingleWithPass(
                        passContext,
                        rs.sharedMaterial,
                        rs.shader,
                        rs.pass,
                        rs.flags.subShaderIndex,
                        passIndex,
                        instance.nodeID,
                        instance.subsetIndex,
                        &renderLoop.m_GrabPasses,
                        hasBakedLightOcclusions && light.IsOcclusionSeparatelyBaked(),
                        kBatchBreakCauseMultipleForwardLights);
    }
    
    ...
}

BatchRenderer 一看就是进行合批处理的逻辑,不过它自然也兼顾普通渲染,合批处理方式又是另一个大内容,暂略过

BatchRenderer::BatchRenderer(RenderLoopStats& stats, const RenderNodeQueue& queue, bool dynamicBatchingEnabled, bool instancingEnabled, bool motionVectorLoop)
    : m_BatchInstances(kMemTempAlloc)
    ...
    , m_ActiveNodeQueue(queue) //渲染节点集合又转移给了 m_ActiveNodeQueue 字段
    ...
{
    m_ApplyInstanceProperty.Init(GetGfxDevice());
    m_BatchInstances.reserve(128);
}
void BatchRenderer::RenderSingleWithPass(
    ShaderPassContext& passContext,
    const SharedMaterialData* material,
    Shader* shader,
    ShaderLab::Pass* pass,
    int subshaderIndex,
    int passIndex,
    UInt32 nodeID, int subsetIndex,
    const ShaderLab::GrabPasses* grabPasses,
    bool useFwdShadowmaskSelector,
    BatchBreakCause cause)
{
    ...
    RenderBatch(&data, 1, vertexInput);
}
void BatchRenderer::RenderBatch(const BatchInstanceData* data, size_t instanceCount, VertexInputMasks vertexInput) const
{
    ...
    const RenderNode& node = m_ActiveNodeQueue.GetNode(data->nodeID);
    if (instanceCount == 1 && !m_InstancingBatcher.IsValid())
    {
        SetupObjectMatrix(node.rendererData.m_TransformInfo.worldMatrix, node.rendererData.m_TransformInfo.transformType);
        DebugAssert(node.executeCallback);
        //单个渲染节点的 渲染函数调用,还记得之前注册过的工具函数 executeCallback
        node.executeCallback(m_ActiveNodeQueue, data->nodeID, vertexInput, data->subsetIndex);
    }
    // 合批渲染方式 略过
    else
    {
        ...
        node.executeBatchedCallback(m_ActiveNodeQueue, batchData, vertexInput);
    }
}

接下来看看渲染的最后一步,工具函数的处理

void DrawUtil::DrawMeshRawFromNodeQueue(const RenderNodeQueue& queue, UInt32 nodeID, VertexInputMasks vertexInput, int submeshIndex)
{
    const RenderNode& node = queue.GetNode(nodeID); //获取当前节点
    const MeshRenderingData& data = *static_cast<const MeshRenderingData*>(node.rendererSpecificData); //获取网格数据
    GfxDevice& device = GetGfxDevice();
    VertexDeclaration* vertexDecl;
    DrawBuffersRange drawRange;
    MeshBuffers buffers;
    //将网格数据填充到 buffers 中
    if (!data.PrepareDraw(device, vertexInput, vertexDecl, buffers, drawRange, submeshIndex))
        return;
    ...
    //使用当前平台的图形接口进行渲染 走
    device.DrawBuffers(buffers.indexBuffer, buffers.vertexBuffers, buffers.vertexBufferCount, &drawRange, 1, vertexDecl);
    GPU_TIMESTAMP();
}
//OpenglES 渲染接口
void GfxDeviceGLES::DrawBuffers(GfxBuffer* indexBuf, UInt32 indexStride,
    GfxBuffer* const* vertexBufs, const UInt32* vertexStrides, int vertexStreamCount,
    const DrawBuffersRange* drawRanges, int drawRangeCount,
    VertexDeclaration* vertexDecl)
{
    ...
    BufferGLES* indexBuffer = static_cast<BufferGLES*>(indexBuf); //网格数据,即 顶点数据缓存
    indexStride = GetStride(indexBuf, indexStride);
#if GFX_SUPPORTS_SINGLE_PASS_STEREO
    m_SinglePassStereoSupport.DrawBuffersStereo(indexBuf, indexStride, vertexBufs, vertexStrides, vertexStreamCount, drawRanges, drawRangeCount, vertexDecl, vertexCount);
#else
    //走
    DrawBufferRanges(indexBuf, indexStride, vertexBufs, vertexStrides, vertexStreamCount, drawRanges, drawRangeCount, vertexDecl, vertexCount, 1);
#endif
    ...
}
//渲染
void GfxDeviceGLES::DrawBufferRanges(GfxBuffer* indexBuf, UInt32 indexStride,
    GfxBuffer* const* vertexBufs, const UInt32* vertexStrides, int vertexStreamCount,
    const DrawBuffersRange* drawRanges, int drawRangeCount,
    VertexDeclaration* vertexDecl, size_t vertexCount, int instanceMultiplier)
{
    VertexDeclarationGLES* vertexDeclaration = static_cast<VertexDeclarationGLES*>(vertexDecl);
    BufferGLES* indexBuffer = static_cast<BufferGLES*>(indexBuf);
    ...
    for (int r = 0; r < drawRangeCount; ++r)
    {
        ...
        if (indexBuffer != NULL)
        {
            //DrawCall 调用图形设备接口渲染。
            m_Api.BindElementArrayBuffer(indexBuffer->GetGLName());
            //内部就是简单封单封装的 基础图形接口 glDrawElements。 具体细节不展示了
            m_Api.DrawElements(range.topology, indexBuffer->GetBindPointer(range.firstIndexByte), range.indexCount, drawBaseVertex, instanceCount, indexStride);
        }
        else
        {
            m_Api.DrawArrays(range.topology, range.firstVertex, range.vertexCount, instanceCount);
        }
        ...
    }
}

至此按照网格的数据流顺藤摸瓜找到了一个完整的数据流向,这只是一个主线脉络,各种细节还有千千万,至少按照这个主线不至于迷路。

最后,做一个总结:

涉及到的关键类:

RenderManager、RendererScene、SceneNode、Camera、CullResults、RenderNode、RenderNodeQueue、RenderLoop、ForwardShaderRenderLoop、BatchRenderer

MeshFilter、MeshRenderer、Renderer

网格数据流的渲染流水线:

1、MeshRenderer 类初始化注册网格数据预处理函数,预处理函数包含 构造渲染节点逻辑,和平台渲染工具函数。

2、MeshRenderer 被激活时会加入到 RendererScene 场景中,包装成 SceneNode 节点。

3、渲染循环开始时会首先调用 RenderManager 中的相机渲染函数 RenderCameras() ,相机又分为 屏幕外相机(设置了TargetTexture属性的) 和 主相机(屏幕)。

4、 Camera 屏幕相机会调用两个步骤 剔除 和 渲染。

5、剔除会执行各种剔除算法 将可被渲染的 SceneNode 保存在交换数据 CullResults 中。

6、渲染开始的时候会将 CullResults 中的场景节点重新构造成 RenderNode 保存在 RenderNodeQueue 中,RenderNodeQueue 同时也存在 CullResults 中。内部调用的是之前在MeshRenderer中注册的网格预处理函数。(RenderNodeQueue 会往下传递)

7、渲染移交到下一步的 RenderLoop 中,内部会根据渲染路径找到对应的渲染逻辑,比如 前向渲染路径 会走到 ForwardShaderRenderLoop 中。(RenderNodeQueue 会往下传递)

8、再次移交到 BatchRenderer 合批处理中,内部会根据是否合批来执行不同的逻辑。如果是普通逻辑,会走之前MeshRenderer预处函数中注册的工具渲染函数 DrawUtil::DrawMeshRawFromNodeQueue

9、工具函数内部就会调用当前平台的图形设备接口,如 OpenGLES 的 GfxDeviceGLES,内部就会调用DrawCall函数 glDrawElements、glDrawArrays 等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值