Cubism SDK‎ > ‎多平台开发‎ > ‎iPhone&iPad‎ > ‎

创建项目

Last update: 2014/06/04

这里介绍从创建 iOS 应用程序项目到显示出 Live2D 模型的步骤。

准备工作
  • Xcode (这里使用 Xcode 5.1.1)
  • Live2D 库
                 ( Live2D SDK 中「lib」文件夹中的「Debug-iphoneos」、「Debug-iphonesimulator」、「Release-iphoneos」、
                  「Release-iphonesimulator」文件夹。这里使用的版本是 1.0.02)
  • Live2D 资源
Live2D 资源的准备根据所使用的模型而有所不同。
这里使用样例中「haru」的资源来说明。

/sample/simple/res/haru/
  • haru.moc
  • haru.1024/haru.1024/texture_00.png
  • haru.1024/haru.1024/texture_01.png
  • haru.1024/haru.1024/texture_02.png



创建项目和预先准备

建立新项目,导入所需的文件。


启动 Xcode、点击菜单栏「File」 > 「New」 > 「Project...」。



选择「Single View Application」,点击「Next」。




设置完项目名等选项之后,点击「Next」,指定保存目录,点击「Create」。
这里把 Product Name 设置为「Live2DSample」。




接下来,添加所需的文件至项目中。


首先把库、模型之类的文件放入一个组中。
在 Xcode 项目根目录右键,点击New Group」。



这里组名设为「Resources」。



把 Live2D SDK 的 /sample/simple/res 文件夹中的模型和贴图文件拖拽至刚才建成的 Resources 组中。 


添加时的设定如下。



对 SDK 中 /lib 文件夹内的库文件,以及 /include 文件夹内的头文件,也做同样的操作。



添加完成后的状态如下。



追加完成后,为了正常使用库文件,对其进行一些设定。


在项目的「Build Settings」 > 「Linking」中,把「Other Linker Flags」的值设置为 -lLive2D。

※注意:-lLive2D 的 "l" 为小写字母L。不是大写字母 I 或分隔符 | 。



在项目的「Build Settings」 > 「Search Paths」中,把「Library Search Paths」 的值设置为库文件的路径,「User Header Search Paths」的值设置为头文件(上文从「include」文件夹中追加)的路径。

在本例中,「Library Search Paths」的值设置为 $(SRCROOT)/$(CONFIGURATION)-$(PLATFORM_NAME) ,
「User Header Search Paths」的值设置为 $(SRCROOT)/include 。
    ・$(SRCROOT) : 项目的完整路径
    ・$(CONFIGURATION) : 设置编译模式是Debug还是Release
    ・$(PLATFORM_NAME) : 平台的名称(比如 iPhoneos)





最后,在「Build Settings」 > 「Apple LLVM 5.0 - Preprocessing」 > 「Preprocessor Macros」中添加 L2D_TARGET_IPHONE ,
则对库文件的准备就完成了。





◆设置OpenGL

为了显示出 Live2D 模型,接下来设置 OpenGL。

右击项目内的 Live2DSample 组,点击「New File...」。
选择 Objective-C class ,点击「Next」,设置类名后点击「Next」,指定文件的保存目录,点击「Create」。
这里类名为「EAGLView」,父类为 UIView。




此外,把 EAGLView.m 的扩展名改为".mm"。
Live2D 的库文件由 C++ 语言编写,若要用在 iPhone 中,扩展名必须是 .cpp (C++ 扩展名),
或者 .mm ( Objective-C 和C++ 均可用的扩展名)。





接下来设置 OpenGL 。
打开生成的头文件 EAGLView.h 、写入代码如下。

  1. #import <UIKit/UIKit.h>
  2. #import <QuartzCore/QuartzCore.h>
  3. #import <OpenGLES/EAGL.h>
  4. #import <OpenGLES/ES1/gl.h>
  5. #import <OpenGLES/ES1/glext.h>
  6.  
  7. @interface EAGLView : UIView
  8. {
  9. @private
  10.     EAGLContextcontext;
  11.    
  12.     GLint deviceWidth, deviceHeight;
  13.    
  14.     GLuint defaultFramebuffer, colorRenderbuffer;
  15. }
  16. - (id)initWithFrame:(CGRect)frame;
  17. - (void) drawView:(id)sender;
  18. - (void) dealloc;
  19.  
  20. @end




打开 EAGLView.mm 、改写 initWithFrame 函数如下,以完成 OpenGL 的初始化

  1. - (id)initWithFrame:(CGRect)frame
  2. {
  3.     if ((self = [super initWithFrame:frame]))
  4.     {
  5.         CAEAGLLayereaglLayer = (CAEAGLLayer*)self.layer;
  6.         self.contentScaleFactor = [UIScreen mainScreen].scale ;
  7.         eaglLayer.opaque = TRUE;
  8.        
  9.         context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
  10.        
  11.         if (!context || ![EAGLContext setCurrentContext:context])
  12.         {
  13.             [self release];
  14.             return nil;
  15.         }
  16.         glGenFramebuffersOES(1&defaultFramebuffer);
  17.         glGenRenderbuffersOES(1&colorRenderbuffer);
  18.         glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
  19.         glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
  20.         glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);
  21.     }
  22.     return self;
  23. }



同样在 EAGLView.mm 中加入 layoutSubViews 函数,代码如下。

  1. - (void) layoutSubviews
  2. {
  3.     [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
  4.     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &deviceWidth);
  5.     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &deviceHeight);
  6.        
  7.    
  8.     glViewport(00, deviceWidth, deviceHeight);
  9.     
  10.     glMatrixMode(GL_PROJECTION);
  11.     glLoadIdentity();
  12.        
  13.     float modelWidth = live2DModel->getCanvasWidth();
  14.    
  15.     glOrthof(
  16.          0,
  17.          modelWidth,
  18.          modelWidth * deviceHeight / deviceWidth,
  19.          0,
  20.          0.5f, -0.5f
  21.          );
  22. }



接下来,进行模型的初始化。
在 EAGLView.h 里写 Live2D 模型、贴图的变量声明,以及 OpenGL 中生成贴图所需要的函数的声明。
在 EAGLView.mm 里写函数的具体实现

  1. @interface EAGLView : UIView
  2. {
  3. @private
  4.     live2d::Live2DModelIPhone* live2DModel;// Live2D模型
  5.     NSMutableArray* textures;// 贴图
  6.    
  7.     EAGLContextcontext;
  8.    
  9.     GLint deviceWidth, deviceHeight;
  10.    
  11.     GLuint defaultFramebuffer, colorRenderbuffer;
  12. }
  13. - (id)initWithFrame:(CGRect)frame;
  14. - (void) drawView:(id)sender;
  15. - (void) dealloc;
  16. - (GLuint)loadTexture:(NSString*)fileNamel;// 用来在OpenGL中生成的函数
  17. @end



在 EAGLView.mm 的 initWithFrame 函数中,进行 Live2D 模型的初始化。

  1. - (id)initWithFrame:(CGRect)frame
  2. {
  3.     if ((self = [super initWithFrame:frame])) 
  4.     {
  5.                
  6.         CAEAGLLayereaglLayer = (CAEAGLLayer*)self.layer;
  7.         self.contentScaleFactor = [UIScreen mainScreen].scale ;
  8.         eaglLayer.opaque = TRUE;
  9.        
  10.         context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
  11.        
  12.         if (!context || ![EAGLContext setCurrentContext:context])
  13.         {
  14.             [self release];
  15.             return nil;
  16.         }
  17.         glGenFramebuffersOES(1&defaultFramebuffer);
  18.         glGenRenderbuffersOES(1&colorRenderbuffer);
  19.         glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
  20.         glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
  21.         glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);
  22.        
  23.         // Live2D模型的初始化
  24.         Live2D::init() ;
  25.        
  26.         NSStringmodelpath = [[NSBundle mainBundle] pathForResource:MODEL_PATH ofType:@"moc"];
  27.         live2DModel = Live2DModelIPhone::loadModel( [modelpath UTF8String] ) ;
  28.        
  29.         for( int i = 0 ; TEXTURE_PATH[i] != NULL ; i++ )
  30.         {
  31.             int texNo = [self loadTexture:(TEXTURE_PATH[i])] ;
  32.             live2DModel->setTexture( i , texNo ) ;
  33.             [textures addObject:[NSNumber numberWithInt:texNo]];// 用于释放
  34.         }
  35.     }
  36.     return self;
  37. }



在 EAGLView.mm 中添加函数,用于 OpenGL 由图像文件生成贴图。

  1. - (GLuint)loadTexture:(NSString*)fileName
  2. {
  3.     GLuint texture;
  4.    
  5.     UIImage* uiImage = [UIImage imageNamed:fileName];
  6.    
  7.     CGImageRef image = uiImage.CGImage ;
  8.    
  9.     size_t width = CGImageGetWidth(image);
  10.     size_t height = CGImageGetHeight(image);
  11.    
  12.     GLubyte* imageData = (GLubyte*) calloc(width * height * 4 , 1);
  13.     CGContextRef imageContext = CGBitmapContextCreate(imageData,width,height,8,width * 4,CGImageGetColorSpace(image),
  14.         kCGImageAlphaPremultipliedLast);
  15.     CGContextDrawImage(imageContext, CGRectMake(00(CGFloat)width, (CGFloat)height), image);
  16.     CGContextRelease(imageContext);
  17.    
  18.     glGenTextures(1&texture);
  19.     glBindTexture(GL_TEXTURE_2D, texture);
  20.     glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
  21.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  22.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  23.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
  24.    
  25.     free(imageData);
  26.    
  27.     return texture;
  28. }



写函数用于绘制出每一帧。
在 EAGLView.mm 中添加 drawView 函数如下。

  1. - (void) drawView:(id)sender
  2. {
  3.     [EAGLContext setCurrentContext:context];
  4.    
  5.     glMatrixMode(GL_MODELVIEW);
  6.     glLoadIdentity();
  7.     glClear(GL_COLOR_BUFFER_BIT);
  8.     glEnable(GL_BLEND);
  9.     glBlendFunc(GL_ONE , GL_ONE_MINUS_SRC_ALPHA );
  10.     glDisable(GL_DEPTH_TEST) ;
  11.     glDisable(GL_CULL_FACE) ;
  12.    
  13.     live2DModel->update();
  14.     live2DModel->draw();
  15.        
  16.     [context presentRenderbuffer:GL_RENDERBUFFER_OES];
  17. }



在 layoutSubViews 函数最下方添加如下语句、令 drawView 函数在每一帧都可被调用。

  1.     [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(1/60)
  2.                                      target:self
  3.                                    selector:@selector(drawView:)
  4.                                    userInfo:nil repeats:TRUE];



最后,把 ViewController.h 中 awakeFromNib 函数改写如下,即完成。


ViewController.h
  1. @interface ViewController : UIViewController{
  2.     UIView* glView;
  3. }

ViewController.m
  1. - (void)awakeFromNib
  2. {
  3.     CGRect rect = CGRectMake(
  4.         0,
  5.         0,
  6.         [[UIScreen mainScreen] bounds].size.width,
  7.         [[UIScreen mainScreen] bounds].size.height ) ;
  8.     glView = [[EAGLView alloc] initWithFrame:rect] ;
  9.     
  10.     [self.view addSubview:glView] ;
  11. }





最终代码如下。
其余部分代码均为自动生成的状态,没有进行修改。

ViewController.h
  1. #import <UIKit/UIKit.h>
  2.  
  3. @interface ViewController : UIViewController{
  4.     UIView* glView;
  5. }
  6.  
  7. @end


ViewController.m
  1. #import "ViewController.h"
  2. #import "EAGLView.h"
  3.  
  4. @implementation ViewController
  5.  
  6. - (void)awakeFromNib
  7. {
  8.     CGRect rect = CGRectMake(
  9.         0,
  10.         0,
  11.         [[UIScreen mainScreen] bounds].size.width,
  12.         [[UIScreen mainScreen] bounds].size.height ) ;
  13.     glView = [[EAGLView alloc] initWithFrame:rect] ;
  14.     
  15.     [self.view addSubview:glView] ;
  16. }
  17.  
  18. - (void)viewDidLoad
  19. {
  20.     [super viewDidLoad];
  21. }
  22.  
  23. - (void)didReceiveMemoryWarning
  24. {
  25.     [super didReceiveMemoryWarning];
  26. }
  27.  
  28. @end


EAGLView.h
  1. #import <UIKit/UIKit.h>
  2. #import <QuartzCore/QuartzCore.h>
  3. #import <OpenGLES/EAGL.h>
  4. #import <OpenGLES/ES1/gl.h>
  5. #import <OpenGLES/ES1/glext.h>
  6. #import "Live2DModelIPhone.h"
  7.  
  8. @interface EAGLView : UIView
  9. {
  10. @private
  11.     live2d::Live2DModelIPhone* live2DModel;
  12.     NSMutableArray* textures;
  13.    
  14.     EAGLContextcontext;
  15.    
  16.     GLint deviceWidth, deviceHeight;
  17.    
  18.     GLuint defaultFramebuffer, colorRenderbuffer;
  19. }
  20. - (id)initWithFrame:(CGRect)frame;
  21. - (void)drawView:(id)sender;
  22. - (GLuint)loadTexture:(NSString*)fileNamel;
  23.  
  24. @end


EAGLView.mm
  1. #import "EAGLView.h"
  2.  
  3. #import "Live2D.h"
  4. #import "UtSystem.h"
  5. using namespace live2d ;
  6.  
  7. @implementation EAGLView
  8.  
  9. NSString* MODEL_PATH = @"haru" ;
  10. NSString* TEXTURE_PATH[] = {
  11.     @"texture_00.png" ,
  12.     @"texture_01.png" ,
  13.     @"texture_02.png" ,
  14.     NULL
  15. } ;
  16.  
  17.  
  18. + (Class) layerClass
  19. {
  20.     return [CAEAGLLayer class];
  21. }
  22.  
  23. - (id)initWithFrame:(CGRect)frame
  24. {
  25.     if ((self = [super initWithFrame:frame])) 
  26.     {
  27.                
  28.         CAEAGLLayereaglLayer = (CAEAGLLayer*)self.layer;
  29.         self.contentScaleFactor = [UIScreen mainScreen].scale ;
  30.         eaglLayer.opaque = TRUE;
  31.        
  32.         context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
  33.        
  34.         if (!context || ![EAGLContext setCurrentContext:context])
  35.         {
  36.             return nil;
  37.         }
  38.         glGenFramebuffersOES(1&defaultFramebuffer);
  39.         glGenRenderbuffersOES(1&colorRenderbuffer);
  40.         glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
  41.         glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
  42.         glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);
  43.        
  44.        
  45.         Live2D::init() ;
  46.        
  47.         NSStringmodelpath = [[NSBundle mainBundle] pathForResource:MODEL_PATH ofType:@"moc"];
  48.         live2DModel = Live2DModelIPhone::loadModel( [modelpath UTF8String] ) ;
  49.        
  50.         for( int i = 0 ; TEXTURE_PATH[i] != NULL ; i++ )
  51.         {
  52.             int texNo = [self loadTexture:(TEXTURE_PATH[i])] ;
  53.             live2DModel->setTexture( i , texNo ) ;// 贴图和模型之间建立联系
  54.             [textures addObject:[NSNumber numberWithInt:texNo]];// 用于释放资源
  55.         }
  56.     }
  57.     return self;
  58. }
  59.  
  60. - (void) drawView:(id)sender
  61. {
  62.     [EAGLContext setCurrentContext:context];
  63.    
  64.     //  OpenGL绘制模型的相关设定
  65.     glMatrixMode(GL_MODELVIEW);
  66.     glLoadIdentity();
  67.     glClear(GL_COLOR_BUFFER_BIT);
  68.     glEnable(GL_BLEND);
  69.     glBlendFunc(GL_ONE , GL_ONE_MINUS_SRC_ALPHA );
  70.     glDisable(GL_DEPTH_TEST) ;
  71.     glDisable(GL_CULL_FACE) ;
  72.    
  73.     live2DModel->update();
  74.     live2DModel->draw();
  75.        
  76.     [context presentRenderbuffer:GL_RENDERBUFFER_OES];
  77. }
  78.  
  79. - (void) layoutSubviews
  80. {
  81.     [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
  82.     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &deviceWidth);
  83.     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &deviceHeight);
  84.        
  85.    
  86.     //  令Viewport符合设备的屏幕尺寸。显示出全部画面。
  87.     glViewport(00, deviceWidth, deviceHeight);
  88.        
  89.     //  简单的使用投影矩阵进行所有变换。
  90.     glMatrixMode(GL_PROJECTION);
  91.     glLoadIdentity();
  92.        
  93.     float modelWidth = live2DModel->getCanvasWidth()//  在Modeler中设定的画布尺寸
  94.    
  95.     //  设定绘图范围。参数顺序为left, right, bottom, top。
  96.     glOrthof(
  97.          0,
  98.          modelWidth,
  99.          modelWidth * deviceHeight / deviceWidth,
  100.          0,
  101.          0.5f, -0.5f
  102.          );
  103.        
  104.     [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(1/60)
  105.                                      target:self
  106.                                    selector:@selector(drawView:)
  107.                                    userInfo:nil repeats:TRUE];
  108. }
  109.  
  110.  
  111. // 从图像文件读取贴图
  112. - (GLuint)loadTexture:(NSString*)fileName
  113. {
  114.     GLuint texture;
  115.     
  116.     // 打开图像文件生成CGImageRef
  117.     UIImage* uiImage = [UIImage imageNamed:fileName];
  118.     
  119.     CGImageRef image = uiImage.CGImage ;
  120.        
  121.     // 获得图像大小
  122.     size_t width = CGImageGetWidth(image);
  123.     size_t height = CGImageGetHeight(image);
  124.        
  125.     // 准备位图数据
  126.     GLubyte* imageData = (GLubyte*) calloc(width * height * 4 , 1);
  127.     CGContextRef imageContext = CGBitmapContextCreate(imageData,width,height,8,width * 4,CGImageGetColorSpace(image),
  128.         kCGImageAlphaPremultipliedLast);
  129.     CGContextDrawImage(imageContext, CGRectMake(00(CGFloat)width, (CGFloat)height), image);
  130.     CGContextRelease(imageContext);
  131.    
  132.     // 生成OpenGL用的贴图
  133.     glGenTextures(1&texture);
  134.     glBindTexture(GL_TEXTURE_2D, texture);
  135.     glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
  136.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  137.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  138.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
  139.    
  140.     free(imageData);
  141.        
  142.     // 返回所生成的贴图
  143.     return texture;
  144. }
  145.  
  146. @end
  147.  



コメント