C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

PS4PRO: USB ストレージへバックアップしようとしたら エラー CE-32539-2 が発生して一悶着あった話

PS4 バックアップ エラー CE-32539-2: 発生

PS4PRO の標準 1TB HDD を Crucial MX500 1TB SSD に換装するため、 PS4 のバックアップと復元の機能を用い、 A-DATA UV131 64GB USB ( USB メモリー )ストレージへバックアップを行おうとした。

  • 1回目: 購入して開封したばかりの A-DATA UV131 64GB を PS4PRO 本体に挿し、バックアップを進める。バックアップ動作に含まれる再起動後、20MB程度のコピーで進捗しなくなり、残り時間だけが増えだし、程なくしてエラー CE-32539-2 が発生する。
  • 2回目: 手抜きせずに PS4 のストレージ機能から OPTION ボタンメニューを呼び出し、 A-DATA UV131 64GB を exFAT でフォーマット。バックアップに再び挑むも220MB程度のコピーで進捗しなくなり、前回と同様に CE-32539-2 が発生する。
  • 3回目: 2回目と同様にもう一度、不具合確認のつもりで作業する。やはり220MB付近でコピーが進捗しなくなり、しかし今度は異なるエラー CE-33299-6 が発生した。

ここまでの期待しない動作の発生状況から CE-32539-2 について SONY 公式のトラブルシューティングを確認する。 CE-33299-6 についてはフォーラムに情報の断片があるのみだった。

つまり、 SONY もこの問題を十分に把握、再現性を確認し、確かな対策を行えていないらしい事がわかる。

PS4 バックアップ エラー CE-32539-2: 解決方法

Note: ここで紹介する方法は SONY 公式ではなく、私個人の解決の一例に基づく方法です。

  • 解決方法: A-DATA UV131 64GB USB ( USB メモリー )を一旦 PC に接続して exFAT で「クイックではなく完全にフォーマット」する

これだけで PS4 でのバックアップが成功するようになる。

PS4PRO のバックアップ機能の動作中はバックアップ先のファイルシステムの実際のデータの記憶域の構造がクイックフォーマットの対象となるアロケーションビットマップなどのメタ情報のみではなく、何らかのより深いフラグないしメタ情報によらない実データの参照などを行ってしまう実装になっていて、それでこのようなエラーが起こるのじゃろうか。あるいは A-DATA UV131 64GB が何か妙なのだろうか、少なくとも PC で使う分には不良は観測されない開封したての USB メモリーなんじゃが…(´・ω・`)

復元: 未解決

その後、SSDへ換装し、システムソフトウェアのインストールは問題なく完了。システムソフトウェアはデータのバックアップと同じ A-DATA UV131 64GB を使った。しかし、再びバックアップの際に発生した CE-32539-2 が発生し、復元が完了しない。何度かやってみたが、その都度、異なる進捗率のタイミングで進まなくなる。

一旦、 A-DATA UV131 64GB を PS4PRO から PC へ挿し、バックアップを PC の適当なところへさらにバックアップした。このバックアップのバックアップから適当な SD カードへ同じディレクトリー構造でバックアップの複製を用意しつつ、ファイルのコピーに要する20分弱の間、A-DATA UV131 64GB の元のバックアップを用いて復元を試みた。バックアップの複製を作っている間に5回くらい A-DATA UV131 64GB からの復元を試したが、無駄だった。

その後、 A-DATA UV131 64GB から改修したバックアップのバックアップから用意した SD カードのバックアップを HUB 機能などない単純な Reader/Writer を介して PS4 の USB ポートへ挿し、バックアップの復元を行った。これは失敗しなかった。

ぼやき

この作業にあたり、私は 8GB までの USB マスストレージデバイスしか持っていなかったし、それらは USB 2.0 規格の古いものだったので、汎用な USB メモリーも USB 3.1 規格へアップグレードするついで買いとして A-DATA UV131 64GB を SSD と同時に買った。恐らく、今回の問題は PS4 のシステムソフトウェアないし BIOS レベルのファームウェアに問題があるような気がする(あくまでも個人の直感です)。 PS4PRO にはおおむね満足して楽しませて頂いていただけに、今回の件はとても残念に感じた。システムソフトウェアのバージョンアップで解消できる問題であれば、速やかに対応して頂けると嬉しい。

ちなみに、現在アクティブに遊んでいるゲームは Monster Hunter World だけで、他のゲームはよほどの事がない限り起動するつもりは無いので、バックアップと復元の時間を節約しようと思いアプリケーションは Monster Hunter World だけに絞っていた。本体の設定とセーブデータを合わせて 16.2GB 。幸い、カメラ用に使っていた SD カードが 32GB UHS1 の製品だったので復元トラブルも迂回してどうにか対処できたものの、A-DATA UV131 64GB に比べると実効転送速度としては桁違いと感じる程度には遅い(´・ω・`) 素早く SSD へ換装して今夜も Monster Hunter World で30分でも1時間でも多く楽しむ時間を確保したい、そういう目論見もあって、せっかく高速で大容量な USB マスストレージデバイスを購入したのに、結局いらない時間を1時間ほど多くとられてしまい、とても残念な事態となりました💀

UE4/C++ で lambda-expression なタスクをお手軽に非同期処理に投げる方法

// 最小限のコード例
// グラフの意味はさておき、単発のタスクを
// とりあえずなんでもよいのでUE4のタスクプールに投げたい場合はこれだけでも動作する
FFunctionGraphTask::CreateAndDispatchWhenReady( []{}, TStatId(), nullptr );
// 解説用に関連して扱う必要のある型が分かりやすいように少し分解したコード例
TFunction< void() > f0 = []{};
FGraphEventRef t0 = FFunctionGraphTask::CreateAndDispatchWhenReady( f, TStatId(), nullptr );

// 第3引数に nullptr ではなく前提条件とする FGraphEventRef を渡すとタスクグラフが構築される
// 第4引数に ENamedThreads を明示的に与えるとスレッドプール内のどのスレッドに実行させたいか、優先度をどうするかなど設定できる
TFunction< void() > f1 = []{};
ENamedThreads p1 = AnyBackgroundThreadNormalTask;
FGraphEventRef t1 = FFunctionGraphTask::CreateAndDispatchWhenReady( f, TStatId(), t0, p1 );

// メインスレッドで実行しないとクラッシュするような処理をさせたい場合には明示的に GameThread を指定しないと
// ありがちなスレッドとコンテキストによる「たまに落ちる」的なバグを埋め込む事があるので注意。
// 例: UProceduralMeshComponent の CreateMeshSection とか
TFunction< void() > f2 = []{};
ENamedThreads p2 = ENamedThreads::GameThread;
FGraphEventRef t2 = FFunctionGraphTask::CreateAndDispatchWhenReady( f, TStatId(), t1, p2 );

// 完了チェックしたい場合
if ( t2.IsComplete() )
  somthing();

ラムダ式UE4のタスクプールに非同期で投げる方法は簡単な非同期処理の実装にお手軽で嬉しい。( C++ 標準の promise / future / thread に対応する UE4 標準の TPromise / TFuture / FRunnableThread の使い方 - C++ ときどき ごはん、わりとてぃーぶれいく☆ での実装例のようにタスクにクラスを定義する必要が無い)

Note: ただし、このお手軽な方法は「それほど重くない処理」または「ゲームスレッド以外でのんびり実行してくれればよい処理」などでは便利に使えるが、「ゲームスレッドで実行する必要があり、1フレームに近いか、あるいは1フレームを超える処理時間を要する重い処理」や「ゲームスレッドで実行する必要があり、1つあたりは0.1msで処理できるがほぼ同時に1000タスク発生する処理」のようなタスクの非同期処理には実質的に使えない。タスクの粒度によらず前提条件さえ満たしていれば溜まっているタスクを Tick 1フレームで全てビッグバン実行してしまうため、メインスレッドや描画スレッドが想定するフレームレートをこなせなくなるようなタスクを投げたい場合には、フレームあたりのタスクの実行粒度を制御する工夫が必要となる・w・

参考

UE4/C++: UMaterialInstanceDynamic を生成したり UPrimitive 的な何かにセットしたりするコードスニペット的なメモ

// ぱたーん1: マテリアルインスタンスダイナミックを複数の何かのマテリアルとして使いまわしたい場合

// 1.1. AActor 系のどこかなどで、とりあえずマテリアルインスタンスダイナミックをマテリアルアセットから作る:
auto m = UMaterialInstanceDynamic::Create( Cast< UMaterial >( StaticLoadObject( UMaterial::StaticClass(), nullptr, TEXT( "/Game/MyDir/MyMaterial" ) ) ), this );
// 1.2. UPrimitiveComponent 系の何か(UStaticMeshComponent など)にマテリアルをセットする:
constexpr auto element_index = 0;
mesh->SetMaterial( element_index , m );
// ぱたーん2: 使い回さず1つの UPrimitiveComponent 系の何かで使う程度の場合

// 2.1. いきなり作れてセットもできる
auto m = mesh->CreateAndSetMaterialInstanceDynamicFromMaterial( 0, Cast< UMaterial >( StaticLoadObject( UMaterial::StaticClass(), nullptr, TEXT( "/Game/MyDir/MyMaterial" ) ) ) );
// 2.optional. この方法でも使い回せる
mesh->SetMaterial( 1, m );
// appendix: UPrimitiveComponent は GetMaterial メンバー関数も持っているので、マテリアルを保持しなくて良い程度の用途はこれでも実装できる
mesh->SetMaterial( 1, mesh->GetMaterial( 0 ) );

参考

UE4 Plugin: SVG Importer Plugin

概要

UE4SVG をテクスチャーで扱いたかったけれど、 svgpp など使ってちまちま実装するよりも $19.99 で SVG Importer Plugin を買った方が楽そうだし、マーケットプレイスでも ☆5 が幾つもついているので試してみようかな、と思い試してみた記録。

SVG Importer Plugin

試した

SVG Importer Plugin はエンジンプラグインなので、 Epic Game Launcher からエンジンにプラグインを install し、プロジェクトのプラグイン設定で有効化すると使用可能になる。

プラグインが有効なプロジェクトで UE4Editor が動作中に .svg をプロジェクトの Content ディレクトリーへ放り込む、或いは UE4Editor の UI から明示的に Import 操作を行うと SVG Import Options が出現する

f:id:USAGI-WRP:20180510161355p:plain

ここで重要なのは "Import Type" (RGBAの絵として読み込むか、ディスタンスフィールドとして読み込むか)と、 "Import Resolution"(後から変えられない取り込み時の解像度)の2つ。大きく拡大して表示されるRGBAテクスチャーにしたい場合は "Import Resolution" を 4096x4096 にしておくとよい。

↓インポートに成功するとSVGテクスチャーのアセットが生成される

f:id:USAGI-WRP:20180510162042p:plain

↓適当なマテリアルアセットを作成し、テクスチャーにインポートしたSVGテクスチャーアセットを設定

f:id:USAGI-WRP:20180510162140p:plain

↓プレビュー等も問題なく動作

f:id:USAGI-WRP:20180510162335p:plain

↓4096x4096でインポートしておけばRGBAテクスチャーで拡大されても綺麗(アタリマエじゃが😅)

f:id:USAGI-WRP:20180510162407p:plain

↓32x32など小さい解像度でインポートしてしまうとそれ以上にはどうにもならなくなる

f:id:USAGI-WRP:20180510162532p:plain

↓32x32はアライ

f:id:USAGI-WRP:20180510162613p:plain

解像度は 4096x4096 でインポートしておけば、SVGテクスチャーアセットの設定で任意に小さく書き出す事もできるので、インポート時は特に理由が無ければ最大解像度でインポートしておくと良さそう。テクスチャーの書き出しも各種圧縮形式も簡単に選択するだけで対応できて便利も好い。

SVGテクスチャーアセットの設定からフィルターを変更すればドット感の高い低解像度テクスチャーにもできる

f:id:USAGI-WRP:20180510163622p:plain

↓同じSVGを無理やりディスタンスフィールドとしてインポートしてディスプレイスメントマップしてみたもの(無理やりだけどたぶんインポート機能そのものは問題なく扱える。)

f:id:USAGI-WRP:20180510165705p:plain

黄色のクルマのSVGの出典

UE4-4.19 で Material Layers を試用する手順

概要

従来の UE4 では「マテリアルのレイヤーブレンド機能」=「マテリアル関数の合成機能」でした。4.19以降で試験実装された "Material Layers" を使うと「マテリアル関数」ではなく、新たなアセットとして追加される「マテリアルレイヤー」と「マテリアルレイヤーブレンド」を用いた新しいマテリアルのレイヤー合成を試用できます。と、いうわけで基礎的な使い方を確認しつつ試用してみます。

なお、この機能の利点は複雑なマテリアルを作成したい場合に、マテリアル1つで全てを実装しようとするとグラフが混沌となってしまう問題をレイヤーと合成それぞれを独立したアセットに分割する事で解消しつつ、従来のマテリアル関数を組み合わせる方法に比べてもマテリアルインスタンスでの一元的なパラメーターの取り扱いが可能となるなど便利も向上する、ということで試験実装が進められたようです。

実際、すっきりするし使いやすい。(この機能追加のために 4.19 からは MaterialInstance 系の実装が C++er 的にはしれっと変更されていて 4.18 までの C++ コードは少し変更してあげないと翻訳不能になっていたりとかあります。 Blueprint で本記事くらいの機能と動作の確認をした上で実装変更をドキュメントなど眺めると、なるほどそれでこうなったのか、とわかります。知らんと翻訳エラーの発生と対応方法に若干戸惑うかも。)

準備

  1. 4.19 以降のエンジンとプロジェクトを用意する
  2. UE4Editor のメニュー "Edit" から "Project Settings" の "Engine - Rendering" の "Experimental" にある "Support Material Layers" チェックボックスをON

f:id:USAGI-WRP:20180510090224p:plain

Note: OFF -> ON にすると UE4Editor の再起動を促されます。

試用

手順

2つのマテリアルレイヤー la lb と、1つのマテリアルレイヤーブレンド blend を使うマテリアル m を作成し、 mインスタンス i を適当な Static Mesh の Material に設定するまで:

  1. "Content Browser" の "Add New" から "Materials & Textures" -> "Material Layer" でマテリアルレイヤーアセット la を作る
  2. 同様に "Material Layer" アセットの lb も作る
  3. 同様に "Material Layer Blend" アセットの blend も作る
  4. 同様に "Material" アセット m も作る
  5. m の出力ノードの "Details" の "Material" の "Use Material Attributes" チェックボックスを ON にする
  6. m を "Content Browser" のコンテキストメニューから "Create Material Instance" してマテリアルインスタンスアセット i を作る
  7. 適当な "Static Mesh" なり "SK_Mannequin" などを配置して "Mesh" の "Material" に i を設定

動作確認として la lb blend それぞれに適当なパラメーターを噛ませた出力を実装:

  1. la lb に自動的に追加されている "SetMaterialAttributes" ノードの "Details" の "Material Attributes" の "Attribute Set Types" に設定したいマテリアル属性の項目を追加し、出現するピンへ "Texture Sample" や "VectorParameter" などのノードを追加してパラメーターを接合
  2. blend に自動的に追加されている "BlendMaterialAttributes" ノードに "ScalarParameter" ノードを追加して接合し、適当な既定値を設定
  3. m に "Material Attribute Layers" ノードを適当な名前で追加し、出力ノードへ接合
  4. m に追加した "Material Attribute Layers" ノードの "Details" の "Layers" の "Bacbkground" の "Layer Asset" に la を設定
  5. m に追加した "Material Attribute Layers" ノードの "Details" の "Layers" に "Layer 1" を追加し、 "Layer Asset" に lb を、 "Blend Asset" に blend をそれぞれ設定
  6. i の "Layer Parameters" に la, lb blend で追加した設定可能な "Parameters" 系のノードの値を適当に調整

動作確認:

  1. i を設定した "Mesh" を眺めるなりプレイするなりして la をベースに lbblend するマテリアルのインスタンスが意図通り動作する事を確認

補足図

↓ "Support Material Layers" を ON にしたプロジェクトでは作成できるアセットに "Material Layer" と "Material Layer Blend" が増える

f:id:USAGI-WRP:20180510095353p:plain

↓ "Material Layer" アセット作成直後のグラフ

f:id:USAGI-WRP:20180510100043p:plain

↓ "Material Layer Blend" アセット作成直後のグラフ

f:id:USAGI-WRP:20180510100436p:plain

↓ "Material" アセット m の "Details" の "Use Material Attributes" チェックボックス

f:id:USAGI-WRP:20180510101127p:plain

↓ "Material" アセット m に "Material Attribute Layer" ノードを追加し、 "Use Material Attributes" で変化した出力のピンと接合

f:id:USAGI-WRP:20180510101255p:plain

la に動作確認用に例として "TextureSampler2D" パラメーターノードを "SetMaterialAttributes" の "BaseColor" へ追加したグラフ

f:id:USAGI-WRP:20180510121802p:plain

lb に動作確認用に例として "VectorParameter" パラメーターノードを "SetMaterialAttributes" の "BaseColor" へ追加したグラフ

f:id:USAGI-WRP:20180510122102p:plain

blend に動作確認用に例として "ScalarParameter" パラメーターノードを "BlendMaterialAttributes" の "Alpha" へ追加したグラフ

f:id:USAGI-WRP:20180510122120p:plain

m に追加した "Material Attribute Layers" ノードの "Details" の "Layers" に la lb blend を設定

f:id:USAGI-WRP:20180510122223p:plain

i の "Layer Parameters" で la, lb, blend のパラメーターを調整

f:id:USAGI-WRP:20180510122357p:plain

↓ マネキンのマテリアルに i を設定した状態での動作確認

f:id:USAGI-WRP:20180510114251p:plain

参考

  1. Material Layering Feedback for 4.19 - Unreal Engine Forums
    • 試験実装中のマテリアルレイヤー機能の公式スレッド
  2. http://historia.co.jp/archives/955/
    • 従来から使用できるマテリアル関数ベースのマテリアルレイヤー合成機能の参考

UE4/C++: 4.18 以降発生するクリップボードのAPI仕様変更に伴う警告と必要な修正

状況

FGenericPlatformMisc::ClipboardCopy または FGenericPlatformMisc::ClipboardPaste を使用している場合、UE4-4.18 以降で API の仕様変更に伴う警告が翻訳時に発生する。

warning C4996: 'FGenericPlatformMisc::ClipboardCopy': FPlatformMisc::ClipboardCopy() has been superseded by FPlatformApplicationMisc::ClipboardCopy() Please update your code to the new API before upgrading to the next release, otherwise your project will no
longer compile.
warning C4996: 'FGenericPlatformMisc::ClipboardPaste': FPlatformMisc::ClipboardPaste() has been superseded by FPlatformApplicationMisc::ClipboardPaste() Please update your code to the new API before upgrading to the next release, otherwise your project will
no longer compile.

必要な修正

実装クラスが変更されただけではなく、変更先のヘッダーが CoreMinimal.h に含まれていない点、加えて実装クラスが提供されるモジュールも独立しているためモジュールの追加も必要となる点に注意。

  1. FGenericPlatformMiscFPlatformApplicationMisc に置き換える。
  2. HAL/PlatformApplicationMisc.h を include 追加。
  3. <project>.Build.csApplicationCore モジュールを追加。

something.cpp:

// ...
#include "HAL/PlatformApplicationMisc.h"
// ...
  // copy to clipboard
  FString hoge = TEXT( "hoge" );
  // old
  FGenericPlatformMisc::ClipboardCopy( *hoge );
  // new
  FPlatformApplicationMisc::ClipboardCopy( *hoge );
// ...
  // paste from clipboard
  FString hoge;
  // old
  FGenericPlatformMisc::ClipboardPaste( hoge );
  // new
  FPlatformApplicationMisc::ClipboardPaste( hoge );

<project>.Build.cs:

    PublicDependencyModuleNames.AddRange
      ( new string[]
        { // ...
        , "ApplicationCore"
        // ...
        }
      );

UE4/C++: 4.18 -> 4.19 エンジンアップデートトラブル; `UMaterialInstance::GetVectorParameterValue` の仕様変更と "Material Layers"

現行プロジェクトに必要なプラグインの 4.19 対応も進んできたので、手元のプロジェクトを 4.18 から 4.19 へエンジンアップデートしてみました。エンジンの仕様変更によるトラブルがあったので対処方法と併せて紹介します。

4.18 -> 4.19 における UMaterialInstance::GetVectorParameterValue の仕様変更

UMaterialInstance::GetVectorParameterValue の引数仕様が後方互換性なしで変更されていました。

Engine/Source/Runtime/Engine/Classes/Materials/MaterialInstance.h:

// 4.18
virtual ENGINE_API bool GetVectorParameterValue(FName ParameterName, FLinearColor& OutValue) const override;
// 4.19
virtual ENGINE_API bool GetVectorParameterValue(const FMaterialParameterInfo& ParameterInfo, FLinearColor& OutValue, bool bOveriddenOnly = false) const override;
  1. 第一引数が変更: FName ParameterName -> const FMaterialParameterInfo& ParameterInfo
  2. 第三引数が追加: bool bOveriddenOnly = false

FMaterialParameterInfo は 4.18 には存在しない 4.19 で追加された型で MaterialInstance.h と同じ場所に追加された MaterialLayersFunctions.h で定義されていた。

Engine/Source/Runtime/Engine/Classes/Materials/MaterialLayersFunctions.h:

// 本来のソースからメンバー変数と ctor を引用、日本語で概説を付けた。
USTRUCT(BlueprintType)
struct ENGINE_API FMaterialParameterInfo
{ GENERATED_USTRUCT_BODY()
  
  // 最低限これだけ与えればよい。 4.18 まで直接与えていた FName のパラメーターに相当
  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=ParameterInfo)
  FName Name;
  
  // グローバルパラメーターか、あるいはレイヤーパラメーターまたはブレンドパラメーターかを設定。 4.19 で追加。
  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=ParameterInfo)
  TEnumAsByte<EMaterialParameterAssociation> Association;
  
  // グローバルパラメーターの場合は INDEX_NONE, レイヤーパラメーターまたはブレンドパラメーターの場合は有効なインデックス値を設定する。 4.19 で追加。
  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=ParameterInfo)
  int32 Index;
  
  // ctor pattern 1
  FMaterialParameterInfo(const TCHAR* InName, EMaterialParameterAssociation InAssociation = EMaterialParameterAssociation::GlobalParameter, int32 InIndex = INDEX_NONE);
  // ctor pattern 2
  FMaterialParameterInfo(FName InName = FName(), EMaterialParameterAssociation InAssociation = EMaterialParameterAssociation::GlobalParameter, int32 InIndex = INDEX_NONE);
  
  // ほかは省略

4.18 まで FName ParameterName として直接扱っていたパラメーターは 4.19 では FMaterialParameterInfo::Name に放り込んで扱うようだ。 4.18 まで第一引数を明示的に FName 型で与えていなかった場合には 4.18 から 4.19 へプロジェクトのエンジンアップデートを行う場合にこの絡みを使っている C++ ソースコードがあれば手書きの対応が必要となる。 第三引数については省略すれば INDEX_NONE がデフォルトパラメーターからセットされるため、さしあたり気にする事はない。

// 4.18 までこんな具合にコードしていた場合は
material->GetVectorParameterValue( "my_vector_param", buffer );
// 4.19 では最低限こんな具合で第一引数を明示的に FName 型で与えるようにすればコンパイル可能になる
material->GetVectorParameterValue( FName( "my_vector_param" ), buffer );

おまけ1: EMaterialParameterAssociation

UENUM()
enum EMaterialParameterAssociation
{
  LayerParameter,
  BlendParameter,
  GlobalParameter,
};

おまけ2: グローバルパラメーター、レイヤーパラメーター、ブレンドパラメーターとは何か。どうしてこうなった?

UE4 では 4.19 の新機能として "Material Layers" を実装した。

従来は1つ1つのマテリアルの単位で、その中でテクスチャーサンプリングしてパラメーターを合成したりするだけだったが、 この新機能により「複数のマテリアル群からなるマテリアル(="Material Layers")」を直接的にまとめて扱えるようになった。

この新機能に対応するため、従来はマテリアルごとに 4.19 からグローバルパラメーターと明示的に呼び分けられるようになったマテリアル内のシンボル名のほか、 「レイヤーのインデックス何番目の」という情報が必要な "Material Layers" タイプのマテリアルへ従来のマテリアルと統合的に対応するため 単なる FName だけのパラメーターから FMaterialParameterInfo への拡張が行われた。

"Material Layers" 参考