[iOS 11][ARKit] UIViewをテクスチャーにしてTwitterクライアントを作ってみる
1 はじめに
ARKitの登場によって、多くのデバイスで手軽にARを楽しめるようになったと思います。Web上でも、日々、色々なアプリが紹介されており、「どれも皆、作って見たい!」という衝動に駆られて忙しいかぎりです。
そして、いよいよ3Dオブジェクトの表現が重要であることを痛感しています。
基本的なシェードで作成するオブジェクトは、変形とテクスチャーを駆使することになりますが、今回は、このテクスチャーにUIViewを貼ってみました。
最初に、参考に作って見たアプリを見てやってください。 普通のTwitterクライアントで表示されるようなタイムラインを仮想オブジェクトにしてみました。
2 UIViewのオブジェクト
仕組みは、簡単で、UIViewを画像化してテクスチャーに使っているだけです。
描画するためのUIViewを、あらかじめ、非表示でアプリ内に作成しておき、そこに通常通り描画します。そして、それを画像(UIImage)に変換し、オブジェクトのテクスチャーに適用しているわけです。
非表示のUIVIewは、画像変換できなかったので、一瞬だけ、表示状態にしていますが、実機では、気になるようなものでは無いようでした。
UIViewを、UIImageに変換しているコードは、以下のとおりです。
参考にさせて頂きました:しめ鯖日記 -UIViewにUIImageへの変換メソッドを追加する(Swift)-
func createImage(view:UIView) -> UIImage? { UIGraphicsBeginImageContextWithOptions(view.frame.size, false, 0) guard let context = UIGraphicsGetCurrentContext() else { return nil } view.isHidden = false // 画像を取得する間だけ表示 view.layer.render(in: context) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() view.isHidden = true // 再び非表示 return image }
また、取得した画像(UIImage)を貼って作成するTweetノードは、以下のようになっています。
class TweetNode: SCNNode { init(image:UIImage, panelColor: UIColor, width: CGFloat, panelThickness: CGFloat) { super.init() let panelNode = SCNNode(geometry: SCNBox(width: width, height: width * 0.5, length: panelThickness, chamferRadius: 0)) let material_front = SCNMaterial() material_front.diffuse.contents = image let material_other = SCNMaterial() material_other.diffuse.contents = panelColor panelNode.geometry?.materials = [material_front, material_other, material_other, material_other, material_other, material_other] addChildNode(panelNode) } // ・・・略・・・ }
TweetNodeは、画像、パネルの色、サイズ(幅)、パネルの厚みを指定して生成されます。
パネルは、SCNBoxで作成され、テクスチャーとして、正面に指定した画像、その他の面に指定した色が適用されています。
縦のサイズは、内部で横幅の1/2で固定されています。
3 STTwitter
Twitterのタイムライン取得は、STTwitterを使用させて頂きました。
https://github.com/nst/STTwitter
STTwitterは、CocoaPodsでインストールが可能です。
pod 'STTwitter'
利用方法は、以下のとおりです。
import STTwitter public final class Twitter { let consumerKey = "カスタマーキー" let consumerSecret = "カスタマーシークレット" let username = "ユーザ名" let password = "パスワード" func get(query: String, complete: @escaping ([Tweet]?)->Void ){ let api = STTwitterAPI(oAuthConsumerKey: consumerKey, consumerSecret: consumerSecret, username: username, password: password) api?.fetchAndFollowCursors(forResource: "search/tweets.json", httpMethod: "GET", baseURLString: "https://api.twitter.com/1.1", parameters: ["q":query], uploadProgressBlock: nil, downloadProgressBlock: nil, successBlock: { (request, requestHeaders, responsHeaders, response, morePagesToCome, stop) in // 結果の受信 var tweets: [Tweet] = [] let json = response as! NSDictionary let statuses = json["statuses"] as! NSArray for status in statuses as! [NSDictionary] { let text = status["text"] as! String let user = status["user"] as! NSDictionary let created_at = status["created_at"] as! String let profile_image_url = user["profile_image_url"] as! String let name = user["name"] as! String let screen_name = user["screen_name"] as! String tweets.append(Tweet(name: name, screen_name: screen_name, profile_image_url: profile_image_url, text: text, created_at: created_at)) } complete(tweets) }, pause: { (nextRequestDate) in // ロード中 }, errorBlock: { (request, requestHeaders, responseHeaders, error) in print("ERROR:\(String(describing: error))") // エラー complete(nil) }) } }
取得した結果は、Tweetクラスで取得しました。
class Tweet { let name: String! let screen_name: String! let profile_image_url: String! let text: String! let created_date: NSDate! init(name: String, screen_name: String, profile_image_url: String, text: String, created_at: String) { self.name = name self.screen_name = screen_name self.profile_image_url = profile_image_url self.text = text let inFormatter = DateFormatter() inFormatter.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy" self.created_date = inFormatter.date(from: created_at)! as NSDate } }
4 最後に
UIViewの表示を、そのままノードに使用できると、結構便利なのでは無いでしょうか。
最後に、もう一つ、作成したサンプルを紹介させて下さい。 下記は、最近、弊社のイベントでよく登場する「クラスメソッドのおみくじ」です。Web上のコンテンツをWKWebViewで表示し、それを、画像化して使用しています。
「クラスメソッドのおみくじ」を、近所の駐車場で引いてみる
5 参考リンク
しめ鯖日記 -UIViewにUIImageへの変換メソッドを追加する(Swift)-
[OS X] 透過型のTwitterクライアントを作ってみた
[iOS 11] はじめてのARKit #WWDC2017
[iOS 11][ARKit] 距離の計測について #WWDC2017
[iOS 11][ARKit] 平面の検出について #WWDC2017
[iOS 11][ARKit] 物理衝突を実装して、キューブを落として見る #WWDC2017
[iOS 11][ARKit] 空間に3Dテキストを表示してみる #WWDC2017
[iOS 11] ARKitでソファー設置からあの子の身長測定まで色々やってみた
[iOS 11][ARKit] 近所の駐車場で、大型ディスプレイでビデオを見る!
[iOS11][ARKit] オブジェクトの位置と回転「常にこっちを向いている怪獣」
[iOS11][ARKit] SCNBoxとSCNTextでラベルみたいなノードを作成してみました