Unity에서 Time.time이 매우 커지면 어떻게 되나요?


37

여기 에 말했듯 :

시간

이 프레임의 시작 시간입니다 (읽기 전용). 게임이 시작된 이후의 시간 (초)입니다.

그리고 내가 아는 것처럼 시간은 float에 저장됩니다. 그래서 제 질문은 시간의 가치가 매우 커지면 어떻게 될까요? 넘칠 수 있습니까? 정밀도가 떨어지고 버그가 발생합니까? 게임이 방금 중단됩니까?



5
@AlexandreVaillancourt "Time.time이 매우 커질 때 문제가 있습니까?"로 해석하면 유용한 질문이 있습니다. 문자 그대로 "오버플로"에만 집중하는 것과는 반대로 귀하의 의견을 반영하기 위해이 행을 따라 질문을 편집했습니다.
DMGregory

2
@DMGregory 그러나 질문에 대한 답변이 이미 접수되어 승인되었습니다. 편집 내용이 좀 더 늦게 유용한 질문을한다는 데 동의합니다.
MichaelHouse

수락 된 답변이 여전히 편집 된 버전에 대한 올바른 답변이되도록 편집 문구를 작성하려고했습니다. (결국 이미 정밀 문제에 대해 이야기하고 있습니다.) 롤백해도 공격하지 않습니다.
DMGregory

답변:


62

단 정밀도 부동 소수점을 사용하면 시간 정확도가 떨어질 위험이 있습니다 .

여전히 97 일 동안 가장 가까운 정확도를 유지합니다 . 그러나 게임에서 우리는 종종 프레임 지속 시간 순서의 정확성에 관심을 갖습니다.

초 단위의 단 정밀도 부동 시간 값은 약 9 시간 후에 밀리 초 정확도를 잃기 시작합니다 .

이미 한 번의 플레이 세션이나 직장 / 학교 또는 수면 중에 "AFK"로 게임을 떠나는 것은 불가능합니다. (이것이 게임을 테스트하는 일반적인 방법이 하룻밤 동안 게임을 실행하고 아침에 게임이 여전히 올바르게 작동하는지 확인하는 이유 중 하나입니다)

게임이 완전히 종료되지 않고 재생 세션간에 일시 중단되고 재개되는 최신 콘솔에서는 짧은 버스트로 재생할 때도 게임의 시각에서 "단일 세션"이 9 시간의 런타임을 초과하는 것이 예상치 못한 것은 아닙니다.

유니티 deltaTime가 고정밀 시간 소스에서 계산 되었다고 가정하면 , 다른 대답에서 Peter의 실험에 의해 계산되며 deltaTime프레임 스케일 타이밍 에 의존하는 것이 상대적으로 안전합니다 ( deltaTime값 을 합산하여 매우 긴 지속 시간을 누적하는 것에주의하십시오). 더 큰 플로트는 정통한 알고리즘으로 보상하더라도 정밀 손실을위한 고전적인 레시피입니다 .

fixedDeltaTime프레임마다 동적으로 변경하는 대신 설정 한 것과 동일한 값을 유지하기 때문에 고정 업데이트 에 타이밍에 민감한 동작을 추가하여 일관성을 더욱 강력하게 보장 할 수 있습니다. deltaTime이 메소드에서 적절한 고정 델타를 자동으로 반환합니다. 고정 및 프레임 업데이트간에 비트 주파수가있을 수 있지만 보간을 통해이를 매끄럽게 할 수 있습니다 .

피하고자하는 것은 하나의 타임 스탬프를 다른 타임 스탬프에서 빼서 계산 시간 입니다. 몇 시간의 플레이 후에는 치명적인 취소가 발생하여 달리기 초기보다 정확도가 떨어집니다. 타임 스탬프를 비교하는 사용자의 시스템에 중요하다면, 당신은 같은 다른 방법을 사용하여 자신 만의 고해상도 시간 값을 생성 할 수 있습니다 System.Diagnostics.Stopwatch대신 Time.time.


언리얼은 코드블루 프린트 모두에서 게임 시간을 단 정밀도 플로트로 노출하도록 선택합니다 . Unity에서와 마찬가지로 타임 스탬프를 사용하여 실시간으로 타임 스탬프를 사용하여 직접 시간을 조정할 수 있습니다. (Unreal의 타임 스탬프 유형은 32 비트 에포크를 기반으로한다는 점에 유의하십시오 ). 원하는 경우 Unreal의 C #에 대한 확장이 존재합니다.
DMGregory

[ms]의 경우, 약 16484-32768 밴드 주위의 정밀도를 잃기 시작합니다. 즉, 4h30min 후에 정밀도가 느슨해 질 수 있으며 9h 후에는 확실하게 신뢰할 수 없습니다.
xmedeko

기술적으로 4.5-9 시간 사이에 정밀도는 0.98 밀리 초 이내입니다. 오류가 1.00 밀리 초를 초과하는 지점에 플래그를 지정했습니다. 그러나 요점은 잘 이해됩니다. 정밀도는 계속 저하되므로 더 정밀한 코드는 더 일찍 잘못 작동하기 시작할 수 있습니다.
DMGregory

16

float의 최대 값은 3.40282347 * 10 ^ 38이며, 초 단위로 측정하면 10 ^ 31 년 (밀리 초 단위로 측정하면 10 ^ 28 년)과 같습니다. 날 믿어 넘치지 않아

나타날 수있는 유일한 것은 부정확성입니다. 그러나 단 정밀도 부동 소수점 숫자의 정확도는 7-8 자리입니다. 초 단위로 측정하면 약 194 일 동안 정확합니다. 밀리 초를 측정하면 4,5 시간 만 정확합니다. 따라서 필요한 정확도에 전적으로 달려 있으며 밀리 초 (정확하지 않을 수도 있음)까지 정확 해야하는 경우 다른 방법을 찾아야 할 수도 있습니다.


7
Wolfram Alpha 는 몇 년 동안 언급 할만한 가치가 있는지에 대한 어조 설정 아이디어를 제공합니다. 현재 우주의 나이보다 약 20 배 더 높습니다. 20 는 아니지만 현재 나이에 20 개가 더 있습니다.
doppelgreener

1
@ Draco18s unity가 deltaTime을 측정하는 방법에 따라 다르지만 각 프레임에 대해 특정 시점을 가져 와서 두 프레임을 빼면 대답이 정답이라고 가정합니다.
LukeG

7
이 답변은 전혀 옳지 않습니다. 실험을 실행할 수 있습니다. 루프에서 플로트를 하나씩 증가시킬 수 있습니다. 10 000 000에 도달하면 증가가 중지됩니다. 플로트를 처리 할 때 큰 숫자에 작은 숫자를 올바르게 추가 할 수 없기 때문입니다. 정답은 @DMGregory
Seagull

2
@Seagull 증분에 대해 쓰지 않습니다. float로 표현할 수있는 최대 수는 (약) 3,4 * 10 ^ 38이므로 엄격한 의미에서 오버플로를 배제합니다 (OP의 의미). 나는 왜 대답이 틀렸는 지 알 수 없습니까?
LukeG

2
@Seagull 나는 LukeG의 대답이 정확하다고 생각합니다 (편집의 개선 이전에도). 그의 대답과 광산은 다른 종류의 요구를 나타냅니다. FloG 정밀도와 제한 사례에 대해 괴롭히는 것을 좋아하지만 LukeG는 정확한 정밀도 요구에 중점을 두지 않고 문제를 좀 더 광범위하게 살펴 봅니다.
DMGregory

12

게임에 얼마나 많은 정밀도가 필요합니까?

32 비트 부동 소수점은 24 비트의 정밀도를 갖습니다. 즉, 시각 t에서 정밀도는 ± 2 -23 × t이다. (이것은 정확하지는 않지만 가깝고 정확한 세부 사항은 그리 흥미롭지 않습니다.)

  • 1ms 정밀도가 필요한 경우 1ms ÷ 2 -23 = 8400 s = 2h 20m 후에 32 비트 부동 소수점을 더 이상 사용할 수 없습니다. 대부분의 게임에는 1ms의 정밀도가 필요하지 않지만 음악 응용 프로그램에는 필요합니다.

  • 게임이 144Hz 모니터에서 실행되고 프레임 정확도가 높은 그래픽을 원한다면 1 ÷ 144 Hz ÷ 2 -23 = 58000 s = 16h 후에 32 비트 부동 소수점을 더 이상 사용할 수 없습니다. 16 시간은 게임을 실행하는 데 오랜 시간이 걸리지 만 상상할 수없는 것은 아닙니다. 비록 우리가 게임을 떠난 상태에서 잠을 자고 있다고해도 우리 중 상당수가 16 시간 동안 한 번의 스트레칭으로 게임을 운영했습니다. 이때 애니메이션 및 물리 업데이트는 144Hz 미만으로 줄어 듭니다.

Unity의 Time.deltaTime정밀도가 높은 시계에서 계산 된 경우 Unity를 사용하여 여전히 전체 정밀도를 얻을 수 있습니다. 이것이 사실인지 아닌지 모르겠습니다.

사이드 노트

Windows의 게임 및 기타 프로그램은 종종 GetTickCount()시간을 알아 내기 위해 사용 합니다. 32 비트 정수를 사용하여 밀리 초를 계산하기 때문에 컴퓨터를 오래 방치하면 약 50 일마다 랩핑됩니다. 50 일 만에 게임을한다면 많은 게임이 중단되거나 충돌하거나 이상한 행동을하게 될 것입니다.

Windows와 같은 정수 GetTickCount()는 오버플로의 위험이 있지만 Unity와 같은 수레 Time.time는 정밀도가 떨어질 위험이 있습니다.


10

다른 답변은 추측 만하 기 때문에 간단한 Unity 프로젝트를 작성하고 잠시 실행했습니다. 몇 시간 후 결과는 다음과 같습니다.

  • UnityEngine.Time.time정확도가 다소 빠릅니다. 예상대로, 4 시간 동안 게임을 실행 한 후에는 값이 1 밀리 초씩 증가하고 그 후에 부정확성이 증가합니다.
  • UnityEngine.Time.deltaTimeUnity가 몇 시간 동안 실행 된 후에도 초기 밀리 초 미만의 정확도를 유지합니다. 따라서 deltaTime플랫폼에 의존하는 고해상도 카운터 (일반적으로 10-1000 년 후에 오버플로 됨)에서 파생 된 것이 사실상 보장 됩니다. deltaTime일부 플랫폼에서는 여전히 정밀도를 잃을 위험 이 여전히 적습니다 .

시간의 부정확성은에 의존하는 모든 것에 대한 문제입니다 UnityEngine.Time.time. 하나의 특정 예는 회전 (예를 들어 풍차의 회전)인데, 이는 일반적으로를 기반으로 UnityEngine.Mathf.Sin(UnityEngine.Time.time*rotationSpeed)합니다. _Time셰이더의 애니메이션에 명시 적으로 사용되는 문제가 훨씬 더 많습니다 . 눈에 띄기 시작하기 전에 부정확성이 얼마나 높아야합니까? 20-30ms의 정확도 (2 일)는 문제를 알고주의를 기울이는 사람들이 알아볼 수있는 지점이어야합니다. 문제를 모르는 50-100ms (5-10 일)의 민감한 사람들이 문제를 파악하기 시작합니다. 200-300ms (20-30 일)에서 문제가 분명합니다.

지금까지 나는의 정확성을 테스트하지 않았습니다 _SinTime, _CosTime그리고 Unity_DeltaTime난 다음에 언급 할 수 있습니다.

이것은 테스트에 사용한 스크립트입니다. UI.Text요소에 첨부되어 있으며 프로젝트의 플레이어 설정을 사용하면 백그라운드에서 프로젝트를 실행할 수 있으며 품질 설정의 VSync는 매초마다 V 공백으로 설정됩니다.

public class Time : UnityEngine.MonoBehaviour {
    void Start () {
        LastTime = (double)UnityEngine.Time.time;
        StartTime =  System.DateTime.Now;
        LastPrintTime =  System.DateTime.Now;
    }
    double LastTime;
    System.DateTime StartTime;
    System.DateTime LastPrintTime;
    void Update () {
        double deltaTimeError = (double)UnityEngine.Time.deltaTime - ((double)UnityEngine.Time.time - LastTime);
        if (System.DateTime.Now - LastPrintTime  > System.TimeSpan.FromMilliseconds(1000))
        {
            GetComponent<UnityEngine.UI.Text>().text = "StartTime: " + StartTime.ToLongTimeString()
                + "\nCurrentTime: " + System.DateTime.Now.ToLongTimeString()
                + "\n\nTime.deltaTime: " + UnityEngine.Time.deltaTime.ToString("0.000000")
                + "\nTime.time - LastTime: " + ((float)(UnityEngine.Time.time - LastTime)).ToString("0.000000")
                + "\nAbsolute Error: " +  System.Math.Abs(deltaTimeError).ToString("0.000E0");
            LastPrintTime = System.DateTime.Now;
        }
        LastTime = UnityEngine.Time.time;       
    }
}

여기에 이미지 설명을 입력하십시오여기에 이미지 설명을 입력하십시오여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오

0.033203값 에 대해 궁금하다면 실제로 0.033203125이진 부동 소수점 표현이 있다고 확신합니다 00111101000010000000000000000000. 0가수 의 많은 것을 주목하십시오 .

해결 방법

대부분의 장르에는 해결 방법이 필요하지 않습니다. 대부분의 플레이어는 총 100 시간 동안 게임을하지 않기 때문에 문제를 해결하기 위해 돈을 투자하면 가상의 며칠간의 연속 재생 시간이 경제적으로 불가능한 후에 만 ​​사람들이 알 수 있습니다. 불행히도 나는 몇 가지 중요한 단점을 겪지 않고 문제 전체를 해결하는 간단한 보편적 인 해결 방법을 제시 할 수 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.