質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

2639閲覧

Unity-動的にサムネイル用画像を作成する

退会済みユーザー

退会済みユーザー

総合スコア0

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2017/10/09 05:39

3Dゲームを製作しています。

ゲーム中で、
複数のオブジェクトを組み合わせて、その集合体をいつでも再現できるように一つの大オブジェクトとして保持する、unityにおけるPrefabのようなシステムを実装したいです。
疑似Prefab化自体は実装できたのですが、その大オブジェクトを呼び出すためのアイコンに使用するサムネイルの作成方法がわかりません。

理想としては、unityのPrefab化のように、大オブジェクトの全体が収まるように画像が自動で撮影され、呼び出し用アイコンに貼り付けられるようにしたいです。

上記のように動的にサムネイル画像を作成するにはどうすればいいですか?
そもそもそのための機能がUnityには存在するのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

IShix

2017/10/10 17:07

これはエディタ上でサムネイルを作成しておきたいってことですか?動的に任意のタイミングで作成したいのですか?
guest

回答1

0

ベストアンサー

エディタ上であればAssetPreviewクラスに面白そうな機能がありましたが、残念ながらランタイムでは使えないようですね...
自前で描画する方法を検討してみました。

  • サムネイル撮影用のレイヤーを作っておく。とりあえず名前を「Photo Booth」とした。
  • サムネイル用のカメラを作り、向きや画角、背景を調整する。とりあえず背景は「Solid Color」とし、デフォルトの背景色は完全透明だったので、これを完全不透明とした。カメラ位置は撮影時に調整するので適当でよい。「Culling Mask」を先ほど作成した「Photo Booth」のみとし、このレイヤーだけを描画させる。コンポーネント名の脇のチェックボックスは切り、無効化しておく。

サムネイル用カメラ
カメラ

  • サムネイル撮影用のライトを作り、「Culling Mask」を「Photo Booth」にして、被写体だけを照らすようにする。
  • それ以外のライトは「Culling Mask」から「Photo Booth」を除外する。
  • 動作テスト用にRawImageとButtonを配置する。RawImageの「Color」は白色にしておく。
  • 撮影用オブジェクトを作り、スクリプトをアタッチする。

撮影用オブジェクト
Photographer

ヒエラルキー
ヒエラルキー

撮影用スクリプト

C#

1using System.Linq; 2using UnityEngine; 3using UnityEngine.UI; 4 5public class Photographer : MonoBehaviour 6{ 7 public Camera ThumbnailCamera; // サムネイル撮影用カメラ 8 public float CameraDistance = 1.5f; // カメラを被写体バウンディングボックス半径の何倍離すか 9 10 public RawImage previewImage; // 動作確認用のテクスチャ表示領域...実際の使用時には不要 11 public GameObject ObjectToCaptureThumbnail; // 動作確認用の撮影対象...実際の使用時には不要 12 13 // ボタンクリックでサムネイルを撮影する動作確認用メソッド...実際の使用時には不要 14 public void Capture() 15 { 16 if (previewImage.texture != null) 17 { 18 Destroy(previewImage.texture); 19 } 20 21 previewImage.texture = this.TakeThumbnail(this.ObjectToCaptureThumbnail); 22 } 23 24 // objのサムネイルを撮影する 25 public Texture2D TakeThumbnail(GameObject obj, int width = 256, int height = 256) 26 { 27 if (obj == null) 28 { 29 return null; 30 } 31 32 var objTransform = obj.transform; 33 var cameraTransform = this.ThumbnailCamera.transform; 34 var renderers = obj.GetComponentsInChildren<Renderer>(); // 被写体中のレンダラーを全部さらってくる 35 var gameObjects = renderers.Select(r => r.gameObject).Distinct().ToArray(); // レンダラーを持つオブジェクト群 36 var gameObjectCount = gameObjects.Length; 37 var currentLayers = new int[gameObjectCount]; 38 var photoBoothLayer = LayerMask.NameToLayer("Photo Booth"); 39 40 // オブジェクト群のレイヤーをPhoto Boothに変更する 41 // 元のレイヤーは後で原状復帰するために覚えておく 42 for (var i = 0; i < gameObjectCount; i++) 43 { 44 var g = gameObjects[i]; 45 currentLayers[i] = g.layer; 46 g.layer = photoBoothLayer; 47 } 48 49 var unitedBounds = new Bounds(objTransform.position, Vector3.zero); 50 51 // レンダラー群のバウンディングボックスを全部結合する 52 foreach (var r in renderers) 53 { 54 unitedBounds.Encapsulate(r.bounds); 55 } 56 57 var boundsCenter = unitedBounds.center; 58 var boundsExtents = unitedBounds.extents; 59 var boundsRadius = boundsExtents.magnitude; 60 61 Debug.LogFormat("Bounds center: {0}, extents:{1}, radius:{2}", boundsCenter, boundsExtents, boundsRadius); 62 63 objTransform.Translate(-boundsCenter); // 被写体を原点に移動 64 cameraTransform.position = -cameraTransform.forward * (boundsRadius * this.CameraDistance); // カメラを原点からboundsRadius * this.CameraDistanceだけ離した位置に据える 65 66 var film = RenderTexture.GetTemporary(width, height); // 撮影用の一時テクスチャ 67 var result = new Texture2D(film.width, film.height); // 撮影結果を格納する新規テクスチャ 68 var currentTexture = RenderTexture.active; // 現在のアクティブなテクスチャは退避 69 70 // サムネイルを撮影し、フレームバッファから結果を取得 71 this.ThumbnailCamera.targetTexture = film; 72 RenderTexture.active = film; 73 this.ThumbnailCamera.Render(); 74 result.ReadPixels(new Rect(0, 0, film.width, film.height), 0, 0); 75 result.Apply(); 76 RenderTexture.active = currentTexture; // アクティブテクスチャを原状復帰 77 RenderTexture.ReleaseTemporary(film); // 一時テクスチャは廃棄 78 this.ThumbnailCamera.targetTexture = null; 79 80 // オブジェクト群のレイヤーを元に戻す 81 for (var i = 0; i < gameObjectCount; i++) 82 { 83 gameObjects[i].layer = currentLayers[i]; 84 } 85 86 objTransform.Translate(boundsCenter); // 被写体の位置を元に戻す 87 88 return result; 89 } 90} 91

撮影した様子

プレビュー

いろいろ最適化できる余地があるかと思いますが、ご質問者さんの設計に合わせてご自由に改造してしまってください。

サムネイルの照明に関してですが、撮影用ライトをオフにしてみるとお分かりかと思いますが、シーン全体の環境照明の影響が残っており、空の色で照らされたりするかと思います。それが気に入らないようでしたら、これらの設定にはRenderSettingsからアクセスできるようですので、撮影前に適宜設定を記憶し撮影後に復帰する必要があるかと思います。真っ暗にするにはUnity5の世界を暗黒の闇で覆う方法 - テラシュールブログもご参考になるでしょうか。あるいは、サムネイル撮影時にRenderWithShaderを使って環境光の影響を受けない独自シェーダーで描画するということもできそうです。

投稿2017/10/10 22:31

編集2017/10/11 06:04
Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/10/12 10:38

リファレンスを見ながら読み解いていたもので返事が遅くなってしまいました、申し訳ないです。 おかげ様で思っていた通りの実装ができそうです。 わかりやすい丁寧な解説でとても助かりました、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問