Motor animation


RE: Motor animation
#5
I try to use your 8860.lua to isolate the engine script and try my Motor_animation.lua with this

Code:
--[[

Advanced animated mechanics for the 8860 set, extensively using the aniTools module.
Copyright Roland Melkert 2017
Free for non-commercial use.
Version 2017-12-29

--]]


--==Options=============================================================================================================
--[[ local doLenStats=false --prints info about minimal needed animation length and estimates POV-Ray rendering time.
local frtA=35 --normal radiosity
local frtB=3.5*60 --HQ radiosity
local doLeftChairTiltDemo=true --left or right chair tilt demo

]]
--==Includes============================================================================================================
genTools=require('genTools')
aniTools=require('aniTools')


--==Sub actors==========================================================================================================
function initEngine(actor)

 --Engine table
 local result={}

 --Animation elements
 result.mainAxleAngle=actor:addAniElm(aniTools.aniElm(0))

 result.pistonRodPosOri={}
 result.pistonTopPosOri={}
 local m=ldc.matrix() --can use a single one as aniElm clones it.
 for i=1,4 do
   result.pistonRodPosOri[i]=actor:addAniElm(aniTools.aniElm(m))
   result.pistonTopPosOri[i]=actor:addAniElm(aniTools.aniElm(m))
 end

 result.coverVis=actor:addAniElm(aniTools.aniElm(true))
 result.coverPos=actor:addAniElm(aniTools.aniElm(0))

 --Joints
 local sf=ldc.subfile()
 local ZZ=ldc.vector(0, 0, -1) --negative to force positive angles for forward motion.
 local mainAxleRef=sf:getRef('axe_motor.ldr')
 actor:addJoint(aniTools.angleJoint(mainAxleRef, result.mainAxleAngle, ZZ))


 result.pistonRodJoint={}
 result.pistonTopJoint={}
 local c=mainAxleRef:getPos()
 for i=1,4 do
   --Use relative posOri joints for both pistons and tops.
   -- This simplifies the below maths as we can assume everything is relative to points along the main axle.
   local ref=sf:getRef('piston.ldr', i)
   c:setZ(ref:getPos():getZ())
   result.pistonRodJoint[i]=actor:addJoint(aniTools.posOriJoint(ref, result.pistonRodPosOri[i], c, false, ldc.matrix()))
   result.pistonTopJoint[i]=actor:addJoint(aniTools.posOriJoint(sf:getRef('2851.dat', i), result.pistonTopPosOri[i], c, false, ldc.matrix()))
 end

 --All axles are depended on de main engine axle, and thus normally would/could be handled in the engine apply function below.
 -- But the gearbox is depended on the resulting drive axle angle, so in order to animate that non static (gear shifts) this angle must be known/available during sequence processing.
 -- For this to be possible actions must be used, so lets define a custom one doing all axles in one go.
 result.depsAction=function(self)
   result=aniTools.depAction(0)
   result.engine=self

   result.calc=function(self, time)
   end

   return result
 end

 result.apply=function(self)

   --The pistons are always depended on a 'normal' animation element, so we can handle their final position in this apply funciton outside normal sequence processing.
   -- This allows for a slightly more efficient way of dealing with all of them in one go and removes the need to worry about it during sequencing.

   --We need to calculate their orientation changes resulting from the cylinder constrains.
   local mainAxleOri=ldc.matrix()
   mainAxleOri:setRotate(self.mainAxleAngle.value, 0, 0, -1)
   for i=1,4 do
     --All related joints maintain a center along the main axle.
     -- So we need the relative position of the piston (in rest) to that.
     local rpNeg=genTools.IF(i>2, 1, -1) --The rods are connect left and right in pairs.
     local bpNeg=genTools.IF((i%2)==0, 1, -1) --The heads go from left to right, odd being at the positive side of X

     --The rods are connected to the offcenter axle's
     local p1=ldc.vector(rpNeg*16, 0, 0)
     --Rotate it to its current position.
     p1:transform(mainAxleOri)

     --The head is normally located 60 units further away.
     local blockPos=ldc.vector(bpNeg*(60+16), 0, 0)

     --Now we get the pistons 'Y' direction in local space directly from its original reference.
     local yDir=self.pistonRodJoint[i].orgAbsPosOri:getOriYRow()
     --How far is the piston position from the line the piston moves on.
     -- getDistance also returns the (pos/neg) distance from the line's position to p1 when based upon the normalized line vector.
     local dist, mul=p1:getDistance(blockPos, yDir)
     --Use this to calculate the (shortest) position on the movement line in relation to the piston position.
     local pShort=blockPos+yDir*mul

     --These two points together with the unknown top position form a triangle.
     -- We use this to calculate the distance of the 'used' part of the movement line in relation to the nearest point on it.
     local s=math.acos(dist/60)
     s=math.sin(s)*60
     --And then use that distance to move the 'near' point along the line.
     -- which is the position of the top.
     local p2=pShort-yDir*s

     --Now we need to orientate the piston so the joint can place it correctly.
     -- Local Y goes from piston to top, note neg due to LDraw.
     local pistonY=p1-p2
     -- Local Z never changes as the axle is parallel to it, so get it from the original reference.
     local pistonZ=self.pistonRodJoint[i].orgAbsPosOri:getOriZRow()
     -- And having two, we can get the third as the crossproduct because everything needs to be perpendicular.
     local pistonX=pistonY:getCross(pistonZ)

     --Use this and the calculated position to construct a matrix.
     local posOri=ldc.matrix()
     posOri:setOriRows(pistonX, pistonY, pistonZ) --Do note we can't do it in the matrix constructor function as that expects 'columns', you could invert it later though.
     posOri:setPos(p1)
     --Apply to the aniElm
     self.pistonRodJoint[i].elm.value:set(posOri)

     --The top piston only needs its position changed, but as we are using relative joints we also need to apply the original top orientation.
     posOri:setOri(self.pistonTopJoint[i].orgAbsPosOri)
     posOri:setPos(p2)
     --Apply to the aniElm
     self.pistonTopJoint[i].elm.value:set(posOri)
   end
 end

 return result
end


--==Main actor==========================================================================================================
function carActor()

 --Start with a basic actor table.
 local result=aniTools.actor()

 --Split mechanics / control elements into logical sub tables.
 result.engine=initEngine(result) -- This handles the engine axles and pistons.

 --Override the apply function so we can do all the auto dependencies.
 -- This could also be done using custom dependency actions.
 -- But there is no real advantage to that method in a large animation like this one.

 --Buffer the default apply function as we are overriding it to do some auto dependencies.
 -- You could skip this if you don't use joints in an animation, but we do.
 result.orgApply=result.apply

 result.apply=function(self)
   self.engine:apply()

   -- The default function processes all joints so it must be called in our version too.
   self:orgApply()
 end


 return result
end

function camActor(story)

 --Initial/rest state 3rd person camera.
 local cam=ldc.camera(3, ldc.vector(46.4297, -27.8264, -53.1873),  2074.9246,  69.8029,  35.1886, 0)

 --Register it as an output camera, the returned cam object is a DIFFERENT one as it needs to be a 'linked' one.
 cam=story:addCamera(cam)

 --Create an actor for this output camera.
 result=story:addActor(aniTools.cameraActor(cam))

 --Easy to use spin action generator.
 result.spin=function(self, seq, ofs, len)
   seq:addAction(aniTools.diffAction(self.yaw, ofs, len, 360))
   return len
 end

 return result
end



--==Events==============================================================================================================
function onStart()

 movie=aniTools.story()

 local car=movie:addActor(carActor())
 print (car)
--  local cam=camActor(movie)


 --Add the main sequence to the story
 local mainSeq=movie:addSequence(aniTools.sequence());

 -- Main dependency actions.
 mainSeq:addAction(car.engine:depsAction())

 --Engine speed
 local driveSeq=aniTools.sequence()
 driveSeq:addAction(aniTools.accelAction(car.engine.mainAxleAngle, 0, 2, 0, 150))
 driveSeq:addAction(aniTools.speedAction(car.engine.mainAxleAngle, 2, nil, 150))
 driveSeq:addAction(aniTools.accelAction(car.engine.mainAxleAngle, 0, 2, 150, 0))
 driveSeq.finLen=function(self, len) self.actions[2].len=len-4  self.actions[3].ofs=len-2 end --The length of motion is set at the end of storyboarding.

 --Put together the story.
 local ofs=0
 local len=0
 local driveOfs=ofs
 mainSeq:addRef(driveSeq, ofs, nil)

 --Done setting up the story
 movie:prep() --If not here it will be automatically done in the first apply call, which might cause a 'too slow playback' error in complicated animations.

 if doLenStats then
   print('Length needed: ', ofs, ', est render time: ', genTools.round(ofs*25*frtA/60/60, 2), ' hours, HQ: ', genTools.round(ofs*25*frtB/60/60, 2), ' hours.')
 end

end

function onFrame()

 movie:apply(ldc.animation():getFrameTime())
end


--==Register============================================================================================================
function register()
 local ani=ldc.animation('Demo')
 ani:setLength(10)
 ani:setEvent('start', 'onStart')
 ani:setEvent('frame', 'onFrame')

end

register()

but I've got this message :


Code:
[string "Motor_animation.lua"]:57: Active refline link needed.


I can't solve it.
Reply
« Next Oldest | Next Newest »



Messages In This Thread
Motor animation - by NEMOOZ - 2018-07-29, 19:04
RE: Motor animation - by Roland Melkert - 2018-07-31, 11:22
RE: Motor animation - by NEMOOZ - 2018-08-07, 18:33
RE: Motor animation - by Roland Melkert - 2018-08-07, 18:49
RE: Motor animation - by NEMOOZ - 2018-09-02, 13:56
RE: Motor animation - by Roland Melkert - 2018-09-02, 19:10

Forum Jump:


Users browsing this thread: 1 Guest(s)