【问题标题】:cocos2d-iphone: iPhone Retina textures cause low fps on iPadcocos2d-iphone:iPhone Retina 纹理导致 iPad 上的低 fps
【发布时间】:2013-02-01 09:10:46
【问题描述】:

我想请你帮忙,我有点迷路了。我正在升级我的游戏,以便它可以通用。我正在使用 cocos2d-iphone 1.0.1 版。我已经扩展了 CCDirectorIOS 类,所以它将 iPhone 分辨率缩放到 iPad(只有宽度,没有拉伸)。它工作得几乎完美。 我得到稳定的 60 fps:

  • 3GS iPhone/iPod,普通纹理,带 Retina 的 4G iPod/iPhone
  • 纹理。

这里是尴尬的部分:

  • iPad 1/2/3/mini,iPhone 应用(非通用),Retina 纹理 = 稳定的 60 fps,
  • iPad 1/2 和 mini,应用设置为 Universal,Retina 纹理 = 20 fps,
  • 正常纹理为 60 fps,而 iPad 3 的 Retina 纹理 = 稳定 60 fps。

因此,它可以在具有视网膜纹理的 20 fps 低分辨率 iPad 上运行。我想不通。

这里是修改后的 CCDirectorIOS 类的源代码(仅修改):

//CCDirectorIOS.h only the modified

typedef enum {
/// sets a 2D projection (orthogonal projection).
kCCDirectorProjection2D,

/// sets a 3D projection with a fovy=60, znear=0.5f and zfar=1500.
kCCDirectorProjection3D,

/// it calls "updateProjection" on the projection delegate.
kCCDirectorProjectionCustom,

/// Detault projection is 3D projection
kCCDirectorProjectionDefault = kCCDirectorProjection2D, // this was 3D

// backward compatibility stuff
CCDirectorProjection2D = kCCDirectorProjection2D,
CCDirectorProjection3D = kCCDirectorProjection3D,
CCDirectorProjectionCustom = kCCDirectorProjectionCustom,

} ccDirectorProjection;

@interface CCDirector : NSObject
{
//...

float m_VirtualWindowScale; //default 1
float m_VirtualWindowHeight; // default 0
float m_VirtualWindowWidth; // default 0
float mScaleFactor;
//...
}
//...

// stretch and virtual height
-(void) setVirtualWindowScale: (float) scale andH:(float) height;
-(float) getVirtualWindowScale;
-(float) getVirtualWindowHeight;
-(float) getVirtualWindowWidth;
//...
@end



//CCDirectorIOS.m only the modified

//...
-(void) setProjection:(ccDirectorProjection)projection
{
CGSize size = winSizeInPixels_;

switch (projection) {
case kCCDirectorProjection2D:
{
glViewport(0, 0, size.width, size.height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
ccglOrtho(0, size.width / m_VirtualWindowScale, 0, size.height / m_VirtualWindowScale, -1024 * CC_CONTENT_SCALE_FACTOR(), 1024 * CC_CONTENT_SCALE_FACTOR()); //-----------
glMatrixMode(GL_MODELVIEW);
//glDepthFunc(GL_ALWAYS);
glLoadIdentity();
break;
}

case kCCDirectorProjection3D:
{
float zeye = [self getZEye];

glViewport(0, 0, size.width, size.height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//   gluPerspective(60, (GLfloat)size.width/size.height, zeye-size.height/2, zeye+size.height/2 );
gluPerspective(60, (GLfloat)size.width/size.height, 0.5f, 1500);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt( size.width/2, size.height/2, zeye,
size.width/2, size.height/2, 0,
0.0f, 1.0f, 0.0f);
break;
}

case kCCDirectorProjectionCustom:
if( projectionDelegate_ )
[projectionDelegate_ updateProjection];
break;

default:
CCLOG(@"cocos2d: Director: unrecognized projecgtion");
break;
}

projection_ = projection;
}

//...

-(CGPoint)convertToGL:(CGPoint)uiPoint
{
CGSize s = winSizeInPoints_;
float newY = s.height - uiPoint.y;
float newX = s.width - uiPoint.x;

CGPoint ret = CGPointZero;
switch ( deviceOrientation_) {
case CCDeviceOrientationPortrait:
ret = ccp( uiPoint.x, newY );
break;
case CCDeviceOrientationPortraitUpsideDown:
ret = ccp(newX, uiPoint.y);
break;
case CCDeviceOrientationLandscapeLeft:
ret.x = uiPoint.y;
ret.y = uiPoint.x;
break;
case CCDeviceOrientationLandscapeRight:
ret.x = newY;
ret.y = newX;
break;
}
ret = ccpMult(ret, 1.0f / m_VirtualWindowScale); //-----------
return ret;
}

-(CGPoint)convertToUI:(CGPoint)glPoint
{
CGSize winSize = winSizeInPoints_;
int oppositeX = winSize.width - glPoint.x;
int oppositeY = winSize.height - glPoint.y;
CGPoint uiPoint = CGPointZero;
switch ( deviceOrientation_) {
case CCDeviceOrientationPortrait:
uiPoint = ccp(glPoint.x, oppositeY);
break;
case CCDeviceOrientationPortraitUpsideDown:
uiPoint = ccp(oppositeX, glPoint.y);
break;
case CCDeviceOrientationLandscapeLeft:
uiPoint = ccp(glPoint.y, glPoint.x);
break;
case CCDeviceOrientationLandscapeRight:
// Can't use oppositeX/Y because x/y are flipped
uiPoint = ccp(winSize.width-glPoint.y, winSize.height-glPoint.x);
break;
}
//uiPoint = ccpMult(uiPoint, 1/__ccContentScaleFactor);
uiPoint = ccpMult(uiPoint, 1/(__ccContentScaleFactor* m_VirtualWindowScale)); //-----------
return uiPoint;
}

//...

在 Appdelegate 中的 applicationDidFinishLaunch 结束时,我添加了这些:

if ([[CCDirector sharedDirector] enableRetinaDisplay: YES]) {
NSLog(@"Retina Display enabled");
}

if ([[UIDevice currentDevice].model isEqualToString:@"iPad"]) {
[[CCDirector sharedDirector] setContentScaleFactor:2.0f];
}

NSLog(@"inpixels: %f inpoints: %f", [[CCDirector sharedDirector] winSizeInPixels].width, [[CCDirector sharedDirector] winSize].width);

int screenWidth = [[CCDirector sharedDirector] winSize].width; 
int screenHeight = [[CCDirector sharedDirector] winSize].height;

float scale = screenWidth / 320.0f;
float virtualHeight = screenHeight / scale;

[[CCDirector sharedDirector] setVirtualWindowScale:scale andH:virtualHeight]; 

我将所有内容定位到 virtualHeight 和 VirtualWidth,因此所有内容都保留在屏幕上。

【问题讨论】:

  • 非 Retina 设备上的 Retina 纹理毫无意义,而且会适得其反。想象一下,在具有 1/4 内存(iPad 1)的 Retina iPad 设备上使用 4 倍内存的纹理。
  • 我将应用程序设置为 iPhone(非通用)并在 iPad 1GEN 上运行,它在信箱中运行,但具有 Retina 纹理。 60 fps,没有内存警告,完美。然后我将它设置为 Universal,游戏运行全屏,相同的 Retina 纹理,没有内存警告和 20 fps。顺便说一句,所有 Retina 资源都适合 16 MB 内存。
  • 区别在于填充率,iPad 应用需要渲染大约 4 倍于 iPhone 应用的像素,你无法比较它们的性能。只需对非 Retina 设备使用非 Retina 纹理即可。

标签: iphone objective-c ipad cocos2d-iphone retina-display


【解决方案1】:

您不应该使用比例因子,即不要使用下面的行 [SPStage setContentScaleFactor:2.0f]

如果您不设置比例因子,则一切都以 30 fps 的速度平稳运行。但缺点是应用程序现在在没有高清显卡的情况下运行。 iPad 上的一切看起来都很模糊。

这是一个艰难的决定。最好是将 iPhone 应用程序转变为 Universal,但您必须牺牲性能。您使用定制纹理和内容比例为 1 的方式提供了完美的结果,但这意味着修改代码的工作量更大。

【讨论】:

  • 是的,我想在没有大量修改的情况下做到这一点。但看起来我必须保留模糊版本。
猜你喜欢
  • 1970-01-01
  • 2023-03-21
  • 2013-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多