Here's code to convert in-game coordinates of an object as found by a memory reader, to a screen coordinate you can click on.
Note that there's sample code for this on another website. I tried it, and it kinda worked - but only if the object was near the center of the screen, the camera was zoomed out the right amount, etc. After failing to fix it, I just wrote my own from scratch. This code works perfectly under all conditions.
Code is in VB.NET. Plenty of comments are included to make it self-explanatory.
First, the public variables - along with what you should fill them with and where to get it:
Code:
Public WowOrigin As Point ' set this to the upper-left corner of the client area
Public WowSize As Point ' set this to the width and height of the client area
Public WowCenter As Point ' set this to the screen coordinates of the center of the client area
Public Const cCameraInfo As Integer = &HC76B48
' cCameraInfo+&h0 : X location (single-precision float)
' cCameraInfo+&h4 : Y location (single-precision float)
' cCameraInfo+&h8 : Z location (single-precision float)
' cCameraInfo+&h24: Facing (single-precision float)
' cCameraInfo+&h20: Tilt (single-precision float)
' Take the Math.Asin() of this value to get proper tilt in radians.
Public Structure strCamera
' Camera coordinates.
Public X, Y, Z As Single
' The left-right rotation of the camera. Range is from 0 to 2*PI.
Public Facing
' The up-down rotation of the camera. Range is from -0.5*PI to +0.5*PI.
' Note that the location I was able to find in memory actually ranges from -1 to +1.
' I'm not sure if I'm reading the correct address! But taking the arcsine of the
' this value converts it to the proper range in radians.
Public Tilt As Single
End Structure
Public Camera As strCamera ' set this to the camera location/rotation
And the function that does the conversion:
Code:
Function GameCoordsToScreenCoords(ByVal X As Double, ByVal Y As Double, ByVal Z As Double) As Point
' Convert game coordinates to screen coordinates.
' Returns -1,-1 if not onscreen.
' The following transform was taken from Wikipedia's page on "3D Projection".
'
' Setup was a little tricky since WoW and the transform coordinate and rotation
' systems were different, thus all the odd assignments.
'
' point location
Dim ax As Double = -X
Dim ay As Double = -Z
Dim az As Double = Y
' camera location
Dim cx As Double = -Camera.X
Dim cy As Double = -Camera.Z
Dim cz As Double = Camera.Y
' camera rotation
Dim Facing2 As Double = Camera.Facing
If Facing2 > Math.PI Then Facing2 -= 2 * Math.PI
Dim ox As Double = Camera.Tilt
Dim oy As Double = -Facing2
Dim oz As Double = 0
' Perform the transform to generate X,Y,Z of the point relative to the current
' camera position and rotation.
Dim dx As Double, dy As Double, dz As Double
dx = Math.Cos(oy) * (Math.Sin(oz) * (ay - cy) + Math.Cos(oz) * (ax - cx)) - Math.Sin(oy) * (az - cz)
dy = Math.Sin(ox) * (Math.Cos(oy) * (az - cz) + Math.Sin(oy) * (Math.Sin(oz) * (ay - cy) + Math.Cos(oz) * (ax - cx))) + Math.Cos(ox) * (Math.Cos(oz) * (ay - cy) - Math.Sin(oz) * (ax - cx))
dz = Math.Cos(ox) * (Math.Cos(oy) * (az - cz) + Math.Sin(oy) * (Math.Sin(oz) * (ay - cy) + Math.Cos(oz) * (ax - cx))) - Math.Sin(ox) * (Math.Cos(oz) * (ay - cy) - Math.Sin(oz) * (ax - cx))
' Check to make sure it's not behind the camera.
If dz <= 0 Then Return New Point(-1, -1)
' Project the point to a screen location.
'
' This wasn't taken from Wiki, it came from somewhere else. I forget where.
' FOV1 - The distance between the virtual eye, and the camera plane.
' If this is too large, you'll find the conversion works great at
' long distances, but falls short (towards the center of the screen)
' at short distances. Not sure what this really is in WoW, but it's
' something small and 0.1 works just fine.
Dim FOV1 As Double = 0.1
' FOV2 - Scaling to the screen. This was found experimentally, at long (>20 yard)
' distance to avoid any potential errors from FOV1. This must be changed
' if FOV1 changes!
Dim FOV2 As Double = 7.4 * WowSize.X
Dim SX As Integer = dx * (FOV1 / (dz + FOV1)) * FOV2 + WowCenter.X
Dim SY As Integer = dy * (FOV1 / (dz + FOV1)) * FOV2 + WowCenter.Y
' Final check to make sure it's on-screen.
If SX < WowOrigin.X Or SY < WowOrigin.Y Or _
SX >= (WowOrigin.X + WowSize.X) Or SY >= (WowOrigin.Y + WowSize.Y) Then Return New Point(-1, -1)
' Return the result.
Return New Point(SX, SY)
End Function
Enjoy!