generic image
Processing...
  • Games
  • Catalog
  • Develop
  • Robux
  • Search in Players
  • Search in Games
  • Search in Catalog
  • Search in Groups
  • Search in Library
  • Log In
  • Sign Up
  • Games
  • Catalog
  • Develop
  • Robux
   
ROBLOX Forum » Game Creation and Development » Scripting Helpers
Home Search
 

Re: Tutorial - Some more advanced CFrame math

Previous Thread :: Next Thread 
stravant is not online. stravant
Forum Moderator
Joined: 22 Oct 2007
Total Posts: 2893
15 Dec 2011 12:17 AM
This is a brief introduction on how to do some more advanced math using CFrames than simply translating stuff by a rotation or an offset.

Note that what we're dealing with here is really Matricies,every CFrame is just a rotation matrix + a position, but I'll be calling them CFrames for simplicity.

You're already familiar with the fact that for every mathematical operation there is a special quantity which is "neutral with respect to" that operation. For example:
For addition that number is 0, that is, every number plus zero will still be that number.
For multiplication that number is 1, that is, every number times one will just be that number.

Well, CFrames as you might already know, have multiplication defined on them in a very special way. However, this special form of multiplication also has a neutral element just like addition and multiplication of normal numbers. CFrame.new() happens to return that value when you give it no arguments. And that makes sense, right? You wouldn't want to get back some arbitrary CFrame from .new(), you want a CFrame that does nothing when you apply it to other CFrames. In the case of a Part's CFrame that would mean not moving the part anywhere for example.

That is, we have the following identity for any CFrame "cf":
cf*CFrame.new() == CFrame.new()*cf == cf

Now, what about inverse operations? Most mathematical operations have some sort of inverse. For example, the inverse with respect to addition is taking the negative of a number, and the inverse with respect to multiplication is taking 1/the value. But what exactly is an inverse operation doing? What any inverse is really doing when applied to an element "x" is satisfying the following identity:
x OPERATION inverse_with_respect_to_operation(x) == the neutral element
That is to say, if you apply the operation to an element and it's inverse with respect to
that operation, you get the neutral element with respect to that operation. For example, with addition ans multiplication:
x + (-x) == 0
x * (1/x) == 1

But what if you apply this same logic to CFrames? There is a slight complication with the fact that multiplication of CFrames is "not commutative", that is to say if you take two frames "a" and "b", "a*b" won't necessarily be the same thing as "b*a", that is, it matters what order you do the CFrame multiplication in. However, aside from needing to be more careful in keeping our order constant, that doesn't change the way inverses work for CFrames: CFrame:inverse() will still give you the inverse of a CFrame. That value you get back from inverse will satisfy the same identity as before. If you take a CFrame "cf":
cf * cf:inverse() == cf:inverse() * cf == CFrame.new()

Note that here commutativity does hold, the multiplication of the CFrames does work both ways for CFrames and their inverses, but ONLY IN THIS CASE, normally it won't give you the same result if you switch the order of a CFrame multiplication.

So, now, what if we apply that to a common situation: Finding out what C0 or C1 you need for a weld to make it work. It turns out all you need to know is a bit of basic algebra, and this understanding of CFrame multiplication to do it. The first thing you need to know is that all joints in Roblox satisfy the following identity:
Part1.CFrame * C1 == Part0.CFrame * C0 * joint_effect()

Where "joint_effect()" is whatever the joint needs to do, for example in the case of welds it does nothing at all, but for motors it's equal to an extra rotation CFrame around a specific axis. Now suppose we know where to parts are, and we set the C0 to something specific, but now we want to find out what C1 to use to not move the parts, how do we do it? It turns out not to be that hard. We just start with the identity (I've just called Part0/1.CFrame Part0/1 here for brevity):

Part1*C1 == Part0*C0

Now, just like you would with normal algebra, we're going to multiply something to both sides of the equation. The only thing to be careful of we have to multiply the thing to the _same side_ of each half o the equation since order matters for CFrames. Remember, we're trying to isolate the "C1" variable since that's what we want to find. To do this we can use Part1:inverse():

Part1:inverse() * Part1*C1 == Part1:inverse() * Part0*C0

Now, remember what we said about inverses? If you multiply a CFrame and it's inverse then you get CFrame.new() back every time, so we can replace "Part1:inverse()*Part1" with just "CFrame.new()":

CFrame.new() *C1 == Part1:inverse() * Part0*C0

But then also remember what we said about the "neutral element" with respect to any operation. CFrame.new() is the neutral element, so multiplying C1 by it should have no effect whatsoever. That means we can remove it without breaking the equality:

C1 == Part1:inverse() * Part0 * C0

And we've successfully isolated the required C1 just like that. You can now plug the known values for Part1, Part0 and C0 into the multiplication to get out the C1 that you need.

And it's really as simple as that. By moving values around using inverse you can easily perform whatever algebra you need in order to find CFrames. For example, rotating a bunch of parts around an origin becomes easy with this knowledge:

We have an origin, we need to know how far the part is displaced from the origin, so:
part.CFrame = origin * displacement
so:
displacement = origin:inverse()*part.CFrame
and then we just need to apply the rotation to the origin before moving the part back:
part.CFrame = origin * rotation * displacement
Report Abuse
smurf279 is not online. smurf279
Joined: 15 Mar 2010
Total Posts: 6871
15 Dec 2011 12:34 AM
Thanks :D I saw it in Scripters but nice to have a copy here. Probably a bit too much for most of the people that aren't regulars here though :/

*Tracking
Report Abuse
tallpie is not online. tallpie
Joined: 09 Feb 2010
Total Posts: 1378
15 Dec 2011 12:35 AM
Thanks!
Report Abuse
stravant is not online. stravant
Forum Moderator
Joined: 22 Oct 2007
Total Posts: 2893
15 Dec 2011 12:34 PM
Bump
Report Abuse
bikerking200 is not online. bikerking200
Joined: 11 Mar 2010
Total Posts: 5047
15 Dec 2011 12:37 PM
Starvant, Can't you just make this a Pinned Post?

~Bikerking200 :P~
Report Abuse
Trioxide is not online. Trioxide
Joined: 29 Mar 2011
Total Posts: 32902
15 Dec 2011 12:45 PM
[ Content Deleted ]
Report Abuse
bikerking200 is not online. bikerking200
Joined: 11 Mar 2010
Total Posts: 5047
15 Dec 2011 12:49 PM
?

~Bikerking200 :P~
Report Abuse
stravant is not online. stravant
Forum Moderator
Joined: 22 Oct 2007
Total Posts: 2893
15 Dec 2011 04:12 PM
Bump
Report Abuse
xvgigakid is not online. xvgigakid
Joined: 22 Jun 2008
Total Posts: 4407
15 Dec 2011 04:16 PM
@Starvant

It looks a bit squished on the forum.
Perhaps it would be a better idea to post it on the wiki where you can organize your paragraphs.

But it is a good tutorial :/

~Dark Sky Gift of Hoarders Lover
Report Abuse
AgentFirefox is not online. AgentFirefox
Top 100 Poster
Joined: 20 Jun 2008
Total Posts: 22404
15 Dec 2011 04:20 PM
Very interesting.
Though, do you know anything regarding the rotation matrices themselves? I'd like to know how to calculate some things with the rotation components of the CFrame.
Report Abuse
TearsofUnclarity is not online. TearsofUnclarity
Joined: 13 Dec 2011
Total Posts: 141
15 Dec 2011 04:28 PM
STRAVANT. NOT STARVANT.

It's not very 'advanced', really.

Advanced would be manipulating tons of welds at once, but with your tutorial you could do that.

Good job.
Report Abuse
stravant is not online. stravant
Forum Moderator
Joined: 22 Oct 2007
Total Posts: 2893
15 Dec 2011 04:29 PM
Doing anything to do with the individual components that you can't do with just the normal multiply / add / subtract operations requires far more mathematical knowledge than I can possibly divulge in a tutorial or even a series of tutorials. And even if I could, I doubt that you really need to decompose a CFrame to do whatever it is you're interested in doing.

If you post some examples of what you would want to do I can probably show you how to solve them using the normal CFrame operations.
Report Abuse
AgentFirefox is not online. AgentFirefox
Top 100 Poster
Joined: 20 Jun 2008
Total Posts: 22404
15 Dec 2011 04:31 PM
I've been working with cameras, and using the toEulerAnglesXYZ function is not very accurate for a frame-by-frame transition from one location and focus to another. I'm wondering how I can smooth out this transition using pure math instead of archiving fixed positions/angles.
Report Abuse
pokemon771 is not online. pokemon771
Joined: 28 Oct 2008
Total Posts: 8671
15 Dec 2011 04:33 PM
Epic tutorial!
Report Abuse
stravant is not online. stravant
Forum Moderator
Joined: 22 Oct 2007
Total Posts: 2893
15 Dec 2011 04:45 PM
@AgentFirefox
That's going to be pretty tricky, and would be one of the legitimate cases. Normally how you do this is using what's called "quaternions" to represent the rotation-part since they can be easily interpolated unlike CFrames. That would look something like this:

local quat1 = toQuaternion(cf[n])
local quat2 = toQuaternion(cf[n+1])
local quat = slerp(quat1, quat2, fraction)
local newCF = toCFrame(quaternion)

(Although if you really want to try: cf:components() will give you a tuple of all of the components that make up the rotation-matrix / position of a CFrame)

That's going to take a lot of reading and implementing formulas to do, so you could always do something like this instead. It wont' be as good but it will work better than decomposing to angles:
Try taking the two CFrame's position parts, and a position say 10 studs in-front of the cameras. Now, take the directions from those offset positions, in the direction from one end-point to the other. Use those two position/direction pairs offset from the movement endpoints as the control points for a 2pointed "spline" (it's easy to implement, you can just read the Wikipedia article). Now, for every point along the line of the camera's movement, construct the CFrame at that point, and pointing at the corresponding point on the spline that you generated. That will give you decent movement and the math isn't too hard.
Report Abuse
smurf279 is not online. smurf279
Joined: 15 Mar 2010
Total Posts: 6871
18 Dec 2011 10:25 PM
"Thanks :D I saw it in Scripters but nice to have a copy here. Probably a bit too much for most of the people that aren't regulars here though :/

*Tracking"

________________________________________________________

Nevermind, didn't notice you posted this in SH not BH :/. . .
bumpp
Report Abuse
bikerking200 is not online. bikerking200
Joined: 11 Mar 2010
Total Posts: 5047
31 Dec 2011 05:53 AM
Bump.

R.I.P Ben Breedlove.
Report Abuse
AxeOfMen is not online. AxeOfMen
Joined: 14 Dec 2011
Total Posts: 196
03 Jan 2012 10:56 AM
Thank you, stravant. There is definitely a need for more advanced tutorials of this nature. I have been struggling the past few days with writing a function that I can call from script to roll a block onto its side. I have a set of four buttons with arrows pointing North, East, South, West. When a player clicks a button, I want the block to roll in that direction. The player ought to be able to click multiple buttons and have the block roll multiple times. Find my channel (username: PoisonousLlama) on YouTube to see a video depicting precisely what I am trying to accomplish.

I am attempting to create a function with the following signature:
function RollBlock(Block, Direction)
where Block is the block that will be rolled and Direction is "North", "South", "East" or "West" (these are fairly arbitrary in a x,y,z axis based world, I realize, but it's meant as a convenience for the script user)

I have been using the CFrame components to try to determine which way the block is facing and use that information to determine what vector to use to multiply with the block's CFrame.

This seems like it ought to be simple to implement and I'm overcomplicating the issue due to my lack of understanding but I could sure use some help figuring out what I'm doing wrong. Can I do this without examining the individual CFrame components to figure out how to

Here is a link to the script I have been working on:
http://www.roblox.com/Block-Roll-Script-item?id=69263373
Report Abuse
Miro034 is not online. Miro034
Joined: 07 Oct 2009
Total Posts: 6568
03 Jan 2012 11:27 AM
I guess stravant is smarter than AgentFireFox in Lua. Thanks stavant by the way.
Report Abuse
AxeOfMen is not online. AxeOfMen
Joined: 14 Dec 2011
Total Posts: 196
03 Jan 2012 01:05 PM
It looks like my video is difficult to find on you tube's search. The id is

g66pWuepWQQ
Report Abuse
stravant is not online. stravant
Forum Moderator
Joined: 22 Oct 2007
Total Posts: 2893
03 Jan 2012 02:04 PM
@Axe.

It's actually fairly simple, the trouble is probably that you're trying to do it something like this:
part.CFrame = part.CFrame*CFrame.Angles(...)

When that's fundamentally the wrong way to do it, because what that does is apply the transformation to the local coordinate system of the part, as opposed to applying it around the global axis. What you want to do is:
part.CFrame = CFrame.Angles(...)*part.CFrame

That will apply the current transformation of the part to the rotation, resulting in a rotation around the global axis rather than the local axis. Of course, it will also rotate the position of the part, so you'll have to fix that afterwards, or subtract away the position before you do the rotation, and then add it back later:
local pos = part.CFrame.p
part.CFrame = part.CFrame - pos
part.CFrame = CFrame.Angles(...)*part.CFrame
part.CFrame = part.CFrame + pos
Report Abuse
AxeOfMen is not online. AxeOfMen
Joined: 14 Dec 2011
Total Posts: 196
03 Jan 2012 06:24 PM
@Stravant

You pinpointed my problem precisely. I appreciate your attention to my concern. My final function is significantly less convoluted (not to mention that it actually works!) thanks to your guidance.

I'm very grateful
Report Abuse
SCS is not online. SCS
Forum Moderator
Joined: 24 Jun 2008
Total Posts: 10075
19 Apr 2012 09:20 PM
This is fascinating. I am looking forward to rereading this entire post numerous times in the future, until I really understand what you are saying. My problem is that, though I am familiar with (or, at least recognize) the mathematics behind this, I am no where near as familiar with it in the context of scripting. However, hopefully through time and practice, I will be able to understand this completely.

Oh, and I was also very glad to finally learn what "CFrame.new()" is and why it is multiplied by the CFrame.

Thank you for making this post, stravant.
Report Abuse
SDuke524 is not online. SDuke524
Joined: 29 Jul 2008
Total Posts: 6267
19 Apr 2012 09:36 PM
@stravant

Why does using quaternion's make the rotation better?
Report Abuse
Wowgnomes is not online. Wowgnomes
Joined: 27 Sep 2009
Total Posts: 26255
20 Apr 2012 12:58 AM
[ Content Deleted ]
Report Abuse
Previous Thread :: Next Thread 
Page 1 of 1
 
 
ROBLOX Forum » Game Creation and Development » Scripting Helpers
   
 
   
  • About Us
  • Jobs
  • Blog
  • Parents
  • Help
  • Terms
  • Privacy

©2017 Roblox Corporation. Roblox, the Roblox logo, Robux, Bloxy, and Powering Imagination are among our registered and unregistered trademarks in the U.S. and other countries.



Progress
Starting Roblox...
Connecting to Players...
R R

Roblox is now loading. Get ready to play!

R R

You're moments away from getting into the game!

Click here for help

Check Remember my choice and click Launch Application in the dialog box above to join games faster in the future!

Gameplay sponsored by:
Loading 0% - Starting game...
Get more with Builders Club! Join Builders Club
Choose Your Avatar
I have an account
generic image