# [HELP] getScreenFromWorldPosition

## Recommended Posts

Hello community, I created a script to mark the location of the location in dx, where it shows the location, how many meters are from the location, and I was looking to improve this function where, basically, if the 3D Dx image is not activated On the player screen , the image will be in the corner of the image corresponding to the side where the mark is.

Image: https://imgur.com/a1AKZ96

Expectation made in the Photo Shop: https://imgur.com/Tskkamp

I am not exactly sure what the raw mathematics are

.

But you can use for your first iteration this function:

```local screenPosX, screenPosY = getScreenFromWorldPosition (  x,  y,  z, 10, true  )
if screenPosX and screenPosY then

end```

It will flatten the complex 3D orientation and therefore allows you to calculate the rotation:

You can use optional argument 'edgeTolerance' of getScreenFromWorldPosition.

If 'location point' is out of screen, function will return screen x,y position outside of screen resolution. You only have to format returned x,y to be on edge of screen resolution.

It will return false if 'location point' is behind the screen.

• 1

Posted (edited)
5 minutos atrás, Skuleris disse:

Você pode usar o argumento opcional 'edgeTolerance' de getScreenFromWorldPosition.

Se o 'ponto de localização' estiver fora da tela, uma função retornará a posição x, e a tela fora da resolução da tela. Você precisa de formatar x, e retorna para estar na borda da resolução da tela.

Ele retornou falso se o 'ponto de localização' estiver atrás da tela.

```The argument you cited is giving an error. I don't know why, am I doing it right?

getScreenFromWorldPosition (x, y, pz + 2, 0.0.3, verdadeiro)```

Edited by Hazardinho

Posted (edited)

Not right. Use 10 instead of 0.0.3

Tip: use /debugscript to see detailed error code. Not hard to figure out yourself!

You will have to format returned x,y to be on the edge of resolution.

Edited by Skuleris

Just now, Skuleris said:

Not right. Use 10 instead of 0.0.3

Tip: use /debugscript to see detailed error code. Not hard to figure out yourself!

Uou will have to format returned x,y to be on the edge of resolution.

Can you give me an example?

Since I am not that terrible at math here is my solution:

```local function get_screen_border_coordinates(wx, wy, wz)
local camMatArray = getElementMatrix(getCamera());
local camMat_right = camMatArray[1];
local camMat_forward = camMatArray[2];
local camMat_up = camMatArray[3];
local camMat_pos = camMatArray[4];
local camMat = Matrix();
local sW, sH = guiGetScreenSize();
local s_ratio = sH / sW;
camMat:setForward(Vector3(camMat_forward[1], camMat_forward[2], camMat_forward[3]));
camMat:setRight(Vector3(camMat_right[1], camMat_right[2], camMat_right[3]));
camMat:setUp(Vector3(camMat_up[1] * s_ratio, camMat_up[2] * s_ratio, camMat_up[3] * s_ratio));
camMat:setPosition(Vector3(camMat_pos[1], camMat_pos[2], camMat_pos[3]));

local invCamMat = camMat:inverse();

local invVec = invCamMat:transformPosition(wx, wy, wz);

local function to_real_coord(val)
return ( val / 2 ) + 1/2;
end

local ratWidth, ratHeight, depthDist = invVec.x, invVec.y, invVec.z;

if (ratWidth == 0) and (ratHeight == 0) then
return 0, 0;
elseif (ratWidth == 0) then
return 0, to_real_coord(1 / ratHeight);
elseif (ratHeight == 0) then
end

local dist_to_width = math.abs(1 / ratWidth);
local dist_to_height = math.abs(1 / ratHeight);

local scale_dist = math.min(dist_to_width, dist_to_height);

ratWidth = ratWidth * scale_dist;
ratHeight = ratHeight * scale_dist;

end

function()
local wx, wy, wz = 0, 0, 0;

local screenRelX, screenRelY = get_screen_border_coordinates(wx, wy, wz);

dxDrawText( "relX: " .. screenRelX .. ", relY: " .. screenRelY, 100, 300 );

local screenWidth, screenHeight = guiGetScreenSize();

local screenX, screenY = screenRelX * screenWidth, screenRelY * screenHeight;

dxDrawRectangle( screenX - 25, screenY - 25, 50, 50, 0xFFFFFFFF );
end
);```

The mathematical background is very much related to my work at 3D software rendering, but I do not want to overcomplicate things for you.

Posted (edited)

22 minutes ago, The_GTA said:

Since I am not that terrible at math here is my solution:

```
local function get_screen_border_coordinates(wx, wy, wz)
local camMatArray = getElementMatrix(getCamera());
local camMat_right = camMatArray[1];
local camMat_forward = camMatArray[2];
local camMat_up = camMatArray[3];
local camMat_pos = camMatArray[4];
local camMat = Matrix();
local sW, sH = guiGetScreenSize();
local s_ratio = sH / sW;
camMat:setForward(Vector3(camMat_forward[1], camMat_forward[2], camMat_forward[3]));
camMat:setRight(Vector3(camMat_right[1], camMat_right[2], camMat_right[3]));
camMat:setUp(Vector3(camMat_up[1] * s_ratio, camMat_up[2] * s_ratio, camMat_up[3] * s_ratio));
camMat:setPosition(Vector3(camMat_pos[1], camMat_pos[2], camMat_pos[3]));

local invCamMat = camMat:inverse();

local invVec = invCamMat:transformPosition(wx, wy, wz);

local function to_real_coord(val)
return ( val / 2 ) + 1/2;
end

local ratWidth, ratHeight, depthDist = invVec.x, invVec.y, invVec.z;

if (ratWidth == 0) and (ratHeight == 0) then
return 0, 0;
elseif (ratWidth == 0) then
return 0, to_real_coord(1 / ratHeight);
elseif (ratHeight == 0) then
end

local dist_to_width = math.abs(1 / ratWidth);
local dist_to_height = math.abs(1 / ratHeight);

local scale_dist = math.min(dist_to_width, dist_to_height);

ratWidth = ratWidth * scale_dist;
ratHeight = ratHeight * scale_dist;

end

function()
local wx, wy, wz = 0, 0, 0;

local screenRelX, screenRelY = get_screen_border_coordinates(wx, wy, wz);

dxDrawText( "relX: " .. screenRelX .. ", relY: " .. screenRelY, 100, 300 );

local screenWidth, screenHeight = guiGetScreenSize();

local screenX, screenY = screenRelX * screenWidth, screenRelY * screenHeight;

dxDrawRectangle( screenX - 25, screenY - 25, 50, 50, 0xFFFFFFFF );
end
);
```

The mathematical background is very much related to my work at 3D software rendering, but I do not want to overcomplicate things for you.

This will help me a lot, but a question, how can I do to identify that the markup is not showing on my screen? since 3D has certain angles that I am not visible on the screen? .

Edited by Hazardinho

Posted (edited)

Dear Hazardinho,

here is an extended (and bugfixed, sorry about that!) version that supports getting screen coordinates as well as the border coordinates in one function.

```local function get_screen_coordinates(wx, wy, wz)
local camMatArray = getElementMatrix(getCamera());
local camMat_right = camMatArray[1];
local camMat_forward = camMatArray[2];
local camMat_up = camMatArray[3];
local camMat_pos = camMatArray[4];
local camMat = Matrix();
local sW, sH = guiGetScreenSize();
local s_ratio = sH / sW;
camMat:setForward(Vector3(camMat_forward[1], camMat_forward[2], camMat_forward[3]));
camMat:setRight(Vector3(camMat_right[1], camMat_right[2], camMat_right[3]));
camMat:setUp(Vector3(camMat_up[1] * s_ratio, camMat_up[2] * s_ratio, camMat_up[3] * s_ratio));
camMat:setPosition(Vector3(camMat_pos[1], camMat_pos[2], camMat_pos[3]));

local invCamMat = camMat:inverse();

local invVec = invCamMat:transformPosition(wx, wy, wz);

local function to_real_coord(val)
return ( val / 2 ) + 1/2;
end

local ratWidth, depthDist, ratHeight = invVec.x, invVec.y, invVec.z;

if (depthDist > 0) then
ratWidth = ratWidth / depthDist;
ratHeight = ratHeight / depthDist;

if (math.abs(ratWidth) <= 1) and (math.abs(ratHeight) <= 1) then
end
end

if (ratWidth == 0) and (ratHeight == 0) then
return 1/2, 1/2;
elseif (ratWidth == 0) then
return 1/2, to_real_coord(1 / ratHeight);
elseif (ratHeight == 0) then
end

local dist_to_width = math.abs(1 / ratWidth);
local dist_to_height = math.abs(1 / ratHeight);

local scale_dist = math.min(dist_to_width, dist_to_height);

ratWidth = ratWidth * scale_dist;
ratHeight = ratHeight * scale_dist;

end

function()
local wx, wy, wz = 0, 0, 0;

local screenRelX, screenRelY, isOnScreen = get_screen_coordinates(wx, wy, wz);

dxDrawText( "relX: " .. screenRelX .. ", relY: " .. screenRelY, 100, 300 );
dxDrawText( "is on screen: " .. tostring(isOnScreen), 100, 320 );

local screenWidth, screenHeight = guiGetScreenSize();

local screenX, screenY = screenRelX * screenWidth, screenRelY * screenHeight;

dxDrawRectangle( screenX - 25, screenY - 25, 50, 50, 0xFFFFFFFF );
end
);```

In order to detect if an object is on the screen, simply use the third return value.

Edited by The_GTA
added condition to check whether on screen or not
• 1

52 minutes ago, The_GTA said:

Caro Hazardinho,

Aqui está uma versão estendida (e com correção de erros, desculpe!) que suporta a obtenção de coordenadas de tela, bem como as coordenadas de borda em uma função.

```

```

Para detectar se um objeto está na tela, basta usar o terceiro valor de retorno.

Incredible, thank you so much for giving me the ready function, it really helped, I am forever grateful

10 minutes ago, Hazardinho said:

Incredible, thank you so much for giving me the ready function, it really helped, I am forever grateful

No problem, I spent some time testing the thing and it turns out I forgot to multiply with the camera Field Of View angle. So here is an ingame screenshot of it working:

```local function get_screen_coordinates(wx, wy, wz)
local camMatArray = getElementMatrix(getCamera());
local camMat_right = camMatArray[1];
local camMat_forward = camMatArray[2];
local camMat_up = camMatArray[3];
local camMat_pos = camMatArray[4];
local camMat = Matrix();
local sW, sH = guiGetScreenSize();
local s_ratio = sH / sW;
local _,_,_,_,_,_,_,fov = getCameraMatrix();
local farclip = getFarClipDistance();
camMat:setForward(Vector3(camMat_forward[1], camMat_forward[2], camMat_forward[3]));
camMat:setRight(Vector3(camMat_right[1] * tanfov, camMat_right[2] * tanfov, camMat_right[3] * tanfov));
camMat:setUp(Vector3(camMat_up[1] * tanfov * s_ratio, camMat_up[2] * tanfov * s_ratio, camMat_up[3] * tanfov * s_ratio));
camMat:setPosition(Vector3(camMat_pos[1], camMat_pos[2], camMat_pos[3]));

local invCamMat = camMat:inverse();

local invVec = invCamMat:transformPosition(wx, wy, wz);

local function to_real_coord(val)
return ( val / 2 ) + 1/2;
end

local ratWidth, depthDist, ratHeight = invVec.x, invVec.y, invVec.z;

if (depthDist > 0) then
ratWidth = ratWidth / depthDist;
ratHeight = ratHeight / depthDist;

if (math.abs(ratWidth) <= 1) and (math.abs(ratHeight) <= 1) then
end
end

if (ratWidth == 0) and (ratHeight == 0) then
return 1/2, 1/2;
elseif (ratWidth == 0) then
return 1/2, to_real_coord(1 / ratHeight);
elseif (ratHeight == 0) then
end

local dist_to_width = math.abs(1 / ratWidth);
local dist_to_height = math.abs(1 / ratHeight);

local scale_dist = math.min(dist_to_width, dist_to_height);

ratWidth = ratWidth * scale_dist;
ratHeight = ratHeight * scale_dist;

end

createObject(1454, 0, 0, 10);

function()
local wx, wy, wz = 0, 0, 10;

local screenRelX, screenRelY, isOnScreen = get_screen_coordinates(wx, wy, wz);

dxDrawText( "relX: " .. screenRelX .. ", relY: " .. screenRelY, 100, 300 );
dxDrawText( "is on screen: " .. tostring(isOnScreen), 100, 320 );

local screenWidth, screenHeight = guiGetScreenSize();

local screenX, screenY = screenRelX * screenWidth, screenRelY * screenHeight;

dxDrawRectangle( screenX - 25, screenY - 25, 50, 50, 0xFFFFFFFF );
end
);```

Gosh I hate myself sometimes 😅🤣

2 minutes ago, The_GTA said:

Sem problemas, passei algum tempo testando a coisa e acabei esquecendo de me multiplicar com o ângulo do campo de visão da câmera. Então, aqui está uma imagem do jogo funcionando:

```

```

Puxa, eu me odeio às vezes 😅 🤣

Perfect thank you

There is a bug in getCameraMatrix() FoV value which prevents proper camera calculation if you are in a vehicle and accelerate. The FoV is not properly returned by that function. Please track this issue so we can get it fixed.

Posted (edited)

Please note that there exists another MTA bug: the camera matrix is sometimes wronly returned. See this Github issue for further details.

I noticed that there was a tiny bug in the get_screen_coordinates function if the world coordinate was directly on the middle vertical line of the screen. Then the screen-y coordinate would be returned as inverted. Even though that issue would be virtually never encountered I decided to give you this following script which has the issue fixed:

```local function get_screen_coordinates(wx, wy, wz)
local camMatArray = getElementMatrix(getCamera());
local camMat_right = camMatArray[1];
local camMat_forward = camMatArray[2];
local camMat_up = camMatArray[3];
local camMat_pos = camMatArray[4];
local camMat = Matrix();
local sW, sH = guiGetScreenSize();
local s_ratio = sH / sW;
local _,_,_,_,_,_,_,fov = getCameraMatrix();
local farclip = getFarClipDistance();
camMat:setForward(Vector3(camMat_forward[1], camMat_forward[2], camMat_forward[3]));
camMat:setRight(Vector3(camMat_right[1] * tanfov, camMat_right[2] * tanfov, camMat_right[3] * tanfov));
camMat:setUp(Vector3(camMat_up[1] * tanfov * s_ratio, camMat_up[2] * tanfov * s_ratio, camMat_up[3] * tanfov * s_ratio));
camMat:setPosition(Vector3(camMat_pos[1], camMat_pos[2], camMat_pos[3]));

local invCamMat = camMat:inverse();

local invVec = invCamMat:transformPosition(wx, wy, wz);

local function to_real_coord(val)
return ( val / 2 ) + 1/2;
end

local ratWidth, depthDist, ratHeight = invVec.x, invVec.y, invVec.z;

-- Screen top is -1 but should be 1 to match the up vector perception.
ratHeight = -ratHeight;

if (depthDist > 0) then
ratWidth = ratWidth / depthDist;
ratHeight = ratHeight / depthDist;

if (math.abs(ratWidth) <= 1) and (math.abs(ratHeight) <= 1) then
end
end

if (ratWidth == 0) and (ratHeight == 0) then
return 1/2, 1/2;
elseif (ratWidth == 0) then
return 1/2, to_real_coord(1 / ratHeight);
elseif (ratHeight == 0) then
end

local dist_to_width = math.abs(1 / ratWidth);
local dist_to_height = math.abs(1 / ratHeight);

local scale_dist = math.min(dist_to_width, dist_to_height);

ratWidth = ratWidth * scale_dist;
ratHeight = ratHeight * scale_dist;

end```

Edited by The_GTA