我如何使用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; }
为什么这只对所有三个使用一个纹理,而不是三个不同的纹理,每个对象一个纹理? 我怎样才能解决这个问题?
我已经实现了地球上的月球在移动。 为地球和月亮不同的纹理。 在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); }
要做多个纹理,你需要做:
effect.texture2d0.name = firstTexture.name; [effect prepareToDraw]; [self renderFirstObject]; effect.texture2d0.name = secondTexture.name; [effect prepareToDraw]; [self renderSecondObject];
或类似的东西。 如果你有很多的对象,我build议使用纹理地图集,然后使用以下方法进行批量渲染:
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]; }
当然这是简化它,没有顶点属性数组设置。
我为这个问题做的一件事是,我做了一个单一的图像,其中所有的纹理…现在我只给我的GLKBaseEffect对象一个纹理。
但是,如果有任何人在GLKit的帮助下,有多个纹理的多个对象的答案,请让我知道…
谢谢。
一种解决方法是分离绘图调用,以便首先绘制所有使用纹理A的对象,然后绘制使用纹理B的所有对象等等。
还有这里描述的纹理地图集替代: https : //stackoverflow.com/a/8230592/64167 。
我正在学习更多的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); }
到目前为止,这对我来说确实很好。