我有一个分配的事,但我似乎无法真实地理解它。 的分配如下:添加纹理背景(太阳能系统),加入纹理2个对象(绘制的形状),并添加动画,其中两个对象具有从海誓山盟&从远壁(如屏幕的端部)反弹。
我已成功地做,除了动画的一切。 我怎样才能做到这种动画? 在那里PS动画是最好的,我可以拿出。
#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;
}
问题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上下文激活。 这不是如何做到这一点。
下一个问题是:你调用从绘图代码动画功能。 在绘制的所有场景状态的点应确定。 此外,调用该动画功能将睡在你的显示功能。 这不是如何做到这一点。
好了,该怎么做:首先把所有的动画发展者职能进入空闲循环。 不睡觉,而不是衡量动画迭代之间的时间,并相应推进动画。 不要在动画函数调用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;
}