Jump to content

Rotation problems...?


AvatoR

Recommended Posts

I have this code:
 

sx, sy = guiGetScreenSize()
movedClip = false
testAngle = 0

function math.rotVecToEular(x, y, z, rot)  -- explained on mta wiki
	local rotx = math.deg( math.atan2 ( z, (x^2+y^2)^0.5 ) ) % 360
	local rotz = math.deg( math.atan2( x, y ) ) % 360
	return rotx, rot, rotz
end

addEventHandler("onClientRender", root, function ()
	local relX, relY = getCursorPosition()
	local cursorX, cursorY = relX * sx, relY * sy
	local camX, camY, camZ = getCameraMatrix()
	local cursorWorldPosX, cursorWorldPosY, cursorWorldPosZ = getWorldFromScreenPosition(cursorX, cursorY, 20)
	hit, hitX, hitY, hitZ, hitElement, normalX, normalY, normalZ = processLineOfSight(camX, camY, camZ, cursorWorldPosX, cursorWorldPosY, cursorWorldPosZ, true, false, false, true, false, true, false, true)
	if hit then
		testAngle = (testAngle + 1) % 360
		angleVectorX, angleVectorY, angleVectorZ = math.rotVecToEular(normalX, normalY, normalZ, testAngle)
		angleVectorX = angleVectorX - 90 -- cone look "up" when testAngle = 0
		hitX = normalX*0.2 + hitX -- a bit up from a plane
		hitY = normalY*0.2 + hitY -- a bit up from a plane
		hitZ = normalZ*0.2 + hitZ -- a bit up from a plane
		if isElement(movedClip) then
			destroyElement(movedClip)
		end
		movedClip = createObject(1238, hitX, hitY, hitZ, angleVectorX, angleVectorY, angleVectorZ, true)
	end
end)

But i need rotation in other axis, like so:

- Need rotation in "Z" axis with ZYX Euler coordinate system.

Script doing that in MTA:

 

And in blender "X" axis in XYZ Euler angles: 

 

I tried set setElementRotation with 5 argument "ZYX" but it didn't work, like it's swap X and Z angles, not a different coordinate system:

local angX = 0
local angY = 0
local angZ = 0
local modelToRotate = false
sx, sy = guiGetScreenSize()

addEventHandler("onClientRender", root, 
	function ()
		if isCursorShowing() then
			if getKeyState("4") then angX = (angX + 1) % 360 end
			if getKeyState("5") then angY = (angY + 1) % 360 end
			if getKeyState("6") then angZ = (angZ + 1) % 360 end
			dxDrawText("X:" .. angX .. " Y:" .. angY .. " Z:" .. angZ, 300, 60)
			local relX, relY = getCursorPosition()
			local cursorX, cursorY = relX * sx, relY * sy
			local camX, camY, camZ = getCameraMatrix()
			local cursorWorldPosX, cursorWorldPosY, cursorWorldPosZ = getWorldFromScreenPosition(cursorX, cursorY, 20)
			local hit, hitX, hitY, hitZ, hitElement, normalX, normalY, normalZ = processLineOfSight(camX, camY, camZ, cursorWorldPosX, cursorWorldPosY, cursorWorldPosZ, true, false, false, true, false, true, false, true)

			if isElement(modelToRotate) then
				destroyElement(modelToRotate)
			end
			modelToRotate = createObject(1238, hitX, hitY, hitZ, 0, 0, 0, true)
			setElementRotation(modelToRotate, angX, angY, angZ, "ZYX")
		end
	end
)

keys 4, 5, 6 for rotation in X, Y, Z axis.

How to rotate a object in Z axis, but to a normal vector from processLineOfSight, like in first attached video? 

  • Sad 1
Link to comment

I realized that the MTA rotation system is broken when I was trying to write the most common vehicle flip. I encountered exactly the same (or about the same) that you show on the video – broken Rotation Y.

As I understand it, the MTA tries to avoid Rotation Y. For example, instead of RY + 90, the MTA seems to have used the chain RX - 90 > RZ - 90 > RX + 90. I believe this is a global MTA flaw, which I hope will be fixed sooner or later.

P.S. I would understand if you indicated the wrong ZXY instead of the correct ZYX, but all seems correct...

Edited by relvarten
Link to comment
  • Scripting Moderators
11 hours ago, relvarten said:

I realized that the MTA rotation system is broken when I was trying to write the most common vehicle flip. I encountered exactly the same (or about the same) that you show on the video – broken Rotation Y.

As I understand it, the MTA tries to avoid Rotation Y. For example, instead of RY + 90, the MTA seems to have used the chain RX - 90 > RZ - 90 > RX + 90. I believe this is a global MTA flaw, which I hope will be fixed sooner or later.

P.S. I would understand if you indicated the wrong ZXY instead of the correct ZYX, but all seems correct...

Refer to Gimbal Lock of Euler rotation system. To resolve this, use rotation matrix to apply rotation changes, and then convert back to eular angles.

Edited by thisdp
  • Like 2
Link to comment
local angX = 0
local angY = 0
local angZ = 0
local modelToRotate = false
sx, sy = guiGetScreenSize()

addEventHandler("onClientRender", root, 
	function ()
		if isCursorShowing() then
			if getKeyState("4") then angX = (angX + 1) % 360 end
			if getKeyState("5") then angY = (angY + 1) % 360 end
			if getKeyState("6") then angZ = (angZ + 1) % 360 end
			dxDrawText("X:" .. angX .. " Y:" .. angY .. " Z:" .. angZ, 300, 60)
			local relX, relY = getCursorPosition()
			local cursorX, cursorY = relX * sx, relY * sy
			local camX, camY, camZ = getCameraMatrix()
			local cursorWorldPosX, cursorWorldPosY, cursorWorldPosZ = getWorldFromScreenPosition(cursorX, cursorY, 20)
			local hit, hitX, hitY, hitZ, hitElement, normalX, normalY, normalZ = processLineOfSight(camX, camY, camZ, cursorWorldPosX, cursorWorldPosY, cursorWorldPosZ, true, false, false, true, false, true, false, true)

			if isElement(modelToRotate) then
				destroyElement(modelToRotate)
			end

      modelToRotate = createObject(1238, hitX, hitY, hitZ, 0, 0, 0, true)
      
			-- Convert the Euler angles to radians
			local radX = math.rad(angX)
			local radY = math.rad(angY)
			local radZ = math.rad(angZ)
			-- Calculate the sin and cosine values
			local sinX = math.sin(radX)
			local cosX = math.cos(radX)
			local sinY = math.sin(radY)
			local cosY = math.cos(radY)
			local sinZ = math.sin(radZ)
			local cosZ = math.cos(radZ)
			-- Calculate the rotation matrix manually
			local rotMatrix = {{}, {}, {}, {}}
			rotMatrix[1][1] = cosY * cosZ
			rotMatrix[1][2] = cosY * sinZ
			rotMatrix[1][3] = -sinY
      rotMatrix[1][4] = 0
			rotMatrix[2][1] = sinX * sinY * cosZ - cosX * sinZ
			rotMatrix[2][2] = sinX * sinY * sinZ + cosX * cosZ
			rotMatrix[2][3] = sinX * cosY
      rotMatrix[2][4] = 0
			rotMatrix[3][1] = cosX * sinY * cosZ + sinX * sinZ
			rotMatrix[3][2] = cosX * sinY * sinZ - sinX * cosZ
			rotMatrix[3][3] = cosX * cosY
      rotMatrix[3][4] = 0
      rotMatrix[4][1] = hitX
			rotMatrix[4][2] = hitY
			rotMatrix[4][3] = hitZ
      rotMatrix[4][4] = 1
			-- Apply the rotation matrix to the object
      setElementMatrix(modelToRotate, rotMatrix)
		end
	end
)

Is this what you're trying to achieve?

Link to comment
On 01/03/2023 at 09:33, Prioq said:
local angX = 0
local angY = 0
local angZ = 0
local modelToRotate = false
sx, sy = guiGetScreenSize()

addEventHandler("onClientRender", root, 
	function ()
		if isCursorShowing() then
			if getKeyState("4") then angX = (angX + 1) % 360 end
			if getKeyState("5") then angY = (angY + 1) % 360 end
			if getKeyState("6") then angZ = (angZ + 1) % 360 end
			dxDrawText("X:" .. angX .. " Y:" .. angY .. " Z:" .. angZ, 300, 60)
			local relX, relY = getCursorPosition()
			local cursorX, cursorY = relX * sx, relY * sy
			local camX, camY, camZ = getCameraMatrix()
			local cursorWorldPosX, cursorWorldPosY, cursorWorldPosZ = getWorldFromScreenPosition(cursorX, cursorY, 20)
			local hit, hitX, hitY, hitZ, hitElement, normalX, normalY, normalZ = processLineOfSight(camX, camY, camZ, cursorWorldPosX, cursorWorldPosY, cursorWorldPosZ, true, false, false, true, false, true, false, true)

			if isElement(modelToRotate) then
				destroyElement(modelToRotate)
			end

      modelToRotate = createObject(1238, hitX, hitY, hitZ, 0, 0, 0, true)
      
			-- Convert the Euler angles to radians
			local radX = math.rad(angX)
			local radY = math.rad(angY)
			local radZ = math.rad(angZ)
			-- Calculate the sin and cosine values
			local sinX = math.sin(radX)
			local cosX = math.cos(radX)
			local sinY = math.sin(radY)
			local cosY = math.cos(radY)
			local sinZ = math.sin(radZ)
			local cosZ = math.cos(radZ)
			-- Calculate the rotation matrix manually
			local rotMatrix = {{}, {}, {}, {}}
			rotMatrix[1][1] = cosY * cosZ
			rotMatrix[1][2] = cosY * sinZ
			rotMatrix[1][3] = -sinY
      rotMatrix[1][4] = 0
			rotMatrix[2][1] = sinX * sinY * cosZ - cosX * sinZ
			rotMatrix[2][2] = sinX * sinY * sinZ + cosX * cosZ
			rotMatrix[2][3] = sinX * cosY
      rotMatrix[2][4] = 0
			rotMatrix[3][1] = cosX * sinY * cosZ + sinX * sinZ
			rotMatrix[3][2] = cosX * sinY * sinZ - sinX * cosZ
			rotMatrix[3][3] = cosX * cosY
      rotMatrix[3][4] = 0
      rotMatrix[4][1] = hitX
			rotMatrix[4][2] = hitY
			rotMatrix[4][3] = hitZ
      rotMatrix[4][4] = 1
			-- Apply the rotation matrix to the object
      setElementMatrix(modelToRotate, rotMatrix)
		end
	end
)

Is this what you're trying to achieve?

Yep, thanks, it's finally works.

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...