문제

OpenGL/GLUT 창에 나만의 커서를 구현하고 싶습니다.이를 수행하는 일반적인 방법은 커서를 고정하고(화면 가장자리에 닿지 않도록) 위치를 직접 추적하는 것입니다.다음을 사용하여 화면 커서를 보이지 않게 만들 수 있습니다.

glutSetCursor(GLUT_CURSOR_NONE);

그런 다음 gluPassiveMotionFunc 콜백 내에서 다음을 사용하여 포인터를 창 중앙으로 이동합니다.

int centerX = (float)kWindowWidth / 2.0;
int centerY = (float)kWindowHeight / 2.0;

int deltaX = (x - centerX);
int deltaY = (y - centerY);

mouseX += deltaX / (float)kWindowWidth;
mouseY -= deltaY / (float)kWindowHeight;

glutWarpPointer( centerX, centerY );

이는 포인터를 창 중앙에 고정시키는 방식으로 작동합니다.문제는 'OpenGL' 마우스(glutDisplayFunc() 콜백 내부)를 그릴 때 매우 불안정하다는 것입니다.

온라인에서 살펴본 결과 lutWarpPointer()로 인해 lutPassiveMotionFunc 콜백이 다시 호출되어 루프가 발생하는 문제가 있을 수 있지만 여기서는 그런 일이 발생하지 않는 것 같습니다.

저는 Mac OS X를 사용하고 있는데 CGDisplayMoveCursorToPoint가 이에 더 적합하다는 게시물을 찾았습니다.CGDisplayMoveCursorToPoint를 호출하면 작동하지만 움직임이 여전히 매우 불안정합니다(그리고 x와 y가 모두 0인 이벤트가 많이 발생하는 것 같습니다).어쨌든 저는 이것이 Linux에서도 작동하기를 원하므로 Mac 전용 솔루션은 이상적이지 않습니다(그러나 다른 시스템에서 다른 작업을 수행하는 것은 괜찮습니다).

나는 이것을 테스트 케이스로 줄였습니다.

#include <stdio.h>
#include <OpenGL/OpenGL.h>
#include <GLUT/GLUT.h>

int curX = 0;
int curY = 0;

void display() {
    glClearColor( 0.0, 0.0, 0.0, 1.0 );
    glClear( GL_COLOR_BUFFER_BIT );

    float vx = (float)curX / 300.0 + 0.5;
    float vy = (float)curY / 300.0 + 0.5;

    glColor3f( 1.0, 0.0, 0.0 );
    glBegin( GL_POINTS );
        glVertex3f( vx, vy, 0.0 );
    glEnd();

    glutSwapBuffers();

}

void passivemotion( int x, int y ) {
    int centerX = 150;
    int centerY = 150;

    int deltaX = x - centerX;
    int deltaY = y - centerY;
    curX += deltaX;
    curY -= deltaY;

    glutWarpPointer( centerX, centerY );
}

void timer( int val ) {
    glutTimerFunc( 16, &timer,  0);
    glutPostRedisplay();
}

int main (int argc, char * argv[]) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB);
    glutInitWindowSize(300,300);
    glutCreateWindow("FPS Mouse Sample");
    glutDisplayFunc(&display);
    glutPassiveMotionFunc(&passivemotion);
    glutSetCursor( GLUT_CURSOR_NONE );
    glutTimerFunc( 16, &timer, 0 );
    glutMainLoop();
    return 0;
}
도움이 되었습니까?

해결책

팁을 알려주셔서 감사합니다.당신은 내가 lutWarpPointer의 분해를 조사하게 했고 무슨 일이 일어나고 있는지 분명해졌습니다.lutWarpPointer CGPostMouseEvent를 호출하면 말도 안되는 이벤트가 많이 발생합니다(그리고 프레임당 한 번만 마우스 이벤트를 가져오므로 이를 건너뛸 수 있는 방법이 없으며 새로운 "실제" 이벤트가 지연됩니다).내가 찾은 해결책은 포인터가 화면 가장자리에 있을 때만 워프하는 것입니다(결국 요점은 점이 화면 가장자리에 도달할 수 없는 것처럼 가장하는 것입니다).어쨌든 여기에 코드가 있습니다.

int lastX = 150;
int lastY = 150;
void passivemotion( int x, int y ) {    
    int deltaX = x - lastX;
    int deltaY = y - lastY;

    lastX = x;
    lastY = y;

    if( deltaX == 0 && deltaY == 0 ) return;

    int windowX     = glutGet( GLUT_WINDOW_X );
    int windowY     = glutGet( GLUT_WINDOW_Y );
    int screenWidth     = glutGet( GLUT_SCREEN_WIDTH );
    int screenHeight    = glutGet( GLUT_SCREEN_HEIGHT );

    int screenLeft = -windowX;
    int screenTop = -windowY;
    int screenRight = screenWidth - windowX;
    int screenBottom = screenHeight - windowY;

    if( x <= screenLeft+10 || (y) <= screenTop+10 || x >= screenRight-10 || y >= screenBottom - 10) {
        lastX = 150;
        lastY = 150;
        glutWarpPointer( lastX, lastY );
        //  If on Mac OS X, the following will also work (and CGwarpMouseCursorPosition seems faster than glutWarpPointer).
        //  CGPoint centerPos = CGPointMake( windowX + lastX, windowY + lastY );
        //  CGWarpMouseCursorPosition( centerPos );
        // Have to re-hide if the user touched any UI element with the invisible pointer, like the Dock.
        //  CGDisplayHideCursor(kCGDirectMainDisplay);
    }

    curX += deltaX;
    curY -= deltaY;
}

다른 팁

더 나은 접근 방식을 찾았습니다.무슨 일이 일어나고 있는지는 마우스를 워프한 후 OS가 약 0.25초 동안 이벤트를 억제한다는 것입니다.따라서 대신 다음을 호출하세요.

#ifdef __APPLE__
CGSetLocalEventsSuppressionInterval(0.0);
#endif

그러면 말더듬 없이 모든 것이 순조롭게 진행될 것입니다.

다음을 포함해야 할 수도 있습니다.

#include <ApplicationServices/ApplicationServices.h>

이 프레임워크를 프로젝트나 컴파일러 옵션에 추가하세요.

마우스가 화면 중앙으로 이동하는 이벤트가 발생할 수 있으므로 이벤트가 화면 중앙에 있으면 이벤트를 무시합니다.

저는 과잉에 대한 경험이 별로 없지만(빨간 책의 예를 제외하면) 커서에 대해 그리는 내용 때문에 불안정합니까, 아니면 얼마나 자주 그리는가요?커서가 OpenGL 호출을 사용하는 것으로 예상되는 지점을 그리는 경우에도 여전히 불안정합니까?타이밍 코드가 문제가 될 수 있나요?

매 틱마다 포인터를 업데이트하기 위해 어떤 코드를 호출하고 있습니까?크기 조정 이벤트 대신 매번 중심점을 계산하므로 나열된 코드가 아니라고 가정합니다.

여기에 맹목적으로 답변한 것에 대해 사과드립니다(예:제한된 과잉 경험으로).

추측이지만 커서가 OS에서 처리되지 않고 응용 프로그램의 그리기 함수(display())에 그려지기 때문에 모션이 불안정한 것으로 의심됩니다.

일반 마우스 포인터는 프레임 버퍼 내용과 커서 이미지를 XOR하는 방식으로 드라이버 수준에서 처리되므로 매우 빠르게 처리되며 인터럽트 서비스 루틴에서 OS에 의해 매우 높은 우선 순위로 처리됩니다(반응성의 환상을 유지하기 위해).

직접 그릴 때 OS의 일반적인 일정 메커니즘을 따르게 되며 전체 창 리가마롤을 정기적으로 지우고 다시 그리는 과정을 거칩니다.이 경우 속도는 빠르지만 위와 같은 이유로 마우스 포인터를 사용하는 데 익숙한 것만큼 빠르지는 않습니다.

간단히 말해서, 기대한 만큼 빠른 속도를 얻을 수 있을지 확신할 수 없습니다(특히 디스플레이 기능 및 앱 로직이 더욱 복잡해짐에 따라).

행운을 빌어요!

몇 프레임에 걸쳐 마우스의 움직임을 평균하고 있습니까?직장에 있어서 이전 프로젝트의 코드를 찾을 수 없습니다.그러나 나는 몇 프레임에서 마우스 움직임을 평균화했다고 생각합니다.

이중 버퍼가 아닌 창에서 버퍼를 교환하고 있기 때문일 수 있습니까?

gluInitDisplayMode()에 GLUT_DOUBLE을 추가하지 않으면 귀하의 예제가 내 Win32 시스템에서 작동하지 않습니다.

편집하다:

당신이 올바른지.모션 함수 내에서 lutWarpPointer()를 호출하면 내 [win32] 시스템에서 루프가 발생하는 것 같습니다.버튼이나 다른 것을 클릭하지 않으면 타이머가 실행될 기회조차 없습니다.메시지 대기열이 모션 이벤트로 넘쳐날 것 같습니다.

모션 함수에서 바로 display()를 호출해도 작동하지 않는 것 같습니다. 이번에는 어떤 종류의 모션도 등록하지 못합니다.

당신의 예가 제대로 작동하도록 할 수 있는 유일한 방법은 수동적인 모션 콜백 활동적인 모션 콜백 및 해당 함수에서 직접 display() 호출.나는 이것이 원래 의도했던 것과는 거리가 멀다는 것을 알고 있지만 적어도 이 방법으로 약간의 부드러운 동작을 얻었습니다.

디스플레이 업데이트를 트리거하기 위해 gluIdleFunc()를 사용해 보셨나요?플러딩된 메시지 대기열에서는 여전히 작동하지 않을 수 있지만 시도해 볼 가치가 있습니다.모든 동작에서 커서를 창 중앙에 수동으로 배치하는 대신 API 호출을 사용하여 마우스 캡처를 살펴볼 수도 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top