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

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

詳細はこちら
Unity

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

Q&A

解決済

1回答

6302閲覧

positionCountを設定する意味と、使う目的。

退会済みユーザー

退会済みユーザー

総合スコア0

Unity

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

0グッド

0クリップ

投稿2019/11/01 17:37

編集2019/11/02 09:38

前提・実現したいこと

こちらのサイトを参考に、
LineRendererを勉強中なのですが、positionCountを使う理由がわからない為、
ご教示お願い致します。

試したこと

下記コードで実装しました。

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class Sample : MonoBehaviour 6{ 7 // Start is called before the first frame update 8 void Start() 9 { 10 GameObject newLine = new GameObject ("Line"); 11 LineRenderer line = newLine.AddComponent<LineRenderer> (); 12 line.positionCount = 2; 13 line.startWidth = 0.2f; 14 line.endWidth =0.2f; 15 Vector3 startVec = new Vector3 (0.0f, 0.0f, 0.0f); 16 Vector3 endVec = new Vector3 (5.0f, 5.0f, 0.0f); 17 line.SetPosition (0, startVec); 18 line.SetPosition (1, endVec); 19 } 20 21 // Update is called once per frame 22 void Update() 23 { 24 25 } 26}

上記ソースに関して、
下記コードをコメントアウトするのとしないのとの両方でゲームを実行して試してみたのですが、
その違いがわかりませんでした。

C#

1line.positionCount = 2;

positionCountを設定する意味はあるのでしょうか?
どんな役割を果たしていますか?

また、今回のコードで仮に書く必要がなかった場合、positionCountはどんなときに有用ですか?
セットすることに意味はなく、頂点数を知る為の読み取りで使う機会が多いのでしょうか?
(頂点数という表現が適切かどうかわかりませんが)。

また、GetPositionsメソッドを使っても、同じように頂点数が取得できるのかと思い、
下記を試してみたのですが、outの使い方がわからなく、実装できませんでした。
GetPositionsメソッドを使って、positionCount(頂点数)を取得できる方法があれば、こちらも教えていただきたいです。

C#

1 Vector3[] positions; 2 line.GetPositions(out positions); 3 Debug.Log(positions.length);

ご教示お願い致します。

追記。

色がなぜか反映されませんでした。

C#

1 void Start() 2 { 3 GameObject newLine = new GameObject ("Line"); 4 LineRenderer line = newLine.AddComponent<LineRenderer> (); 5 line.positionCount = 3; 6 line.startWidth = 0.2f; 7 line.endWidth = 0.2f; 8 line.startColor = Color.red; 9 line.endColor = Color.blue; 10 Vector3 pos1 = new Vector3 (0.0f, 0.0f, 0.0f); 11 Vector3 pos2 = new Vector3 (5.0f, 5.0f, 0.0f); 12 Vector3 pos3 = new Vector3 (3.0f, 2.0f, 1.0f); 13 line.SetPositions(new Vector3[]{pos1, pos2, pos3}); 14 /* 15 Vector3[] positions = new Vector3[line.positionCount]; 16 line.GetPositions(positions); 17 foreach(Vector3 vertex in positions){ 18 Debug.Log(vertex); 19 } 20 */ 21 }

イメージ説明

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

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

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

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

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

guest

回答1

0

ベストアンサー

新規にLineRendererを作った際のデフォルトのpositionCountは2のようなので、今回の場合は違いが現れなかったのだと思います。

positionCountは頂点数を調べるために読み取るだけでなく、どうやら頂点数を変えたい場合は事前に新しい頂点数をセットしておく必要がありそうでした。
下記のようにpositionCountがデフォルトの2の状態でむりやり3点セットしようとする、あるいは3点取得しようとすると...

C#

1var lineRenderer = this.gameObject.AddComponent<LineRenderer>(); 2for (var i = 0; i < 3; i++) 3{ 4 var p = Random.insideUnitSphere; 5 Debug.Log($"SetPosition({i}, {p})"); 6 lineRenderer.SetPosition(i, p); 7} 8for (var i = 0; i < 3; i++) 9{ 10 Debug.Log($"GetPosition({i}) : {lineRenderer.GetPosition(i)}"); 11}

下図のようなエラーメッセージが表示されました。

図1

ただし、範囲外にアクセスしようとしても例外が発生して実行が中断されることはなく、単に無視されるような動きをしていました。

GetPositionsについてですが、リファレンスでは引数のpositionsoutが付いていますが、実際には不要なようです(おそらくリファレンスの不備かと思います)。

使い方としては、あらかじめ頂点座標を受け取るのに十分なサイズの配列を用意しておいて、それを引数にGetPositionsを実行すればよさそうでした。
データが何個詰められたかはGetPositions実行時の返り値を見ればいいかと思います。引数の配列が新しい配列に差し替えられるわけではないため、配列のLengthを調べても最初に配列を生成したときの長さと同じになってしまうでしょう。

また、こちらも範囲外の部分はエラーメッセージだけ出して無視されるようでした。たとえば受け手側の配列の長さが足りない場合...

C#

1var lineRenderer = this.gameObject.AddComponent<LineRenderer>(); 2Debug.Log($"lineRenderer.positionCount:{lineRenderer.positionCount}"); 3 4// むりやり3頂点セットしようとすると、最初の2頂点だけがセットされる(エラーメッセージは出ない) 5lineRenderer.SetPositions(new[] {new Vector3(1, 2, 3), new Vector3(4, 5, 6), new Vector3(7, 8, 9)}); 6 7// 1要素しかない配列で受け取ろうとすると、最初の1頂点だけが取得される 8var positions = new Vector3[1]; 9var count = lineRenderer.GetPositions(positions); 10Debug.Log($"count:{count}"); 11for (var i = 0; i < positions.Length; i++) 12{ 13 Debug.Log($"positions[{i}]:{positions[i]}"); 14}

下図のようにエラーメッセージが表示され、GetPositionsの返り値は1となっています。

図2

ラインマテリアルの例

ShaderLab

1Shader "Unlit/UnlitLine" 2{ 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 } 7 SubShader 8 { 9 Tags { "RenderType"="Opaque" } 10 11 Pass 12 { 13 CGPROGRAM 14 #pragma vertex vert 15 #pragma fragment frag 16 #pragma multi_compile_fog 17 18 #include "UnityCG.cginc" 19 20 struct appdata 21 { 22 float4 vertex : POSITION; 23 fixed4 color : COLOR; // 入力データとして頂点色を追加する 24 float2 uv : TEXCOORD0; 25 }; 26 27 struct v2f 28 { 29 float2 uv : TEXCOORD0; 30 fixed4 color : COLOR; // v2fにも色データを追加する 31 UNITY_FOG_COORDS(1) 32 float4 vertex : SV_POSITION; 33 }; 34 35 sampler2D _MainTex; 36 float4 _MainTex_ST; 37 38 v2f vert (appdata v) 39 { 40 v2f o; 41 o.vertex = UnityObjectToClipPos(v.vertex); 42 o.uv = TRANSFORM_TEX(v.uv, _MainTex); 43 o.color = v.color; // 頂点色をセットする 44 UNITY_TRANSFER_FOG(o,o.vertex); 45 return o; 46 } 47 48 fixed4 frag (v2f i) : SV_Target 49 { 50 fixed4 col = tex2D(_MainTex, i.uv) * i.color; // 受け渡された色を乗算する 51 UNITY_APPLY_FOG(i.fogCoord, col); 52 return col; 53 } 54 ENDCG 55 } 56 } 57 Fallback "Diffuse" // Diffuseに影落としを代行させる 58}

投稿2019/11/01 20:32

編集2019/11/03 19:11
Bongo

総合スコア10811

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

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

退会済みユーザー

退会済みユーザー

2019/11/02 09:40

ご回答ありがとうございます。 なるほど、デフォルトの頂点数が2に設定されていたのですね。 2頂点以外の頂点数の場合は、positionCountで設定する必要があるということですね。 outは書かなくてよいのですね。 GetPositionsの引数の配列の長さは変化しないのですね。 試したところ、positionCountよりも多い要素数で引数の配列を確保した場合、 余った要素には(0,0,0)の頂点が格納されることが確認できました。 使い方や意図にもよると思いますが、 普通はGetPositionsの引数に渡す配列の要素数は、positionCountで確保するのが望ましいということでしょうか? (最初の質問で試そうとしていた、GetPositionsに渡した配列から要素数を調べるという使い方はしなさそうで、 むしろ逆に予めpositionCountで、頂点配列の要素数を確保しておいて、GetPositionsに渡すのが普通なのかと思いました)。 Vector3 pos1 = new Vector3 (0.0f, 0.0f, 0.0f); Vector3 pos2 = new Vector3 (5.0f, 5.0f, 0.0f); Vector3 pos3 = new Vector3 (3.0f, 2.0f, 1.0f); line.SetPositions(new Vector3[]{pos1, pos2, pos3}); Vector3[] positions = new Vector3[line.positionCount]; line.GetPositions(positions); foreach(Vector3 vertex in positions){ Debug.Log(vertex); } あと、質問が増えてしまい、すみません。 ちょっとカラーをいじってみたのですが、反映されていなく、エラーも表示されなくて、 可能であれば原因を教えていただけませんか? 詳細は質問の追記に書きました。
Bongo

2019/11/02 17:53

そうですね。GetPositionsの受け手配列のサイズをどうするべきかについては、基本的にはおっしゃるとおりpositionCountと同数でいいと思います。 positionCountと異なるサイズにするべき状況としては、頂点数を動的にころころ変えたい場合とか、頂点数の異なる複数本のラインを順次処理していく場合とかでしょうね。そんな場合にいちいちpositionCountぴったりのサイズの配列を毎回確保するのは無駄でしょうから、あらかじめ予想される最大サイズの配列を最初に確保しておく方式にすれば(もし当初の予測より大きい数が必要になったら、そのときに新しいサイズの配列を確保しなおすことになるでしょう)メモリの確保・解放処理を最小限に抑えることができ効率的かと思います。 こういった「余分なメモリ領域を確保しておいて、実際に使うのは配列の先頭から実際の要素数個だけ」という戦略はわりとよく見かけるように思います。たとえばList<T>(https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.generic.list-1 )は追加・削除によって要素数が増減しますが、内部的には似たような方式を使用していたはずです。リファレンスによると、Count(https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.generic.list-1.count )が実際に格納されている要素数、Capacity(https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.generic.list-1.capacity )が内部的に確保している領域の容量を示すようです。 色を反映させられなかった件についてですが、メニューの「GameObject」→「Effects」→「Line」で作成されるラインオブジェクトの場合はDefault-Lineマテリアルがセットされているのに対し、スクリプトからLineRendererをアタッチしただけの状態だとマテリアルがセットされていないことによるんじゃないでしょうか。 Default-Lineマテリアルをスクリプトから取得する方法があるのかどうかはよくわかりませんでした。メニューからラインを作成した場合の挙動については、おそらくhttps://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/Commands/GOCreationCommands.cs の最後の方にある「CreateLine」が実行されているんじゃないかと思いますが、ここだとマテリアルを「line.material = Material.GetDefaultLineMaterial();」という風にセットしています。ですがGetDefaultLineMaterialはアクセシビリティがinternalなので普通に使用することはできないでしょう。むりやり... lineRenderer.material = typeof(Material).GetMethod("GetDefaultLineMaterial", BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, null) as Material; とでもしてやれば取得できなくはなさそうでしたが、順当な方法としては... [SerializeField] private Material lineMaterial; のようにフィールドを追加してやり、これにインスペクター上であらかじめDefault-Lineをセットしておいて... lineRenderer.material = this.lineMaterial; という風にしてやるのがいいんじゃないかと思います。
退会済みユーザー

退会済みユーザー

2019/11/03 11:07 編集

ご回答ありがとうございます。 GetPositionsでpositionCountと同数以外の要素数を確保する事例のご教示ありがとうございます。 下記コードで色が反映されることを確認できました。 [SerializeField] Material lineMaterial; void Start() { GameObject newLine = new GameObject ("Line"); LineRenderer line = newLine.AddComponent<LineRenderer> (); line.positionCount = 3; line.startWidth = 0.2f; line.endWidth = 0.2f; line.material = lineMaterial; //line.startColor = Color.red; //line.endColor = Color.green; Vector3 pos1 = new Vector3 (0.0f, 0.0f, 0.0f); Vector3 pos2 = new Vector3 (5.0f, 5.0f, 0.0f); Vector3 pos3 = new Vector3 (3.0f, 2.0f, 1.0f); line.SetPositions(new Vector3[]{pos1, pos2, pos3}); } また、今までラインの影が生成されてなくて悩んでいたのですが、 今回のマテリアルで色を与えるやり方を実装したら、影も生成されるようになりました。 ちなみに、こちらのサイトのように、 https://qiita.com/keito_takaishi/items/f619cf3cb8d0013237ee SetColorsは、今はstartColorやendColorかと思いますが、 今回の動的にGameObjectを生成して、AddComponent<LineRenderer>するコードで startColorとendColorで別々の色を指定する方法って存在しますか? 上記コードにおいてコメントを外してみたのですが、色が反映されませんでした。 また、「GameObject」→「Effects」→「Line」で予め作成しておいた LineオブジェクトのLineRendererコンポーネントをいじるコードでは、 startColorとendColorの色設定が効くことは確認できました。
Bongo

2019/11/03 19:12

私の環境では(2019.2.11f1、Windows版)ではどうも再現せず、ご提示いただいたコードのコメント部分を有効にしてみると赤から緑のグラデーションで塗られました... lineMaterialにセットしたマテリアルは「Default-Line」になっているでしょうかね? 影も生成されるようになったとのことですが、Default-Lineは影を落とさないタイプのマテリアルかと思います。 もしグラデーション付きかつ影落としありにする場合、自前でマテリアルを作る必要があるかもしれません。 シェーダーの例を追記してみましたがどうでしょうか?
退会済みユーザー

退会済みユーザー

2019/11/04 14:52 編集

ご回答ありがとうございます。 Default-Lineを理解していなく、新規作成のマテリアルでセットしてしまっていました。 >これにインスペクター上であらかじめDefault-Lineをセットしておいて... このDefault-LineをUnityエディタのAssetsから取得する方法なのですが、 こちらのサイトを参考にしたのですが、 http://kan-kikuchi.hatenablog.com/entry/GetBuiltinResource C:\Program Files\Unity\Hub\Editor\2019.2.1f1\Editor\Data\Resources\unity_builtin_extra をコピーして、.assetを付けて、UnityエディタのProjectパネルで取り込むという方法で合っていますか? 一応できたのですが、もしかしたら、もっと手軽な方法ってあったりしますか? また、上記参考サイトにより、スクリプトで取得することができました。 #if UNITY_EDITOR Material lineDefaultMaterial = UnityEditor.AssetDatabase.GetBuiltinExtraResource<Material>("Default-Line.mat"); #else Material lineDefaultMaterial = Resources.GetBuiltinResource<Material>("Default-Line.mat"); #endif なるほど、グラデーション付きかつ影落としありにする場合、 シェーダーを自作しなければならないのですね (シェーダーは全然勉強していないので後々勉強していきたいと思っています)。 シェーダーのご提示ありがとうございます。 こちら試させていただき、グラデーションも影落としもありのラインが生成できたことを確認致しました。ありがとうございます。 追記: GetBuiltinResourceを知りたいと思い、公式のスクリプトリファレンスで検索してみたのですが、何故か引っ掛かりませんでした。
Bongo

2019/11/04 15:09 編集

おお、GetBuiltinResourceが使えましたか!私の環境だとなぜかうまくいかず早々にあきらめてしまったのですが、それで取得できましたら問題ないかと思います。 リファレンスに載っていない理由はいまいちわかりませんね...何かの理由でpublicにしてあるけれど、Unityユーザー側から使うことは想定していないということなのでしょうか? 追記: https://docs.unity3d.com/ScriptReference/ParticleSystemRenderer.SetMeshes.html のサンプルコード内で堂々とGetBuiltinResourceを使っているようでした。使ってはいけないというわけでもないんでしょうかね?お役に立てずすみません... 「Default-Lineをセットしておいて」と申し上げたのは、インスペクター上のマテリアル欄の右端にある「◎」(丸の中に点)ボタンを押すと出てくるウィンドウで選択・セットすることを意図しておりました。わかりづらくてすみません...
退会済みユーザー

退会済みユーザー

2019/11/05 15:28

ご回答ありがとうございます。 GetBuiltinResourceそのものはリファレンスになくても、ParticleSystemRenderer.SetMeshesのサンプルコードでは出てくるのですね、謎ですね。 私の環境は、Unity 2019.2.1f1でした。もしかしたら、バージョンによってはまだGetBuiltinResourceが安定していないのかなと思いました。 「◎」ボタンで、デフォルトリソースのアセットが取得できたのですね。 ご教示ありがとうございます。 いろいろな質問をご教示くださり、ありがとうございました。 とても勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問