You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MTKView中计算帧时间步长(deltatime)?

获取Metal中MTKView的帧时间差(DeltaTime)

推荐方案:使用CACurrentMediaTime()(跨平台兼容,精度足够)

这个API获取系统绝对实时时间,完全满足物理模拟对时间精度的要求。实现逻辑简单:在类中存储上一帧的时间戳,每次draw时计算当前时间与上一帧的差值,再更新时间戳。

Swift 代码示例

import MetalKit
import QuartzCore

class CustomMTKViewDelegate: NSObject, MTKViewDelegate {
    private var lastFrameTime: CFTimeInterval = 0.0
    
    func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {}
    
    func draw(in view: MTKView) {
        let currentTime = CACurrentMediaTime()
        var deltaTime: CFTimeInterval = 0.0
        
        if lastFrameTime != 0.0 {
            deltaTime = currentTime - lastFrameTime
        }
        lastFrameTime = currentTime
        
        // 用deltaTime执行物理模拟等逻辑
        print("DeltaTime: \(deltaTime)") // 60FPS时约0.0167,30FPS时约0.0333
    }
}

Objective-C 代码示例

#import <MetalKit/MetalKit.h>
#import <QuartzCore/QuartzCore.h>

@interface CustomMTKViewDelegate : NSObject <MTKViewDelegate>
@property (nonatomic, assign) CFTimeInterval lastFrameTime;
@end

@implementation CustomMTKViewDelegate

- (instancetype)init {
    self = [super init];
    if (self) {
        _lastFrameTime = 0.0;
    }
    return self;
}

- (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size {}

- (void)drawInMTKView:(MTKView *)view {
    CFTimeInterval currentTime = CACurrentMediaTime();
    CFTimeInterval deltaTime = 0.0;
    
    if (self.lastFrameTime != 0.0) {
        deltaTime = currentTime - self.lastFrameTime;
    }
    self.lastFrameTime = currentTime;
    
    // 用deltaTime执行物理模拟等逻辑
    NSLog(@"DeltaTime: %f", deltaTime);
}

@end

MTKView内部通过CADisplayLink(iOS)或CVDisplayLink(macOS)驱动渲染,可直接获取其时间戳计算差值:

Swift 代码示例

func draw(in view: MTKView) {
    guard let displayLink = view.displayLink else { return }
    let currentTime = displayLink.timestamp
    var deltaTime: CFTimeInterval = 0.0
    
    if lastFrameTime != 0.0 {
        deltaTime = currentTime - lastFrameTime
    }
    lastFrameTime = currentTime
    
    // 用deltaTime执行逻辑
}

你之前尝试的方法失效原因

  • 1/view.preferredFramesPerSecond:仅为理论帧率值,无法反映实际卡顿后的帧间隔波动,时间步长完全不准确。
  • clock():获取的是CPU占用时间而非系统实时时间,Metal渲染主要工作在GPU,CPU用时远小于实际帧间隔,因此差值错误。
  • buffer.gpuEndTime - buffer.gpuStartTime:该值是GPU执行当前帧的耗时,不是两帧之间的间隔,无几何渲染时GPU几乎无工作,数值极小,并非所需的timestep。

内容的提问来源于stack exchange,提问作者CPlus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 19:44:56