20200820のC#に関する記事は6件です。

【Unity】Final IKの中にモーション記録の機能があった件

こんにちはっ?八ツ橋まろんです

バーチャルYouTuberの中にはUnity + Final IKを駆使してキャラクターを動かし活動している人も多いことと思います。Final IKはその名の通りIKに関する有料アセットで、これ一つあればHTC Vive + Vive Trackerなどの構成でキャラクターを現実の動きとリンクさせることができます。

例)キャラクターとのリンク: 現実では中の人がだいたい同じ動きをしている

また、バーチャルYouTuberの動画やミュージックビデオにおいては、表情や手の動きを「撮影の後で編集」するために「モーション記録」を行うことがあるかと思います。モーション記録をするためのアセットとして、Githubで公開されているEasy Motion RecorderやAsset Storeの有料アセットなどが存在するようです。(弊調べ)

例)モーション記録:モーションはEasy Motion Recorderで記録し、手や表情、カメラワークなどを後付け編集している


さて、Final IKの理解を深めようとFinal IKを眺めていたら、この中にモーション記録用のスクリプトが入っていることに気が付きました。

なるほど、これを使えばFinal IKだけでキャラクターの動きのリンクから撮影までできちゃうわけですね!知らなかった!!

ということで、このスクリプトを使うための簡単なやり方を紹介します。

①Hierarchyにある対象のキャラクターに"Humanoid Baker" component を追加、設定は画像の通り
無題.png

②HierarchyにCanvasを作成
③Canvasの子にButtonを2つ作成し位置調整
④両方のButtonのButton ComponentのOnClickにキャラクターをドラッグ&ドロップし、片方の内容は"HumanoidBaker.StartBaking"にし、もう片方は"HumanoidBaker.StopBaking"にする。
無題a.png

⑤シーンを再生して記録開始の方のボタンを押し、キャラクターを適当に動かしてみる

⑥記録終了の方のボタンを押すと、①で指定したフォルダにアニメーションが作成される

<↓↓↓↓使い方動画↓↓↓↓>

以上です。お疲れ様でした。

八ツ橋まろん

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【メモ】C#におけるボックス化(boxing)と回避方法

はじめに

Genericsが使うのでボックス化について意識することは減りました。
が、ボックス化について人に説明する機会があったので曖昧だったところを自分の為にまとめておきます。

ボックス化

値型をobject型に代入するときに行われる処理。
参照型であることが必要な場面においても値型を使用できるようにする仕組み。

  • 値型はスタック、参照型はヒープ上に実値が置かれる。
  • object型は参照型なので、値型をobject型に代入したときに実値はヒープにコピーされる。(ボックス化)
  • ヒープに実値コピーされるとき、元の型情報も付与される。

ボックス化解除

ボックス化された値型のコピーを取り出すこと

  • ボックス化されたobject型は実値がヒープ上に置かれている。
  • ボックス化されたobject型を元の型に戻す(キャスト)するときに実値がスタックにコピーされる。(ボックス化解除)
  • 型情報が間違えていたときはInvalidCastExceptionが発生する。

パフォーマンス影響

簡単な代入と比べて、ボックス化およびボックス化解除は負荷の大きいプロセスです。 値型をボックス化するときは、新しいオブジェクトを割り当てて構築する必要があります。 ボックス化ほどではありませんが、ボックス化解除に必要なキャストも大きな負荷がかかります。 詳しくは、「パフォーマンス」をご覧ください。

c.f. https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/types/boxing-and-unboxing#performance

デメリット

  • ボックス化はオブジェクトの一時的なコピーを生成するため、コストがかかる。
  • ボックス化解除はオブジェクトの一時的なコピーを生成するため、コストがかかる。
  • ボックス化解除時のキャストにもコストがかかる。
  • ヒープ上の領域確保は、スタックと比べると重たい処理。
  • キャスト時、型情報が間違えていたときはランタイムエラー(InvalidCastException)が発生する。

ボックス化を起こさないために

  • object型を使用しない
  • Genericsを使用する

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

.NET 5 Preview を Windows環境で試す方法

はじめに

.NET 5 Preview を Windows環境の Visual Sutidio 2019 で試す方法の紹介です。
(オプションダイアログの設定が必要なのに気付かなくて、少しハマったので)

.NET 5 SDK のインストール

以下のサイトから、.NET 5 の SDK をインストールします。
Download .NET 5.0

赤枠部分がSDKのインストーラです。
ちなみに、右側はランタイムで、.NET 5 のプログラムを動作させるために必要なものです。
ここでは、開発するために必要なSDKをインストールします。
image.png

オプションダイアログの設定

.NET 5 SDK をインストールするだけでは、まだ .NET 5 は利用できません。
[オプション]ダイアログの [プレビューの .NET Core SDK を使用] のチェックボックスを有効にする必要があります。

image.png

プロジェクトのプロパティの設定

上記の手順を実施後に、プロジェクトの [プロパティ] の [対象のフレームワーク] の選択肢を表示すると、 [.NET 5] が選択できるようになります。
image.png

まとめ

.NET 5 を設定されたプロジェクトは、.NET 5 SDK をインストールしていない人の環境では、コンパイルエラーになります。
従って、チームで開発しているソースコードを .NET 5 に変更する際は、全員がSDKをインストールしてから行う必要があります。

ちなみに私は「Serverless LT 初心者向け」というコミュニティを運営しています。
社外発表することに興味があるけど、ハードルが高くてなかなか機会が得られないという発表初心者が集まるオンライン発表大会を毎月開催していますので、よろしければご参加ください。
Serverless LT 初心者向け - connpass

Twitterでも開発に役立つ情報を発信しています → @kojimadev

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityでファイル選択画面を使う

↓こんな感じのダイアログボックスを使ってファイルを選択したい:thinking:

image.png

Script

script
using UnityEditor;

 public void OpenFile()
    {
        //パスの取得
        var path = EditorUtility.OpenFilePanel("Open csv", "", "CSV");
        if (string.IsNullOrEmpty(path))
            return;
        Debug.Log(path);

        //読み込み
        var reader = new StreamReader(path);
        Debug.Log(reader);
    }

詳細 //ここでダイアログボックスを出す

1つのファイルを選択

script
        var path = EditorUtility.OpenFilePanel("Open csv", "", "CSV");
        var path = EditorUtility.OpenFilePanel(ダイアログボックスの名前, ディレクトリのデフォルト設定,読み込むファイルの拡張子 );

EditorUtility.OpenFilePanel

複数種類のファイル拡張子を指定する場合

script
var path = EditorUtility.OpenFilePanelWithFilters("Open image", "", {"音楽ファイル","mp3,ogg,wav"});

EditorUtility.OpenFilePanelWithFilters

フォルダーを選択する場合

script
var path = EditorUtility.OpenFolderPanel("Open Folder", "", "");

EditorUtility.OpenFolderPanel

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ReactiveProperty の ReactiveCommand に sender と EventArgs を渡したい

個人的には ViewModel に sender 渡すのはどうかなぁと思いますが厳密にはあり合わせの機能では出来ないですが、近いことは出来なくもないです。やってみましょう。

ReactiveProperty.WPF パッケージに含まれる EventToReactiveCommand のコンバーターには AssociateObject プロパティがあって、これに EventTrigger が割り当てられたオブジェクトのインスタンスが入っています。これが sender と一致することがほとんどだと思う(というか一致しないケースってなんだろう)ので、これと EventArgs を渡してやるようにコンバーターで処理すれば OK ですね。

コンバーターはこんな感じ。

MyConverter.cs
using Reactive.Bindings.Interactivity;
using System;

namespace WpfApp3
{
    public class MyConverter : DelegateConverter<EventArgs, (object sender, EventArgs args)>
    {
        protected override (object sender, EventArgs args) OnConvert(EventArgs source) => (AssociateObject, source);
    }
}

ということで適当に ViewModel を作って…

MainWindowViewModel.cs
using Reactive.Bindings;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfApp3
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public ReactiveCommand<(object sender, EventArgs args)> SomeCommand { get; }
        public ReadOnlyReactivePropertySlim<string> Result { get; }

        public MainWindowViewModel()
        {
            SomeCommand = new ReactiveCommand<(object sender, EventArgs args)>();
            Result = SomeCommand
                .Select(x => $"{DateTime.Now}: {x.sender}, {x.args}")
                .ToReadOnlyReactivePropertySlim();
        }
    }
}

MainWindow.xaml を以下のような感じにして

MainWindow.xaml
<Window
    x:Class="WpfApp3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfApp3"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:rp="clr-namespace:Reactive.Bindings.Interactivity;assembly=ReactiveProperty.WPF"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <StackPanel>
        <Button Content="Click">
            <behaviors:Interaction.Triggers>
                <behaviors:EventTrigger EventName="Click">
                    <rp:EventToReactiveCommand Command="{Binding SomeCommand}">
                        <local:MyConverter />
                    </rp:EventToReactiveCommand>
                </behaviors:EventTrigger>
            </behaviors:Interaction.Triggers>
        </Button>
        <TextBlock Text="{Binding Result.Value}" />
    </StackPanel>
</Window>

実行してボタンを押すと Button のインスタンスとイベント引数がわたってることが確認できます。

image.png

まとめ

でも UI コントロールを ViewModel に直接渡したいというケースってなんだろう??
どうしようもない状態以外ではしない方がいいかな。きっともっといい方法があると願いたい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【C#】 GDI+でカラー オーバーレイ(風)

概要

@Kyome さんのRunCat の記事

・Windowsのタスクバーでもネコ走らせてみた? - Qiita
https://qiita.com/Kyome/items/47aac4979933dac12263

を見ていて、個人的に猫に自由に任意の色を付けたくなったので、WinForm (GDI+) で カラー オーバーレイ が出来ないか試してみた。

カラー オーバーレイ とは?

Photoshopの レイヤー効果 でおなじみ(?)のやつ。
レイヤーの描画ピクセルのに色情報を任意の色に上書きするやつ。
私は良くレイヤーの描画モードを スクリーン にした単色レイヤーを重ね合わせえて色味調整を行うことがよくあるのだけど。カラー オーバーレイ だとカラーピッカーで選択中の色がリアルタイムで反映されるので、 スクリーン レイヤーの色味調整でよく使ってる。

SS.png

開発環境

プログラムは @Kyome22 さんの RunCat for windows を拝借させていただきました。ありがとうございます!

概略

  • Graphics.DrawImage のオプションで使える System.Drawing.Imaging.ImageAttributes で描画時に色を置換させる。
  • 置換情報は ImageAttributes.SetRemapTable()System.Drawing.Imaging.ColorMap をセットして行う。
  • 画像ソースは 白1色 + α の32bit画像
  • 白に対して、置換色表はα = 0~255の 256パターン 用意する。
  • 指定色のα値も反映させるため、置換後の色のα値にもかけ合わせる。
ColorMapはαの深度分.cs
ColorMap[] map = new ColorMap[256];
for (int j = 0; j < map.Length; j++)
{
    colorMap[j] = new ColorMap()
    {
        OldColor = Color.FromArgb(j, 255, 255, 255),
        NewColor = Color.FromArgb(j * newColor.A / 255, newColor.R, newColor.G, newColor.B),
    };
}

ss_00.png
ss_01.png
ss_02.png

こんな塩梅。
Color.Transparent もちゃんと効くのがありがたい。ただ、今回 カラー オーバーレイ(風) としているのは、オーバーレイ対象が描画ピクセルでなく白だけだから。白(+α)以外の色があるとダメなので、実は オーバーレイ としては若干用足らず(苦笑)。

サンプル ソース

カラー オーバーレイを試すにあたり、 @Kyome22 さんの RunCat for windows を勝手に利用させていただきました。ありがとうございます!

バック バッファImageオブジェクト で白猫の画像の枚数分予め作っておき、下記メソッドが呼ばれたら バックバッファ の内容を更新し、Iconオブジェクト を再生成する。 (バック バッファ はタスクトレイなので一応16x16。)

カラー オーバーレイ 抜粋.cs
private void SetIconColor(Color catColor, Color bgColor)
{
    Bitmap[] images = new Bitmap[]
    {
        Resources.cat16_0,
        Resources.cat16_1,
        Resources.cat16_2,
        Resources.cat16_3,
        Resources.cat16_4,
    };
    ImageAttributes attr = new ImageAttributes();

    // remap color table
    {
        ColorMap[] colorMap = new ColorMap[256];
        for (int j = 0; j < colorMap.Length; j++)
        {
            colorMap[j] = new ColorMap()
            {
                OldColor = Color.FromArgb(j, 255, 255, 255),
                NewColor = Color.FromArgb(j * catColor.A / 255, catColor.R, catColor.G, catColor.B),
            };
        }
        attr.SetRemapTable(colorMap);
    }

    //  recreate icons
    for (int i  = 0; i < imgIconBufs.Length; i++)
    {
        Bitmap imgBuf = imgIconBufs[i];
        Bitmap imgCat = images[i];
        Icon ico = icons[i];
        // bg
        {
            Graphics g = Graphics.FromImage(imgBuf);
            g.Clear(bgColor);
            g.DrawImage(imgCat, new Rectangle(new Point(0, 0), imgCat.Size), 0, 0, imgCat.Width, imgCat.Height, GraphicsUnit.Pixel, attr);
        }
        if(icons[i] != null)
        {
            // 再作成時、古いHICONは必ず廃棄する!
            DestroyIcon(icons[i].Handle);
            icons[i] = null;
        }
        icons[i] = Icon.FromHandle(imgBuf.GetHicon());
    }
}

感想

一応それっぽいのは出来たけど、Bitmapクラスから 生成した Iconクラス を明示的に破棄するためにWin32APIの DestroyIcon を呼ぶ必要があって プラットフォーム 呼び出し ( P/Invoke) を使ってしまったのが若干つらい。とは言っても、64bit モジュールがちゃんとがある普通のWin32API だからそんなに気にしなくてもだけど。でもやっぱり.NETは可能な限りマネージド コードだけで行きたい。。。(びば!AnyCPU!)

ただ、最初はピクセル操作になると思っていたので Marshal.Copy するくらいならと Unsafe も覚悟していたけど、一応カラー オーバーレイ(?) 部分だけはマネージド コードだけなので、そこは助かった。今度は ColorMatrix も試してみたい。ColorMapで愚直に対応表を作るとすると。2^32 - 14,294,967,295 パターンにもなり、とても現実的ではないので。。。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む