Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A small Unity helper class to convert viewport, screen or world positions to canvas space.
using UnityEngine;
/// <summary>
/// Small helper class to convert viewport, screen or world positions to canvas space.
/// Only works with screen space canvases.
/// Usage:
/// objectOnCanvasRectTransform.anchoredPosition = specificCanvas.WorldToCanvasPoint(worldspaceTransform.position);
/// </summary>
public static class CanvasPositioningExtensions
{
public static Vector3 WorldToCanvasPosition(this Canvas canvas, Vector3 worldPosition, Camera camera = null)
{
if (camera == null)
{
camera = Camera.main;
}
var viewportPosition = camera.WorldToViewportPoint(worldPosition);
return canvas.ViewportToCanvasPosition(viewportPosition);
}
public static Vector3 ScreenToCanvasPosition(this Canvas canvas, Vector3 screenPosition)
{
var viewportPosition = new Vector3(screenPosition.x / Screen.width,
screenPosition.y / Screen.height,
0);
return canvas.ViewportToCanvasPosition(viewportPosition);
}
public static Vector3 ViewportToCanvasPosition(this Canvas canvas, Vector3 viewportPosition)
{
var centerBasedViewPortPosition = viewportPosition - new Vector3(0.5f, 0.5f, 0);
var canvasRect = canvas.GetComponent<RectTransform>();
var scale = canvasRect.sizeDelta;
return Vector3.Scale(centerBasedViewPortPosition, scale);
}
}
@caneva20

This comment has been minimized.

Copy link

commented Jul 4, 2019

Hey @FlaShG, first off, thank you for the snipet, it really helped me. :)

But I found a BUG with it (and fixed it)

The ViewportToCanvasPosition() does not take into account the scale of the canvas itself, if you are using a CanvasScaler the result would be wrong, by just scaling (again) the result by canvasRect.localScale you can fix it.

I've forked your snipet and fixed the BUG if you want to take a look at. (or if anyone else wants the fixed version)

FIXED VERSION: https://gist.github.com/caneva20/5c5b8950601aac269d34eefbf1be01e9

EDIT:
There's no BUG, it was all a mistake of mine

@FlaShG

This comment has been minimized.

Copy link
Owner Author

commented Jul 5, 2019

Hello @caneva20,

I was not able to reproduce the bug you described in Unity 2018.3.7f1. However, your version produced incorrect results. Is it possible that you are using a newer version of Unity, and that in this version, Canvas properties have changed?

@caneva20

This comment has been minimized.

Copy link

commented Jul 5, 2019

Hi @FlaShG.

I've created a simple project to test both scripts and tested it with 5 different Unity versions (2018.1.9.f2, 2018.2.20f1, 2018.3.1f1, 2018.3.12f1, 2019.1.4f4) and in all of those, I could reproduce the bug.

If don't use the Scale With Screen Size from CanvasScaler you won't find the bug.

Could you please try it too? Here's the link to the project used, it is very simple and contains both versions
Project instructions:
- Right mouse button: Spawns a dot(green) using my version
- Left mouse button: Spawns a dot(red) using your version

Is it possible that you have something else in your project that is changing the canvas in some way?

@FlaShG

This comment has been minimized.

Copy link
Owner Author

commented Jul 5, 2019

You are not using the class as intended. As the summary states, you're supposed to set the resulting values to the RectTransform.anchoredPosition property. Your example uses Instantiate, which has different semantics for its position parameter.

To instantiate objects on the canvas at your mouse position, use

var instance = Instantiate(prefab, canvas.transform);
instance.GetComponent<RectTransform>().anchoredPosition = point;

Using your version breaks my WorldToCanvasPosition test case.

@caneva20

This comment has been minimized.

Copy link

commented Jul 5, 2019

Ohoo, my bad, sorry.
I haven't really noticed that this was a requirement as my use case was something different.
I was looking for something that could convert a point on the screen to a point on the canvas, but not for anchoring it.

Anyway, thank you for your patience, (feeling like a jerk for saying you had a bug)

@FlaShG

This comment has been minimized.

Copy link
Owner Author

commented Jul 5, 2019

No worries 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.