chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

定年退職まであと大体1年→定年サポートアプリ(笑)を再ビルド

定年まであと大体1年になった。会社からの再就職サポート開始はまだまだ先なのだが、マッチングがうまくいかない場合は自力で探す必要がある。できたら幅広くアクセスして情報を集めたい。定年までどれぐらいの時間があるのか??把握する必要がある。頭で考えたらわかることだが、数字に弱いので、、定年までの残り期間をサポートするため、定年まで残り何日か、時間でいうと何時間か?を計算して表示するアプリを数年前に試作した*1*2。さらに、曜日に応じて元気づけるメッセージが表示される機能付き(笑)。試作した後は放置していたので、改めてビルドしてTestFlightで自分のスマフォに入れた。

簡単すぎて参考になるレベルではないと思いますが、ご参考にソースを貼り付けます。

//
//  ViewController.swift
//  simpleUI
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        //outputLabel.text = "Hello world?"
        //lestTime.text = "MM:YY"
        update()
    }
    func update(){
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "ja_JP")
        formatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "ydMMMEEEhm", options: 0, locale: Locale(identifier: "ja_JP"))
        todayYMD.text = formatter.string(from: Date())
        
        //todayYMD.text = "2019/2/2 02:24"
        lestTime.text = "4y12m"
        lestMonthLabel.text = "123m"
        lestDayLabel.text = "12345days"
        lestHourLabel.text = "2342323H"
        messageArea.text = "健康の秘訣:よく寝て食8分目"
        calcLestDate()
        showMessage()
    }
    func showMessage()
    {
        let week = Calendar(identifier: Calendar.Identifier.gregorian).dateComponents([.weekday],from:Date()).weekday
        messageArea.text = getWeekMsg(week: week!)
    }
    func getWeekMsg(week: Int)-> String
    {
        var msg = ""
        let msgOfWeek = [
            1: ["日曜日いかがお過ごしですか",
                "掃除とか片付けすると気持ちもリフレッシュしますよ",
                "休みの日には、何か趣味に打ち込んでみるのもいいかもしれませんね",
                "明日からの一週間に備えて今日は十分リフレッシュしましょう。仕事の事をあれこれ考えすぎないようにしましょう。体を動かすのもいいですね。"],
            2: ["月曜日になりましたが、ゆっくり調子を戻しましょう。月曜日は会社に来ただけで十分!。。等と言ってられませんか",
                "月曜日は気が重いですか?考えすぎないのが一番ですよ。案ずるよりなんとやら"],
            3: ["火曜日になりましたが、調子は戻ってきましたか?金田だと「やっとエンジンが暖まってきたぜ」と言いそうですね",
                "火曜日になりましたが調子はいかがですか。無理せず一週間をこなしましょう"],
            4: ["今日は水曜、一週間の、なか日ですね。ちょっと一息しましょうか",
                "水曜日はたまに早く帰ってみるのもいいかも"],
            5: ["一週間の後半、木曜日になりましたね。今日は調子いかがですか?",
                "木曜日ですが調子はいかがですか"],
            6: ["やっと金曜日まできましたね!! 今日1日頑張りましょう。明日からお休みですね!",
                "今日は金曜日!お疲れ様です!"],
            7: ["やっと休みになりましたね。一週間お疲れ様でした。今日はちょっと夜更かしですか?",
                "一週間お疲れ様でした。土曜日だからといって、あまり生活リズムを変えない方が体調管理のためにはいいそうですよ",
                "今日はどこかにお出かけですか?",
                "とりあえず、ゆっくりしましょう"
            ]]
        msg = msgOfWeek[week]!.randomElement()!
        return msg
    }
    func calcLestDate()
    {
        let complete = "2023/7/31 17:30:00"   //  (例)勤務最終日
    
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: "en_US_POSIX")
        dateFormatter.dateFormat =  "yyyy/MM/dd HH:mm:ss"
        let cmplDate = dateFormatter.date(from: complete)
    
        let calendar = Calendar(identifier: .gregorian)
        let today:Date = Date()
    
        var components = calendar.dateComponents([.year, .month], from: today , to: cmplDate!)
            lestTime.text = String(components.year!) + "年と" + String(components.month!) + "ヶ月"
    
        components = calendar.dateComponents([ .month], from: today , to: cmplDate!)
        //let month = components.month!
        //print(month*7/10)

        lestMonthLabel.text = String(components.month!) + "ヶ月"
        components = calendar.dateComponents([ .day], from: today , to: cmplDate!)
        lestDayLabel.text = String(components.day!*68/100) + "日"
    
        components = calendar.dateComponents([ .hour], from: today , to: cmplDate!)
        lestHourLabel.text = String(components.hour!*68*8/100/24) + "時間"
    }
    
    @IBAction func checkBtn(_ sender: Any) {
        update()
    }
    @IBAction func showNextWord(_ sender: Any) {
        showMessage()
    }
    @IBOutlet weak var messageArea: UILabel!
    @IBOutlet weak var lestTime: UILabel!
    @IBOutlet weak var todayYMD: UILabel!
    @IBOutlet weak var outputLabel: UILabel!
    @IBOutlet weak var lestMonthLabel: UILabel!
    @IBOutlet weak var lestDayLabel: UILabel!
    @IBOutlet weak var lestHourLabel: UILabel!

    @IBAction func settingButtonAction(_ sender: Any) {
        performSegue(withIdentifier: "goSetting", sender: nil)    }
}

■追記
今はもうSwift全然触っていないし、Flutterでしかコードを書けないので、機能アップする場合はFlutterに引っ越しが必要。だけどまぁ、残り勤務日数さえ出たらいいかと。

*1:勤務日数の計算は正確に行おうとするとめちゃくちゃ大変なので、ざっくり7かけで計算

*2:なぜ数年前に作ったか?仕事がしんどいから、定年まであと何日かを数えて気持ちを紛らわしていた。申し訳ない

Blenderによるアニメーション作成を理解する

3Dモデルが自然に動くには、Boneやarmatureを理解している必要がある。そのため、腰から下だけのモデルを作って、これにBoneとArmatureを関連づけてアニメーションとして動かしてみた。今はまだ足がガクガク動くという程度で、到底歩いている動きにはならない。また、IKの設定をまだやっていないので、床を滑っているような動きになっている。今後は、BoneにIK設定して、つま先の動きが足〜腰へと伝わるようにして歩かせたい。

チキチキダンスのボーンにピッタリのモデルを作って踊らせてみる

チキチキダンスの動きがよくわかる様に、ボーンのサイズにきっちりあったモデルを作って、ペアリングすることにした。サイズがきっちり合っていたら、変な所で曲がったり、フロアから浮いたりするこはないはず。以下がBlenderで作ったボーンにきっちり合わさったモデル。ダンスの動きを確認するのが目的なので、シリンダー等だけで作っていて素っ気ないです。
以下はBlender内でダンスさせたところ。関節の位置は合ってるけど、ポーズによってはボーンの動きにモデルが追従できていない場合がある。これはなぜだろうか。動きたくない特性が入ってしまっているから?

分からない点があるものの、Blenderで作ったアニメーションデータ付きのモデルをFBX形式でExport/Importして、UE5に持って来た。動かしみると実にスムーズに動く。床との位置関係も問題ないし、関節の動きも自然な感じ。この品質で、新しいモデルにリターゲットできるように取り組みたい。まずはUE5アンドロイド等にもう一度retargetして、boneのマッピングやらIK-Retarget等の理解を深めたい。大体理解できたら、mixamo等から3Dキャラクターモデルを借りてこよう。理想は自力で3Dモデリングできることだが、、人に見てもらえるレベルのキャラクタを作るには修行に半年はかかるだろう。。

作ったMetahumanに対して、UE5上でチキチキダンスを踊らせる

前回はMetahumanをimportするところまでやったので、IK RigとIK Retargetを使って、BlenderからもってきたダンスデータをMehahumanのRIGにマップしてみた。以下はダンスしているところ

骨格の違いや、初期の姿勢がA型かT型かの違いもあり、どうしても姿勢が不自然になるところがある。そこまで関節曲がるか??とか、オリジナルの手の位置に来ていないとか。。 細かな差異は、稼働範囲の調整パラメータや、IK Target等を駆使して自然な動きに仕上げると思うが、細かい調整ノウハウが分からない。モデルがリアルなだけに、若干不気味の谷に落ちている印象がある。

少なくとも、、明るすぎる上着はもう少し彩度を落としたい。光が明るすぎるせいもあるけど。

■追記
Metahumanはリアルさが売りなのだが、アニメーションデータのマッピングが不適切だとあり得ない関節の動きになって、逆にちょっと気持ちが悪い。人様に見てもらえる品質には上げられないので、やはりモデリングとアニメーションのretargetを基礎的なレベルから学ばないとだめだと思った。

粽を返しに八坂神社へ・・人が少ない

いつも夏になると粽を買って家の玄関に祀っています。普段だと、朝早くに鉾町に行って粽を買うのだけど今年は通販で買えた。去年の分を八坂神社にお返しに行った。四条通りはコロナの影響によるのかガラガラだった。歩きやすいのでありがたいけど、お店は売上が厳しいと思われます。

帰りにびーんず亭でコーヒー豆を買った。「酸味が感じられる豆は?」と相談したら、モカを勧められた。

Blenderで作ったシリンダーマン(仮)にペアレント設定したら動いた→UE5にexport/import、Metahumanを試す

Blenderで最低限の手足を持つ筒状のメッシュで作ったモデル(以降、シリンダーマン)に、チキチキのダンスデータをペアレント設定したら、それなりに動いた。

シリンダーマンをFBX形式でexportしてUE5にimportした。これもまぁなんとか動いた(足先とか手足のモデルがないので、全体の動きだけ確認してOK。retargetしていない状況なのだが、importした時点では回転も一回転のみ、前傾姿勢や手の位置もまぁOK)。以下はUE5に連れてこられたシリンダーマン。引き続きチキチキダンスを元気に踊っている。

前回はUE5のアンドロイドにIK retargetする際、四苦八苦していたのだが、今回はアンドロイドのretarget作業を飛ばして、シリンダーマンの動きをMetahumanにマップしてみようと思った。
MetahumanはブラウザでMetahuman creatorのサイトにアクセスして作る(作らなくても初期設定のMetahumanを使うだけなら作業は不要)。 以下がカスタマイズしたモデル。欧米のキャラクタの濃い人は多いけど、東洋系のモデルがあまりいない。

カスタマイズしたMetahumanのデータはEPICのクラウド側に保存される。UE5にデータを持ってくる作業はブラウザからダウンロードするのではなく、UE5側のプラグイン?(Quixel Bridge)を使って引っこ抜く。データはローカルPCにダウンロードされる。正確にはプロジェクトのフォルダに入る。Quixel BridgeはUE5のメニューから起動可能。操作はContent Browserで右クリック、Add Quixel Contentを選択する。起動時にエラーが出た。メッセージは以下

"Web Browser plugin is not enabled. Please enable it in the plugin manager to use Bridge."

ググると、Plugin画面から、'Web Browser plugin' と 'Bridge plugin' を有効にしろと書かれていた*1。自分の場合、Web Browser pluginにチェックが入っていなかった。ブラウザとどう連携するのか??と思ったが、、これを有効化した。


すると、Metahumanに正常にアクセスできるようになり、Metahumanの一覧が表示される。が、、、初期設定のMehahumanしか表示されない状況であった。根本原因が何かは分からないままだが、、自分の場合、(1)ブラウザ側でMetahuman creatorを走らせる、(2)Quixel Bridgeのログインメニューから認証する、の2つの操作をした結果、 My Metahumansのメニューが出て、先ほどカスタマイズしたデータへのアクセスが可能になった。
DL作業をはじめたものの、レンダリングとダウロードの2段階になっていて、非常に時間がかかる。1時間ぐらい経過したのでは?と思うが、DLの進捗が35%だ。しかも、DL前におまじないのようなステップが必要らしいことが書かれている。うーん、どうしたものか。。。DL下後もいろいろ作業が必要なようで、今日は作業を中断する。

■追記
再度DL操作を行なった。
DL後、Import操作が必要。 Import を行うとLive Link Control Rigのプラグインが無いと怒られる。これを入れる。再起動する。 エラーは解消されMetaHumanがimportされたが、Missing Project SettingsのWarningが2件出ている。モデルを確認すると頭髪がない状況(スキンヘッドというやつか)である。Warningに起因するのではないかと想像。Settingで変更できるパラメータは大量であり、メニュー画面のどこにあるのかすぐには分からない。Settingの情報はExport, Import できるようなので、一旦exportして、出力されたファイルをエディタで編集した。編集項目は以下。これをImportして読み込ませることで、怒られているパラメータ設定誤りが解消できると期待。

% diff  Rendering\ Backup\ 2022-06-26\ 153535.ini Rendering\ Backup\ 2022-06-26\ 153535_kai.ini 
105,106c105,106
< r.SkinCache.CompileShaders=False
< r.SkinCache.DefaultBehavior=1
---
> r.SkinCache.CompileShaders=True
> r.SkinCache.DefaultBehavior=0
116c116
< r.GPUSkin.Support16BitBoneIndex=False
---
> r.GPUSkin.Support16BitBoneIndex=True
121c121
< r.GPUSkin.UnlimitedBoneInfluences=False
---
> r.GPUSkin.UnlimitedBoneInfluences=True

設定しろと怒られるパラメータが見つからないと思っていたら、Warning画面の中に、Enable Mssingのボタンがあり、これをクリックすることで設定がなされるようであった。クリックすると再起動しますと表示されて、UE5が再起動される。この結果、なんとかカスタマイズ版のMetahumanの取り込みができた。取り込み完了の画面は以下

Metahumanもboneが埋め込まれているはずで、IK retargetでダンスデータをリターゲットしたら、チキチキダンスを踊ってくれるはず。

■おまけ
組み込みマイコンでLチカさせるのも面白いが、3Dモデリングもワケ分からなすぎるが面白い。


■参考URL
Unreal Engine で MetaHuman を使ってみよう | MetaHuman Creator ドキュメント
Getting Started with MetaHumans in Unreal Engine | MetaHuman Creator Documentation
UE5用の手順が後半に説明されている
Unreal Engine での IK 剛体 アニメーションのリターゲティング | Unreal Engine ドキュメント

(パリピ孔明のダンス)BlenderからなんとかUE5には持ってこれた。踊ってはいるが、細かな点で動きがおかしい

Blenderを使ってanimationのBoneとオブジェクトをペアリングして、XBF形式でExportした。それをUE5で読み込んで、IK-Reterget
の機能を使ってアンドロイドに動きを複製した。大体はOKなのだけど、腕の動きがおかしい。あり得ない角度にまで曲がっている(肘が開きすぎ)。あと、手首もおかしい(正確には手首はまだ細かくretargetしていない)
3Dアニメーションやっている人なら、マッピングのどこがおかしいのかすぐに見つけて修正できるのだろうけど、何が原因でどうなおせば良いのかが分からない。腕が体に食い込んだりしていて、あり得ないポーズになっている。公式のダンスでは、回転は1回のはずだが、自分がリターゲットしたアンドイドは2回回っている。なぜだ?? rootが2回複製されてしまい、動きが2倍になっている?? 酷くてこのレベルではボツだ。。

もう一度やりなおすとしたら、、blendarでのキャラクタの動きをしっかり仕上げてからUE5に持ってくるというぐらいだろうか。3Dアニメーションを基本的な所から理解できていないので、問題に出会っても手が出せない。自分でモデル作ってboneを埋め込んでマッピングまできっちり仕上げる経験をしたら、もしおかしな動きをしていても原因と対策がわかるのではないだろうか。