20210416のUnityに関する記事は4件です。

UIアイコンアトラスを計画する方法

今回の主な話題:UIアイコンアトラスを計画する方法、Native DLLを使用せずにUnityでプロセス間通信を実現する方法、??演算子を使用してオブジェクトにコンポーネントを追加する方法、キャラクターを追跡するカメラが建物にカバーされる時の半透明案、スクリプトを使用してタイムラインにキーフレームを追加する方法。 UI Q1: アイテムのアイコンが数百または数千個あるかもしれません。同じアトラスに配置すると、サイズは2048Pになります。実際のゲーム中に余分なメモリ浪費が発生します。 タイプごとに分別するのもあまり良くありません。初心者には各タイプの小道具があり、全種類のアトラスが一度引用されます。これは、1つにするのと大差ありません。 レベル区間に従って計画する方が良いかもしれませんが、ストアまたは特定のUIで展示するアイコンに対しては、レベル区間が異なる可能性もあり、複数のアトラスを引用することを引き起こします。使用頻度に従ってアトラスを区別することにも、プランナーさんが全過程を注目する必要があり、間違いやすいです。 または、これらの大量のアイコンをアトラスにパッケージしません、全部散図にします。そうすると、メモリ浪費はそれほど多くありませんが、レンダリング効率は低くなります。 この問題に対して何か良い解決策ありますか? 1、画像の量が1つの画面に表示できる量をはるかに超える場合、より現実的な方法は、自分で動的アトラスを実現することです。つまり、アイコンを散図にして、実行中に要求次第でリアルタイムで大きな画像に組み立てます。Render to Textureによって実現できます。 2、ほとんどのゲームに対して、それが常駐画面インターフェイスでない場合、今の設備のパフォーマンスで、DrawCallに耐えることも無理ではありません。 Script Q2: Native DLLを使用せずにUnityでプロセス間通信を実現するにはどうすればよいですか?UnityでIPCを実装する際にいくつかの問題が発生しました。主な理由は、.Net 3.5にSystem.IO.MemoryMappedFilesクラスがないことです。Unity Editorプラグインを作成するときは、File mappingの方式でIPCを実現する必要があります。さまざまなプロジェクトに普遍的に適応させる必要があり、.Net3.5の互換性がなければなりません。これで、Import C ++で記述されたDLL以外に良い方法はないようですが、プラグインは単純にEditorだけが使用していますから、このせいでゲームに関係のないDLLがBuildにパッケージしたくないです。ですから、何か.Net3.5に対応できるIPCの実現方法はありますか? ① 1、純粋なC#は、socketしてIPCを作成できます。通用性も高いしプラットフォームもクロスできます。 2、Native DLLを使用してもパッケージに入れるかどうかを選択できます。少なくとも現在バージョンのUnityでこういうのはできます。 ② 最下層に近い一部の機能については、自分でNativeプラグインを作成する方が良いです。DLLのImport Settingとマクロ定義であなたが言った問題を回避できます。 PS:非レンダリング機能(例えば、Camera、Microphoneなど)に対して、ほとんどのUnityのパッケージ化は、非効率的で制御できません。 Script Q3: ??演算子を使用してコンポーネントをオブジェクトに追加できないのはなぜですか? ① public class PlayerMoveTest : MonoBehaviour { CharacterController controller; private void Awake() { controller = transform.GetComponent<CharacterController>() ?? gameObject.AddComponent<CharacterController>(); } } ② public class PlayerMoveTest : MonoBehaviour { CharacterController controller; private void Awake() { controller = transform.GetComponent<CharacterController>(); if (controller == null) { controller = gameObject.AddComponent<CharacterController>(); } } } 上記のコードのように、一段目は機能せず、controllerはnullとして表示され、二段目はコンポーネントを追加できます。これはなぜですか? ??演算子の場合、??の前の式がnullであれば、??の後の式が実行されると言うことではありませんか? ① 試しました。 test public class PlayerMoveTest : MonoBehaviour { CharacterController controller; private void Awake() { controller = transform.GetComponent<CharacterController>(); if (controller == null) { controller = gameObject.AddComponent<CharacterController>(); } } } 上記のコードを逆コンパイルすれば、 逆コンパイル if (GUI.Button(new Rect(100f, 100f, 200f, 80f), "Test") && (Object)base.transform.GetComponent<CharacterController>() == (Object)null) { base.gameObject.AddComponent<CharacterController>(); } if (GUI.Button(new Rect(200f, 200f, 200f, 80f), "Test2") && (object)base.transform.GetComponent<CharacterController>() == null) { base.gameObject.AddComponent<CharacterController>(); } 2つのコードが異なることがはっきり見られます。一段目はUnityEngine.Objectタイプを比較し、2つ目はSystem.objectタイプを比較します。 そしで、コードを書いてテストします。 var c1 = (object)base.transform.GetComponent<CharacterController>(); if(c1 == null) Debug.Log(1); var c2 = (Object)base.transform.GetComponent<CharacterController>(); if(c2 ==(Object)null) Debug.Log(2); if(c2 == null) Debug.Log(3); 出力結果は2と3であります。 これらの値をブレークポイントデバッグします。 その原因は、UnityEngine.Objectタイプが==演算子をオーバーロードするため、”null”とnullは同じように見なされます。しかし、System.Objectタイプを使って比較すると、等しくないと見なされるためです。 ② 確認しました、この”null”はあのnullではないことがわかりました。 実際、contor = transform.GetComponent();が実行されると、値が割り当てられますが、割り当てられた値は”null”であります。プリントしたら2つのnullの違いがすぐにわかります。 もう一言、contorのTypeをプリントする際に、oneのところで「オブジェクトの引用はインスタンスとして設定されていない」と報告しますが、twoのところでこのタイプをプリントします。つまり、??演算子の左側の値が割り当てられない場合のみで右側が実行します。例はコードbを参照してください。最後にプリントされたのはvで、cは私が定義した割り当てられないstring cであります。 Script Q4: キャラクターを追跡するカメラが建物にカバーされます。建物を半透明にされたいので、レイキャストが必要です。しかし、パフォーマンスの問題により、シーンオブジェクトでColliderコンポーネントを追加することはできません。単純なShaderで書いた時、効果には常にいくつかの問題があります。何か良い方案ありませんか? ① 1つの方法は、シーンを作成する時にBox Colliderを使用してオブジェクトの形状を真似して物理的な衝突を検出することです。Colliderコンポーネントの追加が許さないから、この形式は許すかどうかがわかりません。 単純なShaderで書く考えはわかりません。ただのShaderでこの要件は処理できないと感じます。 もっと良い方法はあるかどうかがわかりません。通用性も高い、またはtrickyな処理もしない状況で、物理がより直接的で効率的な方法であると感じています。 PS:視角が2.5Dであり、カメラが傾かない場合は、Runtimeで検索するために2Dデータを事前に計算できますが、制限と問題があります。 ② Unity 3Dでは、物理的な検出のためにシーンオブジェクトのような形状を作成するために、Box Colliderよりも直接的な方法は考えていませんでした。 前の人が「Runtimeで検索するためにデータを事前に計算できる」と言及しましたから、何かを思い出しました。Quakeシリーズに、Quakeシリーズでは、シーンレンダリングと物理的な衝突検出データがBSPツリーにプリベイクされていることを覚えています。ランタイムフェーズでのQuakeの衝突検出はBSPに基づいています。 Timeline Q5: 新しいタイムラインを使用すると、キーフレームを手動で追加するオプション/ボタンがなく、関連するAPIも見つからなかったので、キーフレームを手動で追加するにはどうすればよいですか? エディターでは、マウスでクリップの両側をドラッグして、クリップのヘッドまたはテールにキーフレームを追加できます。また、エディターには、現在操作中の+/-フレームの数が表示されます。 Runtimeがbuilt-inトラックにキーフレームを追加したい場合、現在のUnityには関連するインターフェースを提供していません。 スクリプトを通じでカスタムのTrack/Clipを実現できます。スクリプトでTimelineのPlayheadをコントロールして、固定時間にとどまるか、指定した時間にジャンプすることができます。 具体的には、TrackAsset、PlayableAsset、PlayableBehaviourを自分で実現する必要があります。 その中で: TrackAssetの実現は、Trackを操作するための外部Monoスクリプトを提供するために使用されます。 PlayableAssetの実現は、カスタムClipを提供し、Trackに関連するデータを提供するために使用されます。 PlayableBehaviourの実現は、Timelineの再生をコントロールするためのコントロールロジックを実現するために使用されます。 UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサルティングサービスを提供している会社でございます。 UWA公式サイト:https://jp.uwa4d.com UWA公式ブログ:https://blog.jp.uwa4d.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ボーンの数と骨格階層のアート規範

今回の主な話題:ボーンの数と骨格階層のアート規範、最適化前のすべてのボーンの名前を取得する方法、パッケージ化時にコードからSVNバージョン番号を取得する方法、Gitの2つの分かれたPrefabの衝突問題の回避または解決する方法、今でもETC1形式を使用する必要がありますか? FBX Q1:質問したいのですが、ボーンの数と骨格階層は本当にパフォーマンスに大きな影響を与えますか(ある文章がそう言っています)?簡単なテストの結果、影響はそれほど大きくないことがわかりました。 面が3,000のキャラクターに対して、100のボーン、7つのレイヤーは妥当な指標ですか? まだたくさんの浪費がありますか? 問題主のテスト方法は分かりません。GPU skinがデフォルトでオンになっていないか、特別な処理方法が使用されている場合、この部分は主にCPUのパフォーマンスに影響します。したがって、より科学的な方法は、ボーンの数が異なる状況でCPUのアニメーションモジュールの時間コストを統計して判断できます。 たとえば、ターゲットシーンにn人のキャラクターがいる場合、60本のボーンと100本のボーンに従ってn人のキャラクターを置いて、時間のかかる違いを比較します。 そして、100本のボーンが最大化ボーンであるかどうか、またはすべてのキャラクターのスキニングに参与するボーンの数が100本であるかどうかによって、ここのパフォーマンスが異なる可能性があります。私も簡単なテストを行いました。最終的にAnimator.Updateのパフォーマンスを影響するのは、スキニングに参加するボーンの数です。最大化ボーン方案を採用すれば、最大化ボーンの数を特に制限する必要はありませんが、各キャラクターがスキニングに参加するボーンの数を制限する必要があります。 たとえば、PCでアニメーションに関するモジュールのパフォーマンス消費の比較は次のとおりです。 100人のキャラクター、300本のボーンがすべてスキニングに参与します。 100人のキャラクター、300本のボーンがありますが、スキニングに参与するのはそのうちの60本だけです。(更新:確認しました、Unityがエクスポートするときに、スキニングに参与しないボーンはエクスポートしなくなります。ここの300本のボーンの概念はMaxにのみ存在し、Unityではもう60本に最適化されました。) 100人のキャラクター、60本のボーンはすべてスキニングに参与します。 もちろん、これではパフォーマンスの違いのみをテストします、より現実的なデータがターゲットモデルで実行必要があります。 また、骨格階層の深すぎは良くないかもしれません。しかし、GameObject最適化オプションがオンになっていると仮定すると、7層と10層のパフォーマンスに大きな違いはないと思います。この部分にはあまり知っていませんが、ただアニメーション計算の過程から推測します。レイヤーごとに計算する場合、通常、エンジンが子ノードで直接使用するために変換行列をルートノードに格納します。ですから、ここでの余分なコストはあまり多くないです。ただし、これにはいくつかのテストが必要であり、Unityのソースコードを読んでいませんから確定できません。 単純にパフォーマンスから規範を考えると、成立されたばかりのプロジェクトに対して、100本のボーンと7レイヤーはOKって感じます。3000面は少し保守的で、具体的にはゲームタイプによって異なります。もちろん、ボーンの数もゲームタイプに応じて判断する必要があります。例えば、アクションゲームではより多くのボーンが必要になる場合があります。 PS:テストデータは人型モードを使用します。 PPS:この実験についてもう一度説明します。@xin さんと相談した後、この実験はあまり意味がないことがわかりました。 以前の自社開発エンジンでは、モデルをエクスポートした後、スキニングに参加しなかったボーンもモデルにエクスポートされていたため、アニメーションを更新する際に、スキニングに参与しないボーンを削除するために一つの最適化操作があります。この実験を通じて私が最初に検証したかったのは、Unityがそのような最適化を行うかどうかであり(より基本的であるため、行われると思います)、結果もそのようです。しかし、Unityはエクスポート部分ですでにそのような最適化を行っていることがわかりました。つまり、Maxにボーンが300本ある場合にも、60本のみがスキニングに参与し、Unity内にインポートされるのは60本のボーンだけです。 この意味は、前に述べた最大化ボーン数に対する制限にあります。以前のボーン数の制限は、最大化ボーンのレイヤーにありますが、今から見ると最終モデルのボーン数のレイヤーにあるはずです。 FBX Q2: アニメーションシステムでOptimize Game Objectオプションをオンにすると、不要なボーンが消えます。私たちがボーンの下に多くの特殊効果の吊り下げポイントをぶら下げました。Extra Transforms to Exposeでぶら下げポイントを公開できで、後にエディターツールを使用してバッチ処理を行えることもよくわかります。 現在、問題が発生し、アーティストは1つの公開された吊り下げポイントを追加したいです。実際に、一部のFBXにはこのような吊り下げポイントがありません。ツールで処理する時にFBXにこの吊り下げポイントがアあるかどうかを検出したいです。存在しない場合、増加しません。前に処理する時にFBXのOptimize Game Objectオプションをチェックしましたから、LoadAssetの後で最適化する前のすべてのボーンポイント名を取得できませんでした。何かFBXのすべてのボーンポイント名を取得する方法はありますか? ① ModelImporter.transformPathsを使用して、FBXの下のすべてのノードパスを取得できます。 ② ModelImporter以外に、Avatarを解析することもできます。 public static bool HasSkeleton(this GameObject gameObject, string skeletonName) { Avatar avatar = gameObject.GetComponentInChildren<Animator>(true).avatar; SerializedObject serializedObject = new SerializedObject(avatar); var property = serializedObject.FindProperty("m_TOS"); for (int i = 0; i < property.arraySize; i++) { string fullSkeletonPath = property.GetArrayElementAtIndex(i).FindPropertyRelative("second").stringValue; if (fullSkeletonPath.EndsWith(skeletonName)) return true; } return false; } Script Q3: パッケージ化するときに、プロジェクトのSVNバージョン番号を取得したいのですが、どうすればいいですか? ① コマンドラインのSVN infoを使用して、戻り値からバージョン番号を抽出します。 ② CIでパッケージ化をします。 svn log -v -r BASE:HEAD $unity_project_path SvnVersion=`svn info | grep "Last Changed Rev" | tr -d "Last Changed Rev: "` echo "SvnVersion:"$SvnVersion Unityを起動し、パラメーターをインポートします。 $unity_path -batchmode -projectPath $unity_project_path -executeMethod BuildUi.BuildFromCI SvnVersion-$SvnVersion C#取得 public static string SvnVersion { get { //SvnVersion-$1 foreach (string arg in System.Environment.GetCommandLineArgs()) { if (arg.StartsWith("SvnVersion")) { return arg.Split("-"[0])[1]; } } return ""; } } バージョン管理 Q4: Gitの2つの分かれたPrefabの衝突問題の回避または解決する方法はありませんか?外部ネットワークバージョンが急速に更新されており、内部バージョンが数週間後にリリースする大きなバージョンを開発しております。しかし、この2つのバージョンが1つの同じPrefabに変更されており、合併が発生した場合はどうすればよいですか?問題主がGitを使っていますが、SVNで解決できますか?または、他に何か衝突を解決するツールがありませんか?(UnimergeとUnityYAMLMergeのどちらが優れていますか?) ① アイデアを提供します。私たちは、Unimergeを参照してUnity間のプロセス比較および合併ツールを実現して、2つのUnityを開いて対応するPrefabを比較します。 ② Unity 2018.3でNested Prefab機能を提供しました。Prefabの粒度をさらに細かく分割できるため、衝突の発生する可能性を減らすことができます。 Texture Q5: 今でもETC1フォーマットを使用する必要がありますか?4〜5年前の解釈では、ローエンドデバイスはETC2をサポートしていないため、ETC1+Alpha分離を使用する必要があります。 今まで、数年前のハイエンドマシンは、ぎりぎり今のミッドエンドマシンと呼べます。あの時のローエンドマシンのほとんどは淘汰されています。iOSバージョンのゲームもデフォルトで5Sをサポートしていなく、ASTCフォーマットを使用している今に、ETC1+Alpha分離の方式でテクスチャフォーマットを設定することはまだ必要がありますか?デフォルトのETC2はETC1+Alphaの方式に比べて、メモリも仕様も節約し、効果もより良いです。 国内向けのゲームであれば、チェスやカードゲームでない限り(またはローエンドの携帯電話向けの特別なサポート要件がある限り)、ETC2はAndroid端末で直接使用できます。 ただし、ベトナム、タイ、インドなどの海外市場向けの場合は、慎重に検討する必要があります。多くのチームからのフィードバックによると、海外の多くの地域にはまだ低品質の設備が残ってあります。この場合、設備の占有率を運用チームと検討することをお勧めします。 UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサルティングサービスを提供している会社でございます。 UWA公式サイト:https://jp.uwa4d.com UWA公式ブログ:https://blog.jp.uwa4d.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

M1macでjksからpemをつくる

androidアプリをgoogleストアにリリースするにあたり、コンソールに 'アップロード証明書で署名されていない APK をアップロードしました。使用する証明書は同じである必要があります。' と言うエラーが出て何度やっても弾かれるようになりました。 要するに以前にコンソールに上げた証明書を無くしてしまっていて、今回あげようとしたapkの証明書じゃだめってことみたい この通りGoogleに問い合わせて新しい証明書を発行しようとしてみたけど、指示された手順通りにやってもできない。 jksファイルを作るとこまではできるんだけどこのjksからpemを生成するとこで詰んでしまう。 Googleからのメールにある keytool -export -rfc -alias PEMtest -file upload_certificate.pem -keystore /Users/tester/Desktop/Key/PEMtest のコマンドが何度やっても 不正なオプション: -rfc -alias と言うエラーでpemファイルが生成されてくれない。 ググりまくってたどり着いたサイト https://atomic104.hatenadiary.org/entry/2020/08/28/153945 こちらに書かれてる手順が一番正解に近かった ただこれも、私の場合はだめで最後の keytool -export -rfc -alias upload -file 希望のファイル名.pem -keystore jksのパス このコマンドのオプション部分を削除することでやっとpemを出力することができた、つまり keytool -export -alias jks作るときにaliasの項目に入れた値 -file rikod.pem -keystore /Users/UserName/Desktop/Key/hogehoge.jks このコマンドで通りました。 とりあえずメモ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Bio IKで指にIKを付けてみた + スマホVRで動かしてみた

以下の画像のような感じです(Bio IKのストアページより)。 今後、ハンドトラッキングとか流行りそうだし、その際に便利そうかなと思ったので、記事にしてみました。 そもそも何がしたいの? 以前、私は「スマホVRでハンドトラッキングをやってみた」的なUnityアセットを作成して、こちらの記事を投稿しました。 その後、さらに機能を拡張して、HandMRという形になりました。 そこでは、手をLineRendererなどで簡素に表示していましたが、それだけでは面白くないだろうと思い、3Dモデルを動かしてみようと思ったのですが、向きが取得できていないのもあり、あまり上手くいきませんでした。 それで、「指の座標だけでも簡単にモデルを動かせるようなものはないのか」と思い探してみたら、セールの抱き合わせで付いてきたこのアセットが使えそうだということになったので、試してみました。 ちなみに同じIKのアセットにFinal IKというものがあり、そちらにもFinger Rigというもので設定できますが、向き(Rotation)が無いせいなのか、上手くいきませんでした。 ただFinalIKのVRIKという機能も使いたかったので、BioIKとFinalIKを併用することにします(後述)。 もし、FinalIKのみでかつ向き(Rotation)が分からなくても出来る方法があれば、コメントください。 設定方法 モデルにBioIKコンポーネントを付け、各パラメータをサンプルシーンを参考に設定すれば完了です。以上(手抜き)。 なお手の指先のように、空のゲームオブジェクトが追加で必要なことがありますが、サンプル通りにやれば問題ないと思います。 スマホVRで使ってみた 以下のような感じです。 「Articulated Hand」を真似して設定しましたが、手首が上手くいっていないような感じなので、手首にもObjectiveの「Position」を追加しました(パラメータはデフォルト)。 なお、モデルはUnityちゃん(© UTJ/UCL)を、ステージはMagic Mirror Liteを使用しております。 スクリプトからの設定方法 BioIKは自由度が高い反面、パラメータが非常に多く、毎回モデルごとに設定するのはとても手間がかかります。 そこでスクリプトを使って自動で設定してみます。 一部抜粋すると、以下のようなコードになります。 Sample.cs using BioIK; // …(中略) var bioIK = animator.GetBoneTransform(HumanBodyBones.Hips).gameObject.AddComponent<BioIK.BioIK>(); // animatorは対象のモデルのAnimator bioIK.SetGenerations(2); bioIK.SetPopulationSize(75); bioIK.SetElites(2); bioIK.Smoothing = 0f; // 手首の場合 var boneTrans = animator.GetBoneTransform(HumanBodyBones.LeftHand); var bioSegment = bioIK.FindSegment(boneTrans); var bioJoint = bioSegment.AddJoint(); bioJoint.X.Enabled = true; bioJoint.X.Constrained = true; bioJoint.X.LowerLimit = -60f; bioJoint.X.UpperLimit = 60f; bioJoint.Y.Enabled = true; bioJoint.Y.Constrained = true; bioJoint.Y.LowerLimit = -60f; bioJoint.Y.UpperLimit = 60f; bioJoint.Z.Enabled = true; bioJoint.Z.Constrained = true; bioJoint.Z.LowerLimit = -60f; bioJoint.Z.UpperLimit = 60f; bioJoint.JointType = JointType.Rotational; bioJoint.SetOrientation(Vector3.zero); var bioPosition = bioSegment.AddObjective(ObjectiveType.Position) as Position; bioPosition.SetTargetTransform(target); // targetは対象のオブジェクトのTransform 上記のようなコードをStart()やエディタ拡張で実行するようにすれば、モデルごとに設定する手間が省けます。 FinalIKとの併用について 前述のFinal IKには、VRIKというコンポーネントがあります。 これは足のIKを設定して動かすことも出来ます(これだけならBioIKでも出来る)が、設定していない場合でも、他の部位(頭など)に応じて足の動きも自動で行われます。 これを使えば、全身を動かすことも可能ですが、そのままBioIKと併用しようとすると、お互いを上書きしようとするので、以下のようにする必要があります。 Project SettingsのScript Execution Orderで、「RootMotion.~」よりも後ろに「BioIK.BioIK」を追加 BioIKを使いたい箇所以外(手首~指先以外の部分)はJointやObjectiveを設定しない なお前述の通り、指の向き(Rotation)が分かっているのであれば、FinalIKのFinger Rigで済むので、BioIKは不要です。 全身を動かしてみた BioIKとFinalIK(VRIK)を併用して、全身を動かした結果がこちらです。 スマホのカメラでハンドトラッキングしているため、手の認識範囲が限られたり、認識(特に左右の判別やグーにしたとき)が悪かったりしていますが、それでも全身の動かせるというのは魅力的です。 使用アセットが多く手間がかかるため、全体の内容はいまのところ非公開ですが、要望があれば公開するかもしれません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む