Life, Education, Death

プログラミング以外でも思ったことをつらつらと書きたい

PCGを使ってペイントしたら木のモデルが生えるようにする

nilfs.hatenablog.jp

前回はPCGとBlueprintを使って自分でPCGノードを作成するところまでやりました。 これができるとC++を書かなくても色んな事ができることができるようになるのですが、今回は木のモデルをいい感じに生やす機能を実装しようと思います。

ランドスケープを使ってレベルデザインをしている場合、複数のレイヤーを定義してそれぞれ草や地面などのマテリアルを割り当てるのではないかと思います。このレイヤーの情報を元に背景モデルを配置出来たら、簡単にそこそこのクオリティのマップが作れるのではないでしょうか?

どんどん、モデルを生やしていきましょう。

今回重要なノードはこの”Get Interpolated PCGLandscape Layer Weights”です。このノードはある座標のランドスケープのレイヤー情報を取得できるので特定のレイヤーだけ操作の対象にすることができます。 今回は、特定のレイヤー名だった場合はDensityをレイヤーウェイト値、それ以外は0を返す仕様で実装していきます。

まず、前回同様に新しいBPクラスを作成します。PCGE_LandscapeLayerWeightToDensityという名前のBPにしました。 親クラスはPCGBlueprint Elementを指定します。ExcuteWithContextの中身は前回と同じにします。

次に、PointLoopBodyをオーバーライドして中身を以下のように実装します。

変数TargetLandscapeLayerはノードのパラメータとして予めレイヤー名が入っているという想定でBPは実装されています。

左のノードから処理を説明していきます。

  1. Get Interpolated PCGLandscape Layer WeightsにはWorld Context Objectが必要なので、Get Componentを実行します。
  2. Get Interpolated PCGLandscape Layer Weightsは特定の位置のレイヤー情報を取得できるので、現在のポイントのTransformからLocationだけ取り出して渡します。
  3. レイヤーは複数重なってることがあるので配列で結果が返ってきますので、For Each Loopで1つ1つ中身を確認していきます。Target Landscape LayerとElement Nameを比較し、目的のレイヤー名がかどうか判断します。
  4. 目的のものであった場合は、DensityをWeightにして、他の値はそのままにしたいのでPoint Loop Bodyの引数のまま設定してreturnします
  5. エラー処理としてもしも、レイヤーが全く見つからないときはそのままの値を返すようにしています。これは要件によって適切なロジックに変更したほうがよいでしょう。

これで必要なノードが作成できました。これを使ってPCGグラフ上で特定のレイヤーをフィルタしていきましょう。 PCGグラフは先ほどのノードを使って、このようにします。

先ほど作成した、PCGE_LandscapeLayerWeightToDensityノードを通すとDensityがレイヤーのウェイトと同じになるのでDensity Filterノードを使ってフィルタすることができます。

また、PCGE_LandscapeLayerWeightToDensityノードのパラメータはこのように設定されています。デフォルトのレイヤーがSoilとなっていて、そこに木のモデルを出現させたいので、最後のStatic Mesh Spanwnerでは前回同様の木のモデルを設定しています。

この実装をしたPCGグラフをレベルに配置するとこのようになります。砂地のような白っぽいところと茶色(Soil)のレイヤーの繋ぎ目のところは木があったりなかったり、塗られ具合によって結果が異なっていることが確認できます。

これで、ランドマークペイントをしたらモデルが出るところまで出来ました。簡単に地形を作っていく際には使える機能ではないでしょうか?

UE5.2 Procedural Content GenerationのノードをBlueprintで書くチュートリアル

PCGグラフのノードをBPで追加することができるよう話題が以下の動画にありました。これとソースコードをベースにやり方を調べて手順をまとめています。

Unreal Engine 5.2 Feature Showcase | GDC 2023 - YouTube

環境について

  • 2023/05/07 時点
  • UE5.2 Preview
  • Procedual Content Generation Framework version 0.1

となっています。今後バージョンアップにより以下の手順で実装できない可能性があります。

はじめに

PCGはUE5.2に追加される機能です。Blueprintのような画面で実装したルールに従ってマップを生成する機能です。これはエディタ中に使えるもので実行時に影響を及ぼすものではありません。 マップと書きましたが、Static Mesh以外にも特定のActorをSpawnするノードがあったので、好きなものを出せるはずです。

www.youtube.com

まずはUE5.2がインストールされている状態で、プラグイン一覧から、"Procedual Content Generation Framework"をインストールしましょう。 インストール後、自由にPCGを使ったマップ生成が楽しめます。

PCGプラグイン

Densityが必ず固定の値になるオリジナルのノードを作成する

PCGの基本的な使い方は動画内で説明されているので割愛します。

上記のGCDセッションや他のサンプルでもDensity filterを使ってポイントをフィルタする操作をしているものがあったので、 何かをフィルタするのにDensityを使うのが良いと思ったのでDensityを操作するノードを作成します。

まず、適当なPCGグラフを新規作成し、以下のようなグラフにします。 Surface SamplerノードでDキーを押して、水色のマークがついている状態にし、デバッグ描画を行っています。 レベルには適当なLandscapeが置いてある状態です。

ランドスケープの作り方については公式のチュートリアルが参考になります。 docs.unrealengine.com

PCGグラフ初期状態

このとき、レベルはこのようになっていて、適当なDensityを持った状態です。

PCGグラフ初期状態のレベル

ここから具体的にBlueprintを使ってノードを作成していきましょう。継承するクラスをPCGBlueprintElementを選択して新規Blueprintを作成します。

PCGBlueprintElementクラスにはいくつか関数が実装されていますが、必要なものだけをオーバーライドします。

PointLoopBodyをオーバーライドします。この関数は、1つのポイントを入力に、1つのポイントを返すロジックを実装できます。ここで実際のDensity操作ロジックを記述します。 といっても、、、今回はDensityを1に固定するロジックを実装したいので、単純にDensity以外のノードを繋ぎなおしただけです。

PointLoopBodyの中身

そして、ExecuteWithContextをオーバーライドします。この関数は、実際に入力から出力結果を返すまでを担当する関数です。簡単なロジックを実装する場合にはお約束のコードになるかもしれません。

処理の流れとしては

  1. 入力が配列なのでループで分解する
  2. PCGSpatialDataにキャストしてPointDataを取得する準備(Normal To Densityのコードを読む限りこの型でよいはず)
  3. Loop On Pointsを呼び、オーバーライドしたPoint Loop Bodyが呼ばれるようにする
  4. 出力結果をローカル変数ReturnValueに格納する
  5. 全てのループが終わったら、ローカル変数ReturnValueを戻り値として返す

PCGグラフ ExecuteWithContextの中身

Loop On Pointsの呼び出しが重要なところなので、C++側のコードを除くと

void UPCGBlueprintElement::LoopOnPoints(FPCGContext& InContext, const UPCGPointData* InData, UPCGPointData*& OutData, UPCGPointData* OptionalOutData) const
{
~~~
    FPCGAsync::AsyncPointProcessing(&InContext, InPoints.Num(), OutPoints, [this, &InContext, InData, OutData, &InPoints](int32 Index, FPCGPoint& OutPoint)
    {
        return PointLoopBody(InContext, InData, InPoints[Index], OutPoint, OutData->Metadata);
    });
}

となっていて、何やら非同期(FPCGAsync::AsyncPointProcessing)で処理を実行していそうなコードが見られます。この機能を使わないで実装することも可能ですが、単純にやってしまうとパフォーマンスが低いノードになってしまうと思われます。

ここまで実装したら、先ほど作成した自作ノードをコンテンツブラウザからPCGグラフにドロップしてください。新しく追加したノードをSurface Samplerの後ろに追加してPCGグラフは完成です。動作を確認するために、Surface Samplerのデバッグフラグをオフにして、自作ノードのデバッグをオンにするために再びDキーで切り替えてください。

PCGグラフ完成

Densityを全て1にしたので、全てのポイントが白くなりました。

PCGグラフ完成後のレベル

単純なコードでしたが、ノードを追加することができました。実際には追加のパラメータを外部から渡したりしながら、Densityを計算するロジックを追加することになるのでもう少し複雑なものになるはずですが、実装のとっかかりになるのではないでしょうか。

LyraGameのコードリーディングーキャラが死ぬときー

LyraサンプルはGameplayAbilitySystemが多様されていて難解なため、自分の備忘録としてまとめていく。同じようにコードリーディングしていく人の手助けになったらいいな。

GameplayAbilitySystem(以下GAS)が何なのか?についてはスタミナを消費させてみるサンプルを自分でやってみてからのほうが理解が進む。

https://historia.co.jp/archives/17941/

コードを読んでみた感想

キャラのHP管理~死亡処理についても例にもれずGASで実装されている。

大まかな流れとしては ULyraHealthComponentがHealthSetを持ちHPを監視していて、HPと死亡状態の管理を行っている。 死亡時演出はGameplayAbility_Deathをキックしている。継承したBPの方で死亡時カメラや暗転までの時間調整がされているようだ。

死亡時に他の操作をブロックしたいので、BlockやCancelするタグが設定されている。Abilityで色々実装していると、死んだ場合は操作不能にできるので便利。

死亡演出について

HealthComponentには

  • 死んでない(ELyraDeathState::NotDead)
  • 死亡中(ELyraDeathState::DeathStarted)
  • 死亡完了(ELyraDeathState::DeathFinished)

の3つの状態がある。ULyraHealthComponent::StartDeath(), ULyraHealthComponent::FinishDeath()を呼び出すことで状態を変えられる。

この二つの状態変化させる関数はULyraGameplayAbility_DeathとULyraHealthComponentのどちらかから呼ばれる。ULyraHealthComponentから呼ばれるケースはネットワーク同期するケースのように見えるので一旦無視する

StartDeath()は死亡演出アビリティのアクティベート時(ULyraGameplayAbility_Death::ActivateAbility())、FinishDeath()はアビリティの終了時(ULyraGameplayAbility_Death::EndAbility)に呼ばれる。

この死亡演出アビリティを継承して使って演出を差し込んでいく使い方を想定していると思われる。

死亡判定

HPはULyraHealthSetに値の実体があり、GamePlayEffectを経由してHealthを減らしている。

死亡判定の流れとしては、

HealthComponent::InitializeWithAbilitySystemでHealthSet::OnOutOfHealthイベントに登録してイベント通知を受けられるようにして

以下のような流れで死亡演出のアビリティを呼び出している

  1. ULyraHealthSet::PostGameplayEffectExecuteでHPが0だったら
  2. ULyraHealthComponent::HandleOutOfHealth でAbilitySystemComponentにGameplayEvent.Deathを送信して、GameplayAbility_Deathが起動する
  3. GameplayAbility_DeathからULyraHealthComponent::StartDeathが呼ばれる

CVATをWindowsでセットアップ

アノテーションツールのCVATをWindowsで動作させたときのメモ

※20190825更新 developブランチだとパッチを当てるところが変わっていたので以下のようなことをする必要はなさそうです。今後のリリースに期待

環境

セットアップ

基本的には公式ドキュメントの通り実行しておけばOKです。(今見たらdevelopブランチでしたが、このままやりました) cvat/installation.md at develop · opencv/cvat · GitHub

しかしながら、docker-compose buildしたときにこのIssueと同じ問題に当たりビルドが完了しません。 Unable to build on windows · Issue #304 · opencv/cvat · GitHub コメントのやりとりの通りdos2unixなるツールを使えと書かれているのでdockerfileを以下のように編集しとりあえず動かせました。

FROM ubuntu:16.04

ARG http_proxy
ARG https_proxy
ARG no_proxy
ARG socks_proxy

ENV TERM=xterm \
    http_proxy=${http_proxy}   \
    https_proxy=${https_proxy} \
    no_proxy=${no_proxy} \
    socks_proxy=${socks_proxy}

ENV LANG='C.UTF-8'  \
    LC_ALL='C.UTF-8'

ARG USER
ARG DJANGO_CONFIGURATION
ENV DJANGO_CONFIGURATION=${DJANGO_CONFIGURATION}

# Install necessary apt packages
RUN apt-get update && \
    apt-get install -yq \
        dos2unix \
        python-software-properties \
        software-properties-common \
        wget && \
    add-apt-repository ppa:mc3man/xerus-media -y && \
    add-apt-repository ppa:mc3man/gstffmpeg-keep -y && \
    apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -yq \
        apache2 \
        apache2-dev \
        libapache2-mod-xsendfile \
        supervisor \
        ffmpeg \
        gstreamer0.10-ffmpeg \
        libldap2-dev \
        libsasl2-dev \
        python3-dev \
        python3-pip \
        unzip \
        unrar \
        p7zip-full \
        vim && \
    add-apt-repository --remove ppa:mc3man/gstffmpeg-keep -y && \
    add-apt-repository --remove ppa:mc3man/xerus-media -y && \
    rm -rf /var/lib/apt/lists/*

# Add a non-root user
ENV USER=${USER}
ENV HOME /home/${USER}
WORKDIR ${HOME}
RUN adduser --shell /bin/bash --disabled-password --gecos "" ${USER}

COPY components /tmp/components

# OpenVINO toolkit support
ARG OPENVINO_TOOLKIT
ENV OPENVINO_TOOLKIT=${OPENVINO_TOOLKIT}
RUN if [ "$OPENVINO_TOOLKIT" = "yes" ]; then \
        /tmp/components/openvino/install.sh; \
    fi

# CUDA support
ARG CUDA_SUPPORT
ENV CUDA_SUPPORT=${CUDA_SUPPORT}
RUN if [ "$CUDA_SUPPORT" = "yes" ]; then \
        /tmp/components/cuda/install.sh; \
    fi

# Tensorflow annotation support
ARG TF_ANNOTATION
ENV TF_ANNOTATION=${TF_ANNOTATION}
ENV TF_ANNOTATION_MODEL_PATH=${HOME}/rcnn/inference_graph
RUN if [ "$TF_ANNOTATION" = "yes" ]; then \
        bash -i /tmp/components/tf_annotation/install.sh; \
    fi

ARG WITH_TESTS
RUN if [ "$WITH_TESTS" = "yes" ]; then \
        wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
        echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list && \
        wget -qO- https://deb.nodesource.com/setup_9.x | bash - && \
        apt-get update && \
        DEBIAN_FRONTEND=noninteractive apt-get install -yq \
            google-chrome-stable \
            nodejs && \
        rm -rf /var/lib/apt/lists/*; \
        mkdir tests && cd tests && npm install \
            eslint \
            eslint-detailed-reporter \
            karma \
            karma-chrome-launcher \
            karma-coveralls \
            karma-coverage \
            karma-junit-reporter \
            karma-qunit \
            qunit; \
        echo "export PATH=~/tests/node_modules/.bin:${PATH}" >> ~/.bashrc; \
    fi

# Install and initialize CVAT, copy all necessary files
COPY cvat/requirements/ /tmp/requirements/
COPY supervisord.conf mod_wsgi.conf wait-for-it.sh manage.py ${HOME}/
RUN  pip3 install --no-cache-dir -r /tmp/requirements/${DJANGO_CONFIGURATION}.txt

# Install git application dependencies
RUN apt-get update && \
    apt-get install -y ssh netcat-openbsd git curl zip  && \
    wget -qO /dev/stdout https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
    apt-get install -y git-lfs && \
    git lfs install && \
    rm -rf /var/lib/apt/lists/* && \
    if [ -z ${socks_proxy} ]; then \
        echo export "GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o ConnectTimeout=30\"" >> ${HOME}/.bashrc; \
    else \
        echo export "GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o ConnectTimeout=30 -o ProxyCommand='nc -X 5 -x ${socks_proxy} %h %p'\"" >> ${HOME}/.bashrc; \
    fi

# Download model for re-identification app
ENV REID_MODEL_DIR=${HOME}/reid
RUN if [ "$OPENVINO_TOOLKIT" = "yes" ]; then \
        mkdir ${HOME}/reid && \
        wget https://download.01.org/openvinotoolkit/2018_R5/open_model_zoo/person-reidentification-retail-0079/FP32/person-reidentification-retail-0079.xml -O reid/reid.xml && \
        wget https://download.01.org/openvinotoolkit/2018_R5/open_model_zoo/person-reidentification-retail-0079/FP32/person-reidentification-retail-0079.bin -O reid/reid.bin; \
    fi

# TODO: CHANGE URL
ARG WITH_DEXTR
ENV WITH_DEXTR=${WITH_DEXTR}
ENV DEXTR_MODEL_DIR=${HOME}/models/dextr
RUN if [ "$WITH_DEXTR" = "yes" ]; then \
        mkdir ${DEXTR_MODEL_DIR} -p && \
        wget https://download.01.org/openvinotoolkit/models_contrib/cvat/dextr_model_v1.zip -O ${DEXTR_MODEL_DIR}/dextr.zip && \
        unzip ${DEXTR_MODEL_DIR}/dextr.zip -d ${DEXTR_MODEL_DIR} && rm ${DEXTR_MODEL_DIR}/dextr.zip; \
    fi

COPY ssh ${HOME}/.ssh
COPY cvat/ ${HOME}/cvat
COPY tests ${HOME}/tests
RUN dos2unix ${HOME}/cvat/apps/engine/static/engine/js/3rdparty/*.js && \
    patch -p1 < ${HOME}/cvat/apps/engine/static/engine/js/3rdparty.patch
RUN chown -R ${USER}:${USER} .

# RUN all commands below as 'django' user
USER ${USER}

RUN mkdir data share media keys logs /tmp/supervisord
RUN python3 manage.py collectstatic

EXPOSE 8080 8443
ENTRYPOINT ["/usr/bin/supervisord"]

ポケステをハックするのがブームと聞いて感化されてしまった

ポケステ部なるものがあるらしい

追記2017/09/17:他のツールも動いたので最後に追記した。

最近自作キーボードをウォッチしている後輩が、色々と有益な情報(散財の元)をくれる。 キーボードのイベントでポケステをハックしてる人たちがいたらしく、わくわくする画像を見かけた。

何で今更ポケステなのか全くわからないけど、すごく楽しそうである。

ここで疑問。さてはて、ライターはどうやって準備してるんだろう???

ポケステ部のハッシュタグを追っていくとこのツールで書き込んでるようだった。

github.com

知らなかったけど、わざわざこんなツールを用意している人がいるとは頭が下がる。対応ハードウェアは3つあるみたいで

  • DexDrive
  • MemCARDuino
  • PS1CardLink

の3つ。arduinoベースのものがあるからこれを使うのが無難そう。とはいえ接続するアダプタとか準備を考えるとめんどくさそうである。

実はメモリカードアダプタを持ってる

PS3の初期?にメモリカードアダプタという商品が出ている。これはPS3にPS1のデータを持っていってPS1アーカイブスのゲームがプレイできるという優れものである。PS1のゲームはPS Vitaで遊べるのでPS1のメモカからデータを吸い出せればPS Vitaで昔のセーブデータが再生できる。懐かしい!!!

しばらく前に、モンスターファーム2がPS Plusで配布されていたときにすげーやりたくなったのでこの商品を探したところ、全く入手ができずプレミアがついてることがわかり愕然とした・・・。 しかし、何でも持ってる先輩に聞いたところ、やっぱり持っていて譲っていただいたのである。何でも持ってる人は何でも持ってるのである。

そんなこんなで1年以上前にもらったメモリカードアダプタのドライバがあれば、手元のポケステが動くのでは?と思ったわけである。

価格.com - 『メモリーカードアダァプゥタァァァァッ!!!が抜き差しできねぇ!!』 SONY プレイステーション3 HDD 60GB のクチコミ掲示板 純正メモカだったのに、この症状と同様に抜けなくなったのでSonyに送って抜いてもらったことがある。慎重に指すようにするか少し緩くなるように何か考えるかしないと危険な商品ですw

時代は64ビットOS・・・

遠い昔、みんながハックしてた頃は32ビットOSのため色々今だと動かないことがわかった。今回の環境はWindows10 64ビットだ。

64bit OSでMCRWwin.EXEを使いたい! - KAZZ underground

このページを参考に、各種ツールとドライバーを入れていく。注意事項としては、ツールは32ビットでも問題ないが、ドライバーが64ビットじゃないといけないこと。

手順としては、ざっと以下の通り。

  • MCRWwin.EXEから読み書きツールをダウンロードする
  • 汎用USBドライバの64ビット版 uusbd64.sys をダウンロードする
  • ドライバーの署名無効でWindowsを起動してドライバをインストールする。(署名無効はここを参照)

無事インストールした後に、MCRWwin.EXEと同じフォルダにuusbd.dllを配置する。これはオリジナルの配布元にあるDLLで動作する。

無事読み取りまで成功

アインハンダーのセーブデータも残ってるぜ!!!やったー

f:id:Nilfs:20170916020448j:plain

本日のビールはヤッホーブルーイングのゆずセッションエールあら塩仕立てでした

でもまだ何も書き込めていない。PocketStation Read-Writeを見るととりあえず今回の環境で書き込みはできそう。 ポケステのゲームのビルドの仕方とか調べていかないといけば、何かできそうだ。

続く・・・かも

その他試したこと

配布されている汎用USBドライバの64ビット化

配布されている汎用USBドライバは32ビット版しかない、とりあえずビルドが通れば使えるかなと思って確認してみた。VS2015でビルドしようとしたところVC6プロジェクトからの変換は半分成功したけど、そのままではビルドできなかった。32ビット前提のコードがないか?細かい定義の置き換えは問題ないか?慎重にやれば、できそうだけど元気が足りなかったのでやめてしまった。

UUSBD.DLLの概要

2017/09/17追記 PS1 Memory Card Readerも動いた

メモリカードアダプタを持っている幸せな人は他のツールでも動く。

Pocketstationにある。

以下の手順でツール起動まで確認ができた

  • PS1 Memory Card Readerのところにあるダウンロードリンクから本体をダウンロード
  • ドライバインストール時に\usb_driver\PS3_MemoryCard_Adaptor.infを選択してインストールする(ほかのものをインストールしている場合は先にアンインストールすること。Readme通りexeを叩いても動かなかった)

解凍したZipのルートフォルダに移動して、

ps3mca-ps1mc.exe  r backup.mc 0 1024

のようなコマンドを実行すると、何かデータが書き出されるのが確認できた。バックアップ完了!

こっちのツールだと64ビットも最初から対応していて安心。CUIなのでちょっと困るけども

Cloud Drive Syncを使い始めたらエラーが止まらないのが無事に解決した

調べたことの備忘録。

Cloud Drive Syncを使い始めた

あんまりDropboxを使わなくなったけど、アカウントを捨てるほどではないのでどっかに置いておきたいという動機から、QnapのCloud Drive SyncでNASに退避を行なった。

同期はとりあえず成功したので、いいかと思ったらエラーログが出続けて全然解決しなくて困ったことになってしまった。エラーログをスマホで受け取るようにしてあったので今日も順調にエラー出てるなという感情を抱くように・・・

別にCloud Drive Syncのエラーがわかりづらい

同期はできてるようにみるのだが、実行後に必ず

[CloudDriveSync] Sync job [XXXXXX同期してるパス] finished with errors. Please check your event log for more details.

と表示されるようになった。このログの詳細とやらが全くどこにあるのかわからなくて困った。

フォーラムで困っている人が他にもいて

Cloud Drive Sync log files? - QNAP NAS Community Forum

SSHでログインして、それっぽいログを探せという回答だった。ログの詳細はWebUI上からは 見れないのかもしれない。

1. cd /share/CACHEDEV1_DATA/.qpkg/CloudDriveSync/data/500

というパスは見つからなかったが、.qpkgというパスからどこかアプリケーションのインストールパスに置かれているログを見ればいいと判断。

cd share
find . -name "CloudDriveSync"

という形でそれっぽいフォルダを発見できた。

CloudDriveSyncフォルダに移動して、ちょうど

./data/500/sync/1/log/syncengine.log

のログファイルをtailコマンドで調べていくとエラーログを発見し、NotFoundErrorの文字が躍るのを確認した。 フォルダ名にCaseConflictとついてるフォルダが軒並み失敗していることがわかった。

リンクされている別のコンピュータで同期されないファイルがある場合 - Dropbox のヘルプ - Dropbox

Dropboxには大文字小文字で衝突しているフォルダがあった場合に自動で別名のフォルダを作成する仕様になっているようだ。これは怪しい・・・。 試しにCaseConflictとなっているフォルダを全て削除してみたところ。エラーメッセージは全部なくなった。

Barocco MD600はHHKBにはならなかった

みんな大好き分割キーボードの新作?Mistelのキーボードを買ってみました。 だいたい2週間ほど、使ってみた感想をまとめます。買ったのは赤軸です。

www.mistelkeyboard.com

動機

高まる分割キーボードブームの乗りたくて、Ergodox EZとかが欲しくなりこんなイベントに行ってみたりしていました。 Ergodoxの値段も去ることながら配列が普段使っているHHKBと異なっているのですぐに慣れるのか?モヤモヤしていて早数ヶ月すっかりキーボードを買えずにいました。 なかなか新しい分割キーボードが出ないこともありたまに調べてはモヤモヤする日々が続きました。

ググっていると知らないメーカーからHHKBのような形状でキーボードが出るじゃないですか!これなら俺でも使えそうだと思って、早速発売ちょっとしてからアキバへ行き買えず、ヨドバシオンラインで注文することに

使ってみた

開封の儀はあちこちで見かけたので特に触れず気になったところだけ。

キーを外す奴とキーキャップがおまけで付いてました。

f:id:Nilfs:20161119161607j:plain

このキーボードの特徴としてカスタマイズできるレイヤーが3つあり、それぞれで自由にマクロが組めるということになっています。 これを使えばHHKB風の配列に書き換えて、HHKBが割れただけにできるのでは?と考えていたわけです。

ところが様々な障害が待っていたわけで

Fnキーレイヤーにマクロが設定できない問題

HHKBであれば、Fn + ;←キーになります。一方、MD600では、Fn + J←キーになります。

MD600でFn + ;Insertキーに割り当てられています。これをマクロで置き換えようとするとできません。Fnキーで切り替わるキーにマクロを割り当てることが現在できないためです。 日本の代理店に聞いたところでは、ファームウェアで改善できるのか確認中とのこと。

Fnキーレイヤーの重要なキーはやっぱりマクロ登録できない

マクロ登録をハードウェア完結な形で実現しているので、買う前に想像しておけよという感じもありますが、説明書に出現するキーをマクロで置き換えることはできないようです。 HHKB風にするなら、Fn + ? ↓キーになって欲しいのですが、そこにはLayer3キーが配置されていて置き換えできないことがわかりました。

この時点でHHKB風にするのはできないことがわかりました。

できるだけは合わせたかったので、

  • 左Alt、Windowsキーを入れ替え
  • CapLockを消してCtrlに差し替え

だけ設定をして使っています。異なるキーがいくつかありますがだいたいこの設定だけで大きな支障なく仕事ができています。キーレイアウトは慣れの問題でしかないのかも。

Fnキーの入力順問題

問題はこれだけではなかったのです・・・。

MD600ではFn + L→キーなので、範囲選択をキーボードでしようとする場合は

Shift + Fn + L

と入力します。

ここで

Fn + Shift + L

と入力するとShiftキーが食われてしまい、→キーが入力されてしまいました。

MD600を使い始めるまで気づかなかったのですが、HHKBを使っているときは順番がどっちでも、範囲選択ができていて、たまに入力順が入れ替わる癖が自分にあるようでした。 そのため、MD600を使ってからめちゃくちゃ誤爆するようになりました。

この挙動は、Altキーでも発生するします。Fn + Escで`が入力されるので日本語切り替えをしようとする場合はAlt + Fn + ESCと入力する必要があります。 この時のAltキーも順番を間違えると意図した通りの結果になりません。

日本語切り替えについては、何か別のキーに割り当てるとして、カーソルキーについては努力するしかなさそうです。 コードを書いていてよく範囲選択してコピペとか削除とかをするので困ったものです。

(この件については問い合わせ中)

ハードウェア上でマクロ設定するのが難しい

やる前からこれもわかるけど、実際にやってみてやっぱり入力が難しい。 前述の設定不能な場所などの情報がなかったので入力ミスなのか仕様なのかわからなくてつらい。 プログラマーような特殊な人しか買わないだろうし、Yamlとかで設定を書くような仕様でもよかったのでは?と思ってしまう。

複雑な入力パターンも作れるのですが、入力が難しいことと使い道を考えつかなかったのでキーリマップの範囲を超えるような設定はしていません。 いい使い方があれば、教えて欲しい。 (キーボード側に設定を持つので環境に左右されずマクロが組める部分はいいのかも、仕事であっちこっちのPCに移動して作業しないから普段使っているエディタの機能で十分だと思う)

日本語サポートがよかった

そろそろよかったことも書いていこうかと思います。 Mistelのページ上にファームウェアで何が変わったかとか、マクロできないキーがあるとかの細かい使用についてなど全然情報が見つけられなくて困っていた。 日本の代理店にメールを投げたら丁寧に対応してもらえたので、不満があれば色々伝えると改善してもらえる可能性がありそう。

まとめ

分割キーボード自体の可能性を感じる。赤軸は今までのより軽くて気持ちいいな。などあれこれ思うこともあり、トータルではそこそこ満足しています。 あまり売れなくて次が出なかったり、ファームウェアが更新されないんじゃ・・・という心配ぐらいです。 最後プロダクトが終わってしまう前にファームウェアが公開されたら自分で書き換えて改造したいなぁと思うところ。

あとはキーボードの間に入れるものを考えないと

  • タッチディスプレイを置いてTouch Bar風のショートカット集を作る
  • トラックボールを置いてみる
  • 飲み物を置く

などいくつかアイディアをもらっているのですが、どうしたものか・・・

皆さんBarocco MD600を買って分割キーボードへの投資をしましょう!w