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

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

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

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Q&A

解決済

1回答

1244閲覧

Unity5.6.2f1でメインカメラの両目の映像をレンダリングしたい

masa_000

総合スコア18

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

0グッド

0クリップ

投稿2019/10/04 14:52

左右の目を個別にレンダリングして、RenderToCubemapというメソッドでキューブマップにしようと思っているのですがメインカメラの映像を左右別にする方法が調べてみてまったくわかりません。普通のメインカメラの映像はキューブマップにすることはできました。方法だけでもいいので教えてくださると幸いです。
よろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

カメラを左右の目の位置の分だけ少しずらして、左右でそれぞれキューブマップを作成すればいいんじゃないでしょうかね?
RenderToCubemapやConvertToEquirectをUnity5.6.2f1で使いたいで例示しましたコードをベースに改造するとこんな感じでしょうか。

まずCubeToEquirectangularのバーテックスシェーダー内で頂点座標・UV座標を調整できるようにして...

ShaderLab

1Shader "Hidden/CubeToEquirectangular" 2{ 3 Properties 4 { 5 _MainTex ("Texture", Cube) = "white" {} 6 _VertexOffsetAndScale ("Vertex Offset and Scale", Vector) = (0.0, 0.0, 1.0, 1.0) 7 _UvOffsetAndScale ("UV Offset and Scale", Vector) = (0.0, 0.0, 1.0, 1.0) 8 } 9 SubShader 10 { 11 Cull Off ZWrite Off ZTest Always 12 13 Pass 14 { 15 CGPROGRAM 16 #pragma vertex vert 17 #pragma fragment frag 18 19 #include "UnityCG.cginc" 20 21 struct appdata 22 { 23 float4 vertex : POSITION; 24 float2 uv : TEXCOORD0; 25 }; 26 27 struct v2f 28 { 29 float2 uv : TEXCOORD0; 30 float4 vertex : SV_POSITION; 31 }; 32 33 float4 _VertexOffsetAndScale; 34 float4 _UvOffsetAndScale; 35 36 v2f vert(appdata v) 37 { 38 v2f o; 39 o.vertex = UnityObjectToClipPos(v.vertex); 40 o.vertex.xy = o.vertex.xy * _VertexOffsetAndScale.zw + _VertexOffsetAndScale.xy; 41 o.uv = v.uv * _UvOffsetAndScale.zw + _UvOffsetAndScale.xy; 42 return o; 43 } 44 45 samplerCUBE _MainTex; 46 float4x4 _TransformMatrix; 47 48 fixed4 frag(v2f i) : SV_Target 49 { 50 float phi = 2.0 * UNITY_PI * (i.uv.x + 0.5); 51 float theta = (i.uv.y - 0.5) * UNITY_PI; 52 float sinPhi; 53 float cosPhi; 54 float sinTheta; 55 float cosTheta; 56 sincos(phi, sinPhi, cosPhi); 57 sincos(theta, sinTheta, cosTheta); 58 float3 worldDirection = float3(sinPhi * cosTheta, sinTheta, cosPhi * cosTheta); 59 float3 localDirection = mul(_TransformMatrix, worldDirection); 60 return texCUBE(_MainTex, localDirection); 61 } 62 ENDCG 63 } 64 } 65}

キューブマップ描画スクリプトは左右2枚のキューブマップを作るようにし...

C#

1using UnityEngine; 2using UnityEngine.Rendering; 3 4[RequireComponent(typeof(Camera))] 5public class StereoCubemapUpdater : MonoBehaviour 6{ 7 [SerializeField] private int cubemapSize = 1024; 8 [SerializeField, Range(0.0f, 0.2f)] private float separation = 0.065f; 9 private new Camera camera; 10 private Transform cameraTransform; 11 public RenderTexture CubemapLeft { get; private set; } 12 public RenderTexture CubemapRight { get; private set; } 13 14 private void Awake() 15 { 16 this.camera = this.GetComponent<Camera>(); 17 this.cameraTransform = this.camera.transform; 18 this.CubemapLeft = new RenderTexture(this.cubemapSize, this.cubemapSize, 24) 19 { 20 dimension = TextureDimension.Cube 21 }; 22 this.CubemapRight = new RenderTexture(this.cubemapSize, this.cubemapSize, 24) 23 { 24 dimension = TextureDimension.Cube 25 }; 26 } 27 28 private void Update() 29 { 30 this.camera.enabled = false; 31 var cameraCenter = this.cameraTransform.localPosition; 32 this.cameraTransform.Translate(-this.separation * 0.5f, 0.0f, 0.0f); 33 this.camera.RenderToCubemap(this.CubemapLeft); 34 this.cameraTransform.Translate(this.separation, 0.0f, 0.0f); 35 this.camera.RenderToCubemap(this.CubemapRight); 36 this.cameraTransform.localPosition = cameraCenter; 37 this.camera.enabled = true; 38 } 39}

円筒図法展開スクリプトでは左右のキューブマップを並べてそれぞれレンダリングすればどうでしょう。

C#

1using System; 2using UnityEngine; 3 4public class StereoEquirectangularTextureUpdater : MonoBehaviour 5{ 6 public enum Arrangement 7 { 8 TopAndBottom, 9 SideBySide 10 } 11 12 public enum FieldOfView 13 { 14 Full, 15 Half 16 } 17 18 [SerializeField] private StereoCubemapUpdater stereoCubemapUpdater; 19 [SerializeField] private RenderTexture equirectangularTexture; 20 [SerializeField] private bool useLocalDirection; 21 [SerializeField] private Arrangement arrangement; 22 [SerializeField] private FieldOfView fieldOfView; 23 24 private int transformMatrixProperty; 25 private int vertexOffsetAndScaleProperty; 26 private int uvOffsetAndScaleProperty; 27 private RenderTexture cubemapLeft; 28 private RenderTexture cubemapRight; 29 private Material equirectangularMaterial; 30 31 private void Start() 32 { 33 this.transformMatrixProperty = Shader.PropertyToID("_TransformMatrix"); 34 this.vertexOffsetAndScaleProperty = Shader.PropertyToID("_VertexOffsetAndScale"); 35 this.uvOffsetAndScaleProperty = Shader.PropertyToID("_UvOffsetAndScale"); 36 this.cubemapLeft = this.stereoCubemapUpdater.CubemapLeft; 37 this.cubemapRight = this.stereoCubemapUpdater.CubemapRight; 38 this.equirectangularMaterial = new Material(Shader.Find("Hidden/CubeToEquirectangular")); 39 } 40 41 private void LateUpdate() 42 { 43 Vector4 leftVertexOffsetAndScale; 44 Vector4 rightVertexOffsetAndScale; 45 Vector4 uvOffsetAndScale; 46 switch (this.fieldOfView) 47 { 48 case FieldOfView.Full: 49 uvOffsetAndScale = new Vector4(0.0f, 0.0f, 1.0f, 1.0f); 50 break; 51 case FieldOfView.Half: 52 uvOffsetAndScale = new Vector4(0.25f, 0.0f, 0.5f, 1.0f); 53 break; 54 default: 55 throw new ArgumentOutOfRangeException(); 56 } 57 58 switch (this.arrangement) 59 { 60 case Arrangement.TopAndBottom: 61 leftVertexOffsetAndScale = new Vector4(0.0f, -0.5f, 1.0f, 0.5f); 62 rightVertexOffsetAndScale = new Vector4(0.0f, 0.5f, 1.0f, 0.5f); 63 break; 64 case Arrangement.SideBySide: 65 leftVertexOffsetAndScale = new Vector4(-0.5f, 0.0f, 0.5f, 1.0f); 66 rightVertexOffsetAndScale = new Vector4(0.5f, 0.0f, 0.5f, 1.0f); 67 break; 68 default: 69 throw new ArgumentOutOfRangeException(); 70 } 71 72 this.equirectangularMaterial.SetMatrix( 73 this.transformMatrixProperty, 74 this.useLocalDirection ? this.stereoCubemapUpdater.transform.localToWorldMatrix : Matrix4x4.identity); 75 this.equirectangularMaterial.SetVector(this.uvOffsetAndScaleProperty, uvOffsetAndScale); 76 this.equirectangularMaterial.SetVector(this.vertexOffsetAndScaleProperty, leftVertexOffsetAndScale); 77 Graphics.Blit(this.cubemapLeft, this.equirectangularTexture, this.equirectangularMaterial); 78 this.equirectangularMaterial.SetVector(this.vertexOffsetAndScaleProperty, rightVertexOffsetAndScale); 79 Graphics.Blit(this.cubemapRight, this.equirectangularTexture, this.equirectangularMaterial); 80 } 81}

ただでさえ高価なキューブマップレンダリングを2回もやりますので、描画負荷がけっこう大きいと思います。ご注意ください...

左目を上半分、右目を下半分に描画、全方位

図1

左目を左半分、右目を右半分に描画、前方半球のみ

図2

投稿2019/10/04 19:54

Bongo

総合スコア10807

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

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

masa_000

2019/10/05 22:53

前回に続きこんなに詳しく書いていただいて本当にありがとうございます。 C#のスクリプトの意味はなんとなくわかるのですが、ShaderLabはなぜ必要でなんの機能なのでしょうか?
Bongo

2019/10/05 23:54

まずCubeToEquirectangular自体については、ConvertToEquirectが多分内部でやっているであろう処理を代替することが目的となりますね。 キューブマップは内部的にはその名の通り立方体の左右上下前後の6枚のデータからなるテクスチャ形式です。つまりキューブマップが持っているデータをそのまま取りだしてもEquirectangularテクスチャとして使うことはできないはずので、正距円筒図法の形に変形してやる必要があるわけです。 ちなみに、Unityではキューブマップ用の画像をLatitude-Longitude Layout (Cylindrical)で読み込むことでキューブマップとして使用できるようになりますが、おそらくこちらは逆に正距円筒図法から6面のキューブに変換する処理が行われているんじゃないかと思います。 前回のご質問で提示しましたシェーダーコードからの変更点については、これは前回はキューブマップを変形した結果を単純にテクスチャ全面に描画すればよかったところを、今回はステレオ映像として使うためにテクスチャの半分だけに描画する必要が出てきたことによるものです。 _VertexOffsetAndScaleは頂点位置の移動・拡大縮小を表しており、これによって結果の書き込み先を移動・伸縮させることができます。左右の映像を縦に並べる場合は縦を半分に縮小してから垂直位置を調整、横に並べる場合は横を半分に縮小してから水平位置を調整...といった具合です。 _UvOffsetAndScaleはおまけ機能として追加した「前方半球のみ展開」のためのものです。あいにくVR分野は疎いのですが、全天球ではなく前方の半分だけを使う方式があるらしい...と知りまして試しにやってみました(ろくに調べず当てずっぽうですので間違っているかもしれません...)。こちらはUV座標を移動・伸縮する作用があり、元のキューブテクスチャから切り出す範囲を変えることができますので、半球のみの場合は半球領域だけを取り出すようになります。
masa_000

2019/10/06 15:12

ようやく理解できました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問