Rotation: Really weird issue.

Post » Tue Jun 19, 2012 6:30 am

OK, could anyone who knows Trig functions help with this? I made three spells, each of which (by concentration) rotates a test object by a given number of degrees with each "pulse" in an alternating direction (So I could check and see how various rotates affected each other)

The issue is detailed below, but it's basically a need to convert between Euler World rotation in the order Z >>> Y >>> X to a local rotation of Pitch, Roll, and yaw.

The Code on the spells:
Spoiler
Scriptname TestMovementControls extends activemagiceffect  {Script to test movement on an object}Bool Property Roll AutoBool Property Pitch AutoBool Property Yaw Auto ; Tells the script which functions to use. Lets us use one script.Float Property RotateDegrees AutoTestObject TestMeEvent  OnEffectStart(Actor Target, Actor Caster)	if Test.RotatingBridgeClockwise		Test.RotatingBridgeClockwise = False	else		Test.RotatingBridgeClockwise = True	endif	RegisterForUpdate(0.25)	if !Test.TestSubject ; If we have no test subject		Game.GetPlayer().PlaceAtMe(TestObjectType,1,False,False)	endifEndEventEvent OnEffectFinish(Actor Target, Actor Caster)	UnRegisterForUpdate()EndEventEvent OnUpdate()	float HowMuch = RotateDegrees	if !Test.RotatingBridgeClockwise		Howmuch *= -1	endif	If !TestMe && Test.TestSubject ; We have nothing to test, but look for one.		TestMe = Test.TestSubject as TestObject	elseif TestMe		if Roll			TestMe.RollBy(HowMuch)		elseif pitch			TestMe.PitchBy(HowMuch)		else			Testme.YawBy(HowMuch)		endif	endifEndEventActivator Property TestObjectType AutoTestVariables Property Test Auto

The Code on the Test Object:
Spoiler
Scriptname TestObject extends ObjectReference  import mathBool Rotating = falseint UpdateCount = 0int MaxUpdates = 360 ; Approximate 6 minute lifespan.float NextRollfloat NextYawfloat NextPitchfloat CapRotationfloat Dxfloat Dyfloat Dzbool NeedToFix = Falsefunction Rotate(float X,Float Y, Float Z)endFunctionfunction RotateMe()	Self.TranslateTo(X,Y,Z,NextRoll,NextPitch,NextYaw,1.0,CapRotation)endfunctionfloat function Fix(Float N)	if sqrt(N * N) <= 1.0 ; Absolute value of N is very small		return 0.0	else		return N	endifendfunctionFunction RollBy(float N) ; Rotate the object by N Degrees per Second around the X Axis.	if !Rotating		Rotating = True		NextRoll = GetAngleX()+N		NextPitch = GetAngleY()		NextYaw = GetAngleZ()Debug.Notification("X: "+ NextRoll + "," + NextPitch + "," + NextYaw)		CapRotation = Sqrt(N * N) ; Disallow negative CapRotation values.		RotateMe()	endifEndFunctionFunction PitchBy(float N) ; Rotate the object by N Degrees per second around the Y Axis.	if !Rotating		Rotating = True		NextRoll = GetAngleX()		NextPitch = GetAngleY()+N		NextYaw = GetAngleZ()Debug.Notification("Y: "+ NextRoll + "," + NextPitch + "," + NextYaw)		CapRotation = Sqrt(N * N) ; Disallow negative CapRotation values.		RotateMe()	endifEndFunctionFunction YawBy(float N) ; Rotate the object by N Degrees per second around the Z Axis.	if !Rotating		Rotating = True		NextRoll = GetAngleX()		NextPitch = GetAngleY()		NextYaw = GetAngleZ()+NDebug.Notification("Z: "+ NextRoll + "," + NextPitch + "," + NextYaw)		CapRotation = Sqrt(N * N) ; Disallow negative CapRotation values.		RotateMe()	endifEndFunctionEvent OnInit()	Rotating = True ; Don't respond to any rotations until we're set up.	Test.TestSubject = self	Debug.Notification("Moving to start position")	MoveTo(Game.GetPlayer(),0.0,0.0,300.0) ; Above the head of the player by 300.0 units.	TranslateTo(X,Y,Z,0.0,0.0,0.0,1.0,45) ; Reset to zero rotation.	NextRoll = 0.0	NextPitch = 0.0	NextYaw = 0.0	RegisterForUpdate(1) ; Start the Death ClockEndEventEvent OnTranslationComplete()	Dx = GetAngleX()	Dy = GetAngleY()	Dz = GetAngleZ()	NeedToFix = False	if Dx >= 360.0		NeedToFix = True		while Dx >= 360.0			Dx = Dx - 360.0		endwhile		Dx = Fix(Dx)	elseif Dx <= -360.0		NeedToFix = True		while Dx <= 360.0			Dx = Dx + 360.0		endwhile		Dx = Fix(Dx)	endif	if Dy >= 360.0		NeedToFix = True		while Dy >= 360.0			Dy = Dy - 360.0		endwhile		Dy = Fix(Dy)	elseif Dy <= -360.0		NeedToFix = True		while Dy <= 360.0			Dy = Dy + 360.0		endwhile		Dy = Fix(Dy)	endif	if Dz >= 360.0		NeedToFix = True		while Dz >= 360.0			Dz = Dz - 360.0		endwhile		Dz = Fix(Dz)	elseif Dz <= -360.0		NeedToFix = True		while Dz <= 360.0			Dz = Dz + 360.0		endwhile		Dz = Fix(Dz)	endif	if NeedToFix		SetAngle(Dx,Dy,Dz) ; Snap to basically the same spot, but with angles reset.	Endif	NeedToFix = False ; We have now fixed any rounding errors	Rotating = False ; Will now respond to the next call to a rotate function.EndEventEvent OnTranslationFailed() ; couldn't move	Rotating = False	Debug.Notification("Unable to move: " + self)endeventEvent OnUpdate()	UpdateCount += 1	if UpdateCount == MaxUpdates		Self.Disable()		Self.Delete()		Test.TestSubject = None	endifEndEventTestVariables Property Test Auto


The Code for the Global variables
Spoiler
Scriptname TestVariables extends Quest  {A place for those pesky test variables.}TestObject Property TestSubject Auto ; Test.TestSubjectActivator Property TestSubjectType Autobool Property RotatingObjectClockwise auto; To access these variables and functions in a script, place the following line in the script:; TestVariables Property Test Auto

What I am wanting to do is make a nonspherical projectile (like an arrow) point at a target, regardless of whether is is above or below itself, and make it keep an "even keel" (so I could do it with a platform that was at an angle and was rotating around a shaft) - now the game has problems with the player being able to stand on a moving object, but it would be nice to be able to do it anyway.

Plus, if you're going to simulate something like a moving cart like in the opening scene, bouncing down a road and staying upright, good luck doing that using the existing TranslateTo function, and having to manually figure out how to keep the cart upright when it goes around a corner and such...with Roll, Pitch, and yaw, you can easily change the Yaw without affecting the Roll and Pitch, and going up or down a hill, you want to be able to change the pitch without affecting the roll and yaw.

the functions I'm after would be like these:

GetRoll(ObjectReference akObject) - Returns the Roll value of the current object
GetPitch(ObjectReference akObject) - Returns the Pitch value of the current object
GetYaw(ObjectReference akObject) - Returns the Yaw value of the current object.
GetX(Float akRoll, Float akPitch, Float akYaw) - Returns the X rotation corresponding to the given Roll, Pitch, ahd Yaw.
GetY(Float akRoll, Float akPitch, Float akYaw) - Returns the Y rotation corresponding to the given Roll, Pitch, ahd Yaw.
GetZ(Float akRoll, Float akPitch, Float akYaw) - Returns the Z rotation corresponding to the given Roll, Pitch, ahd Yaw.
User avatar
amhain
 
Posts: 3506
Joined: Sun Jan 07, 2007 12:31 pm

Post » Tue Jun 19, 2012 2:30 am

Just found out that capping rotation at a negative value causes the item to go berserk. caution!
User avatar
Chris Jones
 
Posts: 3435
Joined: Wed May 09, 2007 3:11 am

Post » Tue Jun 19, 2012 8:31 am

Ok...I'm way over my head mathematically...as someeone probably guessed by my function names, I'm looking for a way to use Roll, Pitch,and Yaw to control an object.

However, rotations in Skyrim are all Euler type, in Z>Y>X order.

Could someone with a head for mathematics figure out the formulas for Roll, Pitch, and Yaw?


I'm sure the answers are somewhere on http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions...but It's been nearly 20 years since I had anything to do with Trigonometry math...I'll fill in the formulas here if someone can figure them out, so anyone who needs to do this in the future can have them available:

Definition: the object's Local Axis is aligned with the world axis at SetAngle(0.0,0.0,0.0)

Yaw (Turn object left and right on it's local axis): (Matches Z Axis if both X and Y remain 0.0)
Roll (Spin the object along it's Front-to-rear Axis): (Matches X Axis if both Z and Y remain 0.0)
Pitch (Turn the object "Up" or "Down" on it's left to right axis): (Matches Y Axis if both Z and X remain 0.0)
User avatar
Joe Alvarado
 
Posts: 3467
Joined: Sat Nov 24, 2007 11:13 pm

Post » Tue Jun 19, 2012 12:38 am

As I recall, successive rotations in FO3 could be subject to gimbal lock. Don't know if that has changed.
User avatar
jessica breen
 
Posts: 3524
Joined: Thu Aug 03, 2006 1:04 am

Post » Tue Jun 19, 2012 9:52 am

As I recall, successive rotations in FO3 could be subject to gimbal lock. Don't know if that has changed.

I haven't noticed any difficulties doing successive rotations once I fixed the scripts. (Fixing the code above to match what I have now.)

now the problem is converting from Euler rotation to Roll/Pitch/yaw rotations (Global successive rotations to local rotations)
User avatar
Cccurly
 
Posts: 3381
Joined: Mon Apr 09, 2007 8:18 pm

Post » Tue Jun 19, 2012 10:13 am

Ah, c'mon, there's gotta be at least one person here who knows something about Trigonometry (or at least more than I remember) and can figure out the conversion formulae...
User avatar
Kayla Keizer
 
Posts: 3357
Joined: Tue Dec 12, 2006 4:31 pm

Post » Tue Jun 19, 2012 11:13 am

Come on guys, there absolutely has to be a way to figure this out with formulas and not painstakingly rotating a test object by 1 degree intervals and making a table with 1080 individual entries (X, Y, and Z values for each individual degree of rotation around that axis) (360 of those tables for Pitch, 360 for yaw, and 360 for roll), which is the only way I'd ever be able to do it...that is, shall we say, a HELL of a lot of work...time I'd rather spend designing spells or working on modelling my dungeon.
User avatar
Dezzeh
 
Posts: 3414
Joined: Sat Jun 16, 2007 2:49 am

Post » Tue Jun 19, 2012 12:26 am

The angle can be calculated with the difference between the two object's X / Y positions

B|\| \|  \ d|   \|  α \------A

A = Object 1
B = Object 2
d = distance
α = angle

1. Pythagoras theorem
d = sqr ( (xB - xA)2 + ( yB - yA )2 )

2. Law of sine
α = arcsin (( yB - yA ) / d)

For the up/down rotation you simply repeat using Z instead of X
User avatar
Cameron Garrod
 
Posts: 3427
Joined: Sat Jun 30, 2007 7:46 am

Post » Tue Jun 19, 2012 10:46 am

The angle can be calculated with the difference between the two object's X / Y positions

I think you misunderstand the question here. there is no second object in the case of just trying to set roll, pitch, and yaw.

Here is a http://i591.photobucket.com/albums/ss358/RedwoodElf/AngleTest45at-45approximate.jpg of a (close approximation) of a -45 degree downward pitch at 45 degrees positive yaw.

The upper bridge was set for reference purposes by the computer to X = 0.0, Y = 0.0, Z = 45.0 (Since X and Y are both zero, this is exactly Roll = 0.0, Pitch = 0.0, and Yaw = 45.0)

The lower bridge was manually positioned to try to estimate Roll=0.0, Pitch = -45.0, and Yaw = 45.0

the X,Y,Z rotations of the lower bridge are X = -30.0, Y = -26.0, Z = 53.0


The problem is, as I said, the rotate order of the XYZ rotations makes it very tedious to figure out what XYZ values will give you the desired RPY without a formula. RPY are absolute values, while XYZ are relative ones (the rotations are done in order, and the earlier rotations modify the later ones)
User avatar
Steve Bates
 
Posts: 3447
Joined: Sun Aug 26, 2007 2:51 pm

Post » Tue Jun 19, 2012 5:19 am

I think you misunderstand the question here. there is no second object in the case of just trying to set roll, pitch, and yaw.

I answered to that:
What I am wanting to do is make a nonspherical projectile (like an arrow) point at a target, regardless of whether is is above or below itself,

Object 1 is the projectile and Object2 is the target. If you don't change the rotation around the Y axis, the object will keep an "even keel"
But Papyrus already has a Getheadingangle function so that's obsolete anyway.

In previous games, the setangle functions defined the rotation from the object's "point of view" not from the world's

I have a faint idea how to calculate the new world-angles (almost 25 years after school here) but that would require a lot of testing and a detailed description of the purpose.


If you want to make an inclined bridge that orbits around a central platform, the pragmatic approach would be opening the model in Nifskope and changing its inclination and pivot point, so that you just need to rotate it around one axis ingame.
User avatar
le GraiN
 
Posts: 3436
Joined: Thu Mar 22, 2007 6:48 pm

Post » Tue Jun 19, 2012 9:43 am

I answered to that:


Object 1 is the projectile and Object2 is the target. If you don't change the rotation around the Y axis, the object will keep an "even keel"
But Papyrus already has a Getheadingangle function so that's obsolete anyway.

In previous games, the setangle functions defined the rotation from the object's "point of view" not from the world's

I have a faint idea how to calculate the new world-angles (almost 25 years after school here) but that would require a lot of testing.

If you want to make an inclined bridge that orbits around a central platform, the pragmatic approach would be opening the model in Nifskope and changing its inclination and pivot point, so that you just need to rotate it around one axis ingame.

Nope...Been there, tried all that before I repurposed this thread for getting the formlulae. GetHeadingAngle doesn't function as advertised...when I get home and can make a video, I'll demonstrate what happens if you just use GetheadingAngle.And again, that requires a second object as a target, and isn't a local axis manipulation.

New Code to add a "watchme" function and spell

On Object:
Spoiler
Scriptname TestObject extends ObjectReference  import mathBool Rotating = falseint UpdateCount = 0int MaxUpdates = 360 ; Approximate 6 minute lifespan.float NextRollfloat NextYawfloat NextPitchfloat CapRotationfloat Dxfloat Dyfloat Dzbool NeedToFix = Falsefunction Rotate(float X,Float Y, Float Z)endFunctionfunction RotateMe()    Self.TranslateTo(X,Y,Z,NextRoll,NextPitch,NextYaw,1.0,CapRotation)endfunctionfunction WatchMe(ObjectReference WhatToWatch)    if !Rotating        Float Deviation = GetHeadingAngle(WhatToWatch)        if Deviation >= 5.0 || Deviation <= -5.0            Rotating = True            NextRoll = GetAngleX()            NextPitch = GetAngleY()            Nextyaw = GetAngleZ()+DeviationDebug.Notification("Watch: "+ NextRoll + "," + NextPitch + "," + NextYaw)            CapRotation = 10.0            RotateMe()        endif    endifendFunctionfloat function Fix(Float N)    if sqrt(N * N) <= 1.0 ; Absolute value of N is very small        return 0.0    else        return N    endifendfunctionFunction RollBy(float N) ; Rotate the object by N Degrees per Second around the X Axis.    if !Rotating        Rotating = True        NextRoll = GetAngleX()+N        NextPitch = GetAngleY()        NextYaw = GetAngleZ()Debug.Notification("X: "+ NextRoll + "," + NextPitch + "," + NextYaw)        CapRotation = Sqrt(N * N) ; Disallow negative CapRotation values.        RotateMe()    endifEndFunctionFunction PitchBy(float N) ; Rotate the object by N Degrees per second around the Y Axis.    if !Rotating        Rotating = True        NextRoll = GetAngleX()        NextPitch = GetAngleY()+N        NextYaw = GetAngleZ()Debug.Notification("Y: "+ NextRoll + "," + NextPitch + "," + NextYaw)        CapRotation = Sqrt(N * N) ; Disallow negative CapRotation values.        RotateMe()    endifEndFunctionFunction YawBy(float N) ; Rotate the object by N Degrees per second around the Z Axis.    if !Rotating        Rotating = True        NextRoll = GetAngleX()        NextPitch = GetAngleY()        NextYaw = GetAngleZ()+NDebug.Notification("Z: "+ NextRoll + "," + NextPitch + "," + NextYaw)        CapRotation = Sqrt(N * N) ; Disallow negative CapRotation values.        RotateMe()    endifEndFunctionEvent OnInit()    Rotating = True ; Don't respond to any rotations until we're set up.    Test.TestSubject = self    Debug.Notification("Moving to start position")    MoveTo(Game.GetPlayer(),0.0,0.0,300.0) ; Above the head of the player by 300.0 units.    TranslateTo(X,Y,Z,0.0,0.0,0.0,1.0,45) ; Reset to zero rotation.    NextRoll = 0.0    NextPitch = 0.0    NextYaw = 0.0    RegisterForUpdate(1) ; Start the Death ClockEndEventEvent OnTranslationAlmostComplete()EndEventEvent OnTranslationComplete()    Dx = GetAngleX()    Dy = GetAngleY()    Dz = GetAngleZ()    NeedToFix = False    if Dx >= 360.0        NeedToFix = True        while Dx >= 360.0            Dx = Dx - 360.0        endwhile        Dx = Fix(Dx)    elseif Dx <= -360.0        NeedToFix = True        while Dx <= 360.0            Dx = Dx + 360.0        endwhile        Dx = Fix(Dx)    endif    if Dy >= 360.0        NeedToFix = True        while Dy >= 360.0            Dy = Dy - 360.0        endwhile        Dy = Fix(Dy)    elseif Dy <= -360.0        NeedToFix = True        while Dy <= 360.0            Dy = Dy + 360.0        endwhile        Dy = Fix(Dy)    endif    if Dz >= 360.0        NeedToFix = True        while Dz >= 360.0            Dz = Dz - 360.0        endwhile        Dz = Fix(Dz)    elseif Dz <= -360.0        NeedToFix = True        while Dz <= 360.0            Dz = Dz + 360.0        endwhile        Dz = Fix(Dz)    endif    if NeedToFix        SetAngle(Dx,Dy,Dz) ; Snap to basically the same spot, but with angles reset.    Endif    NeedToFix = False ; We have now fixed any rounding errors    Rotating = False ; Will now respond to the next call to a rotate function.EndEventEvent OnTranslationFailed() ; couldn't move    Rotating = False    Debug.Notification("Unable to move: " + self)endeventEvent OnActivate(ObjectReference Player)    TranslateTo(Self.X,Self.Y,Self.Z,0.0,0.0,0.0,1.0,45) ; Reset to zero rotation.EndEventEvent OnUpdate()    UpdateCount += 1    if UpdateCount == MaxUpdates        Self.Disable()        Self.Delete()        Test.TestSubject = None    endifEndEventTestVariables Property Test Auto

In Effects:

Spoiler
Scriptname TestMovementControls extends activemagiceffect  {Script to test movement on an object}Bool Property Roll AutoBool Property Pitch AutoBool Property Yaw Auto ; Tells the script which functions to use. Lets us use one script.Bool Property Watch Auto ; If this is true, this is the "Watch me" spell and not any of the rotate ones.Float Property RotateDegrees AutoTestObject TestMeEvent  OnEffectStart(Actor Target, Actor Caster)    if !Watch        if Test.RotatingBridgeClockwise            Test.RotatingBridgeClockwise = False        else            Test.RotatingBridgeClockwise = True        endif    endif    RegisterForUpdate(0.25)    if !Test.TestSubject ; If we have no test subject        Game.GetPlayer().PlaceAtMe(TestObjectType,1,False,False)    endifEndEventEvent OnEffectFinish(Actor Target, Actor Caster)    UnRegisterForUpdate()EndEventEvent OnUpdate()    if !Watch        float HowMuch = RotateDegrees        if !Test.RotatingBridgeClockwise            Howmuch *= -1        endif        If !TestMe && Test.TestSubject ; We have nothing to test, but look for one.            TestMe = Test.TestSubject as TestObject        elseif TestMe            if Roll                TestMe.RollBy(HowMuch)            elseif pitch                TestMe.PitchBy(HowMuch)            else                Testme.YawBy(HowMuch)            endif        endif    else ; Watch me spell        If !TestMe && Test.TestSubject ; We have nothing to test, but look for one.            TestMe = Test.TestSubject as TestObject        elseif TestMe            Testme.WatchMe(Game.GetPlayer())        endif    endifEndEventActivator Property TestObjectType AutoTestVariables Property Test Auto

by "Even keel" I mean, if it were a boat (or in this case, a bridge) rotating it in Yaw or Pitch or both would not change the "roll" position of the mesh. Because rotations are handled with sequential Euler rotations, if you change any two angles, the third angle is affected (in terms of roll, pitch, and yaw)

Feel free to load these functions up so you can see how they work, and if you can make a version of the WatchMe function that will rotate an object to the correct yaw AND pitch, without affecting roll, using just the information you posted, I'll be amazed beyond belief.

And that's only a small part of what I want to use it for...like I said, I want to rotate an object around any of it's three local axes without affecting the others. It's way more complicated than GetHeadingAngle can handle, particularly without a second object to act as a target.

And I don't know what GetHeadingAngle actually does, but making an object "Face" another object isn't it. Even leaving X and Y at 0.0, my test object bridge (which, as you recall, was default rotated to X Y and Z all at zero when it is summoned.) Does not turn to face me along it's initial X axis (Y axis apparently), and if I rotate X, it's behavior gets even wierder with GetHeadingAngle, even though you said it would be consistant as long as I didn't change the Y axis rotation. (Edit: Apparently this model's "Front" is -90 degrees off, correcting for that it does "Kind of" face me...but it does not aim directly AT me, which is what I'm after.

GetHeadingAngle doesn't even solve the simplest situation, the "make the arrow point directly at the target, even if it's above or below" problem, let alone keep the object upright (That's what "Even Keel" means) if it's angled upward or downward.
User avatar
Jeff Tingler
 
Posts: 3609
Joined: Sat Oct 13, 2007 7:55 pm

Post » Tue Jun 19, 2012 3:23 am

As for editing the mesh, you really think it's worth editing every single model in the game so there is a version of it with every single possible rotation axis offset, just on the off chance the player will drop one on the rotating platform? there has to be a way to make a formula to convert to local axis rotations from Euler rotations and vice versa. The CK's render window can do it...I really have no idea why they didn't include object axis rotation functions in Papyrus to begin with.
User avatar
Stephanie I
 
Posts: 3357
Joined: Thu Apr 05, 2007 3:28 pm

Post » Tue Jun 19, 2012 2:05 am

As for editing the mesh, you really think it's worth editing every single model in the game so there is a version of it with every single possible rotation axis offset, just on the off chance the player will drop one on the rotating platform?

I have no idea what you are intending to do. Describe your problem properly (that includes not hiding it in a wall of text) and there may be a solution. this is the first time you confirm that there is a rotating platform involved and now you want to drop items on that platform and move them? Sorry, I'm currently out of crystal balls.

I'm trying to help as best as I can In lieu of a proper description of the task.

I mentioned Getheadingangle because it supposedly does part of what I wrote in my posting above: Calculating the Z angle you need to turn your object if it should be able to fly to a given point. You still need to calculate the X rotation, so just forget it. The calculations in my first posting worked fine in previous games, at least in Morrowind. (Used them for an auto-targetting cannon) the y-rotation (roll) would be the "keel". In a local system it's independent of pitch and yaw.

By definition you need three points for any angle, one is defined by your system's x/y axes, the other is your object, and the third is a random point on the line you want to align your object to.

Okay... Google thinks this might help: http://wiki.tesnexus.com/index.php/Rotating_an_object_about_local_angles/axes

Skyrim has no artan2 function, but I'm not really motivated to research it right now... should work this way:
x < 0
atan2(y,x) = atan(y/x)+270
else:
atan2(y,x) = atan(y/x)+90
User avatar
Emerald Dreams
 
Posts: 3376
Joined: Sun Jan 07, 2007 2:52 pm

Post » Tue Jun 19, 2012 4:47 am

Rotating platforms is only one use for this code. What I want is, And I apollogise if it wasn't completely clear, is a series of functions that will convert local axis rotations (Roll, Pitch, Yaw) to world axis rotations (X,Y,Z) so that if I want to manipulate an object in ANY of the following ways, I can, without days of fiddling around trying to find just the right X, Y, and Z values at every "frame" of the movement.

1: Rotate an object up or down (so a self-made projectile will keep aiming at it's target if it moves above or below the plane where the projectile is, or a cart going down a hill will tilt realistically as it reaches different slopes, or a moveable bridge (like my test object) can go up or down at an angle other than the 90 degrees the animation allows smoothly, and correctly hit it's mark (and not drop the poor player into the abyss because it turned sideways halfway through the movement))
2) Spin an object along it's axis to simulate horzontal drills, rotating horizontal shafts, or anything that rotates at an angle other than 0.0, (rotates), 0.0 - and have that rotation remain consistant at any angle I care to use that item in a dungeon (So if I want my drill to be at a 45 degree pitch downward, 38 degrees yaw, I can still spin it)

The bridge idea, rotating platforms, and other things mentioned in this thread are the tip of the iceburg, and are primarily mentioned for the purpose of explaining what I need, and the problems in implementing it...I want to make a series of Roll, Pitch, Yaw tools that can have generic application in any number of special uses.

I'm looking at that link you had, and it looks promising...I'll have to convert it to Papyrus of course, and figure out how to implement Atan, but if I remember correctly, it's derived from the other Trig funtions (Sin,Cos, Tan)
User avatar
Alex Vincent
 
Posts: 3514
Joined: Thu Jun 28, 2007 9:31 pm

Post » Tue Jun 19, 2012 2:32 pm

Ouch...Trigonometry...my aching frontal lobe!

Anyone know how to implement ArcTangent(x)? I can't regress my mind back far enough to convert http://www.netlib.org/fn/atan.f to Papyrus!

At least I THINK that's basic...it has Goto statements...Could be Fortran?
User avatar
Nancy RIP
 
Posts: 3519
Joined: Mon Jan 29, 2007 5:42 am

Post » Tue Jun 19, 2012 4:27 am

OK, so ArcTan(X) is just 1/Tan(X)? at least according to Wikipedia...Well I guess I'll find out when the smoke stops coming out of my ears sometimes tomorrow night and I give it a shot...
User avatar
REVLUTIN
 
Posts: 3498
Joined: Tue Dec 26, 2006 8:44 pm

Post » Mon Jun 18, 2012 11:17 pm

nope, 1/tan(x) is the cotangent cot(x)= cos(x)/sin(x). arctan(x) is the inverse function of tan(x) and if thats not natively implemented in papyrus, you'll have bad luck implementing it by hand, since the only other expression for arctan I know is a series expansion(and believe me, thats not feasible to put in computer code...).
User avatar
Isabella X
 
Posts: 3373
Joined: Sat Dec 02, 2006 3:44 am

Post » Tue Jun 19, 2012 11:13 am

nope, 1/tan(x) is the cotangent cot(x)= cos(x)/sin(x). arctan(x) is the inverse function of tan(x) and if thats not natively implemented in papyrus, you'll have bad luck implementing it by hand, since the only other expression for arctan I know is a series expansion(and believe me, thats not feasible to put in computer code...).

Well here's the Fortran for the Atan(X) function...if your fortran is less rusty than mine (Haven't done any in nearly 20 years way back when I was in college) by all means, translate it into Papyrus for us...heh.

Spoiler
	  function inits (os, nos, eta)c april 1977 version.  w. fullerton, c3, los alamos scientific lab.cc initialize the orthogonal series so that inits is the number of termsc needed to insure the error is no larger than eta.  ordinarily, etac will be chosen to be one-tenth machine precision.cc			 input arguments --c os	 array of nos coefficients in an orthogonal series.c nos    number of coefficients in os.c eta    requested accuracy of series.c	  dimension os(nos)c	  if (nos.lt.1) call seteru (	 1  35hinits   number of coefficients lt 1, 35, 2, 2)c	  err = 0.	  do 10 ii=1,nos	    i = nos + 1 - ii	    err = err + abs(os(i))	    if (err.gt.eta) go to 20 10   continuec 20   if (i.eq.nos) call seteru (28hinits   eta may be too small, 28,	 1  1, 2)	  inits = ic	  return	  end	  function csevl (x, cs, n)c april 1977 version.  w. fullerton, c3, los alamos scientific lab.cc evaluate the n-term chebyshev series cs at x.  adapted fromc r. broucke, algorithm 446, c.a.c.m., 16, 254 (1973).  also see foxc and parker, chebyshev polys in numerical anolysis, oxford press, p.56.cc			 input arguments --c x	  value at which the series is to be evaluated.c cs	 array of n terms of a chebyshev series.  in eval-c	    uating cs, only half the first coef is summed.c n	  number of terms in array cs.c	  dimension cs(1)c	  if (n.lt.1) call seteru (28hcsevl   number of terms le 0, 28, 2,2)	  if (n.gt.1000) call seteru (31hcsevl   number of terms gt 1000,	 1  31, 3, 2)	  if (x.lt.(-1.1) .or. x.gt.1.1) call seteru (	 1  25hcsevl   x outside (-1,+1), 25, 1, 1)c	  b1 = 0.	  b0 = 0.	  twox = 2.*x	  do 10 i=1,n	    b2 = b1	    b1 = b0	    ni = n + 1 - i	    b0 = twox*b1 - b2 + cs(ni) 10   continuec	  csevl = 0.5 * (b0-b2)c	  return	  end	  REAL FUNCTION R1MACH(I)	  INTEGER ICC  SINGLE-PRECISION MACHINE CONSTANTSC  R1MACH(1) = B**(EMIN-1), THE SMALLEST POSITIVE MAGNITUDE.C  R1MACH(2) = B**EMAX*(1 - B**(-T)), THE LARGEST MAGNITUDE.C  R1MACH(3) = B**(-T), THE SMALLEST RELATIVE SPACING.C  R1MACH(4) = B**(1-T), THE LARGEST RELATIVE SPACING.C  R1MACH(5) = LOG10(B)C	  INTEGER SMALL(2)	  INTEGER LARGE(2)	  INTEGER RIGHT(2)	  INTEGER DIVER(2)	  INTEGER LOG10(2)C	 needs to be (2) for AUTODOUBLE, HARRIS SLASH 6, ...	  INTEGER SC	  SAVE SMALL, LARGE, RIGHT, DIVER, LOG10, SC	  REAL RMACH(5)	  EQUIVALENCE (RMACH(1),SMALL(1))	  EQUIVALENCE (RMACH(2),LARGE(1))	  EQUIVALENCE (RMACH(3),RIGHT(1))	  EQUIVALENCE (RMACH(4),DIVER(1))	  EQUIVALENCE (RMACH(5),LOG10(1))	  INTEGER J, K, L, T3E(3)	  DATA T3E(1) / 9777664 /	  DATA T3E(2) / 5323660 /	  DATA T3E(3) / 46980 /C  THIS VERSION ADAPTS AUTOMATICALLY TO MOST CURRENT MACHINES,C  INCLUDING AUTO-DOUBLE COMPILERS.C  TO COMPILE ON OLDER MACHINES, ADD A C IN COLUMN 1C  ON THE NEXT LINE	  DATA SC/0/C  AND REMOVE THE C FROM COLUMN 1 IN ONE OF THE SECTIONS BELOW.C  CONSTANTS FOR EVEN OLDER MACHINES CAN BE OBTAINED BYC		  mail netlib@research.bell-labs.comC		  send old1mach from blasC  PLEASE SEND CORRECTIONS TO dmg OR ehg@bell-labs.com.CC	 MACHINE CONSTANTS FOR THE HONEYWELL DPS 8/70 SERIES.C	  DATA RMACH(1) / O402400000000 /C	  DATA RMACH(2) / O376777777777 /C	  DATA RMACH(3) / O714400000000 /C	  DATA RMACH(4) / O716400000000 /C	  DATA RMACH(5) / O776464202324 /, SC/987/CC	 MACHINE CONSTANTS FOR PDP-11 FORTRANS SUPPORTINGC	 32-BIT INTEGERS (EXPRESSED IN INTEGER AND OCTAL).C	  DATA SMALL(1) /    8388608 /C	  DATA LARGE(1) / 2147483647 /C	  DATA RIGHT(1) /  880803840 /C	  DATA DIVER(1) /  889192448 /C	  DATA LOG10(1) / 1067065499 /, SC/987/C	  DATA RMACH(1) / O00040000000 /C	  DATA RMACH(2) / O17777777777 /C	  DATA RMACH(3) / O06440000000 /C	  DATA RMACH(4) / O06500000000 /C	  DATA RMACH(5) / O07746420233 /, SC/987/CC	 MACHINE CONSTANTS FOR THE UNIVAC 1100 SERIES.C	  DATA RMACH(1) / O000400000000 /C	  DATA RMACH(2) / O377777777777 /C	  DATA RMACH(3) / O146400000000 /C	  DATA RMACH(4) / O147400000000 /C	  DATA RMACH(5) / O177464202324 /, SC/987/C	  IF (SC .NE. 987) THEN*	    *** CHECK FOR AUTODOUBLE ***		 SMALL(2) = 0		 RMACH(1) = 1E13		 IF (SMALL(2) .NE. 0) THEN*		   *** AUTODOUBLED ***		    IF (	  SMALL(1) .EQ. 1117925532	 *		  .AND. SMALL(2) .EQ. -448790528) THEN*			  *** IEEE BIG ENDIAN ***			   SMALL(1) = 1048576			   SMALL(2) = 0			   LARGE(1) = 2146435071			   LARGE(2) = -1			   RIGHT(1) = 1017118720			   RIGHT(2) = 0			   DIVER(1) = 1018167296			   DIVER(2) = 0			   LOG10(1) = 1070810131			   LOG10(2) = 1352628735		    ELSE IF ( SMALL(2) .EQ. 1117925532	 *		  .AND. SMALL(1) .EQ. -448790528) THEN*			  *** IEEE LITTLE ENDIAN ***			   SMALL(2) = 1048576			   SMALL(1) = 0			   LARGE(2) = 2146435071			   LARGE(1) = -1			   RIGHT(2) = 1017118720			   RIGHT(1) = 0			   DIVER(2) = 1018167296			   DIVER(1) = 0			   LOG10(2) = 1070810131			   LOG10(1) = 1352628735		    ELSE IF ( SMALL(1) .EQ. -2065213935	 *		  .AND. SMALL(2) .EQ. 10752) THEN*			  *** VAX WITH D_FLOATING ***			   SMALL(1) = 128			   SMALL(2) = 0			   LARGE(1) = -32769			   LARGE(2) = -1			   RIGHT(1) = 9344			   RIGHT(2) = 0			   DIVER(1) = 9472			   DIVER(2) = 0			   LOG10(1) = 546979738			   LOG10(2) = -805796613		    ELSE IF ( SMALL(1) .EQ. 1267827943	 *		  .AND. SMALL(2) .EQ. 704643072) THEN*			  *** IBM MAINFRAME ***			   SMALL(1) = 1048576			   SMALL(2) = 0			   LARGE(1) = 2147483647			   LARGE(2) = -1			   RIGHT(1) = 856686592			   RIGHT(2) = 0			   DIVER(1) = 873463808			   DIVER(2) = 0			   LOG10(1) = 1091781651			   LOG10(2) = 1352628735		    ELSE			   WRITE(*,9010)			   STOP 777			   END IF		 ELSE		    RMACH(1) = 1234567.		    IF (SMALL(1) .EQ. 1234613304) THEN*			  *** IEEE ***			   SMALL(1) = 8388608			   LARGE(1) = 2139095039			   RIGHT(1) = 864026624			   DIVER(1) = 872415232			   LOG10(1) = 1050288283		    ELSE IF (SMALL(1) .EQ. -1271379306) THEN*			  *** VAX ***			   SMALL(1) = 128			   LARGE(1) = -32769			   RIGHT(1) = 13440			   DIVER(1) = 13568			   LOG10(1) = 547045274		    ELSE IF (SMALL(1) .EQ. 1175639687) THEN*			  *** IBM MAINFRAME ***			   SMALL(1) = 1048576			   LARGE(1) = 2147483647			   RIGHT(1) = 990904320			   DIVER(1) = 1007681536			   LOG10(1) = 1091781651		    ELSE IF (SMALL(1) .EQ. 1251390520) THEN*			  *** CONVEX C-1 ***			   SMALL(1) = 8388608			   LARGE(1) = 2147483647			   RIGHT(1) = 880803840			   DIVER(1) = 889192448			   LOG10(1) = 1067065499		    ELSE			   DO 10 L = 1, 3				  J = SMALL(1) / 10000000				  K = SMALL(1) - 10000000*J				  IF (K .NE. T3E(L)) GO TO 20				  SMALL(1) = J 10			   CONTINUE*			  *** CRAY T3E ***			   CALL I1MCRA(SMALL, K, 16, 0, 0)			   CALL I1MCRA(LARGE, K, 32751, 16777215, 16777215)			   CALL I1MCRA(RIGHT, K, 15520, 0, 0)			   CALL I1MCRA(DIVER, K, 15536, 0, 0)			   CALL I1MCRA(LOG10, K, 16339, 4461392, 10451455)			   GO TO 30 20		    CALL I1MCRA(J, K, 16405, 9876536, 0)			   IF (SMALL(1) .NE. J) THEN				  WRITE(*,9020)				  STOP 777				  END IF*			  *** CRAY 1, XMP, 2, AND 3 ***			   CALL I1MCRA(SMALL(1), K, 8195, 8388608, 1)			   CALL I1MCRA(LARGE(1), K, 24574, 16777215, 16777214)			   CALL I1MCRA(RIGHT(1), K, 16338, 8388608, 0)			   CALL I1MCRA(DIVER(1), K, 16339, 8388608, 0)			   CALL I1MCRA(LOG10(1), K, 16383, 10100890, 8715216)			   END IF		    END IF 30	  SC = 987		 END IF*	 SANITY CHECK	  IF (RMACH(4) .GE. 1.0) STOP 776	  IF (I .LT. 1 .OR. I .GT. 5) THEN		 WRITE(*,*) 'R1MACH(I): I =',I,' is out of bounds.'		 STOP		 END IF	  R1MACH = RMACH(I)	  RETURN 9010 FORMAT(/' Adjust autodoubled R1MACH by getting data'/	 *' appropriate for your machine from D1MACH.') 9020 FORMAT(/' Adjust R1MACH by uncommenting data statements'/	 *' appropriate for your machine.')* /* C source for R1MACH -- remove the * in column 1 */*#include *#include *#include *float r1mach_(long *i)*{*    switch(*i){*      case 1: return FLT_MIN;*      case 2: return FLT_MAX;*      case 3: return FLT_EPSILON/FLT_RADIX;*      case 4: return FLT_EPSILON;*      case 5: return log10((double)FLT_RADIX);*      }*    fprintf(stderr, "invalid argument: r1mach(%ld)\n", *i);*    exit(1); return 0; /* else complaint of missing return value */*}	  END	  SUBROUTINE I1MCRA(A, A1, B, C, D)**** SPECIAL COMPUTATION FOR CRAY MACHINES ****	  INTEGER A, A1, B, C, D	  A1 = 16777216*B + C	  A = 16777216*A1 + D	  END	  function atan (x)c jan 1978 edition.   w. fullerton, c3, los alamos scientific lab.	  dimension atancs(9), tanp8(3), conpi8(4), pi8(4)cc series for atan	   on the interval  0.		  to  4.00000d-02c									    with weighted error   1.00e-17c										 log weighted error  17.00c							   significant figures required  16.38c								    decimal places required  17.48c	  data atancs( 1) /    .4869011034 9241406e0 /	  data atancs( 2) /   -.0065108316 36717464e0 /	  data atancs( 3) /    .0000383458 28265245e0 /	  data atancs( 4) /   -.0000002687 22128762e0 /	  data atancs( 5) /    .0000000020 50093098e0 /	  data atancs( 6) /   -.0000000000 16450717e0 /	  data atancs( 7) /    .0000000000 00136509e0 /	  data atancs( 8) /   -.0000000000 00001160e0 /	  data atancs( 9) /    .0000000000 00000010e0 /cc xbndn = tan((2*n-1)*pi/16.0)	  data xbnd1 / +.1989123673 79658006 e+0					 /	  data xbnd2 / +.6681786379 19298919 e+0					 /	  data xbnd3 / +1.496605762 66548901 e+0					 /	  data xbnd4 / +5.027339492 12584810 e+0					 /cc tanp8(n) = tan(n*pi/8.)	  data tanp8(1) / .4142135623 73095048 e+0					 /	  data tanp8(2) / 1.0 e0 /	  data tanp8(3) / 2.414213562 37309504 e+0					 /cc conpi8(n) + pi8(n) = n*pi/8.0	  data conpi8(1) / 0.375 e0 /	  data conpi8(2) / 0.75 e0 /	  data conpi8(3) / 1.125 e0 /	  data conpi8(4) / 1.5   e0 /c	  data pi8   (  1) / +.1769908169 87241548 e-1					 /	  data pi8   (  2) / +.3539816339 74483096 e-1					 /	  data pi8   (  3) / +.5309724509 61724644 e-1					 /	  data pi8   (  4) / 0.0707963267 948966192 e0 /c	  data nterms, sqeps, xbig / 0, 2*0.0 /c	  if (nterms.ne.0) go to 10	  nterms = inits (atancs, 9, 0.1*r1mach(3))	  sqeps = sqrt (6.0*r1mach(3))	  xbig = 1.0/r1mach(3)c 10   y = abs(x)	  if (y.gt.xbnd1) go to 20c	  atan = x	  if (y.gt.sqeps) atan = x*(0.75+csevl(50.*y**2-1., atancs, nterms))	  returnc 20   if (y.gt.xbnd4) go to 30c	  n = 1	  if (y.gt.xbnd2) n = 2	  if (y.gt.xbnd3) n = 3c	  t = (y - tanp8(n)) / (1.0 + y*tanp8(n))	  atan = sign (conpi8(n) + (pi8(n) + t*(0.75 +	 1  csevl(50.0*t**2-1.0, atancs, nterms)) ), x)	  returnc 30   atan = conpi8(4) + pi8(4)	  if (y.lt.xbig) atan = conpi8(4) + (pi8(4) - (0.75 +	 1  csevl (50./y**2-1.0, atancs, nterms))/y )	  atan = sign (atan, x)	  returnc	  end

Written way back in 1978, when computers still used punchcards...whee!
User avatar
Enny Labinjo
 
Posts: 3480
Joined: Tue Aug 01, 2006 3:04 pm

Post » Tue Jun 19, 2012 8:07 am

Oh gawd my brain melted and leaked out of my ears, onto the floor, and dissipated into microscopic particles at a magnification that no known electron microscope can see.

I r doomed..
User avatar
Shannon Marie Jones
 
Posts: 3391
Joined: Sun Nov 12, 2006 3:19 pm

Post » Tue Jun 19, 2012 12:39 am

Oh gawd my brain melted and leaked out of my ears, onto the floor, and dissipated into microscopic particles at a magnification that no known electron microscope can see.

I r doomed..

Yours too? Dang, it must be catching, sorry...

The funny thing is, there HAS to be a set of local rotation functions built into the game, but whoever implemented papyrus didn't think anyone would ever want to realistically pitch and roll an object via scripting.

Another example: If you wanted to animate a large cannon or balista, and have it track, say, a dragon realistically (In other words, change elevation as the dragon flies up and down, and change direction to face it) you need functions like those!
User avatar
Travis
 
Posts: 3456
Joined: Wed Oct 24, 2007 1:57 am

Post » Mon Jun 18, 2012 11:42 pm

... The bridge idea, rotating platforms, and other things mentioned in this thread are the tip of the iceburg, ...

Quite true . . .

A couple of years ago I wanted something (for an Oblivion mod) that was as complex as what you need.

What I needed was to change the angles of a surface (lets say, a table) and needed to recalc the XYZ positions and angles of the objects on it, so they remained in the same relative position to each other.

Not a trivial problem. Fortunately, SkyRanger-1 helped me with the necessary math and I released a Proof of Concept mod with that math

If you think this math may help you, check the code in the file "Placing objects on moving planes" in my http://tes.nexusmods.com/downloads/file.php?id=20878 in the Nexus (and if you use it, the credits should go to SkyRanger-1)
User avatar
NAkeshIa BENNETT
 
Posts: 3519
Joined: Fri Jun 16, 2006 12:23 pm

Post » Tue Jun 19, 2012 9:19 am

SkyRanger-1 helped me with the necessary math and I released a Proof of Concept mod with that math If you think this math may help you, check the code in the file "Placing objects on moving planes" in my http://tes.nexusmods.com/downloads/file.php?id=20878 in the Nexus (and if you use it, the credits should go to SkyRanger-1)

Will an Oblivion mod load in the CK? I don't see any script files in the download...
User avatar
David Chambers
 
Posts: 3333
Joined: Fri May 18, 2007 4:30 am

Post » Mon Jun 18, 2012 11:53 pm

Oh! I assumed you had the Oblivion Construction Set to open the ESP and check the script.

Anyway, this is the script. The language should be kind of easy to figure out for anyone familiar with some other programming language.

Now, from a quick look into the script, this is not what I though it was (has been a while)
This script takes a plane of known dimensions and, based on its ZYX angles, calculates the XYZ position of the four corners.
Oblivion also uses the Euler thing, so the calculation should apply.

Spoiler

scn aaaqqPositionSCRIPTref xPlaneref xMarker1ref xMarker2ref xMarker3ref xMarker4float xPosXfloat xPosYfloat xPosZFloat xPosXplaneFloat xPosYplaneFloat xPosZplanefloat AngleXfloat AngleYfloat AngleZfloat xfloat yfloat zFloat newxFloat newyFloat newzFloat xtoxFloat ytoxFloat ztoxFloat xtoyFloat ytoyFloat ztoyFloat xtozFloat ytozFloat ztozFloat xtox2Float ytox2Float ztox2Float xtoy2Float ytoy2Float ztoy2Float xtoz2Float ytoz2Float ztoz2begin gamemode				set xPlane to aaqqMyKeysQUEST.xPlane				set xMarker1 to aaqqMyKeysQUEST.xMarker1				set xMarker2 to aaqqMyKeysQUEST.xMarker2				set xMarker3 to aaqqMyKeysQUEST.xMarker3				set xMarker4 to aaqqMyKeysQUEST.xMarker4				set xPosXplane		to xPlane.getpos X				set xPosYplane		to xPlane.getpos Y				set xPosZplane		to xPlane.getpos Z;============================================================;;															   Modder's resource code by SkyRanger-1;;============================================================			  				; GET ANGLES				Set angleZ to xPlane.GetAngle, Z				Set angleY to xPlane.GetAngle, Y				Set angleX to xPlane.GetAngle, X				; APPLY Z angle (simplified/optimized slightly since we know where the zeroes and ones were)				Set xtox to COS angleZ				Set xtoy to -1 * SIN angleZ				Set xtoz to 0				Set ytox to SIN angleZ				Set ytoy to COS angleZ				Set ytoz to 0				Set ztox to 0				Set ztoy to 0				Set ztoz to 1				; APPLY Y angle (not simplified/optimized, even though we know where a few zeros and ones were)				Set xtox2 to ( xtox * COS angleY ) + ( -1 * xtoz * SIN angleY )				Set xtoy2 to xtoy				Set xtoz2 to ( 1 * xtox * SIN angleY ) + ( xtoz * COS angleY )				Set ytox2 to ( ytox * COS angleY ) + (  -1 * ytoz * SIN angleY )				Set ytoy2 to ytoy				Set ytoz2 to ( 1 * ytox * SIN angleY ) + ( ytoz * COS angleY )				Set ztox2 to ( ztox * COS angleY ) + (  -1 * ztoz * SIN angleY )				Set ztoy2 to ztoy; TYPO, was "xtoy", should be "ztoy"				Set ztoz2 to ( 1 * ztox * SIN angleY ) + ( ztoz * COS angleY )				; APPLY X angle (cannot be simplified/optimized)				Set xtox to xtox2				Set xtoy to ( xtoy2 * COS angleX ) + ( xtoz2 * SIN angleX )				Set xtoz to ( -1 * xtoy2 * SIN angleX ) + ( xtoz2 * COS angleX )				Set ytox to ytox2; TYPO, was "ztox2", should be "ytox2"				Set ytoy to ( ytoy2 * COS angleX ) + ( ytoz2 * SIN angleX )				Set ytoz to ( -1 * ytoy2 * SIN angleX ) + ( ytoz2 * COS angleX )				Set ztox to ztox2				Set ztoy to ( ztoy2 * COS angleX ) + ( ztoz2 * SIN angleX )				Set ztoz to ( -1 * ztoy2 * SIN angleX ) + ( ztoz2 * COS angleX )				;TRANSFORM COORDINATES				;=== NE corner ===				; ORIGINAL COORDINATES OF CORNER				; change to match your object  <<<<<<<<<<<<<<<<<				Set x to 128				Set y to 128				Set z to 0				; NEW COORDINATES OF CORNER AFTER ROTATION				Set newx to x * xtox + y * ytox + z * ztox				Set newy to x * xtoy + y * ytoy + z * ztoy				Set newz to x * xtoz + y * ytoz + z * ztoz				Set xPosX to xPosXplane + newx				Set xPosY to xPosYplane + newy				Set xPosZ to xPosZplane + newz				xMarker1.setpos X xPosX				xMarker1.setpos Y xPosY				xMarker1.setpos Z xPosZ				;=== NW corner ===				; ORIGINAL COORDINATES OF CORNER				; change to match your object  <<<<<<<<<<<<<<<<<				Set x to -128				Set y to 128				Set z to 0				; NEW COORDINATES OF CORNER AFTER ROTATION				Set newx to x * xtox + y * ytox + z * ztox				Set newy to x * xtoy + y * ytoy + z * ztoy				Set newz to x * xtoz + y * ytoz + z * ztoz				Set xPosX to xPosXplane + newx				Set xPosY to xPosYplane + newy				Set xPosZ to xPosZplane + newz				xMarker2.setpos X xPosX				xMarker2.setpos Y xPosY				xMarker2.setpos Z xPosZ				;=== SW corner ===				; ORIGINAL COORDINATES OF CORNER				; change to match your object  <<<<<<<<<<<<<<<<<				Set x to -128				Set y to -128				Set z to 0				; NEW COORDINATES OF CORNER AFTER ROTATION				Set newx to x * xtox + y * ytox + z * ztox				Set newy to x * xtoy + y * ytoy + z * ztoy				Set newz to x * xtoz + y * ytoz + z * ztoz				Set xPosX to xPosXplane + newx				Set xPosY to xPosYplane + newy				Set xPosZ to xPosZplane + newz				xMarker3.setpos X xPosX				xMarker3.setpos Y xPosY				xMarker3.setpos Z xPosZ				;=== SE corner ===				; ORIGINAL COORDINATES OF CORNER				; change to match your object  <<<<<<<<<<<<<<<<<				Set x to 128				Set y to -128				Set z to 0				; NEW COORDINATES OF CORNER AFTER ROTATION				Set newx to x * xtox + y * ytox + z * ztox				Set newy to x * xtoy + y * ytoy + z * ztoy				Set newz to x * xtoz + y * ytoz + z * ztoz				Set xPosX to xPosXplane + newx				Set xPosY to xPosYplane + newy				Set xPosZ to xPosZplane + newz				xMarker4.setpos X xPosX				xMarker4.setpos Y xPosY				xMarker4.setpos Z xPosZ																																																								;			   printc "newx  %0.2f   newy  %0.2f  newz  %0.2f" newx newy newzend

And no, an Oblivion mod will nor load. If the process suits your needs, you will have to 'translate' the script to papyrus. I have not looked into Papyrus too much yet and I don't know even if it has the required trig functions.
User avatar
Taylah Illies
 
Posts: 3369
Joined: Fri Feb 09, 2007 7:13 am

Post » Tue Jun 19, 2012 11:46 am

Yours too? Dang, it must be catching, sorry...

The funny thing is, there HAS to be a set of local rotation functions built into the game, but whoever implemented papyrus didn't think anyone would ever want to realistically pitch and roll an object via scripting.

Another example: If you wanted to animate a large cannon or balista, and have it track, say, a dragon realistically (In other words, change elevation as the dragon flies up and down, and change direction to face it) you need functions like those!

You could request for these functions in the SKSE thread.
User avatar
sw1ss
 
Posts: 3461
Joined: Wed Nov 28, 2007 8:02 pm

Post » Tue Jun 19, 2012 2:56 am

Don't see any threads with SKSE here anywhere.

Well here's what I've got so far...based on the stuff posted here...unfortunately, either Jog's Atan2 function doesn't work, or there is something wrong in the code I translated into Papyrus, because it doesn't appear to emulate local rotations, and sometimes the test object goes around by large angle changes, even though I capped rotation changes at 1.0 degree per pulse...

Spoiler
Float Function Atan2(float Y, Float X) global	if x < 0		return atan(y/x)+270	else		return atan(y/x)+90	endifendfunctionFunction RotateToRPY(TestObject Rotatee,float Roll,float Pitch,float Yaw, float CapRot) global	int axisOrder =  6 ; specifes order of rotations. 1 = xyz, 2 = xzy, 3 = yxz, 4 = yzx, 5 = zxy, 6 = zyx; world angles  float X  float Y  float Z;sine and cosine of local x, y, z angles  float sinRoll  float cosRoll  float sinPitch  float cosPitch  float sinYaw  float cosYaw;the cells of the rotation matrix - two dimensional arrays not implemented in Papyrus.float[] r1 = new float[3]float[] r2 = new float[3]float[] r3 = new float[3]	sinRoll = sin(Roll)	cosRoll = cos(Roll)	sinPitch = sin(Pitch)	cosPitch = cos(Pitch)	sinYaw = sin(Yaw)	cosYaw = cos(Yaw);creation of rotation matrix in axis order	if	 (axisOrder == 1)  	;XYZ		R1[1] = ( cosPitch *  cosYaw)		R1[2] = ( cosPitch * -sinYaw)		R1[3] = (	sinPitch   )		R2[1] = ( sinRoll *  sinPitch *  cosYaw +  cosRoll *  sinYaw)		R2[2] = ( sinRoll *  sinPitch * -sinYaw +  cosRoll *  cosYaw)		R2[3] = (-sinRoll *  cosPitch)		 R3[1] = ( cosRoll * -sinPitch *  cosYaw +  sinRoll *  sinYaw)		R3[2] = ( cosRoll *  sinPitch *  sinYaw +  sinRoll *  cosYaw)		R3[3] = ( cosRoll *  cosPitch)	elseif (axisOrder == 2)	;XZY		R1[1] = ( cosYaw *  cosPitch)		R1[2] = (   -sinYaw   )		R1[3] = ( cosYaw *  sinPitch)		R2[1] = ( cosRoll *  sinYaw *  cosPitch +  cosRoll *  cosYaw)		R2[2] = ( cosRoll *  cosYaw)		R2[3] = ( cosRoll *  sinYaw *  sinPitch + -sinRoll *  cosPitch)		R3[1] = ( sinRoll *  sinYaw *  cosPitch +  cosRoll * -sinPitch)		R3[2] = ( sinRoll *  cosYaw)		R3[3] = ( sinRoll *  sinYaw *  sinPitch +  cosRoll *  cosPitch)	elseif (axisOrder == 3)	;YXZ		R1[1] = ( cosPitch *  cosYaw +  sinPitch *  sinRoll *  sinYaw)		R1[2] = ( cosPitch * -sinYaw +  sinPitch *  sinRoll *  cosYaw)		R1[3] = ( sinPitch *  cosRoll)		R2[1] = ( cosRoll *  sinYaw)		R2[2] = ( cosRoll *  cosYaw)		R2[3] = (   -sinRoll   )		R3[1] = (-sinPitch *  cosYaw +  cosPitch *  sinRoll *  sinYaw)		R3[2] = ( sinPitch *  sinYaw +  cosPitch *  sinRoll *  cosYaw)		R3[3] = ( cosPitch *  cosRoll)	elseif (axisOrder == 4)	;YZX		R1[1] = ( cosPitch *  cosYaw)		R1[2] = ( cosPitch * -sinYaw *  cosRoll +  sinPitch *  sinRoll)		R1[3] = ( cosPitch * -sinYaw * -sinRoll +  sinPitch *  cosRoll)		R2[1] = (	sinYaw   )		R2[2] = ( cosYaw *  cosRoll)		R2[3] = ( cosYaw * -sinRoll)		R3[1] = (-sinPitch *  cosYaw)		R3[2] = ( sinPitch *  sinYaw *  cosRoll +  cosPitch *  sinRoll)		R3[3] = ( sinPitch *  sinYaw * -sinRoll +  cosPitch *  cosRoll)	elseif (axisOrder == 5)	;ZXY		R1[1] = ( cosYaw *  cosPitch +  sinYaw *  sinRoll * -sinPitch)		R1[2] = (-sinYaw *  cosRoll)		R1[3] = ( cosYaw *  sinPitch +  sinYaw *  sinRoll *  cosPitch)		R2[1] = ( sinYaw *  cosPitch +  cosYaw *  sinRoll *  sinPitch)		R2[2] = ( cosYaw *  cosRoll)		R2[3] = ( sinYaw *  sinPitch +  cosYaw * -sinRoll *  cosPitch)		R3[1] = ( cosRoll * -sinPitch)		R3[2] = (   sinRoll	)		R3[3] = ( cosRoll *  cosPitch)	else	;ZYX		R1[1] = ( cosYaw *  cosPitch)		R1[2] = (-sinYaw *  cosRoll +  cosYaw *  sinPitch *  sinRoll)		R1[3] = ( sinYaw *  sinRoll +  cosYaw *  sinPitch *  cosRoll)		R2[1] = ( sinYaw *  cosPitch)		R2[2] = ( cosYaw *  cosRoll +  sinYaw *  sinPitch *  sinRoll)		R2[3] = ( cosYaw * -sinRoll +  sinYaw *  sinPitch *  cosRoll)		R3[1] = (   -sinPitch   )		R3[2] = ( cosPitch *  sinRoll)		R3[3] = ( cosPitch *  cosRoll)	endif;Extraction of worldangles from rotation matrix  if	 (R1[3] >  0.9998)	;positive gimbal lock		X = -ATan2(R3[2], R2[2])		Y = -90.0		Z = 0.0	elseif (R1[3] < -0.9998)	;negative gimbal lock		X = -ATan2( R3[2], R2[2])		Y = 90.0		Z = 0.0	else	;no gimbal lock		R2[3] = -R2[3]		R1[2] = -R1[2]		X = -ATan2(R2[3], R3[3])		Y = -ASin(R1[3])		Z = -ATan2(R1[2], R1[1])	endif	Rotatee.TranslateTo(Rotatee.X,Rotatee.Y,Rotatee.Z,X,Y,Z,1.0,CapRot)endfunction

Also, sometimes it simply doesn't move at all on a Roll call...(So far I've only called it changing one of the three at a time...once I get THAT working right, I can get into multiple changes at the same time..)even though the code is supposed to check for Gimbal Lock...
User avatar
Emily Shackleton
 
Posts: 3535
Joined: Sun Feb 11, 2007 12:36 am


Return to V - Skyrim