找回密码
 立即注册
查看: 180|回复: 0

游戏开发技术--LOD自动降档(Lua)

[复制链接]
发表于 2024-7-15 18:23 | 显示全部楼层 |阅读模式
一、设计意图

在游戏开发过程中,凡是需要设计一些优化策略,以保证游戏的流畅体验。
LOD自动降档策略就是此中之一,当检测到帧率不达标的时候,可以自动触发画质档位的下降(或者其他优化方案),以保证帧率可以恢复达标的状态。
在游戏中,玩家可以按照需求选择是否开启此项优化功能。
二、设计思路

帧率检测方式:检测当前帧之前必然数量(CheckTotalCount)的游戏帧中,deltaTime超过某一阈值的帧数(DeltaTimeThreshold),若此帧数过高,超过设定数量(CheckFrameCount),则记为一次不达标。
例如,设定CheckTotalCount = 40,CheckFrameCount = 30,DeltaTimeThreshold = 0.05。
则按照策略,在某一检测帧之前的40帧内,如果有75%的帧与前一帧的间隔时间(dt)超过0.05秒,则可以把这40帧标识表记标帜为一次不达标的段。
若不达标的次数在监测范围内超过可容忍的次数, 则进行档位自适应调整。


三、实现方式

注意:代码中使用了本身实现的Update模块,可以对指定的Tick函数进行注册和注销,以实现游戏中的更新逻辑。有机会我会对此模块进行介绍,读者可以按照自身的情况实现本身的更新函数。
  1. --[[引入Update模块]]--
  2. local LuaUpdater = require ”Main/LuaUpdater”
  3. --[[相关配置]]--
  4. local DeltaTimeThreshold = 0.05 --检测达成降档的DT阈值
  5. local CheckTotalCount = 40; -- 当前帧之前,需要统计DT状态的帧数
  6. local CheckFrameCount = 30; -- 需要统计的帧数中,DT高于阈值的数量
  7. local FRFailTolerateTimes = 3;   -- 帧率检测到不达标的容忍次数
  8. local TotalCheckTick = 3000; -- 持续检测帧率的最大次数
  9. --[[定义变量]]--
  10. local OptimizeController = {}
  11. local private =
  12. {
  13.     --bool队列,统计当前帧前CheckTotalCount个帧是否为不达标的帧
  14.     reachQueue = { head = 1, tail = 1, size = 0, capacity = CheckTotalCount, array = {}, },
  15.     --计时队列,统计不达标段的记录时间(帧号)
  16.     frFailTickQueue = { head = 1, tail = 1, size = 0, capacity = FRFailTolerateTimes, array = {}, },
  17.     reachCount = 0, --统计不达标的帧数
  18.     frameCheckTick = 0, --更新函数的计时(帧号)
  19. }
  20. --[[外部接口,开启或封锁]]--
  21. function OptimizeController.EnableAdaptiveLOD(enable)
  22.     if enable then
  23.         private.StartFrameCheck()
  24.     else
  25.         private.StopFrameCheck()
  26.     end
  27. end
  28. --[[内部实现]]--
  29. function private.StartFrameCheck()
  30.     --开启更新
  31.     LuaUpdater.StartRealTimeUpdate(private.Tick)
  32.     --重置变量
  33.     private.ClearQueue(private.reachQueue)
  34.     private.ClearQueue(private.frFailTickQueue)
  35.     private.reachCount = 0
  36.     private.frameCheckTick = 0
  37. end
  38. function private.StopFrameCheck()
  39.     --封锁更新
  40.     LuaUpdater.StopRealTimeUpdate(private.Tick)
  41. end
  42. function private.Tick(deltaTime)
  43.     private.frameCheckTick = private.frameCheckTick + 1
  44.     --如果队列满了,需要出队
  45.     if private.reachQueue.size == CheckTotalCount then
  46.         if private.Dequeue(private.reachQueue) then
  47.             private.reachCount = private.reachCount - 1
  48.         end
  49.     end
  50.     local reach = deltaTime >= DeltaTimeThreshold
  51.     private.Enqueue(private.reachQueue, reach) --记录是否达标的状态,reach == true 代表不达标
  52.     if not reach then
  53.         --当前帧如果没有呈现未达标的情况,可以跳出
  54.         return
  55.     end
  56.     private.reachCount = private.reachCount + 1
  57.     if private.reachCount < CheckFrameCount then
  58.         --还未达到帧率不达标的情况,可以跳出
  59.         return
  60.     end
  61.    
  62.     --已经触发不达标段的计数,可以从头进行统计了
  63.     private.ClearQueue(private.reachQueue)
  64.     private.reachCount = 0
  65.     --判断此次触发是否咋在统计的时间范围内
  66.     if private.frFailTickQueue.size == FRFailTolerateTimes
  67.         and private.frameCheckTick - private.Dequeue(private.frFailTickQueue) < TotalCheckTick then
  68.         private.ClearQueue(private.frFailTickQueue)
  69.         private.frameCheckTick = 0
  70.         --[[
  71.             此处调用本身项目内实现的挡位调节方式
  72.         ]]--
  73.     else
  74.         private.Enqueue(private.frFailTickQueue, private.frameCheckTick)
  75.     end
  76. end
  77. --[[队列操作]]--
  78. function private.Enqueue(queue,item)
  79.     if queue.size == queue.capacity then
  80.         return
  81.     end
  82.     queue.array[queue.tail] = item
  83.     queue.tail = queue.tail % queue.capacity  + 1
  84.     queue.size = queue.size + 1
  85. end
  86. function private.Dequeue(queue)
  87.     if queue.size <= 0 then
  88.         return nil
  89.     end
  90.     local item = queue.array[queue.head]
  91.     queue.array[queue.head] = nil
  92.     queue.head = queue.head % queue.capacity + 1
  93.     queue.size = queue.size - 1
  94.     return item
  95. end
  96. function private.ClearQueue(queue)
  97.     table.clearArray(queue.array)
  98.     queue.head = 1
  99.     queue.tail = 1
  100.     queue.size = 0
  101. end
  102. return OptimizeController
复制代码
可以直接Require此模块进行使用
  1. local ctrl = require ”OptimizeController”
  2. ctrl.EnableAdaptiveLOD(true)   --开启功能
  3. ctrl.EnableAdaptiveLOD(false)  --封锁功能
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-21 21:15 , Processed in 0.124829 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表