格格她爹讲程序---用传统程序员的方式玩UE4(三)

xiaoxiao2021-02-27  337

格格她爹讲程序---用传统程序员的方式玩UE4(三)

 

最近经常有人问我,什么时候出下一章,我觉得还是很高兴的,至少我写的东西得到了认可,但是我也要向大家说明一下,毕竟我现在还有工作,平时工作很忙,所以只能通过闲暇的时间来写,上次的两篇就是在出差的高铁上完成的。

上一章的一个典型应用其实只是为了让大家尽快出点“成绩”,好对UE4的代码开发有点兴趣,这次我们继续回到正规,先从UE4的基本渲染说起。

在第一章里我们也讲过了,渲染是显示平台的核心,所以渲染的代码肯定在Source\Runtime中,在这个接近核心的模块中,比较重要的内容包括三大类:渲染模块(比方RenderCore和Renderer)、RHI抽象层和RHI实现层(比方Windows里的D3D11RHI和Apple里的MetalRHI)。

RHI即Render hardware interface,一般翻译为渲染硬件层接口,目的是想做一套与硬件无关与平台无关的接口。这个概念虽然听起来很高大尚,但是不是UE4专用的,至少我知道OSG里就有GraphicsWindowsX11和GraphicsWindowsIOS等类.

UE4相对来说做的更彻底。它在平台无关之上,还想做到硬件无关,它的接口类里,其实就是几个简单的虚函数,平台运行的时候,会自动判断在哪个平台上,从而决定是调用DX11的实现,还是调用OpenGL的实现。

当然,为了具备有前瞻性,UE4还实现了Vulkan的接口,有兴趣的可以看看,所说实现的还不错,反正我是看不懂这么有技术含量的东西。

要想跟踪渲染流程,最好的办法是找到Tick()函数,在Runtime\Launch\Private中有个LaunchEngineLoop.cpp文件,LaunchEngineLoop.cpp中有一个FEngineLoop::Tick()函数。找到这个函数,可能不太容易,方法有三种:第一种连猜带蒙。第二种从网上先查资料。第三种,从初始化函数跟过来。

在这个函数中下个断点,只要程序运行起来,这是必进的,而且,不取消断点,基本上跑不动。所以,这里我们肯定发现在了正确的函数。

这个函数做了很多的事。如果想认真学习UE4,我希望大家把这个函数至少看完一遍。

这个函数其实做了很多事,首先,进行心跳帧同步,然后进行各种检测,比方不能在加载动画文件的时候进行,或者不能在基准模式下(benchmark mode)操作。

接下来,做的内容就是比较实在了。

 

然后才开始真正的处理,在这之前,调用了AdvanceFrame函数,总之,搞得特别正式,接下来,和大家说,我要处理新的一帧了,在这之前还要调用计算外部的FPS/MS的平均值,然后做些预处理的任务。

ENQUEUE_UNIQUE_RENDER_COMMAND,这个宏要注意一下,因为,和真正渲染的宏ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER,是同一类的,有兴趣的话,进去看看,这个宏写的很怪异。

接下来,还防止程序有事没事的跑一帧两帧的。

然后,就是增加外部回调了。把这些事做完。到了GEngine的Tick函数处。这里也算是接近“更核心”的地方了。

接下来又是一层保护。

再接下来是两个重要的步骤,一个是Shader管理,一个是任务同步管理。 再接下来是从属应用的管理,其实是辅助程序的管理。

再接下来是两个宏,由于是宏,所以,有可能被注释掉,所以肯定不是主线,从字面上看,就是从此是自动控制器,一个是自动操作器。

接下来,就是我们上面讲了半天的RHI,在我的电脑上,跟进去,就是FD3D11DynamicRHI,可见,我上面说的,有一定道理。

再接下来是帧统计,这里有一个甩掉前六帧的统计用法,官方给出的理由是加载时间忽略。

接下来就是清理无效的objects了。

再接下琰,我们又看到了ENQUEUE_UNIQUE_RENDER_COMMAND,只不过,这里是EndFrame,和开始的那个对应(BeginFrame)。大家可以简单的理解为,在这两个宏之间的,才是一帧里真正要做的事。

再接下来就是统计了。对主流程没有什么太大作用。

跟踪完后,我们在这个函数的任意位置,加一个断点,再回过头来看一下,最终的入口在WinMain函数里。可见,在开头说的三种方法中,我应该大概似乎可能是用的第三种方法。

从这里再跟踪一步。到GuardedMain中,我们可以看到一个循环:

玩过任何一个三维平台的同志,应该都会很清楚,几乎所有平台的最根本渲染都是一个类似的循环。而这个循环,也是最基本的一个循环,在这里,我们可以认为,我们在主线程中。

我们都知道,当前流行的平台,不可能是单线程,那么其它线程入口都在哪呢?

想一下,我们在上面跟踪的时候,是不是重点强调了GEngine->Tick,我们从这里出发,继续找,一直走到FGraphEventRefConstructAndDispatchWhenReady

看到了没,又是这个系列宏ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER,由ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER来产生一个TGraphTask,从而驱动渲染线程。

走到这里,大概明白了吧。

可以说UE4的基础渲染其实很简单,缺省和OSG了、OGRE了什么的平台也差不了多少,一个 while,然后,一堆回调,再加上一些子线程。关键是我们想要什么,就找个点切入进去。

转载请注明原文地址: https://www.6miu.com/read-3836.html

最新回复(0)