3Dゲームを製作しています。
ゲーム中で、
複数のオブジェクトを組み合わせて、その集合体をいつでも再現できるように一つの大オブジェクトとして保持する、unityにおけるPrefabのようなシステムを実装したいです。
疑似Prefab化自体は実装できたのですが、その大オブジェクトを呼び出すためのアイコンに使用するサムネイルの作成方法がわかりません。
理想としては、unityのPrefab化のように、大オブジェクトの全体が収まるように画像が自動で撮影され、呼び出し用アイコンに貼り付けられるようにしたいです。
上記のように動的にサムネイル画像を作成するにはどうすればいいですか?
そもそもそのための機能がUnityには存在するのでしょうか?
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答1件
0
ベストアンサー
エディタ上であればAssetPreviewクラスに面白そうな機能がありましたが、残念ながらランタイムでは使えないようですね...
自前で描画する方法を検討してみました。
- サムネイル撮影用のレイヤーを作っておく。とりあえず名前を「Photo Booth」とした。
- サムネイル用のカメラを作り、向きや画角、背景を調整する。とりあえず背景は「Solid Color」とし、デフォルトの背景色は完全透明だったので、これを完全不透明とした。カメラ位置は撮影時に調整するので適当でよい。「Culling Mask」を先ほど作成した「Photo Booth」のみとし、このレイヤーだけを描画させる。コンポーネント名の脇のチェックボックスは切り、無効化しておく。
- サムネイル撮影用のライトを作り、「Culling Mask」を「Photo Booth」にして、被写体だけを照らすようにする。
- それ以外のライトは「Culling Mask」から「Photo Booth」を除外する。
- 動作テスト用にRawImageとButtonを配置する。RawImageの「Color」は白色にしておく。
- 撮影用オブジェクトを作り、スクリプトをアタッチする。
撮影用スクリプト
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総合スコア10807
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/10/12 10:38
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。