Advertisement
Guest User

Untitled

a guest
Jun 10th, 2017
176
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.53 KB | None | 0 0
  1. local chain = {}
  2. local maths = {}
  3. local joint = {}
  4. local rig = {}
  5.  
  6. do
  7.     function chain.new(joints, target)
  8.         local function sum(t)
  9.             local s = 0;
  10.             for _, value in ipairs(t) do
  11.                 s = s + value;
  12.             end;
  13.             return s;
  14.         end;
  15.        
  16.         local self = setmetatable({}, {__index = chain});
  17.    
  18.         local lengths = {};
  19.         for i = 1, #joints - 1 do
  20.             lengths[i] = (joints[i] - joints[i+1]).magnitude;
  21.         end;   
  22.        
  23.         self.n = #joints;
  24.         self.tolerance = 0.001;
  25.         self.target = target;
  26.         self.joints = joints;
  27.         self.lengths = lengths;
  28.         self.origin = CFrame.new(joints[1]);
  29.         self.totallength = sum(lengths);
  30.        
  31.         self.constrained = false;
  32.         self.left = math.rad(89);
  33.         self.right = math.rad(89);
  34.         self.up = math.rad(89);
  35.         self.down = math.rad(89);
  36.        
  37.         return self;
  38.     end;
  39.    
  40.     function chain:constrain(calc, line, cf)
  41.         local scalar = calc:Dot(line) / line.magnitude;
  42.         local proj = scalar * line.unit;
  43.        
  44.         -- get axis that are closest
  45.         local ups = {cf:vectorToWorldSpace(Vector3.FromNormalId(Enum.NormalId.Top)), cf:vectorToWorldSpace(Vector3.FromNormalId(Enum.NormalId.Bottom))};
  46.         local rights = {cf:vectorToWorldSpace(Vector3.FromNormalId(Enum.NormalId.Right)),  cf:vectorToWorldSpace(Vector3.FromNormalId(Enum.NormalId.Left))};
  47.         table.sort(ups, function(a, b) return (a - calc).magnitude < (b - calc).magnitude end);
  48.         table.sort(rights, function(a, b) return (a - calc).magnitude < (b - calc).magnitude end);
  49.        
  50.         local upvec = ups[1];
  51.         local rightvec = rights[1];
  52.    
  53.         -- get the vector from the projection to the calculated vector
  54.         local adjust = calc - proj;
  55.         if scalar < 0 then
  56.             -- if we're below the cone flip the projection vector
  57.             proj = -proj;
  58.         end;
  59.        
  60.         -- get the 2D components
  61.         local xaspect = adjust:Dot(rightvec);
  62.         local yaspect = adjust:Dot(upvec);
  63.        
  64.         -- get the cross section of the cone
  65.         local left = -(proj.magnitude * math.tan(self.left));
  66.         local right = proj.magnitude * math.tan(self.right);
  67.         local up = proj.magnitude * math.tan(self.up);
  68.         local down = -(proj.magnitude * math.tan(self.down));
  69.        
  70.         -- find the quadrant
  71.         local xbound = xaspect >= 0 and right or left;
  72.         local ybound = yaspect >= 0 and up or down;
  73.        
  74.         local f = calc;
  75.         -- check if in 2D point lies in the ellipse
  76.         local ellipse = xaspect^2/xbound^2 + yaspect^2/ybound^2;
  77.         local inbounds = ellipse <= 1 and scalar >= 0;
  78.        
  79.         if not inbounds then
  80.             -- get the angle of our out of ellipse point
  81.             local a = math.atan2(yaspect, xaspect);
  82.             -- find nearest point
  83.             local x = xbound * math.cos(a);
  84.             local y = ybound * math.sin(a);
  85.             -- convert back to 3D
  86.             f = (proj + rightvec * x + upvec * y).unit * calc.magnitude;
  87.         end;
  88.        
  89.         -- return our final vector
  90.         return f;
  91.     end;
  92.    
  93.     function chain:backward()
  94.         -- backward reaching; set end effector as target
  95.         self.joints[self.n] = self.target;
  96.         for i = self.n - 1, 1, -1 do
  97.             local r = (self.joints[i+1] - self.joints[i]);
  98.             local l = self.lengths[i] / r.magnitude;
  99.             -- find new joint position
  100.             local pos = (1 - l) * self.joints[i+1] + l * self.joints[i];
  101.             self.joints[i] = pos;
  102.         end;
  103.     end;
  104.    
  105.     function chain:forward()
  106.         -- forward reaching; set root at initial position
  107.         self.joints[1] = self.origin.p;
  108.         local coneVec = (self.joints[2] - self.joints[1]).unit;
  109.         for i = 1, self.n - 1 do
  110.             local r = (self.joints[i+1] - self.joints[i]);
  111.             local l = self.lengths[i] / r.magnitude;
  112.             -- setup matrix
  113.             local cf = CFrame.new(self.joints[i], self.joints[i] + coneVec);
  114.             -- find new joint position
  115.             local pos = (1 - l) * self.joints[i] + l * self.joints[i+1];
  116.             local t = self:constrain(pos - self.joints[i], coneVec, cf);
  117.             self.joints[i+1] = self.constrained and self.joints[i] + t or pos;
  118.             coneVec = self.joints[i+1] - self.joints[i];
  119.         end;
  120.     end;
  121.    
  122.     function chain:solve()
  123.         local distance = (self.joints[1] - self.target).magnitude;
  124.         if distance > self.totallength then
  125.             -- target is out of reach
  126.             for i = 1, self.n - 1 do
  127.                 local r = (self.target - self.joints[i]).magnitude;
  128.                 local l = self.lengths[i] / r;
  129.                 -- find new joint position
  130.                 self.joints[i+1] = (1 - l) * self.joints[i] + l * self.target;
  131.             end;
  132.         else
  133.             -- target is in reach
  134.             local bcount = 0;
  135.             local dif = (self.joints[self.n] - self.target).magnitude;
  136.             while dif > self.tolerance do
  137.                 self:backward();
  138.                 self:forward();
  139.                 dif = (self.joints[self.n] - self.target).magnitude;
  140.                 -- break if it's taking too long so the game doesn't freeze
  141.                 bcount = bcount + 1;
  142.                 if bcount > 10 then break; end;
  143.             end;
  144.         end;
  145.     end;
  146. end
  147.  
  148.  
  149. do
  150.     function maths.cosine(a,b,c) --a is left of the angle, b is right of the angle, c is opposite to the angle
  151.         return math.acos((a*a+b*b-c*c)/(2*a*b))
  152.     end
  153.    
  154.     function maths.projectvector(a, b)
  155.         return a - a:Dot(b.unit)*b
  156.     end
  157.  
  158.     function maths.vectortoangle(v0,v1,plane)
  159.         v0,v1 = maths.projectvector(v0.unit, plane).unit, maths.projectvector(v1.unit, plane).unit
  160.         local angle = math.acos(v0:Dot(v1))
  161.         local cross = v0:Cross(v1)
  162.         if plane:Dot(cross) < 0 then
  163.             angle = -angle
  164.         end
  165.         return angle
  166.     end
  167. end
  168.  
  169.  
  170. do
  171.     function joint.new(parent,c0,c1,p0,p1,v0)
  172.         local self = setmetatable({}, {__index = joint})
  173.        
  174.         self.weld = Instance.new("ManualWeld", parent)
  175.         self.weld.Part0 = p0
  176.         self.weld.Part1 = p1
  177.         self.weld.C0 = c0
  178.         self.weld.C1 = c1
  179.        
  180.         self.c0 = c0
  181.         self.c1 = c1
  182.         self.p0 = p0
  183.         self.p1 = p0
  184.         self.velocity = v0 or Vector3.new(1,1,1)
  185.        
  186.         return self
  187.     end
  188.    
  189.     function joint:setproperty(property, value)
  190.         if self.weld[property] then
  191.             self.weld[property] = value
  192.         end
  193.     end
  194. end
  195.  
  196.  
  197. do
  198.     function rig.new()
  199.         local self = setmetatable({}, {__index = rig})
  200.        
  201.         self.character = game.Players.LocalPlayer.Character --// Set to instantiated character
  202.         self.head = Instance.new("Part",self.character)
  203.         self.head.Size = Vector3.new(.2,.2,.2)
  204.         self.head.Transparency = 1
  205.         self.neck = joint.new(self.head, CFrame.new(0,-1.5,0), CFrame.new(), self.head, self.character.HumanoidRootPart)
  206.         self.pointTo = Instance.new("Part",self.character)
  207.         self.pointTo.Size = Vector3.new(.2,.2,.2)
  208.         self.pointJoint = joint.new(self.pointTo, CFrame.new(0,0,2), CFrame.new(), self.pointTo, self.head)
  209.         local step = 0
  210.         game:GetService("RunService").RenderStepped:connect(function()
  211.             step = step + 1
  212.             if step >= 60 then
  213.                 step = 0
  214.             end
  215.  
  216.             self.pointJoint.weld.C1 = CFrame.new(0,-step/60,0)
  217.         end)
  218.        
  219.         return self
  220.     end
  221.    
  222.     function rig:createarms()
  223.         self.rightarm = game.ReplicatedStorage.Arm:Clone()
  224.         self.rightarm.Parent = self.character
  225.         self.rightelbow = joint.new(self.rightarm.Bicep, CFrame.new(0,-.7,0), CFrame.new(0, .8, 0), self.rightarm.Bicep, self.rightarm.Forearm)
  226.         self.rightshoulder = joint.new(self.head, CFrame.new(.4,-.7,0) * CFrame.Angles(0,math.rad(180),0), CFrame.new(0,.8,0), self.head, self.rightarm.Bicep)
  227.        
  228.         self.shoulderpivot = CFrame.new(.4,-.7,0)
  229.  
  230.         self.rightarmchain = chain.new({
  231.                 Vector3.new(0,0,0),
  232.                 Vector3.new(0,1.6,0),
  233.                 Vector3.new(0,3.2,0)           
  234.         },
  235.                 Vector3.new(0,3.2,0)
  236.         )
  237.         game:GetService("RunService").RenderStepped:connect(function()
  238.             self.rightarm.Bicep.LocalTransparencyModifier = 0
  239.             self.rightarm.Forearm.LocalTransparencyModifier = 0
  240.         end)
  241.     end
  242.    
  243.     function rig:rightarmpoint()
  244.         local position = (self.head.CFrame * CFrame.new(.4,-.7,0)):toObjectSpace(self.pointTo.CFrame).p
  245.         self.rightarmchain.target = position
  246.         self.rightarmchain:solve()
  247.         local distance = (self.rightarmchain.joints[1] - self.rightarmchain.joints[3]).magnitude
  248.        
  249.         local angleOfArm1 = maths.cosine(distance, self.rightarmchain.lengths[1], self.rightarmchain.lengths[2])
  250.         local angleOfArm2 = maths.cosine(self.rightarmchain.lengths[1], self.rightarmchain.lengths[2], distance)
  251.         local ToPoint = CFrame.new( (self.head.CFrame * self.shoulderpivot).p, self.pointTo.CFrame.p).lookVector
  252.         local shoulderRotation = maths.vectortoangle(Vector3.new(0,0,-1), (self.rightarmchain.joints[3] - self.rightarmchain.joints[1]).unit, Vector3.FromNormalId(Enum.NormalId.Top))
  253.         self.rightshoulder.weld.C0 = CFrame.new(.4,0,0) * CFrame.Angles(0,shoulderRotation,0) * CFrame.Angles(angleOfArm1, 0, 0)
  254.         print(math.deg(shoulderRotation))
  255.         self.rightelbow.weld.C1 = CFrame.new(0,-.7,0) * CFrame.Angles(angleOfArm2, 0, 0)
  256.     end
  257. end
  258.  
  259. local testRig = rig.new()
  260.  
  261. testRig:createarms()
  262. while game:GetService('RunService').RenderStepped:wait() do
  263.     testRig:rightarmpoint()
  264.     local angle = game.Workspace.CurrentCamera.CFrame.lookVector.Y
  265.     testRig.neck.weld.C0 = CFrame.Angles(math.asin(-angle),0,0)
  266.     testRig.neck.weld.C1 = CFrame.new(0,1.5,0)
  267. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement