如何使用GLKit将不同的纹理应用于不同的对象?

时间:2012-12-03 06:52:39

标签: ios opengl-es textures glkit

我在GLKit的帮助下显示3个对象。但是,当我将纹理应用于这些对象时,所有三个纹理只使用一个纹理。

我使用的代码如下:

- (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;
}

为什么这只对所有三个使用一个纹理,而不是三个不同的纹理,每个对象一个?我该如何解决这个问题?

5 个答案:

答案 0 :(得分:1)

要做多个纹理,您需要这样做:

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

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

或类似的东西。如果你有很多物体,我建议使用纹理地图,然后使用:

进行批量渲染

glDrawElements(GL_TRIANGLES,totalIndicies,GL_UNSIGNED_SHORT,indices);

我尝试对每个对象使用glDrawArray,我的应用程序的帧率下降到10fps。

在你的代码中,它为所有对象使用1个纹理的原因是因为你从未将effect.texture2d0.name更改为每个对象之前所需的纹理。如果我要更改你的代码,那就是:

- (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];
 }

当然这是简化它,没有顶点属性数组设置。

答案 1 :(得分:1)

我已经实现了一个场景,即地球周围的月亮在移动。地球和月亮的不同纹理。在GLKit框架下,代码如下:

-(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];  
//......

}

然后,画出地球和月亮。

- (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);  

}  

答案 2 :(得分:0)

我为这个问题做的一件事就是我制作了一张包含所有纹理的单个图像...现在我只为GLKBaseEffect对象提供一个纹理。

但是如果有人在GLKit的帮助下回答了多个具有多个纹理的对象,请告诉我......

谢谢。

答案 3 :(得分:0)

一种解决方案是分离绘图调用,以便首先绘制使用纹理A的所有对象,然后绘制使用纹理B的所有对象,等等。

这里还描述了纹理图集替代方案:https://stackoverflow.com/a/8230592/64167

答案 4 :(得分:0)

我正在学习更多的OpenGL ES,我可能有办法做到这一点。

在我的情况下,我有N个四边形,每个都有一个单独的纹理。在我想绘制的每个四边形的[view drawInRect]中,我在绘制每个四边形之前在baseEffect上设置新的纹理属性,然后在BaseEffect和四边形上调用prepareToDraw,然后渲染四边形。

这是我的意思的一些伪代码:

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);
}

到目前为止,这对我来说还不错。