🌸個人主頁: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)讀出的結果不夠準確,畫面出現了"撕裂感".