2011-05-11 63 views
1

我想提出一个程序在现场 它会像动画中一球,如何管理代码以仅显示一次动画?

void display() 
{ 
/* 
code to draw a field 

*/ 
loop:1 to 5 
loop:1 to 6 
/* 
here comes the code to animate the ball over the field 

*/ 
} 

我想,只要用户按下“RIGHT_ARROW”整个场面得到由
某些角度旋转
问题:每当用户按下“right_Arrow”键可以旋转一定角度的场景,但也会再次显示整个动画...但是我希望动画只显示一次(在最大化窗口之后),然后用户可以将整个场景以一定角度旋转
不按“right_Arrow”键显示任何动画
我应该如何在我的代码中执行此操作?

回答

1

再次,你的问题在于你的错误,在显示功能中完成动画。我延长了我昨天给你写的一个例子,启动程序后,动画将播放5秒钟,然后停止。按[R]重设动画(从而再次启动),按[+]/[ - ]可围绕Y轴旋转场景。

http://homepages.physik.uni-muenchen.de/~Wolfgang.Draxinger/stuff/sinsphere_rot.c 编辑:评论

/* This is ANSI-C - don't try to compile with a C++ compiler, it will fail! */ 
#include <GL/glut.h> 

#include <stdlib.h> 

#include <sys/time.h> 
#include <math.h> 

#define M_PI 3.1415926535897932384626433832795029L 
#define M_PI_2 1.5707963267948966192313216916397514L 

# define timersub(a, b, result)            \ 
    do {                  \ 
    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;        \ 
    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;       \ 
    if ((result)->tv_usec < 0) {            \ 
     --(result)->tv_sec;              \ 
     (result)->tv_usec += 1000000;           \ 
    }                   \ 
    } while (0) 

void idle(void); 
void animate(float dT); 
void display(void); 
void keyboard(unsigned char key, int x, int y); 
void init_sphere(unsigned int rings, unsigned int sectors); 
void draw_sphere(void); 

int main(int argc, char *argv[]) 
{ 
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 
    glutCreateWindow("SinSphere"); 
    glutIdleFunc(idle); 
    glutKeyboardFunc(keyboard); 
    glutDisplayFunc(display); 

    init_sphere(10, 30); 

    glutMainLoop(); 

    return 0; 
} 

这一切只是样板代码,没什么特别的。

struct AnimationState 
{ 
    float time; 
    float duration; 
    float sphere_speed; 
    float sphere_path_radius; 
    float sphere_path_bobbing; 
    float sphere_position[3]; 
}; 

static struct AnimationState animation = { 
    0., 
    5., /* play for 5 seconds */ 
    0.1, 3., 1., 
    {1., 0., 0.} 
}; 

AnimationState得到了一个额外的元素duration;在那段时间之后,动画将停止播放,通过测试是否animation.time < animation.duration并且如果是的话只提前动画步骤。

void animate(float dT) 
{ 
    if(animation.time < animation.duration) { 
     animation.time += dT; 

     animation.sphere_position[0] = animation.sphere_path_radius * cos(2*M_PI * animation.time * animation.sphere_speed); 
     animation.sphere_position[1] = animation.sphere_path_bobbing * sin(2*M_PI * animation.time * 5 * animation.sphere_speed); 
     animation.sphere_position[2] = animation.sphere_path_radius * sin(2*M_PI * animation.time * animation.sphere_speed); 
    } 
} 

struct ViewState { 
    float rotation; 
    float rotation_step; 
}; 

static struct ViewState view = { 
    0., 
    0.1 
}; 

ViewState中存储的旋转。这真是一个虚拟的版本,通常通过视图转换matix和步进来实现这一点。

void keyboard(unsigned char key, int x, int y) 
{ 
    switch(key) { 
    case 'R': 
    case 'r': /* restart animation */ 
     animation.time = 0.; 
     break; 

    case '+': 
     view.rotation += view.rotation_step; 
     break; 

    case '-': 
     view.rotation -= view.rotation_step; 
     break; 
    } 
    glutPostRedisplay(); 
} 

键盘处理函数应该很明显。

GLfloat *sphere_vertices_normals; 
unsigned int sphere_quads = 0; 
GLushort *sphere_indices; 

void init_sphere(unsigned int rings, unsigned int sectors) 
{ 
    float const R = 1./(float)(rings-1); 
    float const S = 1./(float)(sectors-1); 
    int r, s; 

    sphere_vertices_normals = malloc(sizeof(GLfloat)*3 * rings*sectors); 

    GLfloat *v = sphere_vertices_normals; 
    for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) { 
     float const y = sin(-M_PI_2 + M_PI * r * R); 

     float const x = cos(2*M_PI * s * S) * sin(M_PI * r * R); 

     float const z = sin(2*M_PI * s * S) * sin(M_PI * r * R); 

     v[0] = x; 
     v[1] = y; 
     v[2] = z; 

     v+=3; 
    } 

    sphere_indices = malloc(sizeof(GLushort) * rings * sectors * 4); 
    GLushort *i = sphere_indices; 
    for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) { 
     *i++ = r * sectors + s; 
     *i++ = r * sectors + (s+1); 
     *i++ = (r+1) * sectors + (s+1); 
     *i++ = (r+1) * sectors + s; 
     sphere_quads++; 
    } 
} 

init_sphere为我们构建了一个很好的包含球体几何体的顶点和索引数组。练习读者:将其放入顶点缓冲区对象中。

void draw_sphere() 
{ 
    glTranslatef(animation.sphere_position[0], animation.sphere_position[1], animation.sphere_position[2]); 

    glEnableClientState(GL_VERTEX_ARRAY); 
    glEnableClientState(GL_NORMAL_ARRAY); 

    glVertexPointer(3, GL_FLOAT, 0, sphere_vertices_normals); 
    glNormalPointer(GL_FLOAT, 0, sphere_vertices_normals); 
    glDrawElements(GL_QUADS, sphere_quads*4, GL_UNSIGNED_SHORT, sphere_indices); 
} 

void idle() 
{ 
    glutPostRedisplay(); 
} 

在处理了所有输入事件后,会调用idle函数。输入事件是按键等。 GLUT事件只在显示处理程序返回后进行处理。所以你不能在显示处理程序中实现动画计时器循环。相反,您需要确定单个显示器的时间,然后按照该时间步推进循环,以便进行下一次显示迭代。 idle事件处理后启动下一个显示过程。

static GLfloat const light_pos[4] = {-1., 1., 1., 0.}; 
static GLfloat const light_color[4] = {1., 1., 1., 1.}; 

void display() 
{ 
    static struct timeval delta_T = {0., 0.}; 
    struct timeval time_frame_begin, time_frame_end; 

    int win_width, win_height; 
    float win_aspect; 

    gettimeofday(&time_frame_begin, 0); 

    animate(delta_T.tv_sec + delta_T.tv_usec * 1.e-6); 

    win_width = glutGet(GLUT_WINDOW_WIDTH); 
    win_height = glutGet(GLUT_WINDOW_HEIGHT); 
    win_aspect = (float)win_width/(float)win_height; 

    glViewport(0, 0, win_width, win_height); 
    glClearColor(0.6, 0.6, 1.0, 1.0); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glFrustum(-win_aspect, win_aspect, -1., 1., 1., 10.); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    glTranslatef(0,0,-5.5); 

    glRotatef(view.rotation * 180./M_PI, 0, 1, 0); 

    glLightfv(GL_LIGHT0, GL_POSITION, light_pos); 
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color); 

    glPushMatrix(); 

    glEnable(GL_DEPTH_TEST); 

    glEnable(GL_LIGHTING); 
    glEnable(GL_LIGHT0); 
    draw_sphere(); 

    glPopMatrix(); 

    glutSwapBuffers(); 

    gettimeofday(&time_frame_end, 0); 
    timersub(&time_frame_end, &time_frame_begin, &delta_T); 

} 

相反measureing花费在display更准确的方法是测量display每次调用采取花费在PROGRAMM的其他部分考虑在内的时间之间的时间的时间的。这是一个留给读者的练习。

+0

你会介意,如果你可以修改我的代码来实现他所需的功能,因为我在vs2008上运行你的程序时遇到了这么多的错误 – Tarun 2011-05-11 10:34:00

+0

@ fluty:程序是有效的ANSI-C。它不是C++,所以如果你将这些代码粘贴到VS2008 C++项目中,它就是错误的解释。此外,我需要完整的源代码进行更改。但是实际上**编译并运行** *我的程序并不重要。相反,您应该**阅读并理解**代码的作用,并将您在*程序中学到的知识应用到应用程序中。 – datenwolf 2011-05-11 10:59:00

+0

这里是我code..please进行必要的更改我真的很坚持 Hawk.c http://pastebin.com/gEYi9Vsj GluCylinders.h http://pastebin.com/SeYkSTHd – Tarun 2011-05-11 11:28:47