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

该文章介绍了游戏开发中的帧率优化策略,特别是LOD(LevelofDetail)自动降档机制。当检测到帧率低于标准时,系统会降低画质以保证流畅体验。通过统计deltaTime超过阈值的帧数,当达到一定比例时启动降档。文章还提供了具体的实现方式,包括帧率检测、队列管理以及开启和关闭优化功能的接口。
摘要由CSDN通过智能技术生成

设计意图

在游戏开发过程中,通常需要设计一些优化策略,以保证游戏的流畅体验。

LOD自动降档策略就是其中之一,当检测到帧率不达标的时候,可以自动触发画质档位的下降(或者其他优化方案),以保证帧率可以恢复达标的状态。

在游戏中,玩家可以根据需求选择是否开启此项优化功能。

设计思路

帧率检测方法:检测当前帧之前一定数量(CheckTotalCount)的游戏帧中,deltaTime超过某一阈值的帧数(DeltaTimeThreshold),若此帧数过高,超过设定数量(CheckFrameCount),则记为一次不达标。

例如,设定CheckTotalCount = 40,CheckFrameCount = 30,DeltaTimeThreshold = 0.05。

则根据策略,在某一检测帧之前的40帧内,如果有75%的帧与前一帧的间隔时间(dt)超过0.05秒,则可以把这40帧标记为一次不达标的段。

若不达标的次数在监测范围内超过可容忍的次数, 则进行档位自适应调整。

实现方式

注意:代码中使用了自己实现的Update模块,可以对指定的Tick函数进行注册和注销,以实现游戏中的更新逻辑。有机会我会对此模块进行介绍,读者可以根据自身的情况实现自己的更新函数。

--[[引入Update模块]]--
local LuaUpdater = require "Main/LuaUpdater"

--[[相关配置]]--
local DeltaTimeThreshold = 0.05 --检测达成降档的DT阈值
local CheckTotalCount = 40; -- 当前帧之前,需要统计DT状态的帧数
local CheckFrameCount = 30; -- 需要统计的帧数中,DT高于阈值的数量
local FRFailTolerateTimes = 3;   -- 帧率检测到不达标的容忍次数
local TotalCheckTick = 3000; -- 连续检测帧率的最大次数

--[[定义变量]]--
local OptimizeController = {}
local private = 
{
    --bool队列,统计当前帧前CheckTotalCount个帧是否为不达标的帧
    reachQueue = { head = 1, tail = 1, size = 0, capacity = CheckTotalCount, array = {}, },
    --计时队列,统计不达标段的记录时间(帧号)
    frFailTickQueue = { head = 1, tail = 1, size = 0, capacity = FRFailTolerateTimes, array = {}, },
    reachCount = 0, --统计不达标的帧数
    frameCheckTick = 0, --更新函数的计时(帧号)
}

--[[外部接口,开启或关闭]]--
function OptimizeController.EnableAdaptiveLOD(enable)
    if enable then
        private.StartFrameCheck()
    else
        private.StopFrameCheck()
    end
end

--[[内部实现]]--
function private.StartFrameCheck()
    --开启更新
    LuaUpdater.StartRealTimeUpdate(private.Tick)
    --重置变量
    private.ClearQueue(private.reachQueue)
    private.ClearQueue(private.frFailTickQueue)
    private.reachCount = 0
    private.frameCheckTick = 0
end

function private.StopFrameCheck()
    --关闭更新
    LuaUpdater.StopRealTimeUpdate(private.Tick)
end

function private.Tick(deltaTime)
    private.frameCheckTick = private.frameCheckTick + 1

    --如果队列满了,需要出队
    if private.reachQueue.size == CheckTotalCount then
        if private.Dequeue(private.reachQueue) then
            private.reachCount = private.reachCount - 1
        end
    end

    local reach = deltaTime >= DeltaTimeThreshold
    private.Enqueue(private.reachQueue, reach) --记录是否达标的状态,reach == true 代表不达标
    if not reach then
        --当前帧如果没有出现未达标的情况,可以跳出
        return
    end

    private.reachCount = private.reachCount + 1
    if private.reachCount < CheckFrameCount then
        --还未达到帧率不达标的情况,可以跳出
        return
    end
    
    --已经触发不达标段的计数,可以重新进行统计了
    private.ClearQueue(private.reachQueue)
    private.reachCount = 0

    --判断此次触发是否咋在统计的时间范围内
    if private.frFailTickQueue.size == FRFailTolerateTimes 
        and private.frameCheckTick - private.Dequeue(private.frFailTickQueue) < TotalCheckTick then
        private.ClearQueue(private.frFailTickQueue)
        private.frameCheckTick = 0
        --[[
            此处调用自己项目内实现的挡位调节方法
        ]]--
    else
        private.Enqueue(private.frFailTickQueue, private.frameCheckTick)
    end
end

--[[队列操作]]--
function private.Enqueue(queue,item)
    if queue.size == queue.capacity then
        return
    end
    queue.array[queue.tail] = item
    queue.tail = queue.tail % queue.capacity  + 1
    queue.size = queue.size + 1
end

function private.Dequeue(queue)
    if queue.size <= 0 then
        return nil
    end
    local item = queue.array[queue.head]
    queue.array[queue.head] = nil
    queue.head = queue.head % queue.capacity + 1
    queue.size = queue.size - 1
    return item
end

function private.ClearQueue(queue)
    table.clearArray(queue.array)
    queue.head = 1
    queue.tail = 1
    queue.size = 0
end

return OptimizeController

 可以直接Require此模块进行使用

local ctrl = require "OptimizeController"
ctrl.EnableAdaptiveLOD(true)   --开启功能
ctrl.EnableAdaptiveLOD(false)  --关闭功能

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

留四行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值