gpt4 book ai didi

c++ - 过剩的简单二维动画

转载 作者:行者123 更新时间:2023-11-30 02:04:05 25 4
gpt4 key购买 nike

我有一项任务要做,但我似乎无法真正理解它。分配如下:向背景(太阳系)添加纹理,向 2 个对象(绘制的形状)添加纹理,并添加一个动画,其中两个对象必须从彼此和远处的墙壁反弹(如屏幕末端)。

除了动画,我已经设法完成了所有事情。我该怎么做这种动画?附:里面的动画是我能想到的最好的。

#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 误认为是场景图。以你的 animation1 函数为例:

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 上下文中当前处于事件状态的任何矩阵上乱扔垃圾。那不是怎么做的。

下一个问题:您正在从绘图代码中调用动画函数。在绘制时,应确定所有场景状态。此外,调用该动画函数将在您的显示函数中休眠。那不是怎么做的。

好的,要做什么:首先将所有的动画进度条函数放入空闲循环中。不要 sleep ,而是测量动画迭代之间的时间并相应地推进动画。不要在动画函数中调用 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;
}

关于c++ - 过剩的简单二维动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11072951/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com