LScript (Layout) to make an object rotate around its axle dynamically on collision with a plane. Objects to be used must be designed to rotate around there pivot on its B Axis. This then allows key control over any other axis.*Master_MotionBaker compatible.
Changes
- Scaling on X,Y are averaged if not equal
- Objects to rotate must rotate around center on B axis
- Roughness has been added to add noise to surface friction
- Fully validated and interactive interface
- Fully implemented envelopes for animating all controls
- Gizmo implemented to improve setting up
- Presets added for damping, friction and roughness
- *Motion Baking implemented for quicker playback and network baking
- Motion blur is correctly calculated
- Realtime dynamicly calculated with momentum, friction, roughness, damping, braking and acceleration
- Fixed "Automatic" to retrieve correct bounding box extents
- Added Lock / Unlock
- Bake feature can now be used via Master_MotionBaker
- Fixed judder under extreme circumstances
Compatible with Newtek LightWave 9.6 and above.
// LScript Item Animation - www.StephenCulley.co.uk // // web address: http://www.stephenculley.co.uk // email address: email@stephenculley.co.uk /* LScript Item Animation - Wheel & Axle v1.0 Motion_Wheel&Axle.ls */ @version 2.2 @warnings @script motion @name *Wheel & Axle // Title sTitle = "*Wheel & Axle"; // Version sVersion = "v1.0"; // Items Item = nil; // Item GroundItem = nil; // Item GroundItemName = "nil"; // Item // Constant Scene; // Scene() // Variable bAcceleratorInvert = false; // Accelerator Invert iIteration = 0; // Iteration nLength = 1.0; // Length // Samples [1..5] aSample; // Array of Wheel Edge Samples World Position // [1] [1] = b Enable/Disable // [1] [2] = n Offset from center // [1] [3] = n Radius // [1] [4] = v World Position // [1] [5] = v Ground World Position // [1] [6] = n Distance to Ground // Envelope envAccelerator; // Accelerator envBrake; // Brake envDamping; // Damping envFriction; // Friction envMotionBaker; // Motion Baker envRoughness; // Roughness // Cache aCache; // [1] = i Frame // [2] = n time // [3] = v World Position // [4] = n Rotation // [5] = n Momentum // Motion Baker bMotionBakerLocked = false; // Locked bMotionBakerParent = false; // Parent iMotionBakerState = 2; // State // 1 = Disabled // 2 = Reset // 3 = Write // 4 = Read // Requester bRequesterUpdate; // Update iRequesterFrame; // Frame // Gizmo aCirclePoints; // Array of Points of Circle ctrl_d0,ctrl_d0i,ctrl_d1,ctrl_d2,ctrl_d3,ctrl_d4; // Dynamics ctrl_pl,ctrl_pls,ctrl_p0,ctrl_p1,ctrl_p1e,ctrl_p1o,ctrl_p1r,ctrl_p2,ctrl_p2e,ctrl_p2o,ctrl_p2r, ctrl_p3,ctrl_p3e,ctrl_p3o,ctrl_p3r,ctrl_p4,ctrl_p4e,ctrl_p4o,ctrl_p4r,ctrl_p5,ctrl_p5e,ctrl_p5o,ctrl_p5r, ctrl_p6,ctrl_p6e,ctrl_p6o,ctrl_p6r,ctrl_p7,ctrl_p7e,ctrl_p7o,ctrl_p7r,ctrl_p8,ctrl_p8e,ctrl_p8o,ctrl_p8r, ctrl_p9,ctrl_p9e,ctrl_p9o,ctrl_p9r; // Profile ctrl_mb,ctrl_mbe,ctrl_mbl; // Motion Baker /* --------------------------------------------------------------------------------------------------- CREATE --------------------------------------------------------------------------------------------------- */ create : id { // Description setdesc(sTitle); // Items Item = id; // Item // Constant Scene = Scene(); // Envelope envAccelerator = Envelope("Accelerator (Wheel&Axle)",CHAN_NUMBER,id.name); envAccelerator.persist(false); envAccelerator.createKey(0,0.0); envBrake = Envelope("Brake (Wheel&Axle)",CHAN_NUMBER,id.name); envBrake.persist(false); envBrake.createKey(0,0.0); envDamping = Envelope("Damping (Wheel&Axle)",CHAN_NUMBER,id.name); envDamping.persist(false); envDamping.createKey(0,0.05); envFriction = Envelope("Friction (Wheel&Axle)",CHAN_NUMBER,id.name); envFriction.persist(false); envFriction.createKey(0,1.0); envMotionBaker = Envelope("Motion Baker (Wheel&Axle)",CHAN_NUMBER,id.name); // Motion Baker envMotionBaker.persist(false); envRoughness = Envelope("Roughness (Wheel&Axle)",CHAN_NUMBER,id.name); envRoughness.persist(false); envRoughness.createKey(0,0.0); // Cache aCache[1] = -1; // Frame aCache[2] = 0.0; // Time aCache[3] = <0.0,0.0,0.0>; // World Position aCache[4] = 0.0; // Rotation aCache[5] = 0.0; // Momentum // Requester bRequesterUpdate = false; // Update iRequesterFrame = -1; // Frame // Comring comringattach("*MotionBaker","comring_motionbaker"); // Comring *MotionBaker // Variable nRadius = 1.0; // Radius if(id.genus == 1 && id.null == false) // Automatic { // Bounding Box aBoundingBox = Item.position(getlayernumber(Item)); // Length nLength = aBoundingBox[2].z - aBoundingBox[1].z; // Radius nRadius = 0.0; if(abs(aBoundingBox[1].x) > nRadius){nRadius = abs(aBoundingBox[1].x);} if(abs(aBoundingBox[1].y) > nRadius){nRadius = abs(aBoundingBox[1].y);} if(abs(aBoundingBox[2].x) > nRadius){nRadius = abs(aBoundingBox[2].x);} if(abs(aBoundingBox[2].y) > nRadius){nRadius = abs(aBoundingBox[2].y);} } // Sample - 1 aSample[1][1] = true; // b Enable/Disable aSample[1][2] = -0.5; // n Offset aSample[1][3] = nRadius; // n Radius aSample[1][4] = <0.0,0.0,0.0>; // v World Position aSample[1][5] = <0.0,0.0,0.0>; // v Ground World Position aSample[1][6] = 0.0; // n Distance to Ground // Sample - 2 aSample[2][1] = false; // b Enable/Disable aSample[2][2] = -0.375; // n Offset aSample[2][3] = nRadius; // n Radius aSample[2][4] = <0.0,0.0,0.0>; // v World Position aSample[2][5] = <0.0,0.0,0.0>; // v Ground World Position aSample[2][6] = 0.0; // n Distance to Ground // Sample - 3 aSample[3][1] = false; // b Enable/Disable aSample[3][2] = -0.25; // n Offset aSample[3][3] = nRadius; // n Radius aSample[3][4] = <0.0,0.0,0.0>; // v World Position aSample[3][5] = <0.0,0.0,0.0>; // v Ground World Position aSample[3][6] = 0.0; // n Distance to Ground // Sample - 4 aSample[4][1] = false; // b Enable/Disable aSample[4][2] = -0.125; // n Offset aSample[4][3] = nRadius; // n Radius aSample[4][4] = <0.0,0.0,0.0>; // v World Position aSample[4][5] = <0.0,0.0,0.0>; // v Ground World Position aSample[4][6] = 0.0; // n Distance to Ground // Sample - 5 aSample[5][1] = true; // b Enable/Disable aSample[5][2] = 0.0; // n Offset aSample[5][3] = nRadius; // n Radius aSample[5][4] = <0.0,0.0,0.0>; // v World Position aSample[5][5] = <0.0,0.0,0.0>; // v Ground World Position aSample[5][6] = 0.0; // n Distance to Ground // Sample - 6 aSample[6][1] = false; // b Enable/Disable aSample[6][2] = 0.125; // n Offset aSample[6][3] = nRadius; // n Radius aSample[6][4] = <0.0,0.0,0.0>; // v World Position aSample[6][5] = <0.0,0.0,0.0>; // v Ground World Position aSample[6][6] = 0.0; // n Distance to Ground // Sample - 7 aSample[7][1] = false; // b Enable/Disable aSample[7][2] = 0.25; // n Offset aSample[7][3] = nRadius; // n Radius aSample[7][4] = <0.0,0.0,0.0>; // v World Position aSample[7][5] = <0.0,0.0,0.0>; // v Ground World Position aSample[7][6] = 0.0; // n Distance to Ground // Sample - 8 aSample[8][1] = false; // b Enable/Disable aSample[8][2] = 0.375; // n Offset aSample[8][3] = nRadius; // n Radius aSample[8][4] = <0.0,0.0,0.0>; // v World Position aSample[8][5] = <0.0,0.0,0.0>; // v Ground World Position aSample[8][6] = 0.0; // n Distance to Ground // Sample - 9 aSample[9][1] = true; // b Enable/Disable aSample[9][2] = 0.5; // n Offset aSample[9][3] = nRadius; // n Radius aSample[9][4] = <0.0,0.0,0.0>; // v World Position aSample[9][5] = <0.0,0.0,0.0>; // v Ground World Position aSample[9][6] = 0.0; // n Distance to Ground // Gizmo nDegree = 0; for(d = 0; d <= 32; d++) { vPoint =; aCirclePoints[d + 1] = vPoint; // Store vertex nDegree += 360 / 32; // Add Division } aCirclePoints[33] = aCirclePoints[1]; // Add copy of first point } /* --------------------------------------------------------------------------------------------------- DESTROY --------------------------------------------------------------------------------------------------- */ destroy { // Comring comringdetach("*MotionBaker"); // Comring *MotionBaker } /* --------------------------------------------------------------------------------------------------- COMRING --------------------------------------------------------------------------------------------------- */ comring_motionbaker: event,data { // Parent ParentItem = Item.parent; iParent = 1; while(ParentItem != nil) { iParent++; ParentItem = ParentItem.parent; } if(event != 0 && event != iParent) { return; } sMessage = comringdecode(@"s:200"@,data); if(strlower(sMessage) == "lock") // Lock { bMotionBakerLocked = true; } if(strlower(sMessage) == "unlock") // Unlock { bMotionBakerLocked = false; } if(strlower(sMessage) == "disable" && !bMotionBakerLocked) // Disable { iMotionBakerState = 1; } if(strlower(sMessage) == "reset" && !bMotionBakerLocked) // Reset { iMotionBakerState = 2; } if(strlower(sMessage) == "write" && !bMotionBakerLocked) // Write { iMotionBakerState = 3; } if(strlower(sMessage) == "read" && !bMotionBakerLocked) // Read { iMotionBakerState = 4; } if(strlower(sMessage) == "parent" && !bMotionBakerLocked) // Parent { bMotionBakerParent = true; } if(strlower(sMessage) == "bake" && !bMotionBakerLocked) // Bake { motionbaker_bake(); // Bake iMotionBakerState = 1; // Disable bMotionBakerLocked = true; // Lock } // Requester if(reqisopen()) { bRequesterUpdate = true; // Update setvalue(ctrl_mb,iMotionBakerState); // Motion Baker State setvalue(ctrl_mbl,bMotionBakerLocked); // Motion Baker Locked bRequesterUpdate = false; // Update } } /* --------------------------------------------------------------------------------------------------- BAKE --------------------------------------------------------------------------------------------------- */ motionbaker_bake { envChannel = Envelope("Rotation.B",CHAN_NUMBER,Item.name); // B if(envChannel != nil) { for(frame = Scene().previewstart;frame <= Scene().previewend; frame++) { time = (1 / Scene().fps) * frame; iKey = envChannel.keyExists(time); if(iKey == nil) {envChannel.createKey(time, envMotionBaker.value(time) * (3.1415926535 / 180));} else {envChannel.setKeyValue(iKey,envMotionBaker.value(time) * (3.1415926535 / 180));} } } info(Item.name + " baked"); // Info Refresh(); // Refresh } /* --------------------------------------------------------------------------------------------------- PROCESS --------------------------------------------------------------------------------------------------- */ process: ma, frame, time { /* ------------------------------------------------------------------------------- Item ------------------------------------------------------------------------------- */ // Ground Item if(GroundItemName != "nil") {GroundItem = Mesh(GroundItemName); GroundItemName = "nil";} // ---------------------------------------------------------------------- end - /* ------------------------------------------------------------------------------- Requester ------------------------------------------------------------------------------- */ if(reqisopen() && iRequesterFrame != frame) { bRequesterUpdate = true; // Update setvalue(ctrl_d0,envAccelerator.value(Scene.currenttime)); // Accelerator setvalue(ctrl_d1,envBrake.value(Scene.currenttime)); // Brake setvalue(ctrl_d2,envDamping.value(Scene.currenttime)); // Damping setvalue(ctrl_d3,envFriction.value(Scene.currenttime)); // Friction setvalue(ctrl_d4,envRoughness.value(Scene.currenttime)); // Roughness iRequesterFrame = frame; // Frame bRequesterUpdate = false; // Update } // ---------------------------------------------------------------------- end - /* ------------------------------------------------------------------------------- Iteration ------------------------------------------------------------------------------- */ // Iteration iIteration++; if(aCache[1] <> frame) { iIteration = 1; } // ---------------------------------------------------------------------- end - /* ------------------------------------------------------------------------------- Motion Baker Disabled ------------------------------------------------------------------------------- */ if(iMotionBakerState == 1) { return; } // ---------------------------------------------------------------------- end - /* ------------------------------------------------------------------------------- Motion Baker Parent ------------------------------------------------------------------------------- */ if(bMotionBakerParent) { // Parent ParentItem = Item.parent; iParent = 1; while(ParentItem != nil) { iParent++; ParentItem = ParentItem.parent; } sMessage = "*parent"; cMessage = comringencode(@"s:200"@,sMessage); comringmsg("*MotionBaker",iParent,cMessage); bMotionBakerParent = false; } // ---------------------------------------------------------------------- end - /* ------------------------------------------------------------------------------- Motion Baker Reset ------------------------------------------------------------------------------- */ if(iMotionBakerState == 2) { nAxleMomentum = 0.0; // Momentum aCache[1] = frame; // Frame aCache[2] = time; // Time aCache[3] = ma.get(WPOSITION,time); // World Position aCache[4] = ma.get(ROTATION,time).z; // Rotation aCache[5] = 0.0; // Momentum // Motion Baker Write iKey = envMotionBaker.keyExists((1 / Scene.fps) * frame); if(iKey == nil) {envMotionBaker.createKey((1 / Scene.fps) * frame, aCache[4]);} else {envMotionBaker.setKeyValue(iKey,aCache[4]);} // Motion Baker State iMotionBakerState = 3; // Motion Baker Write if(reqisopen()) { bRequesterUpdate = true; // Update setvalue(ctrl_mb,iMotionBakerState); // Motion Baker bRequesterUpdate = false; // Update } } // ---------------------------------------------------------------------- end - /* ------------------------------------------------------------------------------- Motion Baker Read ------------------------------------------------------------------------------- */ if(iMotionBakerState == 3 && iIteration > 1) // Write { vRotation = ma.get(ROTATION,time); // Rotation vRotation.z = aCache[4]; // B Channel ma.set(ROTATION,vRotation); return; } if(iMotionBakerState == 4) // Read { vRotation = ma.get(ROTATION,time); // Rotation vRotation.z = envMotionBaker.value(time); // B Channel ma.set(ROTATION,vRotation); return; } // ---------------------------------------------------------------------- end - /* ------------------------------------------------------------------------------- Process ------------------------------------------------------------------------------- */ // Variable nCircumference = 0.0; // Circumference nDiameter = 0.0; // Diameter nDistanceToGround = 999999999999999.0; // Distance to ground nDistanceDegree = 0.0; // Distance per degree nRadius = 0.0; // Radius nRotation = 0.0; // Wheel Rotation vWorldPosition = ma.get(WPOSITION,time); // World Position vRotation = ma.get(ROTATION,time); // Rotation vScaling = ma.get(SCALING,time); // Scaling vNearest = <0.0,0.0,0.0>; vGroundNearest = <0.0,0.0,0.0>; vnRight = normalize3D(Item.getRight(time)); vnUp = normalize3D(Item.getUp(time)); vnForward = normalize3D(Item.getForward(time)); // Ground Item if(GroundItem) { vGroundWorldPosition = GroundItem.getWorldPosition(time); vnGround = normalize3D(GroundItem.getUp(time)); } else { vGroundWorldPosition = <0.0,0.0,0.0>; // World Position vnGround = <0.0,1.0,0.0>; // Up Vector } // Nearest Ground / Axle vGroundNearest = pointplane3D(vWorldPosition,vGroundWorldPosition,vnGround); vnToGround = normalize3D(vGroundNearest - vWorldPosition); // Vector Normal to Ground vNearest = pointplane3D(vGroundNearest,vWorldPosition,vnForward); vnToward = normalize3D(vWorldPosition - vNearest); // Vector Normal towards center vnAway = normalize3D(vNearest - vWorldPosition); // Vector Normal away from center // Samples // [1] [1] = b Enable/Disable // [1] [2] = n Offset from center // [1] [3] = n Radius // [1] [4] = v World Position // [1] [5] = v Ground World Position // [1] [6] = n Distance to Ground for(s = 1; s <= 9; s++) { if(aSample[s][1]) { aSample[s][4] = vWorldPosition + (vnAway * (aSample[s][3] * ((vScaling.x + vScaling.y) * 0.5))) + (vnForward * (nLength * aSample[s][2] * vScaling.z)); // v World Position aIntersection = lineplaneintersect3D(aSample[s][4],vnToGround,vGroundWorldPosition,vnGround); // Intersection with ground aSample[s][5] = aIntersection[3]; // v Ground World Position aSample[s][6] = aIntersection[2]; // n Distance to Ground if(aSample[s][6] < nDistanceToGround) { nRadius = aSample[s][3]; // n Radius vNearest = aSample[s][4]; // v World Position vGroundNearest = aSample[s][5]; // v Ground World Position nDistanceToGround = aSample[s][6]; // n Distant to ground nDiameter = 2 * nRadius; // Diameter nCircumference = 3.1415926535 * nDiameter; // Circumference if(nCircumference <> 0.0){nDistanceDegree = 360 / nCircumference;} else {nDistanceDegree = 0.0;} // Distance per degree } } } // Motion nMotionDistance = distance3D(aCache[3],vWorldPosition); // Distance frame to frame vnMotionDirection = normalize3D(aCache[3] - vWorldPosition); // Direction Vector // Rotation vnDirectionForwardCrossProduct = normalize3D(crossproduct3D(vnMotionDirection,vnForward)); vnForwardAlignCrossProduct = normalize3D(crossproduct3D(vnMotionDirection,vnDirectionForwardCrossProduct)); if(bAcceleratorInvert) { nAccelerator = -envAccelerator.value(time); // Accelerator } else { nAccelerator = envAccelerator.value(time); // Accelerator } nBrake = 1.0 - clip(0,1.0,envBrake.value(time)); // Brake nDamping = 1.0 - clip(0,1.0,envDamping.value(time)); // Damping nFriction = clip(0,1.0,envFriction.value(time)); // Friction nSlip = abs(dotproduct3D(vnForwardAlignCrossProduct,vnForward)); // Slip nVelocity = dotproduct3D(-vnDirectionForwardCrossProduct,vnGround); // Velocity nRoughness = 1.0 - (randu() * clip(0,1.0,envRoughness.value(time))); // Roughness // Moment if(nDistanceToGround <= 0.0) { // in contact nMomentum = maxmin(maxmin((nDistanceDegree * nMotionDistance * nVelocity * nSlip * (nFriction * (nRoughness * nFriction))),(aCache[5] * (nDamping * (1.0 - (nFriction * (nRoughness * nFriction)))))),nAccelerator) * nBrake; } else { // free wheel nMomentum = maxmin(aCache[5] * nDamping,nAccelerator) * nBrake; } // Rotation nRotation = aCache[4] + nMomentum; // Compound rotation vRotation.z = nRotation; // Rotation // ---------------------------------------------------------------------- end - /* ------------------------------------------------------------------------------- MA ------------------------------------------------------------------------------- */ ma.set(ROTATION,vRotation); // ---------------------------------------------------------------------- end - /* ------------------------------------------------------------------------------- Motion Baker Write ------------------------------------------------------------------------------- */ iKey = envMotionBaker.keyExists((1 / Scene.fps) * frame); if(iKey == nil) {envMotionBaker.createKey((1 / Scene.fps) * frame, nRotation);} else {envMotionBaker.setKeyValue(iKey,nRotation);} // ---------------------------------------------------------------------- end - /* ------------------------------------------------------------------------------- Cache ------------------------------------------------------------------------------- */ aCache[1] = frame; // Frame aCache[2] = time; // Time aCache[3] = vWorldPosition; // World Position aCache[4] = nRotation; // Rotation aCache[5] = nMomentum; // Momentum // ---------------------------------------------------------------------- end - } // CLIP clip: min,max,n { if(n < min) n = min; if(n > max) n = max; return(n); } // CONVERSIONS DEGtoRAD: n // Degree to radian { return(n * (3.1415926535 / 180)); } RADtoDEG: n // Radian to degree { return(n * (180 / 3.1415926535)); } // MAP RANGE maprange01: n1,n2,i { if(n2-n1 == 0.0){return(0.0);} else {return((1/(n2-n1)) * (i-n1));} } // MAX MIN maxmin: n1,n2 { if(n1 < 0.0 && n2 < 0.0){return(min(n1,n2));} // Min else if(n1 >= 0.0 && n2 >= 0.0){return(max(n1,n2));} // Max else {return(n1 + n2);} } // VECTOR 3D crossproduct3D: v1,v2 // v { // Vector return( ); } distance3D: v1, v2 // n { // Vector return(sqrt(((v2.x - v1.x) * (v2.x - v1.x)) + ((v2.y - v1.y) * (v2.y - v1.y)) + ((v2.z - v1.z) * (v2.z - v1.z)))); } dotproduct3D: v1,v2 // n { // Vector return(v1.x * v2.x + v1.y * v2.y + v1.z * v2.z); } lineplanedistance3D: v1,vn1,v2,vn2 // n { // Vector - v1 v2 is Vector / vn1 vn2 is Vector Normal nNumerator = dotproduct3D(vn2,v1) + dotproduct3D(-v2,vn2); nDenomimator = dotproduct3D(vn2,vn1); if(nDenomimator <> 0.0){return(-(nNumerator / nDenomimator));} else{return(0.0);} } lineplaneintersect3D: v1,vn1,v2,vn2 // a[1] b (true / false) // a[2] n (distance) // a[3] v (vector) { // Vector - v1 v2 is Vector / vn1 vn2 is Vector Normal nNumerator = dotproduct3D(vn2,v1) + dotproduct3D(-v2,vn2); nDenomimator = dotproduct3D(vn2,vn1); if(nDenomimator <> 0.0){nDistance = -(nNumerator / nDenomimator);} else{ nDistance = 0.0;} if(nDistance >= 0.0){a[1] = true;}else{a[1] = false;} // True / False a[2] = nDistance; // Distance a[3] = v1 + (vn1 * nDistance); // Vector return(a); } pointplane3D: v1,v2,vn2 // v { // Vector - v1 is Vector / v2 is Vector on Plane / vn2 is Vector Normal on Plane return(v1 + (dotproduct3D(vn2,v2) - dotproduct3D(vn2,v1)) * vn2); } normal3D: v1,v2 // vn { // Vector return( ); } magnitude3D: v // n { // Vector return(sqrt((v.x * v.x) + (v.y * v.y) + (v.z * v.z))); } normalize3D: v // v { // Vector normalize to 0 - 1 nMagnitude = magnitude3D(v); if(nMagnitude <> 0) nMagnitude = 1 / nMagnitude; return(v * nMagnitude); } // ITEM getlayernumber: item { if(item.totallayers == 1){return(1);} sTokens = parse(":",item.name); iLayer = 0; if (strleft(sTokens[2],5)=="Layer") { iLayer = integer(sTokens[2]); } else { iTotal = item.totallayers; for(i = 1; i <= iTotal; i++) { if(item.layerVisible(i) == 1) { if(item.layerName(i) == sTokens[2]) { iLayer = i; break; } } else { iTotal++; } } } return iLayer; } /* --------------------------------------------------------------------------------------------------- LOAD --------------------------------------------------------------------------------------------------- */ load: what,io { if(what == SCENEMODE) // processing an ASCII scene file { if(io.read().asStr() == sTitle + " " + sVersion) { bAcceleratorInvert = io.read().asInt(); // Accelerator Invert nLength = io.read().asNum(); // Length // Samples for(s = 1; s <= 9; s++) { aSample[s][1] := io.read().asInt(); // b Enable/Disable aSample[s][2] := io.read().asNum(); // n Offset aSample[s][3] := io.read().asNum(); // n Radius } // Item GroundItemName = io.read().asStr(); // Motion Baker bMotionBakerLocked = io.read().asInt(); // Motion Baker Locked iMotionBakerState = io.read().asInt(); // Motion Baker State // Envelope envAccelerator.load(); // Accelerator envBrake.load(); // Brake envDamping.load(); // Damping envFriction.load(); // Friction envMotionBaker.load(); // Motion Baker envRoughness.load(); // Roughness } else { info(sTitle + " - Error"); } } } /* --------------------------------------------------------------------------------------------------- SAVE --------------------------------------------------------------------------------------------------- */ save: what,io { if(what == SCENEMODE) { // Header io.writeln(sTitle + " " + sVersion); io.writeln(bAcceleratorInvert); // Accelerator Invert io.writeln(nLength); // Length // Samples for(s = 1; s <= 9; s++) { io.writeln(aSample[s][1]); // b Enable/Disable io.writeln(aSample[s][2]); // n Offset io.writeln(aSample[s][3]); // n Radius } // Item if(GroundItem != nil) { io.writeln(string(GroundItem.name)); } else { io.writeln("nil"); } // Motion Baker io.writeln(bMotionBakerLocked); // Motion Baker Locked io.writeln(iMotionBakerState); // Motion Baker State // Envelope envAccelerator.save(); // Accelerator envBrake.save(); // Brake envDamping.save(); // Damping envFriction.save(); // Friction envMotionBaker.save(); // Motion Baker envRoughness.save(); // Roughness } } /* --------------------------------------------------------------------------------------------------- OPTIONS --------------------------------------------------------------------------------------------------- */ options { if(reqisopen()) { reqend(); return; } // Variable iVar = 0; reqbegin(sTitle + " " + sVersion + " - " + Item.name); reqsize(300,390); ctrl_tab = ctltab("Profile","Dynamics","*Motion Baker","Developer"); // Profile ctrl_p0 = ctlinfo(298,100,"draw_profile"); // Profile Preview ctrl_pb0 = ctlbutton("Reset",50,"button_reset"); // Button Reset ctrl_pb1 = ctlbutton("Automatic",50,"button_automatic"); // Button Automatic ctrl_pb2 = ctlbutton("Mirror 1..4 > 6..9",50,"button_mirror"); // Button Mirror ctrl_pb3 = ctlbutton("S",20,"button_profile_save"); // Button Profile Save ctrl_pb4 = ctlbutton("L",20,"button_profile_load"); // Button Profile Load ctrl_pls = ctlminislider(" ",iVar,-100,100); ctrl_pl = ctldistance("Length (Section Width)",nLength); // Length ctrl_p1o = ctlminislider(" ",iVar,-100,100); // Sample 1 ctrl_p1r = ctlminislider(" ",iVar,-100,100); ctrl_p1 = ctldistance("1) Radius",aSample[1][3]); ctrl_p1e = ctlcheckbox("Enable",aSample[1][1]); ctrl_p2o = ctlminislider(" ",iVar,-100,100); // Sample 2 ctrl_p2r = ctlminislider(" ",iVar,-100,100); ctrl_p2 = ctldistance("2) Radius",aSample[2][3]); ctrl_p2e = ctlcheckbox("Enable",aSample[2][1]); ctrl_p3o = ctlminislider(" ",iVar,-100,100); // Sample 3 ctrl_p3r = ctlminislider(" ",iVar,-100,100); ctrl_p3 = ctldistance("3) Radius",aSample[3][3]); ctrl_p3e = ctlcheckbox("Enable",aSample[3][1]); ctrl_p4o = ctlminislider(" ",iVar,-100,100); // Sample 4 ctrl_p4r = ctlminislider(" ",iVar,-100,100); ctrl_p4 = ctldistance("4) Radius",aSample[4][3]); ctrl_p4e = ctlcheckbox("Enable",aSample[4][1]); ctrl_p5o = ctlminislider(" ",iVar,-100,100); // Sample 5 ctrl_p5r = ctlminislider(" ",iVar,-100,100); ctrl_p5 = ctldistance("5) Radius",aSample[5][3]); ctrl_p5e = ctlcheckbox("Enable",aSample[5][1]); ctrl_p6o = ctlminislider(" ",iVar,-100,100); // Sample 6 ctrl_p6r = ctlminislider(" ",iVar,-100,100); ctrl_p6 = ctldistance("6) Radius",aSample[6][3]); ctrl_p6e = ctlcheckbox("Enable",aSample[6][1]); ctrl_p7o = ctlminislider(" ",iVar,-100,100); // Sample 7 ctrl_p7r = ctlminislider(" ",iVar,-100,100); ctrl_p7 = ctldistance("7) Radius",aSample[7][3]); ctrl_p7e = ctlcheckbox("Enable",aSample[7][1]); ctrl_p8o = ctlminislider(" ",iVar,-100,100); // Sample 8 ctrl_p8r = ctlminislider(" ",iVar,-100,100); ctrl_p8 = ctldistance("8) Radius",aSample[8][3]); ctrl_p8e = ctlcheckbox("Enable",aSample[8][1]); ctrl_p9o = ctlminislider(" ",iVar,-100,100); // Sample 9 ctrl_p9r = ctlminislider(" ",iVar,-100,100); ctrl_p9 = ctldistance("9) Radius",aSample[9][3]); ctrl_p9e = ctlcheckbox("Enable",aSample[9][1]); // Profile ctlposition(ctrl_p0,1,28,299,100); // Profile Preview ctlposition(ctrl_pb0,2,130,41,20); // Button Reset ctlposition(ctrl_pb1,45,130,58,20); // Button Automatic ctlposition(ctrl_pb2,105,130,90,20); // Button Mirror ctlposition(ctrl_pb3,250,130,20,20); // Button Profile Save ctlposition(ctrl_pb4,272,130,20,20); // Button Profile Load ctlposition(ctrl_pls,260,162,10,20); // Length Slider ctlposition(ctrl_pl,60,162,212,20,130); // Length ctlposition(ctrl_p1o,188,184,10,20); // Sample 1 ctlposition(ctrl_p1r,168,184,10,20); ctlposition(ctrl_p1,8,184,172,20); ctlposition(ctrl_p1e,224,184,68,20); ctlposition(ctrl_p2o,188,206,10,20); // Sample 2 ctlposition(ctrl_p2r,168,206,10,20); ctlposition(ctrl_p2,8,206,172,20); ctlposition(ctrl_p2e,224,206,68,20); ctlposition(ctrl_p3o,188,228,10,20); // Sample 3 ctlposition(ctrl_p3r,168,228,10,20); ctlposition(ctrl_p3,8,228,172,20); ctlposition(ctrl_p3e,224,228,68,20); ctlposition(ctrl_p4o,188,250,10,20); // Sample 4 ctlposition(ctrl_p4r,168,250,10,20); ctlposition(ctrl_p4,8,250,172,20); ctlposition(ctrl_p4e,224,250,68,20); ctlposition(ctrl_p5o,188,272,10,20); // Sample 5 ctlposition(ctrl_p5r,168,272,10,20); ctlposition(ctrl_p5,8,272,172,20); ctlposition(ctrl_p5e,224,272,68,20); ctlposition(ctrl_p6o,188,294,10,20); // Sample 6 ctlposition(ctrl_p6r,168,294,10,20); ctlposition(ctrl_p6,8,294,172,20); ctlposition(ctrl_p6e,224,294,68,20); ctlposition(ctrl_p7o,188,316,10,20); // Sample 7 ctlposition(ctrl_p7r,168,316,10,20); ctlposition(ctrl_p7,8,316,172,20); ctlposition(ctrl_p7e,224,316,68,20); ctlposition(ctrl_p8o,188,338,10,20); // Sample 8 ctlposition(ctrl_p8r,168,338,10,20); ctlposition(ctrl_p8,8,338,172,20); ctlposition(ctrl_p8e,224,338,68,20); ctlposition(ctrl_p9o,188,360,10,20); // Sample 9 ctlposition(ctrl_p9r,168,360,10,20); ctlposition(ctrl_p9,8,360,172,20); ctlposition(ctrl_p9e,224,360,68,20); ctlpage(1,ctrl_p0,ctrl_pb0,ctrl_pb1,ctrl_pb2,ctrl_pb3,ctrl_pb4,ctrl_pls,ctrl_pl,ctrl_p1r,ctrl_p1o,ctrl_p1e,ctrl_p1,ctrl_p1e, ctrl_p2o,ctrl_p2r,ctrl_p2,ctrl_p2e,ctrl_p3o,ctrl_p3r,ctrl_p3,ctrl_p3e,ctrl_p4o,ctrl_p4r,ctrl_p4,ctrl_p4e, ctrl_p5o,ctrl_p5r,ctrl_p5,ctrl_p5e,ctrl_p6o,ctrl_p6r,ctrl_p6,ctrl_p6e,ctrl_p7o,ctrl_p7r,ctrl_p7,ctrl_p7e, ctrl_p8o,ctrl_p8r,ctrl_p8,ctrl_p8e,ctrl_p9o,ctrl_p9r,ctrl_p9,ctrl_p9e); // Profile // Dynamics ctrl_d0 = ctlangle("Accelerator",envAccelerator.value(Scene.currenttime)); // Accelerator ctrl_d0i = ctlcheckbox("Invert",bAcceleratorInvert); // Accelerator Invert ctrl_d0e = ctlbutton("E",20,"button_d0e"); // Button ctrl_d1 = ctlpercent("Brake",envBrake.value(Scene.currenttime)); // Brake ctrl_d1e = ctlbutton("E",20,"button_d1e"); // Button ctrl_d2 = ctlpercent("Damping",envDamping.value(Scene.currenttime)); // Damping ctrl_d2e = ctlbutton("E",20,"button_d2e"); // Button ctrl_d3 = ctlpercent("Friction",envFriction.value(Scene.currenttime)); // Friction ctrl_d3e = ctlbutton("E",20,"button_d3e"); // Button ctrl_d4 = ctlpercent("Roughness",envRoughness.value(Scene.currenttime)); // Roughness ctrl_d4e = ctlbutton("E",20,"button_d4e"); // Button ctrl_d5 = ctlpopup("Preset", 1, @"Rubber - Tarmac", "Rubber - Gravel", "Rubber - Snow", "Rubber - Ice", "Rollerskate - Tarmac", "Plastic - Plastic"@); // Ground ctrl_g0 = ctlsep(); ctrl_g1 = ctlmeshitems("Ground Item",GroundItem); ctlposition(ctrl_d0,36,32,152,20,100); // Accelerator ctlposition(ctrl_d0i,212,32,58,20); // Accelerator Invert ctlposition(ctrl_d0e,272,32,20,20); // Accelerator Button ctlposition(ctrl_d1,36,54,212,20,100); // Brake ctlposition(ctrl_d1e,272,54,20,20); // Brake Button ctlposition(ctrl_d2,36,76,212,20,100); // Damping ctlposition(ctrl_d2e,272,76,20,20); // Damping Button ctlposition(ctrl_d3,36,98,212,20,100); // Friction ctlposition(ctrl_d3e,272,98,20,20); // Friction Button ctlposition(ctrl_d4,36,120,212,20,100); // Roughness ctlposition(ctrl_d4e,272,120,20,20); // Roughness Button ctlposition(ctrl_d5,36,142,256,20,100); // Preset ctlposition(ctrl_g0,0,174,300,4); // Seperator ctlposition(ctrl_g1,36,188,256,20,100); // Ground Item ctlpage(2,ctrl_d0,ctrl_d0i,ctrl_d0e,ctrl_d1,ctrl_d1e,ctrl_d2,ctrl_d2e,ctrl_d3,ctrl_d3e,ctrl_d4,ctrl_d4e,ctrl_d5,ctrl_g0,ctrl_g1); // Dynamics // Motion Baker ctrl_mb = ctlchoice("State",iMotionBakerState,@"Disable","Reset","Write","Read"@); // Choice ctrl_mbe = ctlbutton("E",20,"button_mbe"); // Button ctrl_mbl = ctlcheckbox("Lock",bMotionBakerLocked); // Checkbox ctlposition(ctrl_mb,10,32,260,20,60); // Choice ctlposition(ctrl_mbe,272,32,20,20); // Button ctlposition(ctrl_mbl,220,58,72,20); // Checkbox ctlpage(3,ctrl_mb,ctrl_mbe,ctrl_mbl); // Developer ctrl_dev = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk"); ctlposition(ctrl_dev,10,350,280,20,100); ctlpage(4,ctrl_dev); // Refresh ctlrefresh(ctrl_pl,"refresh_pl"); // Length ctlrefresh(ctrl_pls,"refresh_pls"); // Length Slider ctlrefresh(ctrl_p1,"refresh_p1"); // Radius ctlrefresh(ctrl_p1r,"refresh_p1r"); // Radius Slider ctlrefresh(ctrl_p1o,"refresh_p1o"); // Offset Slider ctlrefresh(ctrl_p1e,"refresh_p1e"); // Enable ctlrefresh(ctrl_p2,"refresh_p2"); // Radius ctlrefresh(ctrl_p2r,"refresh_p2r"); // Radius Slider ctlrefresh(ctrl_p2o,"refresh_p2o"); // Offset Slider ctlrefresh(ctrl_p2e,"refresh_p2e"); // Enable ctlrefresh(ctrl_p3,"refresh_p3"); // Radius ctlrefresh(ctrl_p3r,"refresh_p3r"); // Radius Slider ctlrefresh(ctrl_p3o,"refresh_p3o"); // Offset Slider ctlrefresh(ctrl_p3e,"refresh_p3e"); // Enable ctlrefresh(ctrl_p4,"refresh_p4"); // Radius ctlrefresh(ctrl_p4r,"refresh_p4r"); // Radius Slider ctlrefresh(ctrl_p4o,"refresh_p4o"); // Offset Slider ctlrefresh(ctrl_p4e,"refresh_p4e"); // Enable ctlrefresh(ctrl_p5,"refresh_p5"); // Radius ctlrefresh(ctrl_p5r,"refresh_p5r"); // Radius Slider ctlrefresh(ctrl_p5o,"refresh_p5o"); // Offset Slider ctlrefresh(ctrl_p5e,"refresh_p5e"); // Enable ctlrefresh(ctrl_p6,"refresh_p6"); // Radius ctlrefresh(ctrl_p6r,"refresh_p6r"); // Radius Slider ctlrefresh(ctrl_p6o,"refresh_p6o"); // Offset Slider ctlrefresh(ctrl_p6e,"refresh_p6e"); // Enable ctlrefresh(ctrl_p7,"refresh_p7"); // Radius ctlrefresh(ctrl_p7r,"refresh_p7r"); // Radius Slider ctlrefresh(ctrl_p7o,"refresh_p7o"); // Offset Slider ctlrefresh(ctrl_p7e,"refresh_p7e"); // Enable ctlrefresh(ctrl_p8,"refresh_p8"); // Radius ctlrefresh(ctrl_p8r,"refresh_p8r"); // Radius Slider ctlrefresh(ctrl_p8o,"refresh_p8o"); // Offset Slider ctlrefresh(ctrl_p8e,"refresh_p8e"); // Enable ctlrefresh(ctrl_p9,"refresh_p9"); // Radius ctlrefresh(ctrl_p9r,"refresh_p9r"); // Radius Slider ctlrefresh(ctrl_p9o,"refresh_p9o"); // Offset Slider ctlrefresh(ctrl_p9e,"refresh_p9e"); // Enable ctlrefresh(ctrl_d0,"refresh_d0"); // Accelerator ctlrefresh(ctrl_d0i,"refresh_d0i"); // Accelerator Invert ctlrefresh(ctrl_d1,"refresh_d1"); // Brake ctlrefresh(ctrl_d2,"refresh_d2"); // Damping ctlrefresh(ctrl_d3,"refresh_d3"); // Friction ctlrefresh(ctrl_d4,"refresh_d4"); // Roughness ctlrefresh(ctrl_d5,"refresh_d5"); // Preset ctlrefresh(ctrl_g1,"refresh_g1"); // Ground Item ctlrefresh(ctrl_mb,"refresh_mb"); // Motion Baker State ctlrefresh(ctrl_mbl,"refresh_mbl"); // Motion Baker Locked reqopen(); } button_reset { bAcceleratorInvert = false; // Accelerator Invert // Sample - 1 aSample[1][1] = true; // b Enable/Disable aSample[1][2] = -0.5; // n Offset aSample[1][3] = 1.0; // n Radius // Sample - 2 aSample[2][1] = false; // b Enable/Disable aSample[2][2] = -0.375; // n Offset aSample[2][3] = 1.0; // n Radius // Sample - 3 aSample[3][1] = false; // b Enable/Disable aSample[3][2] = -0.25; // n Offset aSample[3][3] = 1.0; // n Radius // Sample - 4 aSample[4][1] = false; // b Enable/Disable aSample[4][2] = -0.125; // n Offset aSample[4][3] = 1.0; // n Radius // Sample - 5 aSample[5][1] = true; // b Enable/Disable aSample[5][2] = 0.0; // n Offset aSample[5][3] = 1.0; // n Radius // Sample - 6 aSample[6][1] = false; // b Enable/Disable aSample[6][2] = 0.125; // n Offset aSample[6][3] = 1.0; // n Radius // Sample - 7 aSample[7][1] = false; // b Enable/Disable aSample[7][2] = 0.25; // n Offset aSample[7][3] = 1.0; // n Radius // Sample - 8 aSample[8][1] = false; // b Enable/Disable aSample[8][2] = 0.375; // n Offset aSample[8][3] = 1.0; // n Radius // Sample - 9 aSample[9][1] = true; // b Enable/Disable aSample[9][2] = 0.5; // n Offset aSample[9][3] = 1.0; // n Radius setvalue(ctrl_pl,1.0); // Length setvalue(ctrl_p1,aSample[1][3]); // Sample 1 setvalue(ctrl_p1e,aSample[1][1]); setvalue(ctrl_p2,aSample[2][3]); // Sample 2 setvalue(ctrl_p2e,aSample[2][1]); setvalue(ctrl_p3,aSample[3][3]); // Sample 3 setvalue(ctrl_p3e,aSample[3][1]); setvalue(ctrl_p4,aSample[4][3]); // Sample 4 setvalue(ctrl_p4e,aSample[4][1]); setvalue(ctrl_p5,aSample[5][3]); // Sample 5 setvalue(ctrl_p5e,aSample[5][1]); setvalue(ctrl_p6,aSample[6][3]); // Sample 6 setvalue(ctrl_p6e,aSample[6][1]); setvalue(ctrl_p7,aSample[7][3]); // Sample 7 setvalue(ctrl_p7e,aSample[7][1]); setvalue(ctrl_p8,aSample[8][3]); // Sample 8 setvalue(ctrl_p8e,aSample[8][1]); setvalue(ctrl_p9,aSample[9][3]); // Sample 9 setvalue(ctrl_p9e,aSample[9][1]); // Motion Baker iMotionBakerState = 3; // Write // Envelope while(envAccelerator.keyCount >= 1) { envAccelerator.deleteKey(envAccelerator.keys[1]); } envAccelerator.createKey(0,0.0); setvalue(ctrl_d0,0.0); // Accelerator setvalue(ctrl_d0i,0); // Accelerator Invert while(envBrake.keyCount >= 1) { envBrake.deleteKey(envBrake.keys[1]); } envBrake.createKey(0,0.0); setvalue(ctrl_d1,0.0); // Brake while(envDamping.keyCount >= 1) { envDamping.deleteKey(envDamping.keys[1]); } envDamping.createKey(0,0.01); setvalue(ctrl_d2,0.05); // Damping while(envFriction.keyCount >= 1) { envFriction.deleteKey(envFriction.keys[1]); } envFriction.createKey(0,1.0); setvalue(ctrl_d3,1.0); // Friction while(envRoughness.keyCount >= 1) { envRoughness.deleteKey(envRoughness.keys[1]); } envRoughness.createKey(0,0.0); setvalue(ctrl_d4,0.0); // Roughness } button_automatic { if(Item.genus != 1) // Check for Mesh { error("*Wheel & Axle - Must be attached to an object to use automatic."); return; } if(Item.null == true) // Check for Null { error("*Wheel & Axle - Must be attached to an object to use automatic."); return; // Check for Mesh } // Bounding Box aBoundingBox = Item.position(getlayernumber(Item)); // Length nLength = aBoundingBox[2].z - aBoundingBox[1].z; // Radius nRadius = 0.0; if(abs(aBoundingBox[1].x) > nRadius){nRadius = abs(aBoundingBox[1].x);} if(abs(aBoundingBox[1].y) > nRadius){nRadius = abs(aBoundingBox[1].y);} if(abs(aBoundingBox[2].x) > nRadius){nRadius = abs(aBoundingBox[2].x);} if(abs(aBoundingBox[2].y) > nRadius){nRadius = abs(aBoundingBox[2].y);} // Sample - 1 aSample[1][1] = true; // b Enable/Disable aSample[1][2] = -0.5; // n Offset aSample[1][3] = nRadius; // n Radius // Sample - 2 aSample[2][1] = false; // b Enable/Disable aSample[2][2] = -0.375; // n Offset aSample[2][3] = nRadius; // n Radius // Sample - 3 aSample[3][1] = false; // b Enable/Disable aSample[3][2] = -0.25; // n Offset aSample[3][3] = nRadius; // n Radius // Sample - 4 aSample[4][1] = false; // b Enable/Disable aSample[4][2] = -0.125; // n Offset aSample[4][3] = nRadius; // n Radius // Sample - 5 aSample[5][1] = true; // b Enable/Disable aSample[5][2] = 0.0; // n Offset aSample[5][3] = nRadius; // n Radius // Sample - 6 aSample[6][1] = false; // b Enable/Disable aSample[6][2] = 0.125; // n Offset aSample[6][3] = nRadius; // n Radius // Sample - 7 aSample[7][1] = false; // b Enable/Disable aSample[7][2] = 0.25; // n Offset aSample[7][3] = nRadius; // n Radius // Sample - 8 aSample[8][1] = false; // b Enable/Disable aSample[8][2] = 0.375; // n Offset aSample[8][3] = nRadius; // n Radius // Sample - 9 aSample[9][1] = true; // b Enable/Disable aSample[9][2] = 0.5; // n Offset aSample[9][3] = nRadius; // n Radius setvalue(ctrl_pl,nLength); // Length setvalue(ctrl_p1,nRadius); // Sample 1 setvalue(ctrl_p1e,1); setvalue(ctrl_p2,nRadius); // Sample 2 setvalue(ctrl_p2e,0); setvalue(ctrl_p3,nRadius); // Sample 3 setvalue(ctrl_p3e,0); setvalue(ctrl_p4,nRadius); // Sample 4 setvalue(ctrl_p4e,0); setvalue(ctrl_p5,nRadius); // Sample 5 setvalue(ctrl_p5e,1); setvalue(ctrl_p6,nRadius); // Sample 6 setvalue(ctrl_p6e,0); setvalue(ctrl_p7,nRadius); // Sample 7 setvalue(ctrl_p7e,0); setvalue(ctrl_p8,nRadius); // Sample 8 setvalue(ctrl_p8e,0); setvalue(ctrl_p9,nRadius); // Sample 9 setvalue(ctrl_p9e,1); } button_mirror { // Sample - 1 to 9 aSample[9][1] = aSample[1][1]; // b Enable/Disable aSample[9][2] = -aSample[1][2]; // n Offset aSample[9][3] = aSample[1][3]; // n Radius // Sample - 2 to 8 aSample[8][1] = aSample[2][1]; // b Enable/Disable aSample[8][2] = -aSample[2][2]; // n Offset aSample[8][3] = aSample[2][3]; // n Radius // Sample - 3 to 7 aSample[7][1] = aSample[3][1]; // b Enable/Disable aSample[7][2] = -aSample[3][2]; // n Offset aSample[7][3] = aSample[3][3]; // n Radius // Sample - 4 to 6 aSample[6][1] = aSample[4][1]; // b Enable/Disable aSample[6][2] = -aSample[4][2]; // n Offset aSample[6][3] = aSample[4][3]; // n Radius // Sample - 5 aSample[5][2] = 0.0; // n Offset setvalue(ctrl_p6,aSample[6][3]); // Sample 6 setvalue(ctrl_p6e,aSample[6][1]); setvalue(ctrl_p7,aSample[7][3]); // Sample 7 setvalue(ctrl_p7e,aSample[7][1]); setvalue(ctrl_p8,aSample[8][3]); // Sample 8 setvalue(ctrl_p8e,aSample[8][1]); setvalue(ctrl_p9,aSample[9][3]); // Sample 9 setvalue(ctrl_p9e,aSample[9][1]); } button_profile_save { filename = getfile("Save Profile","*.prf",,0); if(filename != nil) { if(filename == "") return; if((file = File(filename,"w")) == nil) return; file.writeln("*Wheel & Axle" + sVersion + " - Profile"); file.writeln(nLength); // Length // Samples for(s = 1; s <= 9; s++) { file.writeln(aSample[s][1]); // b Enable/Disable file.writeln(aSample[s][2]); // n Offset file.writeln(aSample[s][3]); // n Radius } file.close(); } } button_profile_load { filename = getfile("Load Profile","*.prf",,1); if(filename != nil) { if(filename == "") return; if((file = File(filename,"r")) == nil) return; if(file.linecount()) { line = file.read(); if(line == "*Wheel & Axle" + sVersion + " - Profile") { nLength = file.read().asNum(); // Length // Samples for(s = 1; s <= 9; s++) { aSample[s][1] = file.read().asInt(); // b Enable/Disable aSample[s][2] = file.read().asNum(); // n Offset aSample[s][3] = file.read().asNum(); // n Radius } setvalue(ctrl_pl,nLength); // Length setvalue(ctrl_p1,aSample[1][3]); // Sample 1 setvalue(ctrl_p1e,aSample[1][1]); setvalue(ctrl_p2,aSample[2][3]); // Sample 2 setvalue(ctrl_p2e,aSample[2][1]); setvalue(ctrl_p3,aSample[3][3]); // Sample 3 setvalue(ctrl_p3e,aSample[3][1]); setvalue(ctrl_p4,aSample[4][3]); // Sample 4 setvalue(ctrl_p4e,aSample[4][1]); setvalue(ctrl_p5,aSample[5][3]); // Sample 5 setvalue(ctrl_p5e,aSample[5][1]); setvalue(ctrl_p6,aSample[6][3]); // Sample 6 setvalue(ctrl_p6e,aSample[6][1]); setvalue(ctrl_p7,aSample[7][3]); // Sample 7 setvalue(ctrl_p7e,aSample[7][1]); setvalue(ctrl_p8,aSample[8][3]); // Sample 8 setvalue(ctrl_p8e,aSample[8][1]); setvalue(ctrl_p9,aSample[9][3]); // Sample 9 setvalue(ctrl_p9e,aSample[9][1]); } } file.close(); } } refresh_pls:value // Length Slider { setvalue(ctrl_pl,clip(0.0,9999999999,nLength + value *.001)); setvalue(ctrl_pls,0); } refresh_pl:value // Length { nLength = clip(0.0,9999999999,value); setvalue(ctrl_pl,nLength); } refresh_p1:value // Sample 1 { aSample[1][3] = clip(0.0,9999999999,value); setvalue(ctrl_p1,aSample[1][3]); requpdate(ctrl_p0); // Update } refresh_p1r:value // Sample 1 { setvalue(ctrl_p1,clip(0.0,9999999999,aSample[1][3] + value *.001)); setvalue(ctrl_p1r,0); } refresh_p1o:value // Sample 1 { aSample[1][2] = clip(-999.0,aSample[2][2] - 0.001,aSample[1][2] + value *.001); setvalue(ctrl_p1o,0); requpdate(ctrl_p0); // Update } refresh_p1e:value // Sample 1 { aSample[1][1] = value; requpdate(ctrl_p0); // Update } refresh_p2:value // Sample 2 { aSample[2][3] = clip(0.0,9999999999,value); setvalue(ctrl_p2,aSample[2][3]); requpdate(ctrl_p0); // Update } refresh_p2r:value // Sample 2 { setvalue(ctrl_p2,clip(0.0,9999999999,aSample[2][3] + value *.001)); setvalue(ctrl_p2r,0); } refresh_p2o:value // Sample 2 { aSample[2][2] = clip(aSample[1][2] + 0.001,aSample[3][2] - 0.001,aSample[2][2] + value *.001); setvalue(ctrl_p2o,0); requpdate(ctrl_p0); // Update } refresh_p2e:value // Sample 2 { aSample[2][1] = value; requpdate(ctrl_p0); // Update } refresh_p3:value // Sample 3 { aSample[3][3] = clip(0.0,9999999999,value); setvalue(ctrl_p3,aSample[3][3]); requpdate(ctrl_p0); // Update } refresh_p3r:value // Sample 3 { setvalue(ctrl_p3,clip(0.0,9999999999,aSample[3][3] + value *.001)); setvalue(ctrl_p3r,0); } refresh_p3o:value // Sample 3 { aSample[3][2] = clip(aSample[2][2] + 0.001,aSample[4][2] - 0.001,aSample[3][2] + value *.001); setvalue(ctrl_p3o,0); requpdate(ctrl_p0); // Update } refresh_p3e:value // Sample 3 { aSample[3][1] = value; requpdate(ctrl_p0); // Update } refresh_p4:value // Sample 4 { aSample[4][3] = clip(0.0,9999999999,value); setvalue(ctrl_p4,aSample[4][3]); requpdate(ctrl_p0); // Update } refresh_p4r:value // Sample 4 { setvalue(ctrl_p4,clip(0.0,9999999999,aSample[4][3] + value *.001)); setvalue(ctrl_p4r,0); } refresh_p4o:value // Sample 4 { aSample[4][2] = clip(aSample[3][2] + 0.001,aSample[5][2] - 0.001,aSample[4][2] + value *.001); setvalue(ctrl_p4o,0); requpdate(ctrl_p0); // Update } refresh_p4e:value // Sample 4 { aSample[4][1] = value; requpdate(ctrl_p0); // Update } refresh_p5:value // Sample 5 { aSample[5][3] = clip(0.0,9999999999,value); setvalue(ctrl_p5,aSample[5][3]); requpdate(ctrl_p0); // Update } refresh_p5r:value // Sample 5 { setvalue(ctrl_p5,clip(0.0,9999999999,aSample[5][3] + value *.001)); setvalue(ctrl_p5r,0); } refresh_p5o:value // Sample 5 { aSample[5][2] = clip(aSample[4][2] + 0.001,aSample[6][2] - 0.001,aSample[5][2] + value *.001); setvalue(ctrl_p5o,0); requpdate(ctrl_p0); // Update } refresh_p5e:value // Sample 5 { aSample[5][1] = value; requpdate(ctrl_p0); // Update } refresh_p6:value // Sample 6 { aSample[6][3] = clip(0.0,9999999999,value); setvalue(ctrl_p6,aSample[6][3]); requpdate(ctrl_p0); // Update } refresh_p6r:value // Sample 6 { setvalue(ctrl_p6,clip(0.0,9999999999,aSample[6][3] + value *.001)); setvalue(ctrl_p6r,0); } refresh_p6o:value // Sample 6 { aSample[6][2] = clip(aSample[5][2] + 0.001,aSample[7][2] - 0.001,aSample[6][2] + value *.001); setvalue(ctrl_p6o,0); requpdate(ctrl_p0); // Update } refresh_p6e:value // Sample 6 { aSample[6][1] = value; requpdate(ctrl_p0); // Update } refresh_p7:value // Sample 7 { aSample[7][3] = clip(0.0,9999999999,value); setvalue(ctrl_p7,aSample[7][3]); requpdate(ctrl_p0); // Update } refresh_p7r:value // Sample 7 { setvalue(ctrl_p7,clip(0.0,9999999999,aSample[7][3] + value *.001)); setvalue(ctrl_p7r,0); } refresh_p7o:value // Sample 7 { aSample[7][2] = clip(aSample[6][2] + 0.001,aSample[8][2] - 0.001,aSample[7][2] + value *.001); setvalue(ctrl_p7o,0); requpdate(ctrl_p0); // Update } refresh_p7e:value // Sample 7 { aSample[7][1] = value; requpdate(ctrl_p0); // Update } refresh_p8:value // Sample 8 { aSample[8][3] = clip(0.0,9999999999,value); setvalue(ctrl_p8,aSample[8][3]); requpdate(ctrl_p0); // Update } refresh_p8r:value // Sample 8 { setvalue(ctrl_p8,clip(0.0,9999999999,aSample[8][3] + value *.001)); setvalue(ctrl_p8r,0); } refresh_p8o:value // Sample 8 { aSample[8][2] = clip(aSample[7][2] + 0.001,aSample[9][2] - 0.001,aSample[8][2] + value *.001); setvalue(ctrl_p8o,0); requpdate(ctrl_p0); // Update } refresh_p8e:value // Sample 8 { aSample[8][1] = value; requpdate(ctrl_p0); // Update } refresh_p9:value // Sample 9 { aSample[9][3] = clip(0.0,9999999999,value); setvalue(ctrl_p9,aSample[9][3]); requpdate(ctrl_p0); // Update } refresh_p9r:value // Sample 9 { setvalue(ctrl_p9,clip(0.0,9999999999,aSample[9][3] + value *.001)); setvalue(ctrl_p9r,0); } refresh_p9o:value // Sample 9 { aSample[9][2] = clip(aSample[8][2] + 0.001,999.0,aSample[9][2] + value *.001); setvalue(ctrl_p9o,0); requpdate(ctrl_p0); // Update } refresh_p9e:value // Sample 9 { aSample[9][1] = value; requpdate(ctrl_p0); // Update } refresh_d0:value // Accelerator { if(bRequesterUpdate) return; // Requester Update iKey = envAccelerator.keyExists(Scene.currenttime); if(iKey == nil) {envAccelerator.createKey(Scene.currenttime,value);} else {envAccelerator.setKeyValue(iKey,value);} } refresh_d0i:value // Accelerator Invert { bAcceleratorInvert = value; // Accelerator Invert } button_d0e // Accelerator { envAccelerator.edit(); } refresh_d1:value // Brake { if(bRequesterUpdate) return; // Requester Update setvalue(ctrl_d1,clip(0.0,1.0,value)); iKey = envBrake.keyExists(Scene.currenttime); if(iKey == nil) {envBrake.createKey(Scene.currenttime,clip(0.0,1.0,value));} else {envBrake.setKeyValue(iKey,clip(0.0,1.0,value));} } button_d1e // Brake { envBrake.edit(); } refresh_d2:value // Damping { if(bRequesterUpdate) return; // Requester Update setvalue(ctrl_d2,clip(0.0,1.0,value)); iKey = envDamping.keyExists(Scene.currenttime); if(iKey == nil) {envDamping.createKey(Scene.currenttime,clip(0.0,1.0,value));} else {envDamping.setKeyValue(iKey,clip(0.0,1.0,value));} } button_d2e // Damping { envDamping.edit(); } refresh_d3:value // Friction { if(bRequesterUpdate) return; // Requester Update setvalue(ctrl_d3,clip(0.0,1.0,value)); iKey = envFriction.keyExists(Scene.currenttime); if(iKey == nil) {envFriction.createKey(Scene.currenttime,clip(0.0,1.0,value));} else {envFriction.setKeyValue(iKey,clip(0.0,1.0,value));} } button_d3e // Friction { envFriction.edit(); } refresh_d4:value // Roughness { if(bRequesterUpdate) return; // Requester Update setvalue(ctrl_d4,clip(0.0,1.0,value)); iKey = envRoughness.keyExists(Scene.currenttime); if(iKey == nil) {envRoughness.createKey(Scene.currenttime,clip(0.0,1.0,value));} else {envRoughness.setKeyValue(iKey,clip(0.0,1.0,value));} } button_d4e // Roughness { envRoughness.edit(); } refresh_d5:value { if(value == 1) // Rubber - Tarmac { setvalue(ctrl_d2,0.025); // Damping setvalue(ctrl_d3,0.975); // Friction setvalue(ctrl_d4,0.2); // Roughness } if(value == 2) // Rubber - Gravel { setvalue(ctrl_d2,0.025); // Damping setvalue(ctrl_d3,0.9); // Friction setvalue(ctrl_d4,0.5); // Roughness } if(value == 3) // Rubber - Snow { setvalue(ctrl_d2,0.025); // Damping setvalue(ctrl_d3,0.75); // Friction setvalue(ctrl_d4,0.1); // Roughness } if(value == 4) // Rubber - Ice { setvalue(ctrl_d2,0.025); // Damping setvalue(ctrl_d3,0.5); // Friction setvalue(ctrl_d4,0.1); // Roughness } if(value == 5) // Rollerskate - Tarmac { setvalue(ctrl_d2,0.005); // Damping setvalue(ctrl_d3,0.975); // Friction setvalue(ctrl_d4,0.2); // Roughness } if(value == 6) // Plastic - Plastic { setvalue(ctrl_d2,0.05); // Damping setvalue(ctrl_d3,0.9); // Friction setvalue(ctrl_d4,0.0); // Roughness } } refresh_g1:value { GroundItem = value; } refresh_mb: value // Motion Baker State { if(bRequesterUpdate) return; // Requester Update iMotionBakerState = value; } button_mbe // Motion Baker Envelope { envMotionBaker.edit(); } refresh_mbl: value // Motion Baker Locked { if(bRequesterUpdate) return; // Requester Update bMotionBakerLocked = value; } draw_profile { // Background drawbox(<127,127,127>,0,0,298,100); // Border drawline(<0,0,0>,0,0,297,0); drawline(<0,0,0>,297,0,297,99); drawline(<0,0,0>,297,99,0,99); drawline(<0,0,0>,0,99,0,0); // Variables aXY = nil; // array of points enabled. nMinX = 0.0; // Min X nMaxX = 0.0; // Max X nMaxY = 0.0001; // Max Y // Min / Max for(s = 1; s <= 9; s++) { if(aSample[s][2] < nMinX) nMinX = aSample[s][2]; // Min X if(aSample[s][2] > nMaxX) nMaxX = aSample[s][2]; // Max X if(aSample[s][3] > nMaxY && aSample[s][1]) nMaxY = aSample[s][3]; // Max Y } nYMultiplier = 1 / nMaxY; // Draw 0 iX = (277 * maprange01(nMinX,nMaxX,0.0)) + 10; // X drawline(<117,117,117>,iX,30,iX,68); drawtext("- 0 0 +",<117,117,117>,iX - 15,43); // Draw Samples (Disabled) for(s = 1; s <= 9; s++) { if(aSample[s][1] == false) { iX = (277 * maprange01(nMinX,nMaxX,aSample[s][2])) + 10; // X iY = clip(10,88,(90 * (nYMultiplier * aSample[s][3])) + 10); // Y if(iY >= 20) drawline(<107,107,107>,iX,20,iX,iY); drawtext(string(s),<107,107,107>,iX - 3,3); } } // Draw Samples (Enabled) iC = 1; // Count for(s = 1; s <= 9; s++) { if(aSample[s][1]) { iX = (277 * maprange01(nMinX,nMaxX,aSample[s][2])) + 10; // X iY = clip(10,88,(90 * (nYMultiplier * aSample[s][3])) + 10); // Y if(iY >= 20) drawline(<255,255,255>,iX,20,iX,iY); drawtext(string(s),<255,255,255>,iX - 3,3); // below used to draw profile preview aXY[iC] = ; iC++; } } // Draw preview of enabled points if(iC > 2) { for(s = 2; s <= sizeof(aXY); s++) { drawline(<200,200,200>,aXY[s - 1].x,aXY[s - 1].y,aXY[s].x,aXY[s].y); } } } // GIZMO gizmodraw: coa { if(!reqisopen()) return; nTimeOffset = -0.0001; vWorldPosition = Item.getWorldPosition(Scene.currenttime + nTimeOffset); // World Position vScaling = Item.getScaling(Scene.currenttime + nTimeOffset); // Scaling vnRight = normalize3D(Item.getRight(Scene.currenttime + nTimeOffset)); vnUp = normalize3D(Item.getUp(Scene.currenttime + nTimeOffset)); vnForward = normalize3D(Item.getForward(Scene.currenttime + nTimeOffset)); // Scaling if(vScaling.x != vScaling.y) { vScaling = <(vScaling.x + vScaling.y) * 0.5,(vScaling.x + vScaling.y) * 0.5,vScaling.z>; } // Draw Center coa.setColor(0.0,0.0,0.78,1.0); coa.setPattern("dash"); coa.drawLine(vWorldPosition + (vnForward * (nLength * 0.5) * vScaling.z),vWorldPosition + (-vnForward * (nLength * 0.5) * vScaling.z),"world"); // Draw Profile coa.setPattern("solid"); for(s = 1; s <= 9; s++) { vCenter = vWorldPosition + (vnForward * aSample[s][2] * nLength * vScaling.z); if(aSample[s][1]) { coa.setColor(1.0,1.0,1.0,1.0); coa.drawText(vCenter,s.asStr(),"world","center"); // Sample for(p = 1; p < 33; p++) { vA = (vnRight * aCirclePoints[p].x * aSample[s][3] * vScaling.x) + (vnUp * aCirclePoints[p].y * aSample[s][3] * vScaling.y) + (vnForward * aCirclePoints[p].z * aSample[s][3] * vScaling.z) + vCenter; vB = (vnRight * aCirclePoints[p + 1].x * aSample[s][3] * vScaling.x) + (vnUp * aCirclePoints[p + 1].y * aSample[s][3] * vScaling.y) + (vnForward * aCirclePoints[p + 1].z * aSample[s][3] * vScaling.z) + vCenter; coa.drawLine(vA,vB,"world"); } } else { coa.setColor(0.4,0.4,0.4,1.0); for(p = 1; p < 33; p++) { vA = (vnRight * aCirclePoints[p].x * aSample[s][3] * vScaling.x) + (vnUp * aCirclePoints[p].y * aSample[s][3] * vScaling.y) + (vnForward * aCirclePoints[p].z * aSample[s][3] * vScaling.z) + vCenter; vB = (vnRight * aCirclePoints[p + 1].x * aSample[s][3] * vScaling.x) + (vnUp * aCirclePoints[p + 1].y * aSample[s][3] * vScaling.y) + (vnForward * aCirclePoints[p + 1].z * aSample[s][3] * vScaling.z) + vCenter; coa.drawLine(vA,vB,"world"); } } } } gizmodown: te { } gizmomove: te { } gizmoup: te { } gizmodirty { }
All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs
Very neat stuff Stephen!
ReplyDelete