[SOLVED] World space to UI space problem

Hello.

So I’m trying to have a health indication over an object in World space.

I’m using something like that:

var elementPos = new pc.Vec3();   
camera.worldToScreen(this.entity.getPosition(), elementPos);
this.text.setLocalPosition(elementPos.x, -elementPos.y, 0)

Text label itself is rooted in screen-spaced UI screen.

However, contrary to what I would expect, result is somewhat offsetted from the object, like this:

in this topic here https://forum.playcanvas.com/t/about-question-worldtoscreen-api/7168 I found info that I think is the root of my problem - the ‘screen’ of that method is not the UI coordinates, but rather viewport coordinates. (I understood that viewport is the resolution of canvas context, and the UI screen has its own virtual coordinates)

in this topic https://forum.playcanvas.com/t/solved-include-devicepixelratio-for-screenspace-to-worldspace-conversion/7616 topic starter claims that formula he has works, but it does not for me, ui label is way off. I guess his setup is different from mine somehow.

could anyone please explain how to do this properly or point me to the simple example i might have missed?

thanks.

Hi @nikita_osyak,

Here is a sample project that implements world to element coordinates conversion:

https://playcanvas.com/project/558460/overview/tutorial-world-to-element

1 Like

Hey @Leonidas, project is not available for me.

Link updated!

Thanks, @Leonidas. It’s weird, since I see your tutorial is working as expected, but when I put it in my project, it doesn’t work still :frowning:

I have also screenElement in screen space, same scaling, element in screenelement with same custom anchor of 0 0 0 0 and same update code. What am I missing then?

Can you share a sample project url to take a look?

Sure, here is my project https://playcanvas.com/project/679178/overview/simon-defence

world to ui is in script (in hierarchy) Prefabs/Rusher/HealthBar, UI itself is in root also

Good point, it seems that the tutorial code didn’t account for high pixel density displays.

Try changing the following, I think it will fix your issue:

HealthBar.prototype.update = function(dt) {
    var screenPos = new pc.Vec3();
    
    Helper.camera.entity.camera.worldToScreen(this.entity.getPosition(), screenPos);
    
    screenPos.x *= window.devicePixelRatio;
    screenPos.y *= window.devicePixelRatio;
    
    var screenEntity = this.textPrefabRoot.screen;
    var scale = screenEntity.scale;
    
    // console.log(scale)
    
    var device = this.app.graphicsDevice;
    
    this.textPrefab.setLocalPosition(screenPos.x / scale, (device.height - screenPos.y) / scale, 0);    
};
1 Like

Yes! That did it. Thanks a lot @Leonidas :pray:

1 Like

Thanks @Leonidas! I’ve added your fix to the tutorial fork and also added it to the tutorials page: https://developer.playcanvas.com/en/tutorials/tutorial-world-to-element/

2 Likes

Hello,

The tutorial does not take in consideration the possibility to look in the opposite direction: the UI element still appears even if you do not look the followed entity (because it is behind the camera).

Maybe you can add this

this.entity.element.enabled = screenPos.z > 0;
2 Likes

Done, thanks! World to UI Screen space | Learn PlayCanvas