2011-01-26 3 views
1

초당 표시 할 프레임이 200 개 있습니다. 프레임은 매우 단순하고 흑백이며 몇 줄 밖에 없습니다. 타이머가 애니메이션을 구동합니다. 목표는 대략 프레임을 재생하는 것입니다. 200 fps.Qt에서 OpenGL을 사용하여 애니메이션의 적절한 속도를 보장하려면 어떻게해야합니까?

Linux에서는 타이머를 5ms로 설정하고 모든 프레임 (즉 200fps)을 표시합니다. 잘 작동하지만 Win 7에서 실패합니다.

Win 7 (동일한 시스템)에서 타이머를 20ms로 설정하고 매 4 프레임 (50fps × 4 = 200)으로 표시해야했습니다. 나는이 마법의 숫자를 시행 착오로 발견했다.

적절한 속도로 애니메이션이 사용자 컴퓨터에서 적절한 속도로 재생되도록 보장하려면 어떻게해야합니까?

예를 들어 사용자의 컴퓨터가 30fps 또는 60fps 만 수행 할 수 있다면 어떻게해야합니까?

+0

실제로는 거의 200fps로 표시 할 수 없습니다. 대부분의 LCD는 현재 60hz로 표시됩니다. 애니메이션 데이터를 60fps로 샘플링 한 다음 거기에서부터 시작하십시오. – Olhovsky

답변

4

짧은 대답은 (일반적으로) 할 수 없다는 것입니다.

최상의 미학을 위해 대부분의 윈도우 시스템에는 기본적으로 "vsync"가 설정되어있어 화면 새로 고침이 모니터의 재생 빈도에서 이루어집니다. 구형 CRT 시절에는 하이 엔드 모니터로 75-90 Hz를 얻을 수 있었지만 오늘날의 LCD에서는 60 fps로 고정 될 가능성이 큽니다.

즉, 프로그램 적으로 VSync를 비활성화 할 수있는 OpenGL 확장 (확장명이 기억 나지 않는)이 있으며 드라이버 수준에서 자주 비활성화 할 수 있습니다. 그러나 사용자 정의 하드웨어를 사용하지 않아도 200fps로 전체 프레임을 표시 할 수는 없습니다.

미리 렌더링 된 이미지가 200fps로 표시되어야하는지, 처음부터 렌더링하고 200fps로 렌더링해야하는지에 대해서는 분명하지 않습니다. 이전의 경우 좋은 옵션은 각 60Hz 업데이트에서 표시 할 프레임을 결정하기 위해 타이머를 사용하고 그 값을 사용하여 미리 렌더링 된 두 프레임 사이를 선형 보간하는 것입니다. 후자라면, 나는 모션을 제어하기 위해 타이머를 사용하고 (또는 장면의 다이내믹이 무엇이든) 시간이 주어진 적절한 장면을 렌더링합니다. 더 빠른 하드웨어 또는 비활성화 된 VSYNC는 동일한 시간에 더 많은 프레임을 제공합니다 (따라서 더 부드러운 애니메이션, 찢어짐에 따라 달라짐). 그러나 장면은 적절한 속도로 진행됩니다.

희망이 있으면 도움이됩니다. 응용 프로그램에 대한 정보와 200fps 요구 사항의 출처에 대해 더 자세히 알려 주시면 더 나은 조언을 드릴 수 있습니다.

+0

감사합니다. :) 200fps를 달성 할 필요가 없습니다.실제 속도의 좋은 근사치 인 속도로 200Hz로 기록 된 모션을 재생해야합니다. 따라서 200fps가 필요합니다. 나는 그것들을 렌더링하는 것이 그렇게 간단한 프레임을 가지고있다. BTW, 어떻게 리눅스는 200 fps를 렌더링 할 수 있습니까? – Ali

+4

@Ali : 아, 제 생각에 프레임을 샘플링하거나 보간하고 싶습니다. Linux는 vsync를 비활성화하고 그 결과로 생존하는 (찢어짐) 것이 가장 좋습니다. 200fps에서 프레임 버퍼를 업데이트하는 것은 200fps로 표시하는 것과 다릅니다. 본질적으로 60Hz 스트로브를 통해 200Hz 장면을보고 있습니다. –

+0

설명 주셔서 감사합니다! – Ali

0

루프의 각 반복마다 1ms 동안 잠자기하고 어느 정도 시간이 경과했는지 확인하는 것도 한 가지 방법입니다.

목표 시간보다 길면 (200/초 = 1000/200 = 5ms) 프레임을 그립니다. 그렇지 않으면 루프의 다음 반복을 계속합니다.

예. 일부 의사 코드 :

target_time = 1000/200; // 200fps => 5ms target time. 
timer = new timer(); // Define a timer by whatever method is permitted in your 
        // implementation. 
while(){ 
    if(timer.elapsed_time < target_time){ 
     sleep(1); 
     continue; 
    } 

    timer.reset(); // Reset your timer to begin counting again. 

    do_your_draw_operations_here(); // Do some drawing. 

} 

이 방법은 사용자의 컴퓨터가 200fps 할 수없는 경우, 당신은 여전히 ​​가능한 한 빨리 이끌어 낼 수 있다는 장점을 가지고 있으며, 잠이 호출되지 않습니다.

+0

나는 이미 가능한 한 빨리 그립니다. 문제는 겉으로보기에는 200fps로 프레임을 재생하는 것입니다. 50fps로 4 프레임마다 그리기는 200fps입니다. 그러나 사용자의 머신이 초당 얼마나 많은 프레임을 그릴 수 있는지를 어떻게 알 수 있습니까? – Ali

+0

나는 당신이 원했던 것을 오해 한 것 같습니다. – Olhovsky

+0

200fps로 저장된 일부 원본 애니메이션이 있기 때문에 느리게 드로잉 할 때 프레임을 건너 뛰고 싶다는 소리가 들립니다. 그러나 직접 애니메이션을 생성하는 경우 프레임을 "건너 뛰는"것은 권장하지 않습니다. – Olhovsky

0

여기에서 고려해야 할 두 개의 완전히 독립적 인 요인 아마이 있습니다

  1. 사용자의 컴퓨터가 얼마나 빨리가?다음 프레임 그리기를 시작할 준비가 될 때까지 컴퓨터가 여전히 마지막 프레임을 처리하고 있기 때문에 목표 프레임 속도를 달성하지 못했을 수 있습니다.

  2. 사용중인 타이머의 해상도는 무엇입니까? 내 인상은 (비록 내가 이것을 뒷받침 할만한 증거는 없지만) Windows 운영체제의 타이머는 Linux의 타이머보다 훨씬 저조한 해상도를 제공한다는 것이다. 그래서 당신은 5mS의 수면을 요구할 수도 있고 대신 15mS의 수면을 취할 수도 있습니다.

추가 테스트를 통해이 두 시나리오 중 어느 것이 더 적절한 지 파악할 수 있습니다.

처리 능력이 부족한 경우 중간 프레임 표시 (지금 수행 중) 또는 영상 품질 저하 (화질 저하, 해상도 저하 또는 속도 향상에 도움이되는 기타 작업) .

타이머 해상도가 문제인 경우 대체 타이머 API를 볼 수 있습니다 (Windows API는 서로 다른 해상도를 가진 두 가지 타이머 기능을 제공하며 잘못된 것을 사용하고있을 수 있습니다). 타임 슬라이스 (Kdoto의 제안에서와 같이). 그러나 이전에 비해 훨씬 많은 처리 작업을 수행하기 때문에 실제로 성능이 저하 될 수 있습니다.이 방법으로 CPU 사용량이 급증 할 수 있습니다.

편집 : 당신이 코드에서 얻을 새로 고침 속도는 화면에 표시되는 실제 재생 속도와 매우 다를 수있다 :

드류 홀은 그의 대답에, 또 다른 사이트 전체가 여기에있다 언급으로. 그러나 출력 장치에 따라 달라지며 출력 하드웨어가 아닌 코드에 문제가있는 것처럼 들릴 것입니다.

+0

사용자의 컴퓨터가 너무 빨리 드로잉하는 경우에만 절전 호출이 이루어지기 때문에 내 솔루션은 상당한 처리 시간을 추가하지 않습니다. 정확한 타이머는 내 방법에도 필요하지 않습니다. – Olhovsky

+0

팁 주셔서 감사합니다! 1. 프레임은 너무 단순하여 오래된 기계조차도 적시에 렌더링 할 수 있어야합니다. 2. 그렇습니다. 타이머는 매우 신뢰할 수 없지만이 경우 타이머는 충분히 정확합니다. – Ali

2

나는 자연스러운 속도로 재생하려는 200Hz에서 샘플링 한 데이터를 이미 읽었습니다. 나는. 샘플링 된 데이터의 1 초는 1 초 동안 렌더링되어야한다.

첫 번째 : 렌더링 조정을 위해 타이머를 사용하지 마십시오. 제대로 작동하지 않을 수 있습니다. 대신 전체 렌더링주기 (v-sync 포함)가 소요되는 시간을 측정하고이를 통해 애니메이션 시간 카운터를 향상시켜야합니다. 이제 200Hz는 이미 아주 좋은 시간 분해능입니다. 따라서 데이터가 충분히 부드러 우면 전혀 보간 할 필요가 없습니다. 이와 같이 (의사 코드) :

objects[] # the objects, animated by the animation 
animation[] # steps of the animation, sampled at 200Hz 
ANIMATION_RATE = 1./200. # Of course this shouldn't be hardcoded, 
         # but loaded with the animation data 

animationStep = 0 

timeLastFrame = None 
drawGL(): 
    timeNow = now() # time in seconds with (at least) ms-accuracy 
    if timeLastFrame: 
     stepTime = timeNow - timeLastFrame 
    else: 
     stepTime = 0 

    animationStep = round(animationStep + stepTime * ANIMATION_RATE) 
    drawObjects(objects, animation[animationStep]) 

    timeLastFrame = timeNow 

렌더링이 화면 새로 고침 사이의 시간보다 훨씬 빠르다는 것입니다. 이 경우 중간 단계의 일부를 렌더링하여 모션 블러 효과를 얻을 수도 있습니다 (애니메이션 데이터를 사용하여 모션 벡터를 얻고 쉐이더에서 벡터 흐림 효과를 만들 수 있음)), 렌더 루프는 다음과 같이 보일 것입니다 :

drawGL(): 
    timeNow = now() # time in seconds with (at least) ms-accuracy 
    if timeLastFrame: 
     stepTime = timeNow - timeLastFrame 
    else: 
     stepTime = 0 

    timeRenderStart = now() 
    animationStep = round(animationStep + stepTime * ANIMATION_RATE) 
    drawObjects(objects, animation[animationStep]) 

    glFinish() # don't call SwapBuffers 
    timeRender = now() - timeRenderStart 

    setup_GL_for_motion_blur() 

    intermediates = floor(stepTime/timeRender) - 1 # subtract one to get some margin 
    backstep = ANIMATION_RATE * (stepTime/intermediates) 
    if intermediates > 0: 
     for i in 0 to intermediates: 
      drawObjects(objects, animation[animationStep - i * backstep]) 

    timeLastFrame = timeNow 
+0

네, 다른 접근 방식입니다, 감사합니다! 하지만 내 경우에는 모션 블러 효과가 과도 할 것입니다 : 나는 두 줄로 구성된 간단한 흰색 막대기 그림을 가지고 있으며 배경은 검은 색입니다. – Ali

관련 문제