alexoy Posted May 26, 2018 Share Posted May 26, 2018 Hi all, When you play a multiplayer game you often can see players name above them. How can I do the same with a BJS ? I've tried a GUI module to create a TextBlock() , it even has a margin parameter, however the result depends on how far the mesh is from you. If it's next to you - the label will be in front of the mesh, if it's far away - the label will look like it's somewhere in the sky. What is the best way to create a label, which will always be faced to my camera, and which is for example 30 pixels above the mesh independently of the distance? I understand that BJS takes mesh's center and puts a label on it, margin is also a distance from center. Maybe it's possible to use another point instead of the center? Like a pivot point in Blender. Then it would be possible to leave the default value for margin. Thanks! Quote Link to comment Share on other sites More sharing options...
Gijs Posted May 26, 2018 Share Posted May 26, 2018 I don't know what the best way is, but I did it by manually setting the TextBlock top and left each frame: To get the screen position of something on screen: function worldToScreen(worldVec: BABYLON.Vector3, engine: BABYLON.Engine, scene: BABYLON.Scene) { let identity = BABYLON.Matrix.Identity(); let viewport = scene.activeCamera!.viewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight()); let transform = scene.getTransformMatrix(); return BABYLON.Vector3.Project(worldVec, identity, transform, viewport); } Then I set the top and left, like this (note the 30 px): let pos = worldToScreen(node.position, engine, scene); textBlock.left = pos.x - this.canvas.width / 2; textBlock.top = pos.y - this.canvas.height / 2 - 30; Quote Link to comment Share on other sites More sharing options...
alexoy Posted May 26, 2018 Author Share Posted May 26, 2018 Too heavy . GUI module has almost good label, problem is to place it on top of the mesh instead of it's center Quote Link to comment Share on other sites More sharing options...
Arte Posted May 26, 2018 Share Posted May 26, 2018 Hi @alexoy Try mesh.setPivotPoint(new BABYLON.Vector3(x,y,z)); https://doc.babylonjs.com/how_to/pivots https://doc.babylonjs.com/how_to/transformnode Quote Link to comment Share on other sites More sharing options...
Wingnut Posted May 27, 2018 Share Posted May 27, 2018 Hi guys. I was working on a playground in another thread... and it will work just fine to illustrate the issue, here. http://playground.babylonjs.com/#41IFI5#8 Up/Down cursoring the camera in/out... causes the labels to move to front-of mesh, or go far-above. See the linkOffsetY setting in lines 103 and 133? Perhaps... hmm... continuously adjust THOSE values (and maybe button height, width, and fontSize too)... per the distance from camera to mesh. var dist = BABYLON.Vector3.Distance(camera.position, mesh.position)... something like that? I dunno. Let's keep thinking. yzthr 1 Quote Link to comment Share on other sites More sharing options...
alexoy Posted May 27, 2018 Author Share Posted May 27, 2018 Hi, @Wingnut, thanks for confirmation and a PG. There was an idea above to do the similar calculations on every frame. However I believe this is too heavy, especially when there are many meshes with labels and the scene is changing often enough. What do you think about adding new GUI option to set the mesh's point where to put the label? Or an image, or another elements. Currently the object's center only is being chosen. There could be 2 new options like: label.position.x = 0; // center on X axis label.position.y = 3; // 3 units above the center (0, 0) by default. In this way you could place the label wherever you wish. Or it can be not parented at all and still be positioned somewhere. For example, if the mesh's height is 2 units - we could set label.position.y = 2; and the label will always be 1 unit above the mesh. Quote Link to comment Share on other sites More sharing options...
Wingnut Posted May 27, 2018 Share Posted May 27, 2018 Origin point, pivot point, and GUI point. (I didn't understand Arte's comment... until just now.) Yeah, fool the GUI into thinking mesh origin is much higher, or tell the GUI linkWithMesh system to use our new mesh.guiPoint. Actually, the GUI must use mesh.origin.add(mesh.guiPoint). Yep, I've been down this trail before. It's full of skeeters and ticks. http://www.html5gamedevs.com/topic/2571-the-wingnut-chronicles/?do=findComment&comment=201402 https://www.babylonjs-playground.com/#1ND6TH#198 Lines 1194-1198... a renderLoop contortion for the 7th line's target circle, and using .moveToVector3. erf Not applicable for LOTS of labels. Generally, I wanted linkOffset to be in world units, and not pixels. DK replied... http://www.html5gamedevs.com/topic/2571-the-wingnut-chronicles/?do=findComment&comment=201739 Invisible dummy mesh. I had the same concern as Alexoy... too many labels for that extra load. SO, I got no solutions. Sorry. @Deltakosh may be reluctant to ever add mesh.guiPoint to core... and consider it in GUI.linkWithMesh ops. In my experience, if DK is reluctant, there's good reason for it... but not necessarily a reason that I could understand the explanation-for. Even if we DID add BABYLON.AbstractMesh.guiPoint [vec3 localspace offset from mesh.origin]... we would need to tell BJS GUI links to use THAT for tracking target... instead of mesh origin. Again, GUI would actually use mesh.origin.add(mesh.guiPoint) as target. I think the mod to GUI... would go right here in adt.checkUpdate... https://github.com/BabylonJS/Babylon.js/blob/master/gui/src/2D/advancedDynamicTexture.ts#L473 Mod: var position = mesh.getBoundingInfo().boundingSphere.center.add(mesh.guiPoint); mesh.guiPoint would be a distance-from-center OFFSET. Two mods... gets it done. One mod to BABYLON.AbstractMesh (adding .guiPoint prop), and one mod to BABYLON.GUI.AdvancedDynamicTexture.prototype._checkUpdate(). (utilizing new mesh.guiPoint). Might work. Custom mod... your project only. I don't know if DK would ever go-for core-ifying those mods. Also, such a mod would/could eliminate the need for linkOffsetX and linkOffsetY. I'll keep thinking, but, my thinking is not too useful. Off-topic note: Anyone trying more "touring" in the Wingnut Chronicles leg-joints physics tests... don't bother. Only a few of the playgrounds still work... due to recent changes in Oimo plugin. I DID manage to get #196... the most modern one... running again... but its red GUI button impulsers are still broken, sending the red femur mesh into outer space somewhere. #197 and #198 got their physics removed... to make them run (now just GUI demos). I know better than to do big, long-life projects in webGL... due to evolution. Backward-compat is really a pipe dream... when the tech changes as fast as webGL does. It's all ok... there was little/no interest in the physics human-leg-joints experiments, anyway. Undertandable. Learning collidesWith/belongsTo physics collision-group crap... and 3-axis hinge joints... is sort of like learning to tolerate physical pain. It's not the most fun learning to be found. Quote Link to comment Share on other sites More sharing options...
alexoy Posted May 27, 2018 Author Share Posted May 27, 2018 If we modify a mesh for that - we won't be able to create independent labels, for example, to put them at different points of the same mesh (zooming will still move some of them from their correct places). But if we configure the label itself, by setting a "connection point" - there won't be such issues. I think about it like it's a mesh parented to another mesh. Wingnut 1 Quote Link to comment Share on other sites More sharing options...
Dad72 Posted May 27, 2018 Share Posted May 27, 2018 There is BabylonGUI3D now, which could be a better solution. http://doc.babylonjs.com/how_to/gui3d Arte 1 Quote Link to comment Share on other sites More sharing options...
alexoy Posted May 27, 2018 Author Share Posted May 27, 2018 Hi @Dad72, Isn't gui3d an almost normal 3D mesh with it's own size, rotation, shadows, etc? I mean label (text on the plane?) will rotate with player's rotation, won't it? And will become smaller when zooming out. Sure it is useful in other use cases, but users/objects labels are just a plaintext on the screen, with no rotation, connected to some point in a virtual 3D space. The working solution I see for now is to place an empty/invisible mesh above the player's head and attach the label to it. But I really feel that an ideal solution would be to "parent" the label to some mesh and set it's position, just like we do with normal mesh-to-mesh Like we do now, but without setting the position yet. One label to the mesh's top, one to the bottom.. rotate/zoom the scene whatever you like and everything will be in a correct places Quote Link to comment Share on other sites More sharing options...
leanderr Posted May 27, 2018 Share Posted May 27, 2018 I recently made a simple Example... Link Offset is what you want I think. GUI can also track meshes. https://doc.babylonjs.com/how_to/gui#tracking-positions https://www.babylonjs-playground.com/#XCPP9Y#456 Hope that helps Quote Link to comment Share on other sites More sharing options...
alexoy Posted May 27, 2018 Author Share Posted May 27, 2018 @leanderr, similar to Wingnut's PG But if you zoom in/out - you'll notice, that the label doesn't stay on the same place relative to the mesh. If you go far away from the mesh - label will look like it is far above the mesh. I wish label is "connected" to the top point of the mesh for example, independently of the zoom level Quote Link to comment Share on other sites More sharing options...
leanderr Posted May 27, 2018 Share Posted May 27, 2018 "The working solution I see for now is to place an empty/invisible mesh above the player's head and attach the label to it." Yep, put a advanced dynamic texture for text or more GUI stuff and make it the child of your mesh. If you want it to appear as if it is always on top of the mesh (seen relatively from the camera) you can offset the plane by using the camera's up-vector. upvector would be const viewVector = this.camera.getFrontPosition(1).subtract(this.camera.position); const right = BABYLON.Vector3.Cross(BABYLON.Axis.Y, viewVector); const upOrDownOneOfThem = BABYLON.Vector3.Cross(right, viewVector).normalize(); If you want the plate to face the camera use lookat(). Hope it helps Quote Link to comment Share on other sites More sharing options...
sable Posted May 27, 2018 Share Posted May 27, 2018 http://playground.babylonjs.com/#41IFI5#16 See lines 134-144. Uses two methods suggested above; modifying linkedoffsetY each frame, or using an empty mesh parented to the desired mesh. On 5/27/2018 at 8:13 AM, alexoy said: Too heavy . GUI module has almost good label, problem is to place it on top of the mesh instead of it's center What @Gijs suggested is basically what the GUI module is doing internally anyway, so is no heavier than relying on that. Regarding linkedOffsetY calculation each frame being too heavy, you're going to run into performance issues with projecting positions to screen space each frame long before performance of such a simple calculation is a concern. alexoy and GameMonetize 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.