Jump to content

Recommended Posts

I've been struggling for some time to create a nametag script that could:

- use drawIcon3D to place the tags over players (like F3) instead of center screen (like ST)

- have multiple lines of text for player roles, group names, etc

- display these multiple lines (in 3D) as if they were one big sprite (psuedo-2D)


( Pictures available here )


drawIcon3D does not support structured text. It does not support text over multiple lines, or with a different justification, or any of that. You can render an icon, and you can render some text. That icon and text will always face you, and will appear the same size no matter the distance between your player and the drawIcon3D's position, but if you want to display multiple lines of text stacked upon each other you were out of luck. I was out of luck. I tried a few things.


My original solution was to use the easy method (modelToWorld[0,0,0] + height for stance, +/- static Z-level spacing between tags) F3 uses, but to dynamically change the spacing between 3D icons on-screen depending on player FOV and distance to target. As you moved closer or further, the tags would space out or scrunch up in 3D accordingly. The problem? That solution only changed the Z levels of the tags, meaning that if I looked down on the tags from above (or up from below, or really any angle other than flat horizontal) the visual spacing would decrease until they appeared to overlap each other.


The next attempt adjusted the spacing by first converting the world coordinates to screen coordinates (worldToScreen), adjusting those screen coordinates with a fixed Y spacing, and then converting them back into world coordinates before displaying them (screenToWorld). It worked, for the most part. Tags viewed from above would be spaced out perfectly. The problem here was twofold: first, screenToWorld gets the world position (going through models and buildings) at the screen position given, even if that world position is kilometers away. The drawIcon3D text looks the same size at any distance, of course, but this lead into a bigger problem -- If you were looking at someone and there was no "world" behind them (ie: just a sky) then screenToWorld would be unable to find a world position, and the tag would not appear.


I had no idea what to do at this point and repeatedly turned to the Arma 3 Discord for help. A lot of people offered advice for which I am very grateful, but I am especially thankful towards cptnnick for helping me work through a solution to the dynamic spacing problem using orthogonal vectors and vector cross products. The solution is available in simplified form in my (unreleased, beta) nametag script, but a more expanded (and easily explained) process is this commented demonstration code graciously provided by cptnnick:


comment "Setup. Not part of dynamic spacing solution.";
removeMissionEventHandler ["Draw3D",missionNamespace getVariable ["drawHandler",-1]];

drawHandler = addMissionEventHandler ["Draw3D", {
	comment "Get the target object and player.";
	_target = cursorObject;
	_player = player;
    comment "Get the position of the player's camera and the middle of the target's body.";
    _targetPosition = _target modelToWorldVisual[0,0,1.3];
    _playerPosition = positionCameraToWorld[0,0,0];
    comment "Calculate the distance from target to player.";
	_distance = _targetPosition distance _playerPosition;
    comment "Get the player's current zoom level. Google 'Killzone Kid Get Zoom.'";
	_fov = call wh_nt_fnc_getZoom;
    comment "Get the vector from target to player (GREEN LINE).";
    _dir = _targetPosition vectorDiff _playerPosition;
    comment "NEW: vectorDir _player doesn't work when the player is using freelook.";
    comment "To get the vectorDir of the player's camera instead of his body, do this:";
    _playerDir = _playerPosition vectorFromTo positionCameraToWorld[0,0,1];
    comment "Get a vector orthogonal to the player's orientation (RED LINE).";
    _cross = (_playerDir) vectorCrossProduct (vectorUp _player);
    comment "Get the relative "UP" direction of the target model (PURPLE LINE).";
    _drawUpNormal = vectorNormalized (_cross vectorCrossProduct _dir); 
    comment "Multiply the direction by how far we want the text spaced.";
    _drawUp = _drawUpNormal vectorMultiply (0.1 * _distance / _fov);
    comment "Flip it for down.";
    _drawDown = _drawUp vectorMultiply -1;

    _drawPosUp = _targetPosition vectorAdd _drawUp;
	_drawPosDown=_targetPosition vectorAdd _drawDown;
    comment "Render some cool drawIcon3D stuff with your new, dynamically-spaced positions.";
    drawLine3D [_targetPosition, _drawPosUp, [1,0,0,1]];
    drawLine3D [_targetPosition, _playerPosition, [0,1,0,1]];    
    drawLine3D [_targetPosition, _targetPosition vectorAdd _cross, [0,0,1,1]];

	drawIcon3D ["", [1,1,1,1], _drawPosUp, 0, 0, 0, "TOP", 2, 0.04, "RobotoCondensed"];
    drawIcon3D ["", [1,1,1,1], _targetPosition, 0, 0, 0, "MIDDLE", 2, 0.04, "RobotoCondensed"];
	drawIcon3D ["", [1,1,1,1], _drawPosDown, 0, 0, 0, "BOTTOM", 2, 0.04, "RobotoCondensed"];


  • Like 3

Share this post

Link to post
Share on other sites

Had to fix an issue with freelook and some commenting stuff, but it's all ace now.

Share this post

Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in

Sign In Now