2018-11-19 12:39:10 wn2utt18 阅读数 158

最近公司要开发一款用于3d展示的应用,通过在网上拜读各大神的帖子,终于完美解决此类问题。(unity3d版本2017.3,xcode9.2)

前边unity3d打包iOS工程的方法在此就不做赘述,其他帖子基本可以解决,本帖直接上干货。

1、在打包好的iOS工程中,找到UnityAppController.m文件(在classes文件夹下),因为我们需要3d物体和控件同屏,所以要首先改造- (void)applicationDidBecomeActive:(UIApplication*)application;这个方法。具体代码如下:

- (void)applicationDidBecomeActive:(UIApplication*)application
{
    ::printf("-> applicationDidBecomeActive()\n");
        
    if(_unityAppReady)
    {
        if(UnityIsPaused())
        {
            UnityPause(0);
            UnityWillResume();
        }
        UnitySetPlayerFocus(1);
    }
    else if(!_startUnityScheduled)
    {
        _startUnityScheduled = true;
        [self performSelector:@selector(startUnity:) withObject:application afterDelay:0];
    }
    _didResignActive = false;
    
    static dispatch_once_t disOnce;
    dispatch_once(&disOnce,  ^ {
        [self performSelector:@selector(startViewC:) withObject:application afterDelay:0];
    });
    
    NSLog(@"_window22222222%@",_window.rootViewController);
}
-(void)startViewC:(UIApplication *)application{
    //自己的需要进入的视图
    MyViewController *root = [[MyViewController alloc] init];
    _window.rootViewController = root;
    
    GetAppController().unityView.frame = CGRectMake(0, 0, 512, 768);//我这里只对ipad进行了适配
    root.controller  = GetAppController();//controller是一个UnityAppController类型
  
}

2、在我们自己的controller中进行iOS代码处理,MyViewcontroller.h

#import <UIKit/UIKit.h>
#import "UnityAppController.h"
@interface MyViewController : UIViewController
@property(nonatomic, strong) UIView *vw;
@property(nonatomic)UnityAppController *controller;

@end

MyViewcontroller.m

#import "MyViewController.h"

@interface MyViewController ()

@end

@implementation MyViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.


    UIView *uview = [[UIView alloc] initWithFrame:CGRectMake(512, 0, 512, 768)];
    [self.view addSubview:uview];
    [uview addSubview:self.controller.unityView];

   //除了uview之外的区域,iOS的控件就可以按自己的项目需求处理了。

}

@end

通过上边的操作基本上已经解决了iOS和unity同窗的问题,如还有疑问或者觉得写的有错误的地方可以留言。

2016-03-19 17:07:54 niuhailei 阅读数 9422

     之前做一个项目时,需要一个界面展示3D模型并进行交互。所以针对这个问题研究了很久,并总结了一些经验。在论坛中总遇到相同需求的人,也有很多人问我,所以写出这篇博客供大家参考。网上资料很少,即时有也比较模糊,所以接下来我尽量说的详细些,看完之后还有不懂得可以继续问我,QQ:1414819100.

   一、如果项目紧紧是展示3d模型,并进行简单的手势交互,这个时候,最好不要选择使用U3D和iOS混编,这个样做起来会比较麻烦,逻辑关系复杂,安全隐患严重。Opengl能很好的解决这个问题,iOS封装成GLView,用起来很简单实用(可以进行交互,缩放,旋转,增删,调整透视等)。附上Demo,弄懂里面的一些主要参数,变量,实现你要的效果不难。有参数不明白可以继续联系我,这个就不多说了,接下来讲解比较棘手的。

  

   二、项目要求3D效果比较绚丽,交互复杂,GLView已经不能满足我们的需求,这个时候我们可以考虑一下U3D和iOS混编。我把自己在这个过程中遇到的问题的感悟分享给大家。

         首先,Unity3d会导出一个工程文件,这个工程文件和我们的iOS项目结构很相似。拿到之后,用打开,并运行。如果遇到报错,

         ld: warning: path '/Users/MAC/Desktop/ZiTest/Libraries/libiPhone-lib.a' following -L not a directory
         ld: library not found for -liPhone-lib
         clang: error: linker command failed with exit code 1 (use -v to see invocation)

        不要紧张,虽然错很多,但只是一个问题。U3D导出的xcode工程文件不支持模拟器运行,换成真机运行,问题就没有了。如果真机感觉每次都是真机测试很麻烦,你可以让u3d导出一份可以模拟器运行的工程文件。

        也有可能你会不能选择模拟器,找到TARGETS---Build Settings---  Supported Platforms   改成iOS。

       解决混编的方法有很多种,总结起来就两大类,一个是u3d导入iOS,一个是iOS导入u3d中。这个可以看看我之前看的一些文章,试过好多,没有成功,大家可以参考下,即时不行,了解一下原理。版本不同,方法可能有些不同,但是原理是一样的。(目前自己找到资料仅仅只有这些,大家好好参考一下)

                          http://blog.sina.com.cn/s/blog_48a8af640102vh2q.html

                          http://segmentfault.com/q/1010000000392448
                         http://www.cnblogs.com/shawn-zp/p/3225477.html

                         原文:http://alexanderwong.me/post/29949258838/building-a-ios-unity-uiview-uiviewcontroller
                          翻译:http://blog.163.com/savage_cui/blog/static/64335507201332834915876/
                         补充:http://user.qzone.qq.com/1523511691/infocenter#!app=2&via=QZ.HashRefresh&pos=1375185802
                         其他参考:http://www.scio.de/en/blog-a-news/scio-development-blog-en/entry/iphone-a-unity3d-integrating-3rd-party-static-libraries-in-unity3d-generated-    

                                         xcode-projects


       u3d导入iOS中会比较麻烦一些,u3d产生的文件很大,setting的参数也要详细设置。

       iOS导入u3d中相对简单,下面介绍这个方法。

       打开u3d导出的xcode工程文件,运行一下。

   

                                                    文件是这个样子。

   运行的时候提示(报错200+个)

说明不支持模拟器运行,这个时候改用真机运行就可以了。最方便的办法就是让u3d导出可以真机运行的工程文件。

好了,能运行之后,拖入或者创建我们自己的ViewController。


打开Classes文件,找到UnityAppController(这个文件相当于我们认知的Appdelegate文件),找到这个方法,改变程序初始视图,由unityView改成我们自己的View。

改成这个样子:

- (void)applicationDidBecomeActive:(UIApplication*)application
{
    ::printf("-> applicationDidBecomeActive()\n");
    
    
    static dispatch_once_t disOnce;
    dispatch_once(&disOnce,  ^ {
    [self performSelector:@selector(startViewC:) withObject:application afterDelay:0];    
    });
    
    NSLog(@"_window22222222%@",_window.rootViewController);
//        [_snapshotView removeFromSuperview];
//        _snapshotView = nil;
    

    if(_unityAppReady)
    {
        if(UnityIsPaused())
        {
            UnityPause(0);
            UnityWillResume();
        }
        UnitySetPlayerFocus(1);
    }
    else if(!_startUnityScheduled)
    {
//        _startUnityScheduled = true;
//        [self performSelector:@selector(startUnity:) withObject:application afterDelay:0];
           }

    _didResignActive = false;
}

-(void)startViewC:(UIApplication *)application{

 //我们自己需要进入的视图

    MyViewController *root = [[MyViewController alloc] init];
    _window.rootViewController = root;
    //[UnityGetMainWindow() makeKeyAndVisible];
}

现在程序启动之后,首先进入的就是我们的视图了,接下来就是怎么在我们的视图中进入到u3d界面视图。[self.UnityAC startUnity:[UIApplication sharedApplication]];方法只能调用一次,所以我们需要设置全局变量观察是第几次启动u3d界面。



//第一次启动
-(void)firstStarUnity{
   [self.UnityAC startUnity:[UIApplication sharedApplication]];
}
//再次启动
-(void)againStarUnity{
    
    
    [self.UnityAC againStartUnity];
}

在UnityAppController里面实现再次启动打方法

//再次启动
-(void)againStartUnity{
    
   
    
    _window            = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    _window.rootViewController = _rootController;
    _unityView        = [self createUnityView];
    
    //[DisplayManager Initialize];
    _mainDisplay    = [DisplayManager Instance].mainDisplay;
    [_mainDisplay createWithWindow:_window andView:_unityView];
    
    [self createUI];
    [self preStartUnity];
    
    UnityPause(true);
    _didResignActive = YES;
    Profiler_UninitProfiler();
    
    NSLog(@"22222%@",_window.rootViewController);
    [self showGameUI];
    [self createDisplayLink];

    
    [[[UnityGetMainWindow() rootViewController] view] setHidden:NO];
//

    
        if (_didResignActive) {
        UnityPause(false);
        _didResignActive = NO;
    }
}



在UnityAppController---- (void)startUnity:(UIApplication*)application方法改成:

- (void)startUnity:(UIApplication*)application
{
    NSAssert(_unityAppReady == NO, @"[UnityAppController startUnity:] called after Unity has been initialized");

    _window            = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    _unityView        = [self createUnityView];
    
    //[DisplayManager Initialize];
    _mainDisplay    = [DisplayManager Instance].mainDisplay;
    [_mainDisplay createWithWindow:_window andView:_unityView];
    
    [self createUI];
    [self preStartUnity];
    
    
    UnityInitApplicationGraphics();

    // we make sure that first level gets correct display list and orientation
    [[DisplayManager Instance] updateDisplayListInUnity];

    UnityLoadApplication();
    Profiler_InitProfiler();

    [self showGameUI];
    [self createDisplayLink];

    UnitySetPlayerFocus(1);
}

现在我们就可从我们的界面进入u3d界面了,现在写在u3d退出后回到我们的界面中。

找到u3d预留的返回按钮的方法,在里面实现如何返回。在这里我没有用按钮,写在了UnityView.mm的touch的方法里。

在UnityAppController里实现:

//退出的方法
-(void)exitUnity{
    _window            = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    _unityView        = [self createUnityView];
    
    //[DisplayManager Initialize];
    _mainDisplay    = [DisplayManager Instance].mainDisplay;
    [_mainDisplay createWithWindow:_window andView:_unityView];
    
    [self createUI];
    [self preStartUnity];
    
    UnityPause(true);
    _didResignActive = YES;
    Profiler_UninitProfiler();
    NSLog(@"1111%@",_window.rootViewController);
    [[UnityGetMainWindow() rootViewController] view].hidden = YES;
//    _window            = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.myViewC = [[MyViewController alloc] init];
    _window.rootViewController = self.myViewC;
    NSLog(@"%@",self.window);
    NSLog(@"33333%@",_window.rootViewController);
    NSLog(@"%@",self.myViewC);
    
    //[UnityGetMainWindow() makeKeyAndVisible];
    
}


好了,现在就可以都实现了。本人目前还不是很精通,但经过好几天日夜的研究,基本的已经没有问题。欢迎各位优化,并通知我QQ:1414819100,谢谢!


GLview Demo下载地址:http://download.csdn.net/detail/niuhailei/9463994。

iOS,u3d混编Demo下载地址:https://yunpan.cn/cYX7fTFQXLeSc (提取码:ed6b)






2015-04-15 13:45:51 diveinedu 阅读数 848

Unity3D是一个非常强大的跨平台游戏引擎,但还是也免不了需要访问平台本身的一些功能。Unity3D并没有将平台方方面面都创建对应的API,尤其是比较新的一些功能。这时需要我们自己编写本地插件来解决,本文主要介绍如何开发Unity3D的iOS本地相册插件GlobalBrowser(能够自动扫描Documents目录,并且使用照片墙展示,其中展示功能使用了一个Objective-C的开源控件MWPhotoBrowser)。

准备工作

本文使用Unity 5和Xcode 6.2进行开发,目前只有Unity 4.6和Unity 5支持arm64,并且只有Unity 5支持在插件中使用子目录。我们有三种使用Objective-C代码的方式:源码、静态库(.a)和框架(iOS 8),这一次我们选择纯源码的方式。

本地代码编写

1、新建iOS的项目PhotoBrowser,在项目目录下创建Library文件夹。

2、将MWPhotoBrowser以及所使用的其它开源代码复制到Library,并添加到Xcode项目中。

3、创建GlobalBrowser目录,然后创建DVIGlobalBrowser类。我们在这个类中实现图片浏览插件的本地代码。为了简单起见,我们只实现了几个类方法,然后使用一个静态变量保存对象。

#import <Foundation/Foundation.h>

@interface DVIGlobalBrowser : NSObject
+ (void)show;
+ (void)dismiss;
@end

/////////////实现代码////////////////////////

#import "DVIGlobalBrowser.h"

#import <UIKit/UIKit.h>

#import "MWPhotoBrowser.h"
#import "MWPhoto.h"

static DVIGlobalBrowser *sharedInstance = nil;

@interface DVIGlobalBrowser () <MWPhotoBrowserDelegate>
{
    NSArray *_photosArray;
    NSString *_photoDir;
}
@property (nonatomic, strong) MWPhotoBrowser *photoBrowser;
@end

@implementation DVIGlobalBrowser

+ (void)initialize {
    sharedInstance = [[DVIGlobalBrowser alloc] init];
    sharedInstance.photoBrowser = [[MWPhotoBrowser alloc] initWithDelegate:sharedInstance];
    sharedInstance.photoBrowser.displayActionButton = YES;
    sharedInstance.photoBrowser.displayNavArrows = YES;
    sharedInstance.photoBrowser.displaySelectionButtons = NO;
    sharedInstance.photoBrowser.alwaysShowControls = NO;
    sharedInstance.photoBrowser.zoomPhotosToFill = YES;
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
    sharedInstance.photoBrowser.wantsFullScreenLayout = YES;
#endif
    sharedInstance.photoBrowser.enableGrid = YES;
    sharedInstance.photoBrowser.startOnGrid = YES;
    sharedInstance.photoBrowser.enableSwipeToDismiss = YES;
//    [sharedInstance.photoBrowser setCurrentPhotoIndex:0];
}

+ (void)show {
    [sharedInstance loadPhotos];

    UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:sharedInstance.photoBrowser];
    nc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;

    UIWindow *appWin = [UIApplication sharedApplication].keyWindow;
    [appWin.rootViewController presentViewController:nc animated:YES completion:nil];

    [sharedInstance.photoBrowser reloadData];
}

+ (void)dismiss {
    [sharedInstance.photoBrowser dismissViewControllerAnimated:YES completion:nil];
}

- (void)loadPhotos {
    if (_photoDir == nil) {
        _photoDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];

    }
    NSArray *array = [[NSFileManager defaultManager] subpathsAtPath:_photoDir];

    _photosArray = array;
}

- (NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser {
    return _photosArray.count;
}

- (id <MWPhoto>)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index {
    NSString *filename = _photosArray[index];
    NSString *path = [_photoDir stringByAppendingPathComponent:filename];

    MWPhoto *photo = [MWPhoto photoWithURL:[NSURL fileURLWithPath:path]];
    return photo;
}

- (id <MWPhoto>)photoBrowser:(MWPhotoBrowser *)photoBrowser thumbPhotoAtIndex:(NSUInteger)index {
    NSString *filename = _photosArray[index];
    NSString *path = [_photoDir stringByAppendingPathComponent:filename];

    MWPhoto *photo = [MWPhoto photoWithURL:[NSURL fileURLWithPath:path]];
    return photo;}

@end

4、由于Unity3D那边只支持C/C++的函数,我们需要再进一步封装上面的代码,并且用extern "C"导出必要的函数。

//.h文件中
extern "C" void showPhotoBrowser(void);

//.m文件中
void showPhotoBrowser(void) {
    [DVIGlobalBrowser show];
}

void dismissPhotoBrowser(void) {
    [DVIGlobalBrowser dismiss];
}

5、在iOS项目中测试DVIGlobalBrowser

接口代码编写

在Unity3d中调用Objective-C代码,最终要的是编写C#的接口。在GlobalBrowser文件夹中创建C#接口文件PhotoBrowser.cs。

public class PhotoBrowser  {
    //引入C语言中的函数
    [DllImport ("__Internal")]
    private static extern void showPhotoBrowser();

    //暴露给C#的函数
    public static void showPhotoBrowserEx() {
        //平台判断
        if (Application.platform == RuntimePlatform.IPhonePlayer) {
            showPhotoBrowser();     
        }
    }
}

测试项目

在Unity3d的一个场景中加入按钮。没有使用过截屏功能的,需要注意存储路径。

using UnityEngine;
using System.Collections;

public class MyFile : MonoBehaviour {

    // Use this for initialization
    void Start () {
//      print ("Start...");
    }

    // Update is called once per frame
    void Update () {
//      print ("Update...");
    }

    void OnGUI () {
//      print ("onGUI...");

        //创建按钮,用来显示相册
        if (GUI.Button (new Rect (100, 100, 100, 100), "Button")) {
            PhotoBrowser.showPhotoBrowserEx();
        }

        //创建截屏按钮
        if (GUI.Button(new Rect(100, 220, 100, 100), "Save")) {
            var savePath = Application.persistentDataPath + "/" + (Random.value * 100) + "image.png";

            print (savePath + "<--->Capture");

            //截屏并保存图片到Documents目录
            Application.CaptureScreenshot((Random.value * 100) + "image.png");
        }
    }
}

本文档由长沙戴维营教育整理。

2018-01-23 16:52:08 Fantasy_Jun 阅读数 1465

一,预备工作

首先要在IOS上开发AR需要版本在ios11.0及以上,xcode9及以上,你才能进行开发

二,创建项目

打开Xcode,选择ARKit项目模板:


建好后会有一台默认的飞机模型出现在镜头里

三,实现3D立方体

替换的viewDidLoad中的代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];
/*    
    //存放所有3D集合体的容器
    SCNScene *scene = [SCNScene scene];
    
    //想要绘制的3D立方体
    SCNBox *boxGeometry = [SCNBox boxWithWidth:0.1 height:0.1 length:0.1 chamferRadius:0.0];
    
    //将几何体包装为node以便添加
    SCNNode *boxNode = [SCNNode nodeWithGeometry:boxGeometry];
    
    //把box放在摄像头正前方
    boxNode.position = SCNVector3Make(0, -0.25, -0.5);
    
    //rootNode是一个特殊的node,是所有node的起始点
    [scene.rootNode addChildNode:boxNode];
    
    //创建渲染器
    SCNMaterial *material = [SCNMaterial material];
    material.diffuse.contents = [UIColor redColor];   //  渲染器可以决定怎样渲染,这个 contents 属性可以设置很多东西,UILabel, UIImage,甚至 AVPlayer 都可以
    //用渲染器对几何图形进行渲染
    boxGeometry.materials = @[material];
    
    //将scene赋给view
    _sceneView.scene = scene;
    
    //光效
    _sceneView.automaticallyUpdatesLighting = YES;
    
    
}
然后就大功告成啦~
效果如下图:


参考链接:https://www.jianshu.com/p/396a0d1c16f9(Swift)


2014-03-13 16:13:53 qqMCY 阅读数 2180

项目的首页界面要一个3D效果的,这个做个Demo,大家可以参考下。这个例子呢?是我从网上找个,不过不知道,之前写Demo的人,多么的神奇,很简单就能搞定的东西,那人弄的好神奇,我看了足足1个小时。这里传一个容易看懂的,至少我觉得好懂。

代码下载:http://download.csdn.net/detail/qqmcy/7035009

框架类例子中有。

ViewController.h

#import <UIKit/UIKit.h>
#import "FlowCoverView.h"

@interface ViewController : UIViewController<FlowCoverViewDelegate>

@property (strong , nonatomic) FlowCoverView* m_FlowCoverView;

@end

ViewController.m

//获取屏幕高度
#define ScreenHeight [[UIScreen mainScreen] bounds].size.height
//获取屏幕宽度
#define ScreenWidth [[UIScreen mainScreen] bounds].size.width


#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    
    self.m_FlowCoverView = [[FlowCoverView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, ScreenHeight)];
    self.m_FlowCoverView.delegate = self;
    [self.view addSubview:self.m_FlowCoverView];
}

- (int)flowCoverNumberImages:(FlowCoverView *)view
{
	return 6;
}

- (UIImage *)flowCover:(FlowCoverView *)view cover:(int)image
{
	switch (image % 6) {
		case 0:
		default:
			return [UIImage imageNamed:@"changmen.jpg"];
		case 1:
			return [UIImage imageNamed:@"changmen.jpg"];
		case 2:
			return [UIImage imageNamed:@"changmen.jpg"];
		case 3:
			return [UIImage imageNamed:@"changmen.jpg"];
		case 4:
			return [UIImage imageNamed:@"changmen.jpg"];
		case 5:
			return [UIImage imageNamed:@"changmen.jpg"];
	}
}

- (void)flowCover:(FlowCoverView *)view didSelect:(int)image
{
	NSLog(@"Selected Index %d",image);
}





没有更多推荐了,返回首页