iPhoneBuddy
iPhoneBuddy

Reputation: 49

How can I apply different textures to different objects using GLKit?

I am displaying 3 objects with the help of GLKit. However, when I am applying textures to these objects, only one texture is being used for all three.

The code I am using is as follows:

- (void)setUpGL{


    NSLog(@"i : %d, %d, %d",i,j,k);
    firstPlayerScore = 0;
    secondPlayerScore = 0;
    staticBall = YES;
    isSecondPlayer = NO;

    self.boxPhysicsObjects = [NSMutableArray array];
    self.spherePhysicsObjects = [NSMutableArray array];
    self.immovableBoxPhysicsObjects = [NSMutableArray array];
    self.cylinderPhysicsObjects = [NSMutableArray array];
    self.secondPlayerCylinderPhysicsObjects = [NSMutableArray array];
    self.sphereArray = [NSMutableArray array];

    GLKView *view = (GLKView *)self.view;
    NSAssert([view isKindOfClass:[GLKView class]],@"View controller's view is not a GLKView");

    view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
    view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    [EAGLContext setCurrentContext:view.context];

    self.baseEffect = [[GLKBaseEffect alloc] init];

    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);

    //glGenBuffers(1, &_vertexBuffer);
    //glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    //glBufferData(GL_ARRAY_BUFFER, (i+j)*sizeof(float), sphereVerts, GL_STATIC_DRAW);

    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);

    self.baseEffect.light0.enabled = GL_TRUE;
    self.baseEffect.light0.ambientColor = GLKVector4Make(0.7f, 0.7f, 0.7f, 1.0f);


    [self addImmovableBoxPhysicsObjects];
    [self addRandomPhysicsSphereObject];
    //[self addFirstPlayerCylinderObject];
    //[self addSecondPlayerCylinderObject];
    //[self scheduleAddRandomPhysicsSphereObject:nil];

}


- (void)addRandomPhysicsObject{
   if(random() % 2 == 0)
   {
      [self addRandomPhysicsBoxObject];
   }
   else
   {
      [self addRandomPhysicsSphereObject];
   }
}

- (void)setUpBox{

    CGImageRef image = [[UIImage imageNamed:@"outUV2.PNG"] CGImage];
    textureInfo1 = [GLKTextureLoader textureWithCGImage:image options:nil error:NULL];
    self.baseEffect.texture2d0.name = textureInfo1.name;
    self.baseEffect.texture2d0.enabled = YES;

    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer( GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), final_meshVerts);

    glEnableVertexAttribArray(GLKVertexAttribNormal);
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), final_meshNormals);

    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), final_meshTexCoords);

    //glDisableVertexAttribArray(GLKVertexAttribTexCoord0);

}

- (void)drawPhysicsBoxObjects{

    //self.baseEffect.texture2d0.target = textureInfo1.target;

    PAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];

    GLKMatrix4 savedModelviewMatrix = self.baseEffect.transform.modelviewMatrix;

    for(PPhysicsObject *currentObject in self.boxPhysicsObjects){
        self.baseEffect.transform.modelviewMatrix =
        GLKMatrix4Multiply(savedModelviewMatrix,[appDelegate physicsTransformForObject:currentObject]);

        [self.baseEffect prepareToDraw];

        glDrawArrays(GL_TRIANGLES, 0, final_meshNumVerts);
    }

    self.baseEffect.light0.diffuseColor = GLKVector4Make(1.0f, 1.0f, 1.0f, 1.0f);// Alpha

    for(PPhysicsObject *currentObject in self.immovableBoxPhysicsObjects){
        self.baseEffect.transform.modelviewMatrix = GLKMatrix4Multiply(savedModelviewMatrix, [appDelegate physicsTransformForObject:currentObject]);
        [self.baseEffect prepareToDraw];

        glDrawArrays(GL_TRIANGLES,0, final_meshNumVerts);
    }

    self.baseEffect.transform.modelviewMatrix = savedModelviewMatrix;
}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    static float a = 0;
    a = a+0.1;
    //NSLog(@"a : %f",a);
    self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeLookAt(
                                                                     0, 9.8, 10.0, // Eye position
                                                                     0.0, 1.0, 0.0,  // Look-at position
                                                                     0.0, 1.0, 0.0); // Up direction

    const GLfloat  aspectRatio = (GLfloat)view.drawableWidth / (GLfloat)view.drawableHeight;

   self.baseEffect.transform.projectionMatrix =
   GLKMatrix4MakePerspective(GLKMathDegreesToRadians(35.0f),aspectRatio,0.2f,200.0f); // Far arbitrarily far enough to contain scene

   self.baseEffect.light0.position = GLKVector4Make(0.6f, 1.0f, 0.4f, 0.0f);

   [self.baseEffect prepareToDraw];

   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    [self drawPhysicsSphereObjects];
    [self drawPhysicsBoxObjects];
    //[self drawPhysicsCylinderObjects];
}

- (void)addRandomPhysicsSphereObject{
    PAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];

    PPhysicsObject *anObject = nil;

    if([self.spherePhysicsObjects count] < PMAX_NUMBER_BLOCKS)
    {
        NSLog(@"if");
        anObject = [[PPhysicsObject alloc] init];
    }
    else
    {
        NSLog(@"else");
        anObject = [self.spherePhysicsObjects objectAtIndex:0];
        [self.spherePhysicsObjects removeObjectAtIndex:0];
    }

    [self.spherePhysicsObjects addObject:anObject];

    [appDelegate physicsRegisterSphereObject:anObject
                                    position:GLKVector3Make(0,3.5,-2)
                                        mass:0.0f];
    [self setUpSphere];

    /*[appDelegate physicsSetVelocity:GLKVector3Make(
     random() / (float)RAND_MAX * 2.0f - 1.0f,
     0.0f,
     random() /(float)RAND_MAX * 2.0f - 1.0f)
     forObject:anObject];*/
}

- (void)setUpSphere{

    CGImageRef image = [[UIImage imageNamed:@"basketball.png"] CGImage];
    textureInfo = [GLKTextureLoader textureWithCGImage:image options:nil error:NULL];

    self.baseEffect.texture2d0.name = textureInfo.name;
    self.baseEffect.texture2d0.enabled = YES;

    glEnableVertexAttribArray( GLKVertexAttribPosition);
    glVertexAttribPointer( GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), newbasketballVerts);

    glEnableVertexAttribArray(GLKVertexAttribNormal);
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), newbasketballNormals);

    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), newbasketballTexCoords);

    //glDisableVertexAttribArray(GLKVertexAttribTexCoord0);

}

- (void)drawPhysicsSphereObjects{
    NSLog(@"draw");
    /*static int x = 1;
     if (x>20) {
     x=20;
     }
     matrix = GLKMatrix4Identity;
     matrix = GLKMatrix4MakeTranslation(0.1 * (x++), 0.0, 0.0);*/
    //self.baseEffect.texture2d0.target = textureInfo2.target;

    PAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];

    GLKMatrix4 savedModelviewMatrix = self.baseEffect.transform.modelviewMatrix;

    /*CGImageRef image = [[UIImage imageNamed:@"basketball.png"] CGImage];
     GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:image options:nil error:NULL];

     self.baseEffect.texture2d0.name = textureInfo.name;
     self.baseEffect.texture2d0.target = textureInfo.target;*/

    self.baseEffect.light0.diffuseColor = GLKVector4Make(1.0f, 1.0f, 1.0f, 1.0f);
    //glVertexPointer(3, GL_FLOAT, 0, sphereVerts);
    //glNormalPointer(GL_FLOAT, 0, sphereNormals);
    //glTexCoordPointer(2, GL_FLOAT, 0, final meshTexCoords);

    /*glGenBuffers(1, &ballVertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, ballVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(MeshVertexData), MeshVertexData, GL_STATIC_DRAW);

    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(arrowVertexData), 0);
    glEnableVertexAttribArray(GLKVertexAttribNormal);
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_TRUE, sizeof(arrowVertexData), (void *)offsetof(arrowVertexData, normal));
    glBindVertexArrayOES(arrowVertexArray);*/

    //glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    //glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), newbasketballTexCoords);
    if (!isSecondPlayer) {
        for(PPhysicsObject *currentObject in self.spherePhysicsObjects)
        {NSLog(@"first");
            self.baseEffect.transform.modelviewMatrix =
            GLKMatrix4Multiply(savedModelviewMatrix, [appDelegate physicsTransformForObject:currentObject]);
            [self.baseEffect prepareToDraw];

            glDrawArrays(GL_TRIANGLES,  0, newbasketballNumVerts);
            //glDrawArrays(GL_TRIANGLES, 0, sizeof(MeshVertexData) / sizeof(arrowVertexData));
        }
    }
    else{
        for(PPhysicsObject *currentObject in self.secondSpherePhysicsObjects)
        {
            self.baseEffect.transform.modelviewMatrix =
            GLKMatrix4Multiply(savedModelviewMatrix, [appDelegate physicsTransformForObject:currentObject]);
            [self.baseEffect prepareToDraw];

            glDrawArrays(GL_TRIANGLES,  0, newbasketballNumVerts);
            //glDrawArrays(GL_TRIANGLES, 0, sizeof(MeshVertexData) / sizeof(arrowVertexData));
        }
    }
    //glBindBuffer(GL_ARRAY_BUFFER, 0);
    //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    //glDisableVertexAttribArray(GLKVertexAttribTexCoord0);
    self.baseEffect.transform.modelviewMatrix = savedModelviewMatrix;
}

Why is this only using one texture for all three, and not three different textures, one for each object? How can I fix this?

Upvotes: 0

Views: 1256

Answers (5)

罗大柚
罗大柚

Reputation: 260

I had achieved a scene that the moon around the earth moving. different textures for the earth and the moon. under GLKit frame, the code just like this:

-(void)viewDidLoad
{
     //......
    // Setup Earth texture  
CGImageRef earthImageRef =  
[[UIImage imageNamed:@"Earth512x256.jpg"] CGImage];  

earthTextureInfo = [GLKTextureLoader  
                    textureWithCGImage:earthImageRef  
                    options:[NSDictionary dictionaryWithObjectsAndKeys:  
                             [NSNumber numberWithBool:YES],  
                             GLKTextureLoaderOriginBottomLeft, nil nil]  
                    error:NULL];  

// Setup Moon texture  
CGImageRef moonImageRef =  
[[UIImage imageNamed:@"Moon256x128.png"] CGImage];  

moonTextureInfo = [GLKTextureLoader  
                   textureWithCGImage:moonImageRef  
                   options:[NSDictionary dictionaryWithObjectsAndKeys:  
                            [NSNumber numberWithBool:YES],  
                            GLKTextureLoaderOriginBottomLeft, nil nil]  
                   error:NULL];  
//......

}

then, draw earth and moon.

- (void)drawEarth  
{  
//setup texture
self.baseEffect.texture2d0.name = earthTextureInfo.name;  
self.baseEffect.texture2d0.target = earthTextureInfo.target;  

//  
GLKMatrixStackPush(self.modelviewMatrixStack);  


GLKMatrixStackRotate(   // Rotate (tilt Earth's axis)  
                     self.modelviewMatrixStack,  
                     GLKMathDegreesToRadians(SceneEarthAxialTiltDeg),  
                     1.0, 0.0, 0.0);  
GLKMatrixStackRotate(   // Rotate about Earth's axis  
                     self.modelviewMatrixStack,  
                     GLKMathDegreesToRadians(earthRotationAngleDegrees),  
                     0.0, 1.0, 0.0);  


self.baseEffect.transform.modelviewMatrix =  
GLKMatrixStackGetMatrix4(self.modelviewMatrixStack);  

//draw earth  
[self.baseEffect prepareToDraw];  


glBindVertexArrayOES(_vertexArray);  
glDrawArrays(GL_TRIANGLES, 0, sphereNumVerts);  

//pop 
GLKMatrixStackPop(self.modelviewMatrixStack);  

self.baseEffect.transform.modelviewMatrix =  
GLKMatrixStackGetMatrix4(self.modelviewMatrixStack);  

}

- (void)drawMoon  
{  

self.baseEffect.texture2d0.name = moonTextureInfo.name;  
self.baseEffect.texture2d0.target = moonTextureInfo.target;  


GLKMatrixStackPush(self.modelviewMatrixStack);  

GLKMatrixStackRotate(   // Rotate to position in orbit  
                     self.modelviewMatrixStack,  
                     GLKMathDegreesToRadians(moonRotationAngleDegrees),  
                     0.0, 1.0, 0.0);  
GLKMatrixStackTranslate(// Translate to distance from Earth  
                        self.modelviewMatrixStack,  
                        0.0, 0.0, SceneMoonDistanceFromEarth);  
GLKMatrixStackScale(    // Scale to size of Moon  
                    self.modelviewMatrixStack,  
                    SceneMoonRadiusFractionOfEarth,  
                    SceneMoonRadiusFractionOfEarth,  
                    SceneMoonRadiusFractionOfEarth);  
GLKMatrixStackRotate(   // Rotate Moon on its own axis  
                     self.modelviewMatrixStack,  
                     GLKMathDegreesToRadians(moonRotationAngleDegrees),  
                     0.0, 1.0, 0.0);  
// 
self.baseEffect.transform.modelviewMatrix =  
GLKMatrixStackGetMatrix4(self.modelviewMatrixStack);  

//draw moon  
[self.baseEffect prepareToDraw];  


glBindVertexArrayOES(_vertexArray);  
glDrawArrays(GL_TRIANGLES, 0, sphereNumVerts);  

GLKMatrixStackPop(self.modelviewMatrixStack);  

self.baseEffect.transform.modelviewMatrix =  
GLKMatrixStackGetMatrix4(self.modelviewMatrixStack);  

}  

Upvotes: 1

shiningabdul
shiningabdul

Reputation: 181

To do multiple textures you will need to do:

effect.texture2d0.name = firstTexture.name;
[effect prepareToDraw];  
[self renderFirstObject];

effect.texture2d0.name = secondTexture.name;
[effect prepareToDraw];
[self renderSecondObject];

or something similar. If you have lots of objects, I recommend using texture atlases and then doing batch rendering using:

glDrawElements(GL_TRIANGLES, totalIndicies, GL_UNSIGNED_SHORT, indices);

I tried to use glDrawArray for every single object and the framerate of my app dipped to like 10fps.

In your code, the reason it was using 1 texture for all objects is because you never changed the effect.texture2d0.name to the texture you need before each object. If I were to change your code it would be:

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
     static float a = 0;
     a = a+0.1;
     //NSLog(@"a : %f",a);
     self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeLookAt(
                                                                 0, 9.8, 10.0, // Eye position
                                                                 0.0, 1.0, 0.0,  // Look-at position
                                                                 0.0, 1.0, 0.0); // Up direction

     const GLfloat  aspectRatio = (GLfloat)view.drawableWidth / (GLfloat)view.drawableHeight;

     self.baseEffect.transform.projectionMatrix =
     GLKMatrix4MakePerspective(GLKMathDegreesToRadians(35.0f),aspectRatio,0.2f,200.0f); // Far arbitrarily far enough to contain scene

     self.baseEffect.light0.position = GLKVector4Make(0.6f, 1.0f, 0.4f, 0.0f);

     [self.baseEffect prepareToDraw];

     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

     self.baseEffect.texture2d0.name = textureInfo.name;
     [self.baseEffect prepareToRender];
     [self drawPhysicsSphereObjects];
     self.baseEffect.texture2d0.name = textureInfo1.name;
     [self.baseEffect prepareToRender];
     [self drawPhysicsBoxObjects];
     //[self drawPhysicsCylinderObjects];
 }

Of course this is simplifying it, and without the vertex attribute array setup.

Upvotes: 1

MarkFromMars
MarkFromMars

Reputation: 386

I am playing around with learning more OpenGL ES and I may have a way to do this.

In my case I have N quads, each with an individual texture. In [view drawInRect] for each quad I want to draw I set new texture properties on baseEffect before I draw each quad, then call prepareToDraw on the BaseEffect and the quad, then render the quad.

Here is some pseudocode for what I mean:

for (int i = 0; i < quads.count; i++) {
    baseEffect.texture2d0.name = textureInfo[i].name;
    baseEffect.texture2d0.target = textureInfo[i].target;
    [baseEffect prepareToDraw];
    [quads[i] prepareToDraw];
    glDrawArrays(GL_TRIANGLES, 0, 4);
}

This is working ok for me so far.

Upvotes: 0

Mihai Damian
Mihai Damian

Reputation: 11432

One solution would be to separate your drawing calls so that first you draw all objects that use texture A, then all objects that use texture B and so on.

There is also the texture atlas alternative described here: https://stackoverflow.com/a/8230592/64167.

Upvotes: 0

iPhoneBuddy
iPhoneBuddy

Reputation: 49

One thing i did for this problem is that i made one single image with all textures in it... now i give only one texture to my GLKBaseEffect object.

But if any person have answer for multiple objects with multiple textures with the help of GLKit, please let me know...

Thank You.

Upvotes: 0

Related Questions