再次,你的问题在于你的错误,在显示功能中完成动画。我延长了我昨天给你写的一个例子,启动程序后,动画将播放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的其他部分考虑在内的时间之间的时间的时间的。这是一个留给读者的练习。
你会介意,如果你可以修改我的代码来实现他所需的功能,因为我在vs2008上运行你的程序时遇到了这么多的错误 – Tarun 2011-05-11 10:34:00
@ fluty:程序是有效的ANSI-C。它不是C++,所以如果你将这些代码粘贴到VS2008 C++项目中,它就是错误的解释。此外,我需要完整的源代码进行更改。但是实际上**编译并运行** *我的程序并不重要。相反,您应该**阅读并理解**代码的作用,并将您在*程序中学到的知识应用到应用程序中。 – datenwolf 2011-05-11 10:59:00
这里是我code..please进行必要的更改我真的很坚持 Hawk.c http://pastebin.com/gEYi9Vsj GluCylinders.h http://pastebin.com/SeYkSTHd – Tarun 2011-05-11 11:28:47