Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: Want to move only one of many identical objects. How?

  1. #1
    Junior Member Newbie
    Join Date
    May 2014
    Posts
    7

    Want to move only one of many identical objects. How?

    Hi everyone.

    I use the below code to create scene with multiple spheres, and with the keyboard method I intend to move only one of them (first one for example). Unfortunately, every time I press a key the whole scene gets redrawn (because of glutPostRedisplay, which recalls the display method). How do I bypass this behavior, so that a single sphere moves and the others keep their old positions? Any help is welcome.

    Code :
    class SolidSphere
    {
    protected:
        std::vector<GLfloat> vertices;
        std::vector<GLfloat> normals;
        std::vector<GLfloat> texcoords;
        std::vector<GLushort> indices;
     
    public:
        SolidSphere(float radius, unsigned int rings, unsigned int sectors)
        {
            float const R = 1.0f / (float)(rings - 1);
            float const S = 1.0f / (float)(sectors - 1);
            unsigned int r, s;
     
            vertices.resize(rings * sectors * 3);
            normals.resize(rings * sectors * 3);
            texcoords.resize(rings * sectors * 2);
            std::vector<GLfloat>::iterator v = vertices.begin();
            std::vector<GLfloat>::iterator n = normals.begin();
            std::vector<GLfloat>::iterator t = texcoords.begin();
            for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
    				float const x = sinf(M_PI * r * R) * cosf(2 * M_PI * s * S);
                    float const y = sinf(-M_PI_2 + M_PI * r * R );                
                    float const z = sinf(2.0f * M_PI * s * S) * sinf(M_PI * r * R );
     
                    *t++ = s*S;
                    *t++ = r*R;
     
                    *v++ = x * radius;
                    *v++ = y * radius;
                    *v++ = z * radius;
     
                    *n++ = x;
                    *n++ = y;
                    *n++ = z;
            }
     
            indices.resize(rings * sectors * 6);
            std::vector<GLushort>::iterator i = indices.begin();
            for(r = 0; r < rings - 1; r++) for(s = 0; s < sectors - 1; s++) {
    			*i++ = r * sectors + s;
    			*i++ = (r + 1) * sectors + (s + 1);
    			*i++ = r * sectors + (s + 1);
     
    			*i++ = r * sectors + s;
    			*i++ = (r + 1) * sectors + s;
    			*i++ = (r + 1) * sectors + (s + 1);
    		}
        }
     
    	void draw(GLfloat x, GLfloat y, GLfloat z)
        {
    		glMatrixMode(GL_MODELVIEW);
    		glPushMatrix();
    		glTranslatef(x,y,z);
     
    		glEnableClientState(GL_VERTEX_ARRAY);
    		glEnableClientState(GL_NORMAL_ARRAY);
    		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     
    		glVertexPointer(3, GL_FLOAT, 0, &vertices[0]);
    		glNormalPointer(GL_FLOAT, 0, &normals[0]);
    		glTexCoordPointer(2, GL_FLOAT, 0, &texcoords[0]);
    		glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, &indices[0]);
    		glPopMatrix();
     
    		glDisableClientState(GL_VERTEX_ARRAY);
    		glDisableClientState(GL_NORMAL_ARRAY);
    		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        }
    };
     
    void init()
    {
    	struct Light {
    		float ambient[4];
    		float diffuse[4];
    		float specular[4];
    		float position[4];
    	} light = {
    		{ .2, .2, .2, 1. },
    		{ .8, .8, .8, 1. },
    		{ 1., 1., 1., 1. },
    		{ 1., 1., 1., .0 }
    	};
     
    	struct Material {
    		float ambient[4];
    		float diffuse[4];
    		float specular[4];
    		float shininess[1];
    	} material = {
    		{ .8, .8, .8, 1. },
    		{ .8, .8, .8, 1. },
    		{ 1., 1., 1., 1. },
    		{ 96 }
    	};
     
    	glClearColor(.5, .5, 1., 1.);
    	glShadeModel(GL_SMOOTH);
     
    	glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, material.shininess);
    	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material.specular);
    	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material.diffuse);
     
    	glLightfv(GL_LIGHT0, GL_POSITION, light.position);
    	glLightfv(GL_LIGHT0, GL_AMBIENT, light.ambient);
    	glLightfv(GL_LIGHT0, GL_DIFFUSE, light.diffuse);
    	glLightfv(GL_LIGHT0, GL_SPECULAR, light.specular);
     
    	glEnable(GL_LIGHTING);
    	glEnable(GL_LIGHT0);
    	glEnable(GL_DEPTH_TEST);
    	glEnable(GL_COLOR_MATERIAL);
    }
     
    SolidSphere **createSpheres()
    {
    	SolidSphere **spheres = new SolidSphere*[numSpheres];
    	for (int i = 0; i < numSpheres; i++)
    		spheres[i] = new SolidSphere(1, 12, 24);
     
    	return spheres;
    }
     
    void display()
    {
    	SolidSphere **spheres = createSpheres();
    	float const win_aspect = (float)win_width / (float)win_height;
     
    	glViewport(0, 0, win_width, win_height);
     
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glColor3f(.6, 0, 0);
    	glMatrixMode(GL_PROJECTION);
    	glLoadIdentity();
    	gluPerspective(45, win_aspect, 1, 10);
     
    	glMatrixMode(GL_MODELVIEW);
    	glLoadIdentity();
     
    	for (int i = 0; i < numSpheres; i++)
    	{
    		posX = ((float)rand())/RAND_MAX * 4 - 2;
    		posY = ((float)rand())/RAND_MAX * 4 - 2;
    		posZ = ((float)rand())/RAND_MAX * 5 - 10;
    		spheres[i]->draw(posX,posY,posZ);
    	}
    	for (int i = 0; i < numSpheres; i++)
    	{
    		delete spheres[i];
    	}
     
    	delete[] spheres;
     
    	glutSwapBuffers();
    }
     
    void keyboard(unsigned char key, int x, int y)
    {
    	switch(key)
    	{
    	case 27:
    		exit(0);
    	case 'a':
    		posX -= 0.05f;
    		glutPostRedisplay();
    		break;
    	case 'd': 
    		posX += 0.05f;
    		glutPostRedisplay();
    		break;
    	case 's':
    		posY -= 0.05f;
    		glutPostRedisplay();
    		break;
    	case 'w':
    		posY += 0.05f;
    		glutPostRedisplay();
    		break;
    	case 'x':
    		posZ -= 0.05f;
    		glutPostRedisplay();
    		break;
    	case 'z': 
    		posZ += 0.05f;
    		glutPostRedisplay();
    		break;
    	}
    }

  2. #2
    Advanced Member Frequent Contributor
    Join Date
    Apr 2010
    Posts
    797
    You allocate (and destroy) all sphere objects within your display function and assign completely new positions to them (hence they all move). That is not only wasteful performance wise, but also means that you can not easily keep track of the position of each sphere for the duration of your program. Instead create the sphere objects during program initialization and store the spheres position within a SolidSphere object (possibly initialized to a random location). In your keyboard callback you modify the position of the sphere you want to move only and in the display callback render each sphere at its current location.

  3. #3
    Junior Member Newbie
    Join Date
    May 2014
    Posts
    7
    Done this. It worked. May I ask one more thing? I've created this function:

    Code :
    bool checkCollisions(GLfloat x_1, GLfloat y_1, GLfloat z_1)
    {
    	float distance = sqrt(pow((x_1 - x_2),2) + pow((y_1 - y_2),2) + pow((z_1 - z_2),2));
    	if(distance <= 2) return true;
    	return false;
    }

    ... and inside display() I assign its return value to bool collision:

    Code :
    bool collision = checkCollisions(x_1, y_1, z_1);

    So far OK, but when I compile I get "error C3861: 'checkCollisions': identifier not found". Any ideas?

    EDIT: Solved! I needed to declare prototype of checkCollisions() at the beginning of my code.
    Last edited by thebigbo; 05-12-2014 at 12:37 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •