How to get the correct relative angle

I want to align a prop to a ragdoll bone. My current method doesn’t work however.

Piece of the draw method of the custom entity:
[lua]
local position, angles = ply:GetBonePosition(bone)
local pitch = relative_angle.p
local yaw = relative_angle.y
local roll = relative_angle.r

angles:RotateAroundAxis(angles:Forward(), pitch)
angles:RotateAroundAxis(angles:Right(), yaw)
angles:RotateAroundAxis(angles:Up(), roll)

self:SetAngles(angles)
[/lua]
Works without a problem. My problem is retrieving the correct relative angle to use in the above code.

Currently I do this by posing the prop on the ragdoll, selecting both the desired ragdoll bone and prop (using a custom tool I made) and then retrieving and comparing their angles.

But how do I get the correct relative angle from this? I tried [prop angle] - [bone angle], but that returns incorrect values (the prop is rotated incorrect using the custom entity).

I think what you want is ent:LocalToWorld(vector) and ent:WorldToLocal(vector) ?

I’m talking about angles, not vectors. And this has nothing to do with the relativity to the world, but a relative rotation to a ragdoll bone.

Let me put is like this.

For the prop to be drawn in the right place, I need:



bone angle -> do stuff with relative angle -> result: prop angle


If I pose a ragdoll and a prop, and retrieve their angles, I have:



bone angle -> prop angle -> calculate stuff -> result: relative angle


My problem is, I don’t get the correct relative angle, probably because I’m doing something wrong with the calculations.

Angles are a real bitch. I did some work with them a while back trying to do something similiar to what you are doing. I was trying to fake a bonemerge so weapon models would be correctly positioned. It involved getting the bone position of the player’s right hand bone and getting the relative offsets of the weapon’s right hand bone, then rotating and positioning the weapon model in such a way that the reference bone and player’s right hand bone were in the same positions/angles in the world.

I can probably help you with this, but not right now since I’m at school. I’ll need access to a decent paint editor first to make some diagrams to help explain my process…

I’m glad someone wants to be of assistance. I’ve been unsuccessful in finding the right way to calculate the relative angle so far. Tried all sorts of things. It looks as if different functions handle the angles differently (negative pitch for example).

You’re rotating around the wrong axises.

It should be:
[ul]
[li]Pitch - Right[/li][li]Yaw - Up[/li][li]Roll - Forward[/li][/ul]

Hope it works now^^

Nope, it doesn’t. Angles are still fucked.

I should try to reverse RotateAroundAxis math. Should be failproof…

[editline]07:51PM[/editline]

Argh, too much linear algebra. Think I’ll just wait for J89.

Then try play around with AlignAngles

Can’t you just do something like this?

[lua] local ent = ents.Create(“entity_class”)
ent:SetModel(“path/to/model.mdl”)
ent:SetParent(self.Owner)
ent:SetPos( self.Owner:GetPos() )
ent:Spawn()
ent:Fire(“setparentattachmentmaintainoffset”, “anim_attachment_RH”, 0.01)
ent:SetAngles( ent:GetAngles() + Angle(0,5,0) )[/lua]

This places the model in your hand and it moves together with the hand, you can use +Angle() to rotate it on all axis. Or did I get something wrong?

I don’t know if they’re still bugged or not but objects parented to the player moved incorrectly a while back. From what I can tell the parented objects thought the player was a box rotating about it’s origin and didn’t take into consideration the player’s bones. So you got this weird behavior that made the parented object look like it was floating around the player moving independently.

It still does, which is why I’m attaching it to the right hand so that it behaves properly. This works perfectly well.

Just use the bone matrix.

[lua]local matrix = pl:GetBoneMatrix( bone );
matrix:Rotate( relative_angle );

local angles = matrix:GetAngle();[/lua]

Don’t think that function will be of much help.

The drawing code is fine, it’s used in all the hat scripts I’ve seen. The problem is calculating the right relative angle for that script to use, by grabbing the absolute bone angle and absolute prop angle (and their absolute positions, but that part of the script works fine) and doing something that will get me that angle.

My code is all based on being able to align props to different bones, not only the parts that have attachments.

And for relative angle I could just use [absolute prop angle] - [absolute bone angle] = relative angle?

[editline]10:24PM[/editline]

Just tried it Jinto, no dice. Angles are still way off.

[editline]10:30PM[/editline]

I really think the whole ‘[absolute prop angle] - [absolute bone angle] = relative angle’ is incorrect.
The calculation is:

angle_a rotate over angle_b = angle_c

Now I have angle_a and angle_c, how do I get angle_b?

That’s how you’re calculating relative angle? My solution works in the local coordinate space of the bone. Thus your angle value needs to be in local coordinate space as well. It should be a fixed value if you want it to follow the bone. So don’t don’t worry about calculating an angle between the prop and bone. Just figure out some fixed value in local coordinate space and pass that to rotate.

Example: Angle( 0, 0, -90 )

The resulting angle after applying that to the matrix would always be the same, regardless of bone angle.

On a side note, can you show more of your code? The code you’re using to calculate the angle, etc.

Final explanation of what I’m doing:

First I pose a ragdoll in sandbox. I spawn a prop and place it somewhere alongside its body.

[img_thumb]http://www.mr-green.nl/clavus/bone.jpg[/img_thumb]
(click to view)

Using my own bone info tool, I select a ragdoll bone and the prop.

It grabs the ragdoll bone angles and position using Entity.GetBonePosition( )

It grabs the props rotation using GetAngles( )

It then calculates the relative position and the relative angle (<- where I think the problem is) and prints this to console as a lua table. Example:



{ model = "models//gibs/hgibs.mdl", bone = "ValveBiped.Bip01_Head1", pos = Vector(0.66467, -0.94526, 2.07958), ang = Angle(80.25862, -194.19928, 118.75885) },


Now in my gamemode I use this table to spawn a sent that puts the ‘ang’ value in NetworkedAngle “angles”.

My current clientside code of this sent:

[lua]
function ENT:Draw()
if (LocalPlayer() == self:GetOwner()) then return end

local ply = self:GetOwner():GetRagdollEntity() or self:GetOwner()
local bone = ply:LookupBone(self:GetNWString("bone"))  
if bone then  
	local position, angles = ply:GetBonePosition(bone)
	
	local offset = self:GetNWVector("position")
	
	local x = angles:Up() * offset.x   
	local y = angles:Right() * offset.y  
	local z = angles:Forward() * offset.z 

	
	local matrix = ply:GetBoneMatrix( bone )
	matrix:Rotate( self:GetNWAngle("angles") )

	local angles = matrix:GetAngle()
	
	//local pitch = self:GetNWAngle("angles").p
	//local yaw = self:GetNWAngle("angles").y
	//local roll = self:GetNWAngle("angles").r
	
	//angles:RotateAroundAxis(angles:Forward(), pitch)  
	//angles:RotateAroundAxis(angles:Right(), yaw)  
	//angles:RotateAroundAxis(angles:Up(), roll) 
	
	self:SetPos(position + x + y + z)  
	self:SetAngles(angles)  

	self:DrawModel()
end 

end
[/lua]

Ingame, it draws like this:

[img_thumb]http://www.mr-green.nl/clavus/bone2.jpg[/img_thumb]
(click to view) (ignore the other two props sticking out of him)

THAT is my problem.

if it was entities, not physobjs, you could use that:
Entity.LocalToWorldAngles

or you could employ trickery and do the following:

  1. prop:SetAngles(phys:GetAngles())
  2. prop:SetAngles(prop:LocalToWorldAngles(local_angle))
    (prop being your prop, phys being the head/arm/whatever PhysObj)

btw: try PAC :slight_smile:

Ideally you’d want to apply the inverse of the bone matrix to the angle and position of the prop. That would give you the angle and position in the local coordinate space of the bone.

LocalToWorld does just that, but since we can’t just do it with a matrix ourselves you have two options. What the guy below said, or try the PhysObj:LocalToWorld.

Physics objects have a local to world method as well.

I don’t quite grasp your explanation yet, or actually, where it needs to be applied. What do I need to change in the code I posted above? Is it for the part where I retrieve the angle, or the part where the sent draws it?

I think I understand what he’s saying. To get the offset angle you grab the angles of the entity you’re positioning, then choose a physics object that is attached to the bone you want to attach to, do PhysObj:WorldToLocalAngles() and convert the angle you got earlier to local angles. Likewise, get the first entity’s position and then convert those to local angles with PhysObj:WorldToLocal().

Now that you have both the local position and angles relative to the physics object, you can move an entity to that relative position at any time by doing ent:SetPos(PhysObj:LocalToWorld(localPos)) and ent:SetAngles(PhysObj:LocalToWorldAngles(localAngles)).

Ah, but wait, do PhysObjs have a LocalToWorldAngles/WorldToLocalAngles? I’m aware they have a LocalToWorld/WorldToLocal, but…

Nope, they don’t. But isn’t there a way I can just use the GetBonePosition values I retrieved from the bone, because those are (I think) the same as its PhysicsObject. I’m pretty confused because of all the local and world angles being mixed up…