我目前正在写一篇关于游戏内摄影的试卷,在此过程中,我希望(简要)指出相机和截图之间的区别——但我对后者的技术方面知之甚少如此称职。我希望你们中的一些人可能知道?
换句话说,截图是如何工作的?它会“冻结”像素吗?是显卡还是它的驱动程序起作用?其他一些硬件或软件组件?
在摄影中,光线被传感器捕获,而计算机则通过屏幕发出光线 - 但我认为屏幕截图本身是在数据转换为像素之前发生的?
我目前正在写一篇关于游戏内摄影的试卷,在此过程中,我希望(简要)指出相机和截图之间的区别——但我对后者的技术方面知之甚少如此称职。我希望你们中的一些人可能知道?
换句话说,截图是如何工作的?它会“冻结”像素吗?是显卡还是它的驱动程序起作用?其他一些硬件或软件组件?
在摄影中,光线被传感器捕获,而计算机则通过屏幕发出光线 - 但我认为屏幕截图本身是在数据转换为像素之前发生的?
它发生在数据转换为物理像素(如果有的话)之前,但它发生在数据转换为像素值(即位图图像)之后。
例如,如果一个程序正在显示文本或矢量图形或 3D 视觉效果,则屏幕截图过程根本不关心这些,它只关心这些图形被渲染为位图后的结果图像。
但是,屏幕截图是直接从操作系统内存中截取的,或者最坏的情况是从 GPU 内存中读取的——它不是从实际的 VGA 或 HDMI 信号中捕获的。
取决于您要询问的操作系统。通常,核心图形系统(允许应用程序将窗口显示在屏幕上的系统,例如 Windows 上的 GDI 或 Linux 上的 X11)将在内存中保留屏幕上所有像素的副本(即帧缓冲区),以便它们可以在需要时再次发送到 GPU。因此,它只是为程序提供检索该副本的功能。
例如,在 Windows 上有GetDC()和GetWindowDC()函数。在 Linux 上,X11 系统有一些类似的方法,例如XGetImage()。这些只是给程序一个位图图像,它已经保存在系统 RAM 的某个地方,没有任何特殊的硬件参与。
(尽管在某些情况下,例如在 Linux 上使用 GNOME,窗口管理器实际上使用 GPU 来组成屏幕的内容——因此,为了制作屏幕截图,它实际上必须先将数据请求回 CPU。)
附带说明一下,帧缓冲区中的内容与实际显示的内容之间可能存在一些差异。例如,许多视频游戏会生成非常暗的屏幕截图,因为它们使用 GPU 的伽马校正功能来调整图像亮度,而这种校正仅在生成视频信号时作为最后一步应用 - 所以屏幕截图只会捕获未经校正的黑暗- 外观图像。(除非游戏实际上用自己的方式覆盖了整个 OS 截图功能。)
查看差异的一种方法是考虑两者的结果。
屏幕截图相当于计算机以数字形式拍摄全屏图像并将其保存为文件。以这种方式,基于监视器和显示适配器的能力,数字信息尽可能精确。如果您有支持 4K 的显卡和显示器,您的屏幕截图将是 4K 的完美细节。
另一方面,屏幕的相机快照是数字到模拟到数字的转换。第一个数字是来自显示适配器的上述信息。模拟部分是将光从显示器传输到您的眼睛和/或相机,而最终的数字是通过相机数字传感器将该光转换为数字。
与屏幕捕获相比,相机提供的图像质量会有很大差异。相机通过使“信号”以光的形式通过具有像差和损失的镜头,从而进一步降低了质量。
相机从光传感器读取数据并将该数据存储在 RAM 或其他存储中。在摄像机而不是静态摄像机的情况下,它不断地这样做。来自传感器的“原始”数据可能与显示设备所需的格式不兼容,例如 PC 显卡或相机上的 LCD,所以如果带有相机的设备需要显示相机看到的内容,需要从相机格式转换为显示设备格式。
屏幕截图是已存在于 RAM 中的数据的导出,这些数据被视频卡使用或最终用于显示设备。通常,此数据采用 PC 显卡或其他显示设备所需的格式。当它被捕获时,它必须从这种格式转换为众所周知的图像格式。
所以主要的区别是数据流之一:
相机 -> RAW 数据 -> 捕获(复制)到存储或 RAM -> 显示设备二进制格式 -> 显示设备视频 RAM -> 显示设备(如果相机看到的应该直接显示)
相机 -> RAW 数据 -> 捕获(复制)到临时存储或 RAM -> 从那里转换为 JPEG 等(如果相机看到的应该保存到文件中)
显示设备 -> 显示设备视频 RAM -> 显示设备二进制格式 -> 捕获(复制)到其他系统 RAM -> 从那里转换为 BMP、JPEG 等(将显示设备用于生成图片的文件保存到文件中)
前言:这个答案并不意味着完全回答这个问题(现有答案做得很好),但它只是一些概念背景,评论太长了。
软件工程的很大一部分归结为设计良好的抽象、系统边界,并将大问题分解为更小的简单模块,这些模块组合在一起形成整体解决方案。这是一个完美的例子。
操作系统在这里有两个广泛的组件:某种 GUI 渲染器,以及某种与其接口的输出机制。虽然实现细节可能不同,但从概念上讲它非常简单。视频屏幕只是一种输出设备,可能是最常见的一种,但不是唯一的一种。
远程桌面客户端是另一个。例如,Windows 的远程桌面功能可以让您登录到计算机上的会话,即使有人在物理上使用该计算机进行另一个会话。您会话的图形通过网络流式传输到您的计算机,而其他用户会话的图形正常显示在监视器上。
保存到文件(生成屏幕截图)只是另一种输出设备。
这里的美妙之处在于不需要任何单独的系统来渲染屏幕截图的 GUI,就像渲染屏幕的 GUI 一样。可以使用相同的渲染,但随后它与不同的输出系统(硬件屏幕/RDP/屏幕截图/屏幕录像机)接口。
理想情况下,像这样的系统的接口应该尽可能通用,这样很简单,任何实现都可以自行插入,而不需要太多复杂性。
但是,有时使界面复杂化可能会有所回报,因为它可以让您做更多的小众事情。例如:
Windows 的 RDP 不只是消耗屏幕的视频输出并将其流式传输,就好像它是 Twitch 直播一样。这使用了太多的带宽,发送了太多的冗余数据,并且具有更高的延迟。相反,RDP 传输绘图命令(例如,在 12 pt Helvetica 中的 px 200、200 处写入文本“Hello World!”),客户端使用该命令来重现 GUI。因此,必须有特殊的机制来拦截 GUI 绘图调用,然后再将它们发送到图形卡以像往常一样渲染(到硬件屏幕)。
macOS 的屏幕截图功能允许您对窗口进行屏幕截图,即使它被另一个窗口遮挡,或者具有显示下方内容的透明度。生成的屏幕截图不会被遮挡(您可以完整地看到它),也不会显示透明度下方的内容。这告诉我们,他们的 GUI 渲染系统的某些组件允许屏幕截图系统截取单个窗口的渲染输出,然后再将其与其他窗口合成以形成全屏的最终帧。
我还没有看到提到的一件事是“屏幕截图”并不总是当前帧的快照,或者根本不是“屏幕”的捕获。
您会看到,现代分辨率需要每秒多次将大量像素数据从图形处理器 (GPU) 传输到显示器。软件和硬件都发展到不传输重复信息,因此特别是 GPU 渲染的像素只发送到显示器,而不是 CPU,除非请求。
这样做的一个后果是,对于屏幕截图,像素数据通常必须“重建”,并且至少必须从 GPU 发送回 CPU,从按下的那一刻起,这两者都需要相当长的时间PrtScrn 按钮。
尽管如此,即使在负载较重的情况下,较新的 GPU 通常也可以从最近的帧中重建数据并将其发送回 CPU,但这样做的结果是屏幕截图可能略微过时。当您尝试流式传输/录制时,您会更加注意到这种延迟,在某些硬件上可能会超过一秒钟。
再一次,造成这种情况的原因是信息溢出;GPU 上的数以百万计的像素首先必须被重建/转换/压缩/其他,然后才能以合理的速度和 CPU 可以理解的格式传输到 CPU。
请记住,CPU 和 GPU 在执行此操作时必须进行通信并花时间互相等待,同时还必须执行其他操作。
我们早已远离直接将像素数据发送到显示器的时代,甚至根本不必担心发送像素数据(今天的软件正在发送纹理/模型/三角形,它可以用更少的信息传达相同的图片)。我们习惯了多个/可移动/可重叠/透明的窗口,但实际上有许多复杂的系统允许这种情况发生,每个系统都可能有自己的方式来获取具有不同细节级别的“屏幕截图”。我知道至少有 4 种在我的 Linux 机器上获取屏幕截图的方法,每种方法都有自己的优点和缺点。重要的是,这些方法中没有一个能真正保证它们准确地捕捉到屏幕上显示的内容。
有些系统可以毫无延迟地截取普通窗口,但不能在游戏或高负载下,有些系统可能会要求 GPU 截取每一帧,因此您可以获得您想要的完美截屏,即使您正在捕获的内容被遮挡,有些系统可以一次只能“截屏”一个窗口,而其他窗口则根本不支持实时截屏。
没有一个系统是相同的,但每个截图机制的一个共同点是它必须担心接收 1920x1080(或更多!)像素并将它们转换为图像文件而不会锁定整个计算机。为此,必须做出妥协,哪些相机不必处理。