Jump to content
⚠ Known Issue: Media on User Profiles ×

Local to global rotations - that old chestnut!


dafydd99

Recommended Posts

Thanks Rasikko - yes it's all too easy to slip into Fallout4 forums!

 

The project I most want it for is this... https://www.nexusmods.com/skyrimspecialedition/mods/38420. The Sidrat - a moveable home, that can take many different external appearances (or 'models' as I'm calling them). I've made ten models, but in some cases (eg the mushroom home, like one from Tel Mithryn) it would be great to be able to eg put lanterns on the ropes around the edge (there are more serious reasons why I need to do the rotation, but this is a good example). My scripts move the models to the new location on moving, and add an extra 'rotation' step as you exit into the arrival cell (to fix the moveto bug when you're not in the same cell as the object reference). All well and good, and works fine, as long as the RotateX and RotateY aren't set. And to put lanterns on the rope so they look natural they need to be rotate in x and y.

 

I've thought that perhaps using 'attach ref' might work - but unfortunately I'm not sure that works when moving an objectreference between unloaded cells.

 

But perhaps you're right - the solution might just be to work out the maths!

 

Cheers - dafydd99

Link to comment
Share on other sites

  • 3 weeks later...

Have done some more work on 'attach ref' stuff, and it pretty much works. I need to make a 'marker' object, attach an 'attach node' to it in nifskope, then set the attach refs for all the objectreferences I want to attach to it. When the objects are moved to be part of the model, you can then rotate the marker object to the correct rotation and all the attached refs will rotate correctly.

 

And every time you return to that cell you have to repeat this process as the engine seems to forget those objects. So an 'OnCellAttach' event has to be added to the marker to repeat this everytime. Also the marker must have 'respawn' turned off, or it'll break on respawn.

 

One slight problem - it works in every situation except game load - so if you have a save just by the model the rotatable pieces will have gone on loading. Fast travel away and back and they're okay. I can't find an event that is fired at game load... as mentioned here... https://www.creationkit.com/index.php?title=OnCellAttach_-_ObjectReference

 

Cheers - dafyd99

Link to comment
Share on other sites

Thanks again for supporting this Rasikko. Hm... I was thinking that might be a little too far off as the rotation code should run when the 3d of the 'marker' object. But in theory there could be some way I could register that marker with the quest, and have an OnePlayerLoadGame event trigger this - it's a bit convoluted but it might just work!

 

Cheers - dafydd99

Edited by dafydd99
Link to comment
Share on other sites

Right - so I got quite some way down the OnCellAttach route - and it mostly works. But sometimes inexplicably it doesn't - it's possible it's not designed for moving objects between cells.

 

HOWEVER! After an eternity of mucking about with the rotation stuff - I FINALLY think I might have got something that works...

import utility
import math

function zAxisRotate(ObjectReference ref, float angleZRotate) global
	rotateRefAroundZAxis(ref, ref.GetAngleX(), ref.GetAngleY(), ref.GetAngleZ(), angleZRotate)
endfunction

function rotateRefAroundZAxis(ObjectReference ref, float originalXAngle, float originalYAngle, float originalZAngle, float angleZRotate) global
	float[] xyz=getRotateAroundZAxisAngles(originalXAngle, originalYAngle, originalZAngle, angleZRotate)
	ref.SetAngle(xyz[0], xyz[1], xyz[2])
endfunction

float[] function getRotateAroundZAxisAngles(float originalXAngle, float originalYAngle, float originalZAngle, float angleZRotate) global
	float[] normalisedAngles=getLocalAngles(originalXAngle, originalYAngle, -originalZAngle)
	float[] angles=getLocalAngles(normalisedAngles[0], normalisedAngles[1], -normalisedAngles[2]+angleZRotate)
	return angles
endfunction 

float[] function getLocalAngles(float localAngX, float localAngY, float localAngZ) global
	;the world angles
	float worldAngX
	float worldAngY
	float worldAngZ

	localAngX=-localAngX
	localAngY=-localAngY
	localAngZ=-localAngZ

	;sine and cosine of local x, y, z angles
	float sx=sin(localAngX)
	float cx=cos(localAngX)
	float sy=sin(localAngY)
	float cy=cos(localAngY)
	float sz=sin(localAngZ)
	float cz=cos(localAngZ)

	;ZYX
	float r11=cz*cy
	float r12=-sz*cx+cz*sy*sx
	float r13=sz*sx+cz*sy*cx
	float r21=sz*cy
	float r22=cz*cx+sz*sy*sx
	float r23=cz*(-sx)+sz*sy*cx
	float r31=-sy
	float r32=cy*sx
	float r33=cy*cx

	;Extraction of worldangles from rotation matrix
	if (r13 >  0.9998)
		;positive gimbal lock
		worldAngX=-atan2(r32, r22)
		worldAngY=-90
		worldAngZ=0
	elseif (r13 < -0.9998)
		;negative gimbal lock
		worldAngX=-atan2(r32, r22)
		worldAngY=90
		worldAngZ=0
	else
		;no gimbal lock
		r23=-r23
		r12=-r12
		worldAngX=-atan2(r23, r33)
		worldAngY=-asin(r13)
		worldAngZ=-atan2(r12, r11)
	endif
	float[] toReturn=new float[3]
	toReturn[0]=worldAngX
	toReturn[1]=worldAngY
	toReturn[2]=worldAngZ
	
	return toReturn
Endfunction

float function atan2(float y, float x) global ; returning degrees
	if x>0
		return atan(y/x)
	elseif x<0
		if y>=0
			return atan(y/x)+180.0
		elseif y<0
			return atan(y/x)+(-180.0)
		endif
	elseif x==0
		if y>0
			return 90
		elseif y<0
			return -90
		else ; undefined - we'll return zero
			return 0.0
		endif
	endif
endfunction

Above is a collection of global functions that should allow an object reference to be rotate around the Z-Axis, no matter what the X and Y rotations are. It's been very hit and miss getting here, so I suspect this could be optimised further.

 

Once again - thanks to Rasikko for the support through this.

 

cheers - dafydd99

Link to comment
Share on other sites

  • 7 months later...

Oh~ that is real nifty. I think you can also use math to get the local x, y and z positions(position relative to the cell).

 

 

x:13000 - ((13000 / 4096) as int * 4096) = 13000 - 12288 = x:712

(12288 is the 3rd cell from the origin on the x axis)

 

Negative positions has to be accounted for, thus the result has to be multiplied or added by -1.

Edited by AnishaDawn
Link to comment
Share on other sites

My pleasure dylbill - just glad it wasn't only of use to me.

 

It's the kind of thing that really should be built into the engine - fingers crossed we'll find it's much improved in ES6.

 

My application of this code was to move a home constructed of several refs, and allow little add-on refs at any angle. However if I was doing this again, I might look more at doing this at the nif level as it's soooo much easier.

Link to comment
Share on other sites

Ahh gotcha, yeah doing it at the nif level would be easier. I agree that setting or modding local angles should be included in the engine. I'm going to maybe update my positioner mod with this. Right now it changes world angles of objects, but would be nice to include local angles as an option.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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