Unity에서 Time.time이 매우 커지면 어떻게 되나요? 프레임의 시작

여기 에 말했듯 :

시간

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

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



답변

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

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

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

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

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

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

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

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


답변

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

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


답변

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

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는 정밀도가 떨어질 위험이 있습니다.


답변

다른 답변은 추측 만하 기 때문에 간단한 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 시간 동안 게임을하지 않기 때문에 문제를 해결하기 위해 돈을 투자하면 가상의 며칠간의 연속 재생 시간이 경제적으로 불가능한 후에 만 ​​사람들이 알 수 있습니다. 불행히도 나는 몇 가지 중요한 단점을 겪지 않고 문제 전체를 해결하는 간단한 보편적 인 해결 방법을 제시 할 수 없습니다.


답변