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

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

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

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

Q&A

解決済

1回答

2164閲覧

TransformPointでUI Textを設定すると文字が薄くなる。

退会済みユーザー

退会済みユーザー

総合スコア0

Unity

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

0グッド

0クリップ

投稿2020/02/29 18:50

編集2020/03/04 17:13

前提・実現したいこと

以前、このような質問をしたことがあり、
UIをスクリプトで普遍的に画面中央に配置させる方法として、
下記がScreen Space – CameraとScreen Space – Overlayのどちらでも有効で、1番汎用的な方法と認識しているのですが
(間違っていたらご指摘お願いします)、

C#

1this.transform.position = this.transform.root.TransformPoint(Vector2.zero);

その際、Screen Space – Overlayの下記コードでセットした場合と見比べたら、

C#

1this.transform.position = new Vector2(Screen.width/2, Screen.height/2);

TransformPointで設定したUI Textがぼやけてしまう、もしくは色が薄く表示されてしまったのですが、
この不具合の原因、対処法を教えていただきたいです。
ご教示よろしくお願いいたします。

試したこと

Screen Space – Overlayでそれぞれ設定。

・Screenで設定した場合。

C#

1 this.transform.position = new Vector2(Screen.width/2, Screen.height/2);

「Sample」の文字が濃い。
イメージ説明

・TransformPointで設定した場合。

C#

1 this.transform.position = this.transform.root.TransformPoint(Vector2.zero);

「Sample」の文字が薄い、もしくは、ぼやけている。
イメージ説明

両者の違いは上記コードだけです。他の設定は同じままです。

文字が薄れてしまったので、
TransformPointで設定するのは何か非推奨なことがありますか?

追記、Screen Space - Cameraでの現状

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class UISample : MonoBehaviour 6{ 7 void Start() 8 { 9 Vector2 center = this.transform.root.TransformPoint(Vector2.zero); 10 // Debug.Log(center); 11 // center.x = Mathf.Floor(center.x); 12 // center.y = Mathf.Floor(center.y); 13 // Debug.Log(center); 14 this.transform.position = center; 15 } 16}

全体
イメージ説明

Canvas
イメージ説明

Text (インスペクタ前半)
イメージ説明

Text (インスペクタ後半)
イメージ説明

実行時テキストのインスペクタ
イメージ説明

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

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

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

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

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

guest

回答1

0

ベストアンサー

座標がきっちり整数になっているかどうかによる微妙な違いなんじゃないでしょうか?
2つの映像を重ねて見てみたところ、ぼやけている方は少しだけ右上にずれているようでした。

ゲームビューが「Free Aspect」になっていますが、もしたまたま幅・高さが奇数だったとすると、後者の方法では座標の値に端数が出ると想像されます。
ですが前者の方法だとScreen.widthScreen.heightint型ですのでScreen.width/2Screen.height/2の結果も整数となるはずです。

C#

1var center = this.transform.root.TransformPoint(Vector2.zero); 2Debug.Log(center); // ここで出力される座標の成分に「.5」が付いていないでしょうか? 3center.x = Mathf.Floor(center.x); 4center.y = Mathf.Floor(center.y); 5Debug.Log(center); // ぴったり整数の位置にしてみるとどうでしょう。 6this.transform.position = center;

ルートキャンバスの「Pixel Perfect」をオンにすれば端数のある座標でもくっきり表示してくれるかもしれません。
これに頼らず位置を調整するなら、たとえば下記のようなやり方はどうでしょうか?

C#

1// まず自分が所属するルートキャンバスの矩形を取得し... 2var rootCanvasRectTransform = this.GetComponentInParent<Canvas>().rootCanvas.transform as RectTransform; 3var canvasRect = rootCanvasRectTransform.rect; 4var canvasSize = canvasRect.size; 5 6// 左下を起点とした、整数に丸めた中心座標を求め... 7var quantizedCenter = canvasRect.min + new Vector2(Mathf.Round(canvasSize.x * 0.5f), Mathf.Round(canvasSize.y * 0.5f)); 8Debug.Log(quantizedCenter.ToString("F6")); 9 10// それを自分の親の座標系に変換し、localPositionにセットする 11var parentTransform = this.transform.parent; 12var canvasToParentMatrix = (parentTransform != null ? parentTransform.worldToLocalMatrix : Matrix4x4.identity) * rootCanvasRectTransform.localToWorldMatrix; 13var localQuantizedCenter = canvasToParentMatrix.MultiplyPoint3x4(quantizedCenter); 14Debug.Log(localQuantizedCenter.ToString("F6")); 15this.transform.localPosition = localQuantizedCenter;

投稿2020/02/29 21:50

編集2020/03/02 00:23
Bongo

総合スコア10811

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

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

退会済みユーザー

退会済みユーザー

2020/03/01 18:33 編集

ご回答ありがとうございます。 なるほど、UIの位置が端数になると、そのUIはぼやけてしまうのですね。 また、int型は割って商に端数が含まれる場合、その端数は切り捨てられて整数になるんですね。 下記で確認しました。 int i = 3; Debug.Log(i/2); //1 ご提示いただいた前者のコードで試したところ、 Debug.Log(center); 座標の成分に「.5」が付いていることが確認できました。 そして、Mathf.Floorを行ったところ、 UIのぼやけが解消されたことを確認できました。 また、端数のある状態でも、Pixel Perfectをオンにしたところ、 やはり、UIのぼやけが解消されたことを確認できました。 後者のコードはすみません、わからない点が多く理解はしていないのですが、 試したところ、やはりぼやけずに中央に配置されることが確認できました。 すみません、下記質問させていただけたらと思います。 質問1。 前者のMathf.Floor、Pixel Perfectをオン、後者のlocalQuantizedCenterと、 3つの解決方法を教えていただいたのですが、 Pixel Perfectの方法を避ける場合、後者の方法をお奨めいただいたのですが、 前者のMathf.Floorの方法でも、Pixel Perfectを使わず、 ぼやけるのを防いで中央配置できるように思えたのですが、 前者のMathf.Floorの方法は何か問題点がありますか? 質問2。 ご提示のPixel Perfectのマニュアルを拝見した所、 Screen Spaceに限って、ぼやけ解消として使えるみたいですが、 UIを動かす場合、スムーズに動かないという注意点が書かれていたみたいで、 下記コードを試してみたのですが、 void Update() { this.transform.Translate(Vector3.up * 10f *Time .deltaTime, Space.World); } 確かにカクついた動きになり、 これはおそらく、UIの位置が端数にきた場合、Pixel Perfectによって、 端数じゃない位置に矯正されることが原因かと思うのですが、 ここで、Pixel Perfectをオフにして動かしてみた所、 今度は動きが滑らかな代わりに、例のぼやけ現象が起きてしまい、 これはもう、カクつくのを妥協するか、ぼやけるのを妥協するか、 という選択になってしまいますか? それとも、UIをぼやけさせずに滑らかにを動かすことは可能ですか? (今回の質問が解決したら、次はUIを動かすことを考えようとしていたので、 マニュアルの注意点がちょうど関連していたので、質問させていただきました、すみません。)
Bongo

2020/03/01 22:26 編集

質問1について 「this.transform.root」は自分の所属する階層構造のルートということですので、おそらくルートキャンバスを指すでしょう(後述しますが、階層構造によってはルートキャンバスではないかもしれません...)。 ですので「this.transform.root.TransformPoint(Vector2.zero)」が示すのはルートキャンバスのワールド座標です。これは「this.transform.root.position」と同じはずで、ルートオブジェクトのインスペクターに表示されるPos X、Pos Y、Pos Zと同じ値になるかと思います。 つまりMathf.Floorの方法はこのPos X、Pos Yを整数にして、Textのワールド座標をその位置にする...ということになります。キャンバスの描画モードが「Screen Space - Overlay」ならおそらくこれでうまくいくんじゃないかと思いますが、「Screen Space - Camera」だとしたら意図通りにいかない可能性があるでしょう。 キャンバスを「Screen Space - Camera」にしてカメラを適当に移動・回転させ、さらに問題を際立たせるためにキャンバスの「Plane Distance」をデフォルトの100よりもかなり小さく...たとえば1にしてみるとどうでしょうか。キャンバスはカメラ前方1mの位置に追従し、インスペクター上のPos X、Pos Y、Pos Zは単なる???.5のような半整数ではなく複雑な小数が表示されているかと思います。 これを整数に変えてTextオブジェクトのpositionにセットしてしまうと、最終的な画面上の座標がピクセルぴったりになるとは限らないばかりか、中心から大きく外れた見当違いの位置に移動してしまう可能性が高いでしょう。 先ほど「階層構造によってはルートキャンバスではないかも」と申し上げましたが、回答中のコードで「this.GetComponentInParent<Canvas>().rootCanvas.transform as RectTransform;」などと回りくどい書き方をしたのはキャンバスがヒエラルキー最上位にないケースを考慮してのことです。 もし最初のヒエラルキーが Canvas -Text だったとして、そこから空のゲームオブジェクトをヒエラルキー最上位に作成してCanvasを中に入れ GameObject -Canvas --Text という階層構造に変更した場合、「this.transform.root」で取得されるのはCanvasではなくGameObjectになってしまうでしょう。 まあ普通はCanvasをヒエラルキー最上位に置くだろうとは思いましたが、念のためそのような形でもCanvasを探し出せるようにしてみました。 質問2について これはおっしゃるように妥協して、なめらかなモーションとくっきり描画のどちらをとるか選ぶ必要がありそうですね... なめらかなモーションには1ピクセル以下の微妙な移動も表現する必要がありますが、Pixel Perfectがオンだと動きがピクセル単位に矯正されてしまいますから、短い距離をゆっくり動くときには特にカクつきが目立つでしょう。 なるべく2つを両立させる案としては「Pixel Perfectはオフにして、モーションの開始点や終了点だけは整数ぴったりの座標を使う」とかですかね。小数の座標を許しますのでなめらかな移動を表現でき、なおかつ最終的に静止する座標が整数ならモーションを終えた後はくっきり描画されるんじゃないでしょうか。
退会済みユーザー

退会済みユーザー

2020/03/02 15:52

ご回答ありがとうございます。 質問1について。 this.transform.root.TransformPoint(Vector2.zero) のコードで、 Screen Space - Cameraに設定しただけで、既にUI Textが中心からずれる現象となりました。 (これはこれで不思議です。) また、Screen Space - Overlayの場合でも、上記のコードならば、 ルートオブジェクトをCanvasでなく、 空のゲームオブジェクトにしてその空のゲームオブジェクトを任意の位置に設定した場合、 UI Textが中心に配置されないことも確認できました。 ちなみにこの状態でも、 this.transform.position = new Vector2(Screen.width/2, Screen.height/2); のコードならば、UI Textが中心に配置されることも確認できました。 ...ということは、 var center = this.transform.root.TransformPoint(Vector2.zero); のコードは、Mathf.Floorを使う以前に、 Screen Space - Overlayでも、Screen Space - Cameraでも、 必ず中心に配置されることが保証されるわけではないので、使い所が無さそうですね。 (Screen Space - Overlayの場合だったら、Screen.width/2で書くコードの方が簡潔に書けて なおかつ、いかなる場合でも中心にぼやけずに配置されるみたいなので。) そうしますと、 UIを中心に配置させる汎用的なコードは、コードの短さとかも考慮して、 Screen Space - Overlayの場合は、Screen.width/2のコード、 Screen Space - Cameraの場合は、canvasToParentMatrix.MultiplyPoint3x4(quantizedCenter) のコードということでしょうか? 質問2について。 なるほど、開始点や終了点だけは整数ぴったりの座標を使うことで理想に近づきますね。
Bongo

2020/03/03 21:54

返信が遅れてすみません。「Screen Space - Cameraに設定しただけで中心からずれてしまう」とおっしゃるのは、Mathf.floorで整数化する部分がなくてもずれてしまうということでしょうか? 整数化した場合にずれるのは想定通りなのですが、そうでなくてもずれるのでしたらまだ何か見落としている要素があったのかもしれません。今回のご質問のぼやけ現象が問題にならないケースなら「this.transform.position = this.transform.root.TransformPoint(Vector2.zero);」のやり方はシンプルで名案だと思ったのですが、正常にいかない場合があるなら、おっしゃるとおりこれ以外の方法を使うことになるでしょうね... 私の試したかぎりでは整数化しなくてもずれてしまう現象は再現させられなかったのですが、もしこの現象が気になるようでしたら、各オブジェクトの配置や階層構造、インスペクター上の設定などを詳しくお伝えいただければ、可能であれば原因を調べてみようと思います。
退会済みユーザー

退会済みユーザー

2020/03/04 17:11

ご回答ありがとうございます。 はい、Mathf.floorで整数化する部分がなくてもずれてしまいます。 ありがとうございます、現状を追記しました。 足りない情報などありましたら、お申し付けください。 すみません、今頃理解したのですが、整数化した場合にずれる理由というのは、 Screen Space - Cameraの場合、Pos X、Pos Y、Pos Zは単なる???.5のような半整数ではなく複雑な小数を取りうるから、それを整数化すると整数化前と比べて大きな差異が生じるからずれるということですか?
Bongo

2020/03/04 21:31

整数化した場合にずれる理由についてはおっしゃるとおりです。 「Screen Space - Overlay」だとシーンビュー上のキャンバスは非常に大きく配置されるはずですが、これはこのモードだとキャンバスのワールド座標とスクリーン座標が一致するようになっていることによります。ですのでワールド座標を整数化してやることはスクリーン座標を整数化してやるのと同等ですので、うまくくっきり描画されるようになるわけです。 対して「Screen Space - Camera」だとワールド座標とスクリーン座標が一致しなくなりますので、ワールド座標を整数化してやる方法が通用しなくなってしまうということですね。 次にMath.floorなしでも中心からずれてしまう現象に関してですが、どうやらTextのZ座標が狂っているようですね... シーンビューで視点を動かして斜めから見てみると、TextがCanvas上から浮き上がってカメラの方にかなり寄っていると思います。ですのでカメラの映像ではTextがかなり大きく表示されているのでしょう。 おそらくカメラのワールド座標はデフォルトの(0, 1, -10)だと思われますので、Plane Distanceが100ですからキャンバスの中心座標は(0, 1, 90)を示しています。 ここで実行中のTextのPos Zを見てみますと-282.9305となっています。これにキャンバスのスケール0.3180993を掛けると-90となり、つまりワールド座標のZ成分が0であると考えられます。 コード中の Vector2 center = this.transform.root.TransformPoint(Vector2.zero); の部分を Vector3 center = this.transform.root.TransformPoint(Vector2.zero); に変更してみるとどうでしょうか? centerの型がVector2だと、求めたキャンバス中心ワールド座標のZ成分が捨てられてしまいます。これをthis.transform.positionに代入するときに自動的にVector3に変換された結果、Zが0になってしまったものと思われます。
退会済みユーザー

退会済みユーザー

2020/03/05 14:55

ご回答ありがとうございます。 キャンバスのRectTransformのScaleは、その子UIのRectTransformに、そのキャンバスのScaleの影響を与えるものですか? (すみません、あまり、Scaleについて考えたことがなかったので。親のTransformのスケールが2ならば、その子オブジェクトのtransformのスケール自体は1でも、親のスケールの影響を受けて、子のtransformも2倍になるという考え方で合っていますか?) Vector3 center = this.transform.root.TransformPoint(Vector2.zero); で、中心に位置することが確認できました。 ちなみに細かいことではありますが、 Vector3 center = this.transform.root.TransformPoint(Vector3.zero); の方が意味的には合っているということですか? (Vector3.zeroのコードでも試してみて、中心に位置することが確認できました。) とすると、 UIを中心に配置させる汎用的なコードは、 Screen Space - Overlayの場合だったら、Screen.width/2のコードで、 Screen Space - Cameraの場合だったら、ぼやけを気にせず、なおかつルートオブジェクトがCanvasであることを条件として、今回のthis.transform.root.TransformPointのコードということになりそうですね。
Bongo

2020/03/05 21:30

そうですね。RectTransformに限らず普通のTransformでも、おっしゃるように親のスケールが子に影響するでしょう。 つまり子オブジェクトのlocalScale...つまりインスペクター上に表示されるスケールの値が同じでも、親オブジェクトのスケールが違えば最終的に画面に映る子オブジェクトの大きさは違って見えるはずです。 後半のご質問に関してもおっしゃるとおりで、TransformPointのリファレンス(https://docs.unity3d.com/ja/current/ScriptReference/Transform.TransformPoint.html )をご覧いただきますと... public Vector3 TransformPoint (Vector3 position); public Vector3 TransformPoint (float x, float y, float z); の2種類の形式が用意されていることがわかります。今回は前者のVector3を引数としてVector3を返す方を使っているわけです。 このメソッドについて、ご質問者さんが行ったように「Vector2型の引数を渡して、Vector2型の変数で結果を受け取る」という使い方をしてもコンパイルエラーは起こりませんが、これはVector2のリファレンス(https://docs.unity3d.com/ja/current/ScriptReference/Vector2.html )の一番下の「Operator」の節に載っている「Vector2」と「Vector3」の作用によるものです。自動的に相互変換してくれるのでコードがすっきりするものの、今回のようなZ成分の欠落には要注意ですね。
退会済みユーザー

退会済みユーザー

2020/03/06 17:29 編集

ご回答ありがとうございます。 スケールとVector2.zeroのご教示ありがとうございます。 ご提示のURL拝見しました、勉強になります。 スケール関係で気になったことがあり、すみませんが、最後にもう1点質問させていただけませんか? Screen Space - Cameraの場合のCanvasのRectTransformなのですが、このScaleはどんな規則で値が設定されるかご存知ですか? 試してみた所、Plane Distanceとは連動しているみたいで、Plane Distanceが0のときは、Scaleも0になるのはわかったのですが、Plane Distanceを1,10,100などの区切りのいい数値に設定してみても、 Scaleは0.003180993,0.03180993,0.3180993と連動して10倍ずつ増えていくことはわかったものの、元の(1のときの)に、なぜ0.003180993という値になるのかがわからなかったです。
Bongo

2020/03/07 11:23 編集

以前申し上げたようにシーンビューを回転させて斜めから見てみると、カメラの前方に四角くキャンバスが浮かんでいるのを確認いただけると思います。カメラがPerspectiveの場合、キャンバスのPlane Distanceを操作すると四角がカメラの視線に沿って前後に移動し、サイズはカメラからの距離に比例して変化するはずです。 ワールド空間内のキャンバスの四隅は、カメラの位置を頂点とする四角錐の4本の辺に沿って移動します。四角錐の縦方向の頂角はCamera.fieldOfView(https://docs.unity3d.com/ja/current/ScriptReference/Camera-fieldOfView.html )ですので、デフォルトの60°だとPlane Distanceが1の時のワールド空間におけるキャンバスの縦の長さは2×tan(60°/2)となり、2×0.577350269189...ということになります。一方、キャンバスの本来の高さはScreen.heightですから、Plane Distanceが1の時のスケールは2×0.577350269189/Screen.heightというわけです。 ですので、キャンバスをcとすると... Debug.Log(c.planeDistance * 2.0f * Mathf.Tan(c.worldCamera.fieldOfView * Mathf.Deg2Rad / 2) / Screen.height); でキャンバスのスケールが出てくるかと思います。 また、カメラがOrthographicなら視界は直方体となり、高さはPlane Distanceに関わらずCamera.orthographicSize(https://docs.unity3d.com/ja/current/ScriptReference/Camera-orthographicSize.html )の2倍です。ですからキャンバスのスケールは... Debug.Log(2.0f * c.worldCamera.orthographicSize / Screen.height); となるでしょう。
退会済みユーザー

退会済みユーザー

2020/03/07 07:16

ご回答ありがとうございます。 とても勉強になりました。 たくさんの質問にご回答いただき、本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問