//tips
//unity/webview理解
RectTransformUtility.WorldToScreenPointが機能しなかった要因を確認し、3次元の物体にも対応できるようにしていく。
まずWorld SpaceとScreen Spaceという二つの座標系について考える。
World spaceは3D空間上の座標で、XYZで指定するもの。worldの中心点(x:0, y:0, z:0)を基準にした座標であり、カメラに依存せず、座標の一部をカメラが切り取って映すことになる。
Screen Spaceは、UIの座標で初期設定の場合、0,0は画面の中心となる。World座標と異なり、位置はカメラや画面サイズに依存する。
World座標からUIの座標へ変換する場合、canvasのRender ModeがScreen Space OverlayかScreen Space CameraかScreen Space Worldかで計算式が異なる。
Screen Space Overlayの場合にworld座標に変換する場合、RectTransformUtility.WorldToScreenPoint で変換できる。
現在imageを含むcanvasのrendermodeはscreen space overlayなのでRectTransformUtility.WorldToScreenPoint の使用方法は間違っていないことになる。
Canvas scalerをscale with screen sizeに変更してみたがやはり座標がおかしい。
Screen Space OverlayのはCanvasが常に最前面に描画され、スクリーン全面に配置され、Screen-Space Cameraはカメラに追従するが、画面の最前面ではなく奥行きも反映するものとなる。world spaceはワールド空間上の決まった位置に配置するもの。
Render ModeがオーバーレイのときにはCameraをnullにしないといけないとのことだったのでmycamera = null;を追加。
これにより無事にmarginsをtargetScreenCornersをベースに作成できた。下記が変更したスクリプト。
var canvas = target.GetComponentInParent<Canvas>();
//var camera = canvas.worldCamera;
Vector3[] targetWorldCorners = new Vector3[4];
target.GetWorldCorners(targetWorldCorners);//targetworldcornersに格納
Vector2[] targetScreenCorners = new Vector2[4];
//UI座標
Debug.Log(targetWorldCorners[0]);//(313.0, 330.0, 0.0)
Debug.Log(targetWorldCorners[1]);//(313.0, 430.0, 0.0)
Debug.Log(targetWorldCorners[2]);//(413.0, 430.0, 0.0)
Debug.Log(targetWorldCorners[3]);//(413.0, 330.0, 0.0)
Debug.Log(targetWorldCorners[0]);//(313.0, 330.0, 0.0)
//overlayの場合はScreenPointToLocalPointInRectangleにnullを渡さないといけないので書き換える
mycamera = null;
//screen座標
targetScreenCorners[0] = RectTransformUtility.WorldToScreenPoint(mycamera, targetWorldCorners[0]);
targetScreenCorners[1] = RectTransformUtility.WorldToScreenPoint(mycamera, targetWorldCorners[1]);
targetScreenCorners[2] = RectTransformUtility.WorldToScreenPoint(mycamera, targetWorldCorners[2]);
targetScreenCorners[3] = RectTransformUtility.WorldToScreenPoint(mycamera, targetWorldCorners[3]);
margins[0] = Math.Abs((int)targetScreenCorners[0].x);
margins[1] = Math.Abs(Screen.height - (int)targetScreenCorners[2].y);
margins[2] = Math.Abs(Screen.width - (int)targetScreenCorners[2].x);
margins[3] = Math.Abs((int)targetScreenCorners[0].y);
return margins;
ここからは移動できるcapsuleオブジェクトの子要素にcanvasをworldspaceモードで配置し、その上にgoogleの画面を表示させる。
camera=null部分をコメントアウトすれば良い。
実行すると該当箇所に、googleの画面が表示された。ただ、画面の最上面に表示されていること、移動時に追随を行なっていないことが問題として出てきたのでそちらも対応していく。
Imageではなくcanvasのrotateを変更したが画面の表示角度は変わらなかったデバッグを確認するとWorldToScreenPointによって座標が2次元に変換されてしまっていることが確認できたので、こちらを三次元のものに直す必要がある。
大元のwebViewObject.SetMargins(margins[0], margins[1], margins[2], margins[3]);の設定を確認すると、webViewObjectの表示方法が記載されており、それが2次元スクリーンに基づくものであることがわかるのでここを変更していく。
public void SetMargins(int left, int top, int right, int bottom, bool relative = false)
{
…
#elif UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
if (webView == IntPtr.Zero)
return;
…
#endif
mMarginLeft = left;
mMarginTop = top;
mMarginRight = right;
mMarginBottom = bottom;
mMarginRelative = relative;
float ml, mt, mr, mb;
…
#elif UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
ml = left;
mt = top;
mr = right;
mb = bottom;
…
bool r = relative;
if (ml == mMarginLeftComputed
&& mt == mMarginTopComputed
&& mr == mMarginRightComputed
&& mb == mMarginBottomComputed
&& r == mMarginRelativeComputed)
{
return;
}
mMarginLeftComputed = ml;
mMarginTopComputed = mt;
mMarginRightComputed = mr;
mMarginBottomComputed = mb;
mMarginRelativeComputed = r;
…
#elif UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
int width = (int)(Screen.width - (ml + mr));
int height = (int)(Screen.height - (mb + mt));
_CWebViewPlugin_SetRect(webView, width, height);
rect = new Rect(left, bottom, width, height);
…
}
下記をworld spaceを対象としたありかたに変更させる必要がある。
#elif UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
int width = (int)(Screen.width - (ml + mr));
int height = (int)(Screen.height - (mb + mt));
_CWebViewPlugin_SetRect(webView, width, height);
rect = new Rect(left, bottom, width, height);
方法を模索していたところ複数のカメラを使用することで同様な効果をあげる仕組みを別途見つけたのでそちらも試した。
こちらのやり方でもスクリーン中央に表示がなされてしまうのでwebviewobjectをいじるしかなさそう。