🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Unity

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

Q&A

解決済

1回答

2732閲覧

Unity内のprojectorでWebカム映像を映したい

shin067

総合スコア5

Unity

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

0グッド

0クリップ

投稿2019/10/31 12:36

編集2019/11/04 07:23

前提・実現したいこと

PCにつないだWebカメラをUnity内のprojectorで投影したいと思っています.
現在,以下のサイトを参考に,Webカムで取得した映像のキャプチャをオブジェクトに貼り付けるところまでは実装できました.

また,以下のサイトから,用意した画像をprojectorで投影することもできています.
http://haraken.hatenablog.com/entry/2016/11/30/RenderTexture%E3%81%A8%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%BF%E3%83%BC%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

しかし,projectorでWebカム画像を投影することができずに悩んでいます.

上のサイトのスクリプトを少し変え,projectorにアタッチしてみたのですがうまくいきません.

この方法ではなにも投影されないのですが,考え方が間違っているのでしょうか?
また,別の手段でも構いませんので,実装できるような方法があれば教えてください.
初歩的な質問で申し訳ないですが,よろしくお願いします.

using System.Collections; using System.Collections.Generic; using UnityEngine; public class WebCam : MonoBehaviour { public int Width = 1920; public int Height = 1080; public int FPS = 30; public WebCamTexture webcamTexture; public Color32[] color32; void Start() { WebCamDevice[] devices = WebCamTexture.devices; webcamTexture = new WebCamTexture(devices[0].name, Width, Height, FPS); GetComponent<Projector>().material.mainTexture = webcamTexture; webcamTexture.Play(); } void Update() { if (Input.GetKeyDown(KeyCode.Space) || Input.touchCount > 0) { color32 = webcamTexture.GetPixels32(); Texture2D texture = new Texture2D(webcamTexture.width, webcamTexture.height); this.GetComponent<Projector>().material.mainTexture = texture; texture.SetPixels32(color32); texture.Apply(); } } }

補足情報(FW/ツールのバージョンなど)

Unity2018.3.4f1

追記(実行後の画面)

![イメージ説明]

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

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

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

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

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

guest

回答1

0

ベストアンサー

マテリアルの「Cookie」テクスチャと対応するプロパティ名は_MainTexではなく_ShadowTexですので、mainTextureではセットできなかったものと思われます。
代わりにSetTextureを使ってみてはいかがでしょうか。

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class WebCam : MonoBehaviour 6{ 7 public int Width = 1920; 8 public int Height = 1080; 9 public int FPS = 30; 10 public WebCamTexture webcamTexture; 11 public Color32[] color32; 12 13 void Start() 14 { 15 WebCamDevice[] devices = WebCamTexture.devices; 16 webcamTexture = new WebCamTexture(devices[0].name, Width, Height, FPS); 17 GetComponent<Projector>().material.SetTexture("_ShadowTex", webcamTexture); 18 webcamTexture.Play(); 19 } 20 21 void Update() 22 { 23 if (Input.GetKeyDown(KeyCode.Space) || Input.touchCount > 0) 24 { 25 color32 = webcamTexture.GetPixels32(); 26 Texture2D texture = new Texture2D(webcamTexture.width, webcamTexture.height); 27 this.GetComponent<Projector>().material.SetTexture("_ShadowTex", texture); 28 texture.SetPixels32(color32); 29 30 texture.Apply(); 31 } 32 } 33}

追記
外周部が引き延ばされる現象を防止する措置を加えてみました。

ShaderLab

1Shader "Projector/LightClipped" { 2 Properties { 3 _Color ("Main Color", Color) = (1,1,1,1) 4 _ShadowTex ("Cookie", 2D) = "" {} 5 _FalloffTex ("FallOff", 2D) = "" {} 6 } 7 8 Subshader { 9 Tags {"Queue"="Transparent"} 10 Pass { 11 ZWrite Off 12 ColorMask RGB 13 Blend DstColor One 14 Offset -1, -1 15 16 CGPROGRAM 17 #pragma vertex vert 18 #pragma fragment frag 19 #pragma multi_compile_fog 20 #include "UnityCG.cginc" 21 22 struct v2f { 23 float4 uvShadow : TEXCOORD0; 24 float4 uvFalloff : TEXCOORD1; 25 UNITY_FOG_COORDS(2) 26 float4 pos : SV_POSITION; 27 }; 28 29 float4x4 unity_Projector; 30 float4x4 unity_ProjectorClip; 31 32 v2f vert (float4 vertex : POSITION) 33 { 34 v2f o; 35 o.pos = UnityObjectToClipPos(vertex); 36 o.uvShadow = mul (unity_Projector, vertex); 37 o.uvFalloff = mul (unity_ProjectorClip, vertex); 38 UNITY_TRANSFER_FOG(o,o.pos); 39 return o; 40 } 41 42 fixed4 _Color; 43 sampler2D _ShadowTex; 44 sampler2D _FalloffTex; 45 46 fixed4 frag (v2f i) : SV_Target 47 { 48 // まずuvShadowをプロジェクション座標に直し... 49 float4 projCoord = UNITY_PROJ_COORD(i.uvShadow); 50 51 // 元のコードでは同次座標形式のままtex2Dprojでテクスチャサンプリングしているが、 52 // 代わりに事前にwで割ってしまい... 53 projCoord /= projCoord.w; 54 55 // 得られたUV座標を0~1にクランプ、さらにクランプ前の座標の絶対値を引くと 56 // 結果は座標が0~1の範囲内であれば0、範囲を外れていればマイナスになるはずなので 57 // これをclipに渡せば、値がマイナスのフラグメントは破棄される 58 clip(clamp(projCoord.xy, 0.0, 1.0) - abs(projCoord.xy)); 59 60 // _ShadowTexからテクスチャサンプリングを行う 61 // projCoordはw除算済みなので、tex2Dprojの代わりにtex2Dを使う 62 fixed4 texS = tex2D (_ShadowTex, projCoord.xy); 63 64 texS.rgb *= _Color.rgb; 65 texS.a = 1.0-texS.a; 66 67 fixed4 texF = tex2Dproj (_FalloffTex, UNITY_PROJ_COORD(i.uvFalloff)); 68 fixed4 res = texS * texF.a; 69 70 UNITY_APPLY_FOG_COLOR(i.fogCoord, res, fixed4(0,0,0,0)); 71 return res; 72 } 73 ENDCG 74 } 75 } 76}

もし色合成方法を通常のUnlitシェーダー風にする場合、下記のようにしてみてはどうでしょうか。

ShaderLab

1Shader "Projector/UnlitClipped" { 2 Properties { 3 _Color ("Main Color", Color) = (1,1,1,1) 4 _ShadowTex ("Cookie", 2D) = "white" {} 5 _FalloffTex ("FallOff", 2D) = "white" {} 6 } 7 8 Subshader { 9 Tags {"Queue"="Transparent"} 10 Pass { 11 ZWrite Off 12 13 // 合成方法を一般的なアルファブレンディングに変更 14 // カラーマスクも指定せず、アルファチャンネルへも通常通り書き込むようにする 15 Blend SrcAlpha OneMinusSrcAlpha 16 17 Offset -1, -1 18 19 CGPROGRAM 20 #pragma vertex vert 21 #pragma fragment frag 22 #pragma multi_compile_fog 23 #include "UnityCG.cginc" 24 25 struct v2f { 26 float4 uvShadow : TEXCOORD0; 27 float4 uvFalloff : TEXCOORD1; 28 UNITY_FOG_COORDS(2) 29 float4 pos : SV_POSITION; 30 }; 31 32 float4x4 unity_Projector; 33 float4x4 unity_ProjectorClip; 34 35 v2f vert (float4 vertex : POSITION) 36 { 37 v2f o; 38 o.pos = UnityObjectToClipPos(vertex); 39 o.uvShadow = mul (unity_Projector, vertex); 40 o.uvFalloff = mul (unity_ProjectorClip, vertex); 41 UNITY_TRANSFER_FOG(o,o.pos); 42 return o; 43 } 44 45 fixed4 _Color; 46 sampler2D _ShadowTex; 47 sampler2D _FalloffTex; 48 49 fixed4 frag (v2f i) : SV_Target 50 { 51 // _ShadowTexのサンプリングはLightClippedと同様に行い... 52 float4 projCoord = UNITY_PROJ_COORD(i.uvShadow); 53 projCoord /= projCoord.w; 54 clip(clamp(projCoord.xy, 0.0, 1.0) - abs(projCoord.xy)); 55 fixed4 texS = tex2D (_ShadowTex, projCoord.xy); 56 57 // 以降の色合成は通常のUnlitシェーダーと同様に 58 // 普通のアルファブレンディングを前提としたスタイルに変える 59 texS *= _Color; 60 fixed4 texF = tex2Dproj (_FalloffTex, UNITY_PROJ_COORD(i.uvFalloff)); 61 fixed4 res = texS * fixed4(1.0, 1.0, 1.0, texF.a); 62 UNITY_APPLY_FOG(i.fogCoord, res); 63 return res; 64 } 65 ENDCG 66 } 67 } 68}

投稿2019/10/31 20:41

編集2019/11/08 19:45
Bongo

総合スコア10811

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

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

shin067

2019/11/04 07:25

回答ありがとうございます. ご指摘の通り,スクリプトを修正してみたところ,なにも映らない状態からなにかしらの映像が映るようになりました. webカムに手をかざすと,黒くなるのでwebカム映像だとは思うのですが,何が写っているのかわからない状況です. 解像度やprojectorの投影角等の問題でしょうか? ご存知でしたら教えていただけると幸いです.
Bongo

2019/11/04 09:03

おそらく、ご提示のスクリーンショットに映っている十字状の模様の交点あたりにごちゃごちゃっと映っているのがWebカメラの映像じゃないかと思います。周囲の部分は映像の外周が上下左右に引き延ばされてできたものじゃないでしょうか。 Standard Assetsに収録されているGridProjectorはOrthographicがオンになっており、そのOrthographic Sizeは0.25と小さく設定されているようです。 ですので、シーン上に配置したGridProjectorをヒエラルキー上で右クリックして「Unpack Prefab Completely」でプレハブとのリンクを切り(Standard Assetsのプレハブそのものを編集してしまうのはいまいちかな...と思っての処置です)、その後インスペクター上のOrthographic Sizeを映像投影先に見合ったサイズまで大きくしてみてはいかがでしょう。
shin067

2019/11/08 17:44

返事が遅くなって申し訳ありません. Orthographic Sizeの値を大きくしたら思っているように投影できました. ありがとうございます. 重ね重ねで申し訳ないのですが,映像が十字状に伸びてしまわないようにすることはできないのでしょうか?
Bongo

2019/11/08 19:45

おそらくStandard Assets付属のシェーダーの代わりに改造版シェーダーを作って、マテリアルのシェーダーをそれに差し替える必要があるかと思います。 範囲外のピクセルを破棄するようにしたものを追記しましたが、あんな感じでいかがでしょうか? また、おまけとして色の合成方法を普通のUnlitシェーダー風に変更したバージョンも作ってみました。 元々のシェーダーは現実のプロジェクター装置で映像を映したように加算合成されますが、これだと明るい面に投影すると映像も明るくなってしまうでしょう(映像をはっきり映すには、現実同様シーンの照明を消して暗くして上映することになるでしょう)。 単に投影先の形に合わせてテクスチャをひずめて映せればいいという場合には、こちらのような一般的な合成方法の方が適しているんじゃないかと思います。
shin067

2019/11/09 06:31

シェーダーまで作っていただきありがとうございます. こちらを試したところ,引き延ばされずに綺麗に表示されました. また,色みもかなり綺麗で作りたいものが作れそうです. 初歩的な質問から親切にお答えいただき,本当にありがとうございました.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問