2012-06-17 42 views
1

我有一个任务要做,但我似乎无法真正理解它。 作业如下:向背景(太阳系)添加纹理,向2个物体(绘制的形状)添加纹理,并添加一个动画,其中两个物体必须从远处墙壁互相反弹&(与屏幕末端相同) 。简单的二维动画过度

我设法做了除动画之外的所有事情。 我该如何做这种动画? p.s.那里的动画是我能想到的最好的。

#include <gl/glut.h> 
#include <gl/gl.h > 
#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <time.h> 


float x; 
float y; 



unsigned char *imageData; 
int imageRows, imageCols; 

extern void loadBMP(char *); 
char cotton1[] = "cotton1.bmp"; 
char cotton2[] = "cotton2.bmp"; 
char fons[] = "solar.bmp"; 

GLuint texture[3]; 
float cube[1], Vcube[1]; 

/* GLUT callback Handlers */ 

void init() 
{ 
cube[0]=0; 
Vcube[0]=0.01; 
cube[1]=0; 
Vcube[1]=0.01; 


glShadeModel(GL_SMOOTH); 

glGenTextures(3, &texture[0]); 

    loadBMP(cotton1); 
    glBindTexture(GL_TEXTURE_2D, texture[0]); 
    glTexImage2D(GL_TEXTURE_2D, 0, 3, imageCols, imageRows, 
     0, GL_RGB, GL_UNSIGNED_BYTE, imageData); 

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 

    loadBMP(cotton2); 
    glBindTexture(GL_TEXTURE_2D, texture[1]); 
    glTexImage2D(GL_TEXTURE_2D, 0, 3, imageCols, imageRows, 
     0, GL_RGB, GL_UNSIGNED_BYTE, imageData); 

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 

     loadBMP(fons); 
    glBindTexture(GL_TEXTURE_2D, texture[2]); 
    glTexImage2D(GL_TEXTURE_2D, 0, 3, imageCols, imageRows, 
     0, GL_RGB, GL_UNSIGNED_BYTE, imageData); 

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 

} 

static void 
resize(int width, int height) 
{ 
    const float ar = (float) width/(float) height; 

    glViewport(0, 0, width, height); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity() ; 
} 

static void 
idle(void) 
{ 
    glutPostRedisplay(); 
} 

void animation() 
{ 
cube[1]+=Vcube[1]; 
if (cube[1]<0.1) 
{ Vcube[1]+=Vcube[1]; } 
if (cube[1]>0.095) 
{ Vcube[1]=-0.01; } 
if (cube[1]<0) 
{ Vcube[1]=+0.01; } 

glTranslatef(cube[1],0,0); 
     Sleep(100); 
     glutPostRedisplay(); 
} 


void animation2() 
{ 
    cube[0]+=Vcube[0]; 
if (cube[0]<(-0.1)) 
{ Vcube[0]-=0.01; } 
if (cube[0]>0) 
{ Vcube[0]-=0.01; } 
if (cube[0]<0.1) 
{ Vcube[0]+=0.01; } 


glTranslatef(cube[0],0,0); 
     Sleep(100); 
     glutPostRedisplay(); 
} 

void display() { 


    glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT); 


//Background 
    glLoadIdentity(); 
    glBindTexture(GL_TEXTURE_2D, texture[2]); 
    glEnable(GL_TEXTURE_2D); 

    glPushMatrix(); 
    glBegin(GL_QUADS); 
     glTexCoord2f(1.0,1.0); glVertex2f(-1.0,1.0); 
     glTexCoord2f(0.0,1.0); glVertex2f(1.0,1.0); 
     glTexCoord2f(0.0,0.0); glVertex2f(1.0,-1.0); 
     glTexCoord2f(1.0,0.0); glVertex2f(-1.0,-1.0); 
     glEnd(); 
     glPopMatrix(); 
    glDisable(GL_TEXTURE_2D); 

    animation(); 

//TEXTURE 1 
    glBindTexture(GL_TEXTURE_2D, texture[0]); 

    glEnable(GL_TEXTURE_2D); 

    glPushMatrix(); 
    glBegin(GL_TRIANGLE_FAN); 
glTexCoord2f(0.5f, 0.5f); glVertex2f( 0.5f, 0.0f); //center 
glTexCoord2f(1.0f, 0.5f); glVertex2f( 0.8f+x, 0.0f); //right 
glTexCoord2f(0.75f, 1.0f); glVertex2f( 0.55f+x, 0.3f+x); //top right 
glTexCoord2f(0.25f, 1.0f); glVertex2f( 0.35f-x, 0.3f+x); //Top left 
glTexCoord2f(0.0f, 0.5f); glVertex2f( 0.25f-x, 0.0f); //left 
glTexCoord2f(0.25f, 0.0f); glVertex2f( 0.45f-x,-0.3f-x); //bottom left 
glTexCoord2f(0.75f, 0.0f); glVertex2f( 0.7f+x, -0.2f-x); //bottom right 
glTexCoord2f(1.0f, 0.5f); glVertex2f( 0.8f+x, 0.0f); //right 
     glEnd(); 
     glPopMatrix(); 
    glDisable(GL_TEXTURE_2D); 
//TEXTURE 2 

    animation2(); 
    glBindTexture(GL_TEXTURE_2D, texture[1]); 

    glEnable(GL_TEXTURE_2D); 
    glPushMatrix(); 
    glBegin(GL_TRIANGLE_FAN); 
glTexCoord2f(0.5f, 0.5f); glVertex2f(-0.5f, 0.0f); //center 
glTexCoord2f(1.0f, 0.5f); glVertex2f(-0.2f+y, 0.0f); //right 
glTexCoord2f(0.75f, 1.0f); glVertex2f(-0.4f+y, 0.2f+y); //top right 
glTexCoord2f(0.25f, 1.0f); glVertex2f(-0.7f-y, 0.1f+y); //Top left 
glTexCoord2f(0.0f, 0.5f); glVertex2f(-0.8f-y, 0.0f); //left 
glTexCoord2f(0.25f, 0.0f); glVertex2f(-0.7f-y, -0.1f-y); //bottom left 
glTexCoord2f(0.75f, 0.0f); glVertex2f(-0.3f+y, -0.2f-y); //bottom right 
glTexCoord2f(1.0f, 0.5f); glVertex2f(-0.2f+y, 0.0f); //right 
     glEnd(); 
     glPopMatrix(); 
    glDisable(GL_TEXTURE_2D); 
glutSwapBuffers(); 
glFlush(); 
} 


static void 
key(unsigned char key, int a, int b) 
{ 
    switch (key) 
    { 
     case 27 : 
     case 'q': 
      exit(0); 
      break; 

     case '+': 
      if ((x+0.01)<0.98) 
      x=x+0.01; 
      if ((y+0.01)<0.98) 
      y=y+0.01;   
      break; 

     case '-': 
      if ((x-0.1)>(-0.15)) 
       x=x-0.01; 
      if ((y-0.1)>(-0.10)) 
       y=y-0.01; 
      break; 

     case 'o': 
      if ((x+0.01)<0.98) 
      x=x+0.01; 
      break; 
     case 'p': 
      if ((x-0.1)>(-0.15)) 
      x=x-0.01; 
      break; 


     case '[': 
      if ((y+0.01)<0.98) 
      y=y+0.01; 
      break; 
     case ']': 
      if ((y-0.1)>(-0.10)) 
      y=y-0.01; 
      break; 



    } 
    glutPostRedisplay(); 
} 

int main(int argc, char *argv[]) { 
    glutInit(&argc, argv); 

    glutInitWindowSize(640, 640); 
    glutInitWindowPosition(50, 50); 
    glutCreateWindow("Assignment number 3"); 
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 



    glutReshapeFunc(resize); 
    glutDisplayFunc(display);  
    glutKeyboardFunc(key);   
    glutIdleFunc(idle); 

    glClearColor(1.0, 1.0, 1.0, 1.0); 

    init(); 

    glutMainLoop();    
    return EXIT_SUCCESS; 
} 

回答

3

问题1:您将OpenGL误认为场景图。把你的动画1功能,例如:

void animation2(
    ) 
{ 
    cube[0] += Vcube[0]; 
    if(cube[0] < (-0.1)) { 
     Vcube[0] -= 0.01; 
    } 
    if(cube[0] > 0) { 
     Vcube[0] -= 0.01; 
    } 
    if(cube[0] < 0.1) { 
     Vcube[0] += 0.01; 
    } 


    glTranslatef(cube[0], 0, 0); 
    Sleep(100); 
    glutPostRedisplay(); 
} 

glTranslatef有在年底将只垃圾桶周围任何矩阵目前在OpenGL上下文激活。这不是如何做到这一点。

下一个问题:您正在从绘图代码调用动画功能。在绘制的时候,应该确定所有的场景状态。另外,调用该动画功能将会在您的显示功能中休眠。这不是如何做到这一点。

好的,该怎么办:首先将所有动画progressor函数放入空闲循环。不要睡觉,而是测量动画迭代之间的时间并相应地推进动画。不要在动画功能中调用glutPostRedisplay。在空闲处理程序结束时是,但不在动画制作人员中。在绘图代码中使用评估的动画状态来相应地放置对象。使用矩阵堆栈(glPushMatrix,glPopMatrix)可以很好地分离事物。


#include <GL/glut.h> 

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 

/* for gettimeofday */ 
#include <sys/time.h> 

/* In general, littering your program with global variables should be avoided. 
* I admit, that sometimes even I don't adhere to this rule, and especially 
* using GLUT it takes to jump several very arcane hoops to avoid it. 
* So in this case, yes, having global variables is in order. 
* 
* The principle idea of global variables is to put data into them, that is 
* valid and the same for the whole of the program. More importantly they 
* must not be used to pass around data. 
* 
* It's also a good idea to make those variables static, so that they are 
* contained withing this compilation unit. 
*/ 
static float x; 
static float y; 

/* This is not how globals should be used. They're used to pass data around between 
* functions. DON'T DO THAT! 
* 
* Also this misses the extern keyword. Unless the compilation unit loading the 
* bmp files declares those being extern, hence relying on another compilation unit 
* to expose them like this, this code is likely to break. 

unsigned char *imageData; 
int imageRows, imageCols; 

extern void loadBMP(char *); 

* BTW: You don't need the extern keyword here. 

* Instead have a nice little function that loads a BMP file and puts it into a 
* newly allocated texture object. 
*/ 

GLuint loadBmpToTexture(char const * const filename) 
{ 
    /* Implementation of this left as an exercise to the reader */ 
    return 0; 
} 

static double ftime(void) 
{ 
    /* Now this is a bit complicated: There's no portable high resolution 
    * timer function. On Linux and Unices (hence also MacOS X) you have 
    * gettimeofday, on Windows there are the High Performance Counters. 
    * ... Totally annoying. 
    * Look here for a comparison: 
    * http://www.songho.ca/misc/timer/timer.html 
    * 
    * Since I'm on a Linux box this is using gettimeofday 
    */ 

    struct timeval t; 
    gettimeofday(&t, NULL); 

    return 1.0*t.tv_sec + 1e-6*t.tv_usec; 
} 

/* In this variable we store the time of the last iteration of the animation 
* loop to determine the time to time difference for the next one. */ 
static double last_T; 

/* Actually those should be of type char const * const 
* This is one of the finer details of C. The arrays like you've declared them 
* here are mutable, but of constant size. 
* However you normally don't want string constant be like this. The preferred 
* modus operandi is to have the string constants in read only memory and pointers 
* to them. Like this: 
*/ 
char const * const cotton1 = "cotton1.bmp"; 
char const * const cotton2 = "cotton2.bmp"; 
char const * const fons = "solar.bmp"; 

/* Okay, now consider what would happen if you had several objects, not just two or 
* three? How would you keep track of all those indices? Really, that's bad style. 
* If you've data belonging together, like state of an object, put it into a struct 
* and then also use useful variable names. 
*/ 

GLuint texture_background; 

typedef struct s_Cube { 
    float x, V_x; 
    GLuint texture; 
} Cube; 

/* also we can statically initialize here */ 
Cube cube[2] = { 
    {-0.05, 0.01, 0}, 
    {0.05, -0.02, 0} 
}; 

/* GLUT callback Handlers */ 

static void init(void) 
{ 
    /* loadBmpToTexture is defined to return 0 in case of failure 
    * which is also the OpenGL default texture object, so this 
    * fails safely. */ 
    texture_background = loadBmpToTexture(fons); 
    cube[0].texture = loadBmpToTexture(cotton1); 
    cube[1].texture = loadBmpToTexture(cotton2); 

    glClearColor(0.0, 0.5, 0.7, 1.0); 

    last_T = ftime(); 
} 

static void animation(
    float const speed 
    ) 
{ 
    /* The objective is to let the cubes bounce into each other 
    * (collision) and with the walls. First the collision: */ 

    if(cube[0].x > cube[1].x && cube[0].V_x > 0 && cube[1].V_x < 0) { 
     /* cubes bounced off each other. Exchange their velocities */ 
     double const V_x = cube[0].V_x; 
     cube[0].V_x = cube[1].V_x; 
     cube[1].V_x = V_x; 

     double const x = cube[0].x; 
     cube[0].x = cube[1].x; 
     cube[1].x = x; 
    } 

    /* and the wall bounce */ 
    if(cube[0].x < -0.1 && cube[0].V_x < 0) { 
     /* left cube bounced into left wall */ 
     cube[0].V_x *= -1; 
    } 

    if(cube[1].x > 0.1 && cube[1].V_x > 0) { 
     /* right cube bounced into left wall */ 
     cube[1].V_x *= -1; 
    } 

    cube[0].x += speed * cube[0].V_x; 
    cube[1].x += speed * cube[1].V_x; 
} 

/* Ideally we'd use a precise animation loop interleaved with event processing here. 
* Unfortunately GLUT doesn't offer those, so we use this arcane kludge. 
* 
* It would get a bit more robust by putting the whole timing into the display function 
* but better abandon GLUT and get a true event loop. 
*/ 
static void idle(
    void) 
{ 
    const double now_T = ftime(); 
    const double delta_T = now_T - last_T; 
    last_T = now_T; 

    const double speed = delta_T * 60; 

    animation(speed); 
    glutPostRedisplay(); 
} 


static void display(void) 
{ 
    /* We try to be as stateless as possible. Yes, in the face of a statefull 
    * API, like OpenGL, this may sound a bit pedantic. */ 
    const int width = glutGet(GLUT_WINDOW_WIDTH); 
    const int height = glutGet(GLUT_WINDOW_HEIGHT); 
    const float ar = (float) width/(float) height; 

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    /* It's really best practice to set everything related to drawing 
    * – and that includes the projection – in the drawing function */ 
    glViewport(0, 0, width, height); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glOrtho(-ar, ar, -1, 1, -1, 1); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
//Background 
    if(texture_background) { 
     glBindTexture(GL_TEXTURE_2D, texture_background); 
     glEnable(GL_TEXTURE_2D); 
     glBegin(GL_QUADS); 
     glTexCoord2f(1.0, 1.0); 
     glVertex2f(-1.0, 1.0); 
     glTexCoord2f(0.0, 1.0); 
     glVertex2f(1.0, 1.0); 
     glTexCoord2f(0.0, 0.0); 
     glVertex2f(1.0, -1.0); 
     glTexCoord2f(1.0, 0.0); 
     glVertex2f(-1.0, -1.0); 
     glEnd(); 
     glDisable(GL_TEXTURE_2D); 
    } 

//TEXTURE 1 
    glBindTexture(GL_TEXTURE_2D, cube[1].texture); 
    glEnable(GL_TEXTURE_2D); 
    /* Remember we're still in modelview matrix mode. 
    * This push creates a copy of the currently modelview matrix, 
    * for our disposal. With a following pop we restore to the 
    * state saved now. Pushes and Pops nest. */ 
    glPushMatrix(); 

    /* This applies our animation position to the modelview matrix. 
    * All geometry drawing to follow is subject to this additional 
    * transformation, until the matrix changes again. */ 
    glTranslatef(cube[1].x, 0, 0); 
    glBegin(GL_TRIANGLE_FAN); 
    glTexCoord2f(0.5f, 0.5f); 
    glVertex2f(0.5f, 0.0f); //center 
    glTexCoord2f(1.0f, 0.5f); 
    glVertex2f(0.8f + x, 0.0f); //right 
    glTexCoord2f(0.75f, 1.0f); 
    glVertex2f(0.55f + x, 0.3f + x); //top right 
    glTexCoord2f(0.25f, 1.0f); 
    glVertex2f(0.35f - x, 0.3f + x); //Top left 
    glTexCoord2f(0.0f, 0.5f); 
    glVertex2f(0.25f - x, 0.0f); //left 
    glTexCoord2f(0.25f, 0.0f); 
    glVertex2f(0.45f - x, -0.3f - x); //bottom left 
    glTexCoord2f(0.75f, 0.0f); 
    glVertex2f(0.7f + x, -0.2f - x); //bottom right 
    glTexCoord2f(1.0f, 0.5f); 
    glVertex2f(0.8f + x, 0.0f); //right 
    glEnd(); 
    glPopMatrix(); 
    glDisable(GL_TEXTURE_2D); 
//TEXTURE 2 
    /* in the original code you didn't use the other texture, 
    * Probably because you lost track of variables and indices. */ 
    glBindTexture(GL_TEXTURE_2D, cube[0].texture); 
    glEnable(GL_TEXTURE_2D); 
    glPushMatrix(); 
    glTranslatef(cube[0].x, 0, 0); 
    glBegin(GL_TRIANGLE_FAN); 
    glTexCoord2f(0.5f, 0.5f); 
    glVertex2f(-0.5f, 0.0f); //center 
    glTexCoord2f(1.0f, 0.5f); 
    glVertex2f(-0.2f + y, 0.0f); //right 
    glTexCoord2f(0.75f, 1.0f); 
    glVertex2f(-0.4f + y, 0.2f + y); //top right 
    glTexCoord2f(0.25f, 1.0f); 
    glVertex2f(-0.7f - y, 0.1f + y); //Top left 
    glTexCoord2f(0.0f, 0.5f); 
    glVertex2f(-0.8f - y, 0.0f); //left 
    glTexCoord2f(0.25f, 0.0f); 
    glVertex2f(-0.7f - y, -0.1f - y); //bottom left 
    glTexCoord2f(0.75f, 0.0f); 
    glVertex2f(-0.3f + y, -0.2f - y); //bottom right 
    glTexCoord2f(1.0f, 0.5f); 
    glVertex2f(-0.2f + y, 0.0f); //right 
    glEnd(); 
    glPopMatrix(); 
    glDisable(GL_TEXTURE_2D); 

    glutSwapBuffers(); 
    /* Your glFinish here was totally pointless. 
    * First it would belong _before_ glutSwapBuffers. 
    * Second glutSwapBuffers implies a glFinish, so it's totally redundant. */ 
} 


static void key(
    unsigned char key, 
    int a, 
    int b) 
{ 
    switch (key) { 
    case 27: 
    case 'q': 
     exit(0); 
     break; 

    case '+': 
     if((x + 0.01) < 0.98) 
      x = x + 0.01; 
     if((y + 0.01) < 0.98) 
      y = y + 0.01; 
     break; 

    case '-': 
     if((x - 0.1) > (-0.15)) 
      x = x - 0.01; 
     if((y - 0.1) > (-0.10)) 
      y = y - 0.01; 
     break; 

    case 'o': 
     if((x + 0.01) < 0.98) 
      x = x + 0.01; 
     break; 
    case 'p': 
     if((x - 0.1) > (-0.15)) 
      x = x - 0.01; 
     break; 


    case '[': 
     if((y + 0.01) < 0.98) 
      y = y + 0.01; 
     break; 
    case ']': 
     if((y - 0.1) > (-0.10)) 
      y = y - 0.01; 
     break; 
    } 
    glutPostRedisplay(); 
} 

int main(
    int argc, 
    char *argv[]) 
{ 
    glutInit(&argc, argv); 

    glutInitWindowSize(640, 640); 
    glutInitWindowPosition(50, 50); 
    /* glutInitDisplayMode must be called before calling glutCreateWindow 
    * GLUT, like OpenGL is stateful */ 
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 
    glutCreateWindow("Assignment number 3"); 

    glutDisplayFunc(display); 
    glutKeyboardFunc(key); 
    glutIdleFunc(idle); 

    init(); 

    glutMainLoop(); 
    return EXIT_SUCCESS; 
} 
+0

没关系,谢谢你,会尝试。 :) – user1462023

+0

@ user1462023:FYI:我冒昧地将所有提到的固定和修改添加到您的代码中。所以如果你被困住了,我可以给你一个工作版本。 – datenwolf

+0

@ user1462023:您的动画代码本身也存在一些问题,例如测试错误的边界条件。 – datenwolf