🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:🍕 Collection与数据结构 (91平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀Java EE(94平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
目录
- 1. 问题描述与引入
- 2. 画面帧数与帧率
- 2.1 画面是怎么"动起来的"
- 2.2 帧数与帧率
- 2.2.1 帧数
- 2.2.2 帧率
- 3. 写时拷贝原理与线程安全问题
- 3.1 显卡渲染画面原理
- 3.2 线程安全问题
1. 问题描述与引入
最近有好多玩家反馈,《无畏契约》这款国民枪战游戏,在镜头移动加快或者是镜头距离拉近的时候,画面会出现一种"撕裂感".就像老式电视机那种感觉,当然,许多玩家在出现这种问题的第一反应就是:是否是显卡出了什么问题,或者是游戏画面帧数太低.但是有的玩家即使调好了所有的配置,画面还是会出现这种"撕裂感".
那么"出现画面撕裂感"这其中的背后原理是什么呢?下面我们来分析这个问题.
2. 画面帧数与帧率
2.1 画面是怎么"动起来的"
- 原因1: 动态的画面是由好多张图片组成的.
其实我们在平时看到的动态画面是由好多张图片组成的,计算机就会连续展示这些图片,只不过这些图片结合地太紧密,我们人类感觉就是动态的.其次,平时经常打游戏的同学都会有"帧数"这个概念.当我们游戏画面出现卡顿的时候,我们经常会把游戏画面帧数调高.比如从90Hz调整到144Hz.但是我们平时玩家对所谓"帧数"的叫法是不准确的,这些数字准确来说,==应该叫"帧率"==那么什么又是帧率,什么又是帧数呢?后续介绍. - 原因2:人眼视觉残留
这样的说法现存两种:(以下内容来自百度百科)
【说法1】是因为人眼的视觉残留特性:是光对视网膜所产生的视觉在光停止作用后,仍保留一段时间的现象,其具体应用是电影的拍摄和放映。原因是由视神经元的反应速度造成的。其时值是二十四分之一秒。是动画、电影等视觉媒体形成和传播的根据。
【说法2】当物体在快速运动时, 当人眼所看到的影像消失后,人眼仍能继续保留其影像1/24秒左右的图像,这种现象被称为视觉暂留现象。是人眼具有的一种性质。人眼观看物体时,成像于视网膜上,并由视神经输入人脑,感觉到物体的像。但当物体移去时,视神经对物体的印象不会立即消失,而要延续1/24秒左右的时间,人眼的这种性质被称为“眼睛的视觉暂留”。
2.2 帧数与帧率
2.2.1 帧数
下面是来自百度百科对帧数的定义:
帧数(Frames),为帧生成数量的简称。由于口语习惯,我们通常将帧数与帧率混淆。
通俗地来将,其实就是计算机在一定时间内所要展示的图片总数,这些图片之间有着略微的变化,所以就可以形成动态的画面.
2.2.2 帧率
首先,我们不应该把帧数和帧率的概念混淆,它们两个之间的关系就像速度与路程之间的关系.
我们知道,速率(Speed)=距离(Distance)/时间(Time),单位为米每秒(m/s, meterspersecond, mps);
同理,帧率(Frame rate)=帧数(Frames)/时间(Time),单位为帧每秒(f/s, frames per second, fps)。
也就是说,如果一个动画的帧率恒定为60帧每秒(fps),那么它在一秒钟内的帧数为60帧,两秒钟内的帧数为120帧。
上面的一段话通俗来讲,就是我们平时说的90Hz,144Hz,就是计算机在一秒钟之内,所要展示的图片有几张.帧率越高,画面之间的衔接越流畅,反之越卡顿.
3. 写时拷贝原理与线程安全问题
那么为什么游戏会出现"撕裂感",继承我们上面"帧率"的说法,也就是会出现"掉帧"这样的现象.
其实这设计到了一种数据结构上的操作,就是"写时拷贝".
这个问题我们在之前谈到过.
https://blog.csdn.net/2301_80050796/article/details/138542361?spm=1001.2014.3001.5501
- 使用CopyOnWriteArrayList.
CopyOnWrite即写时拷贝容器.
如果我们想要修改一个容器中的值的时候,如果直接进行修改,比如想要修改两个数据,一个线程刚好修改完第一个数据的时候,有第二个线程想要来读取修改后的数据,这时候就读到的是一种"中间结果",不够准确.
这时候就需要引入写时拷贝容器:
- 当我们往一个容器中添加或者修改数据的时候,不直接修改当前容器,而是先拷贝当前容器,之后在复制出的容器中进行修改.
- 在修改完成之后,将原容器的引用指向修改后的容器.
这样如果在有线程去读取数据的时候,如果修改未完成的时候,读取的就是原容器的数据,修改完成之后,就是读取新容器的数据了.所以CopyOnWrite容器采用的便是读写分离思想.举例说明:不停机更新
在我们玩一个游戏,比如王者荣耀的时候,经常会出现不停机更新这样的现象.在更新的时候,并不会影响用户的游戏体验,在一场游戏结束之后,自动获取游戏更新内容.
3.1 显卡渲染画面原理
显卡在渲染图像的时候,就会采用"写时拷贝"原理,当在显示器上显示一个画面的时候,在显卡背后额外的空间中,生成下一个画面,这时候其实就是采用了读写分离的思想,显示器在读取画面,而在显卡中额外的空间又会重新渲染另一个画面.之后显示器在显卡渲染完成另一个画面的时候,又会读取下一个画面.
3.2 线程安全问题
上面的操作是在显卡的背后去渲染下一个要展示的画面.如果说我们不这样做, 我们直接在 上一个画面的基础上直接修改画面,此时线程就会出现"撕裂感",也就是说,在显示器(线程1)在读取显卡中渲染的画面的时候,显卡(线程2)在此时对显示器正在读取的画面进行了修改,这时候就会造成显示器(线程1)读出的结果不够准确,画面出现了"撕裂感".