//CKeyHook _oKeyHook_ThighSpread; //--------------------------------------------------------------------------- CREATE / DESTROY public override void OnStart_DefineLimb() { _nDrivePos = 0.5f * C_DrivePos; // Weaken the leg pin drive over default //=== Init Bones and Joints === CJointDriver oJointPelvis = _oBody._oActor_Pelvis._oJointExtremity; _aJoints.Add(_oJointThighBend = CJointDriver.Create(this, oJointPelvis, _sSidePrefixL+"ThighBend", 15, 3.0f, -115, 035, 000, 085, 1)); // X = Leg forward (-115) / back (35), Z = Thigh split (85) / together (20) ###BAD: Super-important thigh split needed same value for thigh together makes no sense! ###IMPROVE: 2nd joint? _aJoints.Add(_oJointThighTwist = CJointDriver.Create(this, _oJointThighBend, _sSidePrefixL+"ThighTwist", 20, 2.0f, -000, 000, 075, 000, 1)); // Y = Thigh twist -75 to 75 Ok _aJoints.Add(_oJointShin = CJointDriver.Create(this, _oJointThighTwist, _sSidePrefixL+"Shin", 10, 2.0f, -011, 155, 015, 005, 1)); // X = Knee bent (+155) or backward (-11), Y = Knee rotate -25 to 10 with compromise at 15, Z = Knee side-to-side -5 to 5 _aJoints.Add(_oJointFoot = CJointDriver.Create(this, _oJointShin, _sSidePrefixL+"Foot", 15, 1.0f, -025, 010, 020, 040, 1)); // X = Foot up (-40) and down (+75), inward -25 to +10, twist -35 to 15: ###IMPROVE: FootX not up/down!! ###IMPROVE: 2 joints? ###PROBLEM: Foot up down on Z with poor bending along down _aJoints.Add(_oJointMetatarsals = CJointDriver.Create(this, _oJointFoot, _sSidePrefixL+"Metatarsals", 20, 0.5f, -000, 000, 020, 012, 1)); // X = Metatarsals left/right = useless, Y = twist -20 to 20, Z = foot bend -12 to 12 _aJoints.Add(_oJointExtremity = CJointDriver.Create(this, _oJointMetatarsals, _sSidePrefixL+"Toe", 20, 3.0f, -000, 000, 020, 050, 1)); // X = Toes bend backward (-45) to forward (65), Y = Toe twist -20/20, Z = meaningless ###IMPROVE: Rotate axe? ###CHECK: Toe mass?? _oJointShin._oConfJoint.targetRotation = Quaternion.Euler(-160, 0, 0); //###WEAK: Set knee default position so it can easily bend (with very week drive) //###SOON: Proper bending of knee calculations from height //=== Init Hotspot === if (_eBodySide == 0) //###IMPROVE: Rediculously long path... switch to 'search for bone' (would not be as fast tho) _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/chestLower/abdomenUpper/abdomenLower/hip/pelvis/lThighBend/lThighTwist/lShin/lFoot/lMetatarsals/lToe"), "Left Leg", true, new Vector3(0, 0, 0)); else _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/chestLower/abdomenUpper/abdomenLower/hip/pelvis/rThighBend/rThighTwist/rShin/rFoot/rMetatarsals/rToe"), "Right Leg", true, new Vector3(0, 0, 0)); //=== Init CObject === _oObj = new CObject(this, _oBody._oBodyBase._nBodyID, typeof(EActorLeg), "Leg", "Leg" + _sSidePrefixU); _oObj.PropGroupBegin("", "", true); AddBaseActorProperties(); // The first properties of every CActor subclass are Pinned, pos & rot _oObj.PropAdd(EActorLeg.Thigh_Spread, "Thigh-Spread", 0, -100, 100, ""); _oObj.PropAdd(EActorLeg.Thigh_Rotate, "Thigh-Rotate", 0, -100, 100, ""); _oObj.FinishInitialization(); //_oKeyHook_ThighSpread = new CKeyHook(_oObj.PropFind(EActorLeg.Thigh_Spread), KeyCode.F, EKeyHookType.QuickMouseEdit, "Thigh Spread", -1); }
//--------------------------------------------------------------------------- CREATE / DESTROY public override void OnStart_DefineLimb() { //=== Init Bones and Joints === _aJoints.Add(_oJointExtremity = CJointDriver.Create(this, null, "chestUpper", 15, 8, -000, 000, 000, 000, 1)); //### The body's root bone... is kinematic and has no joint to a parent bone so all zeros _aJoints.Add(_oJointChestLower = CJointDriver.Create(this, _oJointExtremity, "chestLower", 15, 8, -015, 015, 010, 010, 1)); _aJoints.Add(_oJointAbdomenUpper = CJointDriver.Create(this, _oJointChestLower, "abdomenUpper", 15, 6, -035, 025, 012, 020, 1)); _aJoints.Add(_oJointAbdomenLower = CJointDriver.Create(this, _oJointAbdomenUpper, "abdomenLower", 15, 6, -040, 025, 024, 020, 1)); _aJoints.Add(_oJointHip = CJointDriver.Create(this, _oJointAbdomenLower, "hip", 15, 6, -035, 020, 015, 015, 1)); //###NOTE: Pelvis bone is in CActorPelvis for extra processing there. //###CHECK: Keep? _oJointExtremity._oRigidBody.isKinematic = (CGame.INSTANCE._GameMode == EGameModes.Configure); //###HACK ###TEMP ####REVA If play no anim just set everything to kinematic... for temp cloth exploration //###OBS? _oJointExtremity._oRigidBody.isKinematic = false; // We need to disable kinematic on bone as we're driving it with our pin! //=== Init Hotspot === _oHotSpot = CHotSpot.CreateHotspot(this, transform, "Chest", true, new Vector3(0, 0, 0), C_SizeHotSpot_BodyNodes); //_oHotSpot = CHotSpot.CreateHotspot(this, _oBody.FindBone("chestUpper"), "Chest", true, new Vector3(0, 0, 0), C_SizeHotSpot_TorsoNodes); //=== Init CObject === _oObj = new CObject(this, _oBody._oBodyBase._nBodyID, typeof(EActorChest), "Chest", "Chest"); _oObj.PropGroupBegin("", "", true); AddBaseActorProperties(); // The first properties of every CActor subclass are Pinned, pos & rot _oObj.PropAdd(EActorChest.Torso_LeftRight, "Torso_LeftRight", 0, -100, 100, ""); //###BUG: Have to recalibrate to make new abdoment-centric bones look good. _oObj.PropAdd(EActorChest.Torso_UpDown, "Torso_UpDown", 0, -100, 100, ""); //###NOW###: Forced to enter crappy name because of new CProp restrictions with naming! _oObj.PropAdd(EActorChest.Torso_Twist, "Torso_Twist", 0, -100, 100, ""); _oObj.FinishInitialization(); //###PROBLEM: Base actor adds 'pinned' but chest is always pinned? //###CHECK?? _oObj.PropSet(EActorChest.Pinned, 1); // Manually set pinned to 1 on torso so body doesn't float in space when no pose is loaded (Weak that we can't set in PropAdd() due to init-time problems) if (CGame.INSTANCE.EnableIdlePoseMovement) StartCoroutine(Coroutine_ChangeRandomPose()); //###CHECK: When destroyed OK?? }
public CBody(CBodyBase oBodyBase) { //###NOW#11 _oBodyBase = oBodyBase; _oBodyBase._oBody = this; //###WEAK#13: Convenience early-set of our instance into owning parent. Needed as some of init code needs to access us from our parent! ###DESIGN! _oBodySkinnedMeshGO_HACK = new GameObject("RuntimeBody"); // Create the game object that will contain our important CBody component early (complex init tree needs it!) _oBodySkinnedMeshGO_HACK.transform.SetParent(_oBodyBase._oBodyRootGO.transform); _bEnabled = true; // Enabled at creation by defnition. //bool bForMorphingOnly = false; //###JUNK (CGame.INSTANCE._GameMode == EGameModes.MorphNew_TEMP); //####DEV!!!! Debug.Log(string.Format("+ Creating body #{0}", _oBodyBase._nBodyID)); _oObj = new CObject(this, _oBodyBase._nBodyID, typeof(EBodyDef), "Body"); _oObj.PropGroupBegin("", "", true); //_oObj.PropAdd(EBodyDef.Sex, "Sex", typeof(EBodySex), (int)EBodySex.Woman, ""); //_oObj.PropAdd(EBodyDef.ClothingTop, "Top Clothing", typeof(EBodyClothingTop_HACK), 0, ""); //###HACK!!!! //_oObj.PropAdd(EBodyDef.ClothingBottom, "Bottom Clothing", typeof(EBodyClothingBottom_HACK), 0, "" + CProp.Hide); //###BROKEN: Need to switch off v****a soft body!! //_oObj.PropAdd(EBodyDef.Hair, "Hair", typeof(EBodyHair), 0, ""); //_oObj.PropAdd(EBodyDef.BtnUpdateBody, "Update Body", 0, "", CProp.AsButton); _oObj.PropAdd(EBodyDef.BreastSize, "Breast Size BROKEN", 1.0f, 0.5f, 2.5f, ""); //###BROKEN#11 _oObj.FinishInitialization(); //=== Give some reasonable defaults to use when game loads === ###TODO: Load these from the user's last used body definitions! ####TEMP ####DESIGN: Load from user pref or file? NOT IN CODE!! // if (_oBodyBase._nBodyID == 0) { // _oObj.PropSet(EBodyDef.Sex, (int)EBodySex.Woman); // //_oObj.PropSet(EBodyDef.Sex, (int)EBodySex.Shemale); // _oObj.PropSet(EBodyDef.Hair, (int)EBodyHair.TiedUp); //// oObj.PropSet(EBodyDef.Hair, (int)EBodyHair.Messy); //// oObj.PropFind(EBodyDef.ClothingTop)._nPropFlags |= CProp.Hide; //###HACK!!!! //// oObj.PropFind(EBodyDef.BreastSize)._nPropFlags |= -CProp.Hide; //// oObj.PropFind(EBodyDef.Hair)._nPropFlags |= CProp.Hide; // } else { // //_oObj.PropSet(EBodyDef.Sex, (int)EBodySex.Man); ####REVB // _oObj.PropSet(EBodyDef.Sex, (int)EBodySex.Shemale); // //oObj.PropSet(EBodyDef.ClothingTop, (int)EBodyClothingTop_HACK.TiedTop); // _oObj.PropSet(EBodyDef.Hair, (int)EBodyHair.TiedUp); // //if (CGame.INSTANCE._bRunningInEditor) //###TEMP! :) // // oObj.PropSet(EBodyDef.BreastSize, 1.3f); // } //===== DETACHED SOFTBODY PARTS PROCESSING ===== if (_oBodyBase._eBodySex != EBodySex.Man) { //_aSoftBodies.Add(_oBreastL = (CBreastL)CSoftBody.Create(this, typeof(CBreastL), "chestUpper")); //###DEVNOW //_aSoftBodies.Add(_oBreastR = (CBreastR)CSoftBody.Create(this, typeof(CBreastR), "chestUpper")); } if (_oBodyBase._eBodySex == EBodySex.Woman) { //_aSoftBodies.Add(_oVagina = (CVagina)CSoftBody.Create(this, typeof(CVagina), "chest/abdomen/hip")); } else { //_aSoftBodies.Add(_oPenis = (CPenis)CSoftBody.Create(this, typeof(CPenis), "chest/abdomen/hip")); } ////####TEMP ####DESIGN ####TEMP ####MOVE //_aCloths.Add(CBCloth.Create(this, "MyShirt", "Shirt", "HACK-Cloth-TankTop", "_ClothSkinnedArea_ShoulderTop")); //_ClothSkinnedArea_Top ///_aCloths.Add(CBCloth.Create(this, "MyShirt", "Shirt", "BodySuit", "_ClothSkinnedArea_ShoulderTop")); //_ClothSkinnedArea_Top ////_aCloths.Add(CBCloth.Create(this, "Rough1-Holds")); ////_aCloths.Add(CBCloth.Create(this, "Rough2-Spreads")); ////_aCloths.Add(CBCloth.Create(this, "BodySuit-Top-Trimmed")); ////////////###DEV _aCloths.Add(CBCloth.Create(this, "FullShirt")); ////=== Create the various soft-body mesh parts that are dependant on the body sex === ////###IMPROVE!!!! Parse array of Blender-pushed softbody into our parts (instead of pulling like below?) //if (_bForMorphingOnly == false) { // if (_eBodySex == EBodySex.Woman || _eBodySex == EBodySex.Shemale) { // _aSoftBodies.Add(_oBreastL = (CBreastBase)CBMesh.Create(null, this, _sNameGameBody, "_Detach_Breasts", "Client", "Unity_GetMesh", "'SkinInfo'", typeof(CBreastBase))); //###WEAK: Create utility function like before??? // } // if (_eBodySex == EBodySex.Shemale || _eBodySex == EBodySex.Man) // _aSoftBodies.Add(_oPenis = (CPenis)CBMesh.Create(null, this, _sNameGameBody, "_Detach_Penis", "Client", "Unity_GetMesh", "'NoSkinInfo'", typeof(CPenis))); // if (_eBodySex == EBodySex.Woman) // _oVagina = new CVagina(this); // //=== Create the important body collider that will repel fluid in the scene === // _oBodyCol = (CBBodyCol)CBBodyCol.Create(null, this, _sNameGameBody); //} //=== Obtain the source mesh body for normal extraction === ///_oBodySource = CBMesh.Create(null, this, "oMeshSource", typeof(CBMesh)); ///_oBodySource.GetComponent<MeshRenderer>().enabled = false; // This mesh is to pull normals only. Not visible at runtime! //===== MAIN SKINNED BODY PROCESSING ===== //=== Get the main body skinned mesh (has to be done once all softbody parts have been detached) === _oBodySkinnedMesh = (CBSkin)CBMesh.Create(_oBodySkinnedMeshGO_HACK, _oBodyBase, ".oBody.oMeshBody", typeof(CBSkin)); //###IMPROVE#13: Create blender instance string for our CBody? _oBodySkinnedMesh.name = "GametimeBody"; //_oBodySkinnedMesh.GetComponent<SkinnedMeshRenderer>().enabled = false; //=== Create a hotspot at the character's head the user can use to invoke our (important) context menu === //###BROKENN // Transform oHeadT = FindBone("chest/neck/head"); // Our hotspot is located on the forehead of the character. //_oHotSpot = CHotSpot.CreateHotspot(this, oHeadT, this._sHumanCharacterName, false, new Vector3(0, 0.09f, 0.03f), 2.0f); //###IMPROVE: Get these offsets from pre-placed nodes on bone structure?? ////=== Create the head look controller to look at parts of the other body === //###BROKENN // _oHeadLook = _oBodyRootGO.gameObject.AddComponent<CHeadLook>(); //####DESIGN: Keep for morph mode?? //_oHeadLook.OnStart(this); //=== Instantiate the requested hair and pin as child of the head bone === //###BROKENN //EBodyHair eBodyHair = (EBodyHair)_oObj.PropGet(EBodyDef.Hair); //if (eBodyHair != EBodyHair.None) { // string sNameHair = "HairW-" + eBodyHair.ToString(); //###HACK!!! W extension! ###HACK!!!! Man support!! // GameObject oHairTemplateGO = Resources.Load("Models/Characters/Woman/Hair/" + sNameHair + "/" + sNameHair, typeof(GameObject)) as GameObject; // Hair has name of folder and filename the same. //###HACK: Path to hair, selection control, enumeration, etc // _oHairGO = GameObject.Instantiate(oHairTemplateGO) as GameObject; // Transform oBoneHead = FindBone("chest/neck/head"); // _oHairGO.transform.parent = oBoneHead; // _oHairGO.transform.localPosition = Vector3.zero; // _oHairGO.transform.localRotation = Quaternion.identity; // if (_eBodySex == EBodySex.Man) { //###HACK!!!!!! To reuse messy hair for man!! // _oHairGO.transform.localPosition = new Vector3(0, 0.0f, 0.0f); // _oHairGO.transform.localScale = new Vector3(1.07f, 1.07f, 1.08f); // } //} Body_InitActors(); ////=== Setup the keys to handle penis control on non-woman bodies === //if (_eBodySex != EBodySex.Woman) { //###MOVE? ###OBS ###F // bool bSelectedBodyOnly = (CGame.INSTANCE._nNumPenisInScene_BROKEN > 1); // Keys below are active if this body is the selected body ONLY if we have more than one man in the scene // if (_oPenis != null) { // _oKeyHook_PenisBaseUpDown = new CKeyHook(_oPenis._oObjDriver.PropFind(EPenis.BaseUpDown), KeyCode.Q, EKeyHookType.QuickMouseEdit, "Penis up/down", 1, bSelectedBodyOnly); // _oKeyHook_PenisShaftUpDown = new CKeyHook(_oPenis._oObjDriver.PropFind(EPenis.ShaftUpDown), KeyCode.E, EKeyHookType.QuickMouseEdit, "Penis bend up/down", 1, bSelectedBodyOnly); // _oKeyHook_PenisDriveStrengthMax = new CKeyHook(_oPenis._oObjDriver.PropFind(EPenis.DriveStrengthMax), KeyCode.G, EKeyHookType.QuickMouseEdit, "Penis erection", -1, bSelectedBodyOnly); // } //} _oKeyHook_ChestUpDown = new CKeyHook(_oActor_Chest._oObj.PropFind(EActorChest.Torso_UpDown), KeyCode.T, EKeyHookType.QuickMouseEdit, "Chest forward/back"); //=== Create the face and its associated morph channels === ///_oFace = (CFace)CBMesh.Create(null, this, "oMeshFace", typeof(CFace)); //=== Reparent our actor base to the pose root so that user can move / rotate all bodies at once === _oActor_Base.transform.SetParent(CGame.INSTANCE._oPoseRoot.transform); //###DESIGN#15! Causes problems with regular init/destory of CBody? Do we really want to keep reparenting for easy full pose movement??> _oActor_Base.gameObject.name = _oBodyBase._sBodyPrefix + "_Base"; //=== Copy references to our actors to our script-friendly CObject variables to provide friendlier access to our scriptable objects === Base = _oActor_Base._oObj; // CGamePlay passed us the reference to the right (empty) static object. We fill it here. Chest = _oActor_Chest._oObj; Torso = _oActor_Torso._oObj; Pelvis = _oActor_Pelvis._oObj; ArmL = _oActor_ArmL._oObj; ArmR = _oActor_ArmR._oObj; LegL = _oActor_LegL._oObj; LegR = _oActor_LegR._oObj; Face = null;/// _oFace._oObj; ///###BROKEN ###DEVO Penis = (_oPenis == null) ? null : _oPenis._oObjDriver; _oScriptPlay = CUtility.FindOrCreateComponent(_oBodyBase._oBodyRootGO.transform, typeof(CScriptPlay)) as CScriptPlay; _oScriptPlay.OnStart(this); //=== Rotate the 2nd body toward the first and separate slightly loading poses doesn't pile up one on another === ####MOVE? ####OBS? (Depend on pose?) //####PROBLEM: Set separation and don't do in all game modes if (_oBodyBase._nBodyID == 0) { _oActor_Base.transform.position = new Vector3(0, 0, -CGame.C_BodySeparationAtStart); //###DESIGN: Don't load base actor instead?? ###BUG Overwrites user setting of base!!!! } else { _oActor_Base.transform.position = new Vector3(0, 0, CGame.C_BodySeparationAtStart); _oActor_Base.transform.rotation = Quaternion.Euler(0, 180, 0); // Rotate the 2nd body 180 degrees } ///_oClothEdit_HACK = new CClothEdit(this, "Shirt"); ///CGame.gBL_SendCmd("CBody", "CBodyBase_GetBodyBase(" + _oBodyBase._nBodyID.ToString() + ").Breasts_ApplyMorph('RESIZE', 'Nipple', 'Center', 'Wide', (1.6, 1.6, 1.6, 0), None)"); //###F ###HACK!!! //=== Create the left and right canvases on each side of the body so that panels have a place to be pinned for close-to-body editing === _aUICanvas[0] = CUICanvas.Create(CUtility.FindChild(_oActor_Chest.transform, "_CanvasPin_Left")); //###HACK _aUICanvas[1] = CUICanvas.Create(CUtility.FindChild(_oActor_Chest.transform, "_CanvasPin_Right")); //###DESIGN: Which pin? Torso or chest? //=== Create the Flex collider in Blender and serialize it to Unity === CGame.gBL_SendCmd("CBody", _oBodyBase._sBlenderInstancePath_CBodyBase + ".oBody.CreateFlexCollider(" + CGame.INSTANCE.nDistFlexColliderShrinkMult + ")"); _oBodyFlexCollider = (CBSkin)CBMesh.Create(null, _oBodyBase, ".oBody.oMeshFlexCollider", typeof(CBSkin)); _oBodyFlexCollider.name = "FlexCollider"; _oBodyFlexCollider.transform.SetParent(_oBodySkinnedMesh.transform); //###IMPROVE#15: Put this common re-parenting and re-naming in Create! _oBodyFlexCollider.gameObject.AddComponent<CFlexSkinnedBody>(); _oBodyFlexCollider.GetComponent<SkinnedMeshRenderer>().enabled = false; //###IMPROVE: Move into CFlexSkinnedBody?? _oBodyFlexCollider.UpdateNormals(); //###NOW#15 }
public override void OnDeserializeFromBlender() { base.OnDeserializeFromBlender(); _sBlenderInstancePath_CCloth = CBCloth.s_sNameClothSrc_HACK; //=== Create the skinned-portion of the cloth. It will be responsible for driving Flex particles that heavily influence their corresponding particles in fully-simulated cloth mesh === _oBSkinBaked_SkinnedPortion = (CBSkinBaked)CBSkinBaked.Create(null, _oBodyBase, "." + _sBlenderInstancePath_CCloth + ".oMeshClothSkinned", typeof(CBSkinBaked)); //###WEAK#13!!! F*****g dot!! _oBSkinBaked_SkinnedPortion.transform.SetParent(transform); _oBSkinBaked_SkinnedPortion._oSkinMeshRendNow.enabled = false; // Skinned portion invisible to the user. Only used to guide simulated portion //=== Receive the aMapPinnedParticles array Blender created to map the skinned verts to their pertinent simulated ones === List<ushort> aMapPinnedParticles = CByteArray.GetArray_USHORT("'CBody'", _oBodyBase._sBlenderInstancePath_CBodyBase + "." + _sBlenderInstancePath_CCloth + ".aMapPinnedParticles.Unity_GetBytes()"); //=== Create the simulated part of the cloth === MeshFilter oMeshFilter = GetComponent<MeshFilter>(); MeshRenderer oMeshRend = GetComponent<MeshRenderer>(); //oMeshRend.sharedMaterial = Resources.Load("Materials/BasicColors/TransWhite25") as Material; //####SOON? Get mats! ###F oMeshRend.sharedMaterial = Resources.Load("Materials/Test-2Sided") as Material; //####SOON? Get mats! ###F _oBSkinBaked_SkinnedPortion._oSkinMeshRendNow.sharedMaterial = oMeshRend.sharedMaterial; // Skinned part has same material _oMeshNow = oMeshFilter.sharedMesh; _oMeshNow.MarkDynamic(); // Docs say "Call this before assigning vertices to get better performance when continually updating mesh" //=== Create the 'cloth at startup' mesh. It won't get simulated and is used to reset simulated cloth to its startup position === _oBMeshClothAtStartup = CBMesh.Create(null, _oBodyBase, "." + _sBlenderInstancePath_CCloth + ".oMeshClothSimulated", typeof(CBMesh)); _oBMeshClothAtStartup.transform.SetParent(_oBodyBase.FindBone("chestUpper")); // Reparent this 'backup' mesh to the chest bone so it rotates and moves with the body _oBMeshClothAtStartup.GetComponent<MeshRenderer>().enabled = false; //_oBMeshClothAtStartup.gameObject.SetActive(false); // De activate it so it takes no cycle. It merely exists for backup purposes //=== Create the Flex object for our simulated part === CFlex.CreateFlexObject(gameObject, _oMeshNow, _oMeshNow, uFlex.FlexBodyType.Cloth, uFlex.FlexInteractionType.None, CGame.INSTANCE.nMassCloth, Color.yellow); uFlex.FlexProcessor oFlexProc = CUtility.FindOrCreateComponent(gameObject, typeof(uFlex.FlexProcessor)) as uFlex.FlexProcessor; oFlexProc._oFlexProcessor = this; _oFlexParticles = GetComponent<uFlex.FlexParticles>(); _oFlexSprings = GetComponent<uFlex.FlexSprings>(); //=== Create the managing object and related hotspot === _oObj = new CObject(this, 0, typeof(EFlexCloth), "Cloth " + gameObject.name); //###IMPROVE: Name of soft body to GUI _oObj.PropGroupBegin("", "", true); _oObj.PropAdd(EFlexCloth.Tightness, "Tightness", 1.0f, 0.01f, 2.5f, ""); _oObj.PropAdd(EFlexCloth.Length, "Length", 1.0f, 0.50f, 1.10f, ""); _oObj.PropAdd(EFlexCloth.ClothMass, "Mass", 1.0f, 0.0001f, 1000.0f, ""); _oObj.FinishInitialization(); _oWatchBone = _oBodyBase.FindBone("chestUpper"); //####HACK ####DESIGN: Assumes this cloth is a top! _oHotSpot = CHotSpot.CreateHotspot(this, _oWatchBone, "Clothing", false, new Vector3(0, 0.22f, 0.04f)); //###IMPROVE!!! Position offset that makes sense for that piece of clothing (from center of its verts?) //=== Backup the startup cloth arrays so we can adjust in a non-destructive way === _aSpringRestLengthsBAK = new float[_oFlexSprings.m_springsCount]; System.Array.Copy(_oFlexSprings.m_springRestLengths, _aSpringRestLengthsBAK, _oFlexSprings.m_springsCount); //=== Create the Flex-to-skinned-mesh component responsible to guide selected Flex particles to skinned-mesh positions === _oPinnedParticles = CUtility.FindOrCreateComponent(gameObject, typeof(CPinnedParticles)) as CPinnedParticles; _oPinnedParticles.Initialize(ref aMapPinnedParticles, _oBSkinBaked_SkinnedPortion); }
//--------------------------------------------------------------------------- CREATE / DESTROY public override void OnStart_DefineLimb() { _nDrivePos = 0.1f * C_DrivePos; // Weaken the hand drive so hand doesn't fly from pin to pin //###TUNE //_memVecRayHitInfo = new CMemAlloc<Vector3>(2); //=== Init Bones and Joints === CJointDriver oJointChestUpper = _oBody._oActor_Chest._oJointExtremity; _aJoints.Add(_oJointCollar = CJointDriver.Create(this, oJointChestUpper, _sSidePrefixL+"Collar", 30, 2.5f, -010, 050, 030, 021, 1)); // X = Collar Up/Down OK, Z has 17 back and 25 forward (avg looks ok) _aJoints.Add(_oJointShoulderBend = CJointDriver.Create(this, _oJointCollar, _sSidePrefixL+"ShldrBend", 15, 2.0f, -085, 035, 000, 110, 1)); // X = Shoulder Up/Down OK, Z = Back goes to -40, Forward to 110!!! (###IMPROVE: Another joint?) _aJoints.Add(_oJointShoulderTwist = CJointDriver.Create(this, _oJointShoulderBend, _sSidePrefixL+"ShldrTwist", 20, 1.5f, -000, 000, 080, 000, 1)); // Y = Shoulder twist goes from -95 to 80 so max. ###PROBLEM: Shimmer in high rotation! _aJoints.Add(_oJointForearmBend = CJointDriver.Create(this, _oJointShoulderTwist, _sSidePrefixL+"ForearmBend", 10, 1.5f, -020, 135, 000, 000, 1)); // X = Elbow bend from -20 to 135. ok. _aJoints.Add(_oJointForearmTwist = CJointDriver.Create(this, _oJointForearmBend, _sSidePrefixL+"ForearmTwist", 20, 1.0f, -000, 000, 080, 000, 1)); // Y = Forearm twist from -90 to 80 so max. ###IMPROVE: Could rotate the axes on the twists so we use XL/XH _aJoints.Add(_oJointExtremity = CJointDriver.Create(this, _oJointForearmTwist, _sSidePrefixL+"Hand", 10, 0.5f, -070, 080, 010, 029, 1)); // X = Hand -down(-70) / +up (+80), Y = Hand twist +/-10, Z = Hand side-to-side -28 to +30 //ConfigFingerRoot(1, "Index"); // Thumb is handled below ###DESIGN!!! Fingers in Unity PhysX is just a no-go because of extremely poor latency... what to do????? //ConfigFingerRoot(2, "Mid"); //ConfigFingerRoot(3, "Ring"); //??? ###HACK!! Disabled man's carpal1&2 in 3dsMax so we can use same code as women's! //ConfigFingerRoot(4, "Pinky"); //CJointDriver oJointFingerBoneParent = _oJointExtremity; //oJointFingerBoneParent = ConfigFingerBone(oJointFingerBoneParent, 0, 0, "Thumb", 005f, -030f, 005f, 025f); //oJointFingerBoneParent = ConfigFingerBone(oJointFingerBoneParent, 0, 1, "Thumb", 010f, -015f, 000f, 000f); //oJointFingerBoneParent = ConfigFingerBone(oJointFingerBoneParent, 0, 2, "Thumb", 010f, -015f, 000f, 000f); //=== Init Hotspot === if (_eBodySide == 0) _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/lCollar/lShldrBend/lShldrTwist/lForearmBend/lForearmTwist/lHand"), "Left Hand", true, new Vector3(0, 0, 0)); else _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/rCollar/rShldrBend/rShldrTwist/rForearmBend/rForearmTwist/rHand"), "Right Hand", true, new Vector3(0, 0, 0)); //=== Init CObject === _oObj = new CObject(this, _oBody._oBodyBase._nBodyID, typeof(EActorArm), "Arm", "Arm" + _sSidePrefixU); _oObj.PropGroupBegin("", "", true); AddBaseActorProperties(); // The first properties of every CActor subclass are Pinned, pos & rot //_oObj.PropAdd(EActorArm.HandTarget, "HandTarget", typeof(EHandTargets), (int)EHandTargets.ManualPosition, ""); _oObj.PropAdd(EActorArm.Hand_UpDown, "Hand-UpDown", 0, -100, 100, ""); _oObj.PropAdd(EActorArm.Hand_LeftRight, "Hand-LeftRight", 0, -100, 100, ""); _oObj.PropAdd(EActorArm.Hand_Twist, "Hand-Twist", 0, -100, 100, ""); //_oObj.PropAdd(EActorArm.Fingers_Close, "Fingers-Close", 0, -100, 100, "", CProp.Hide); //###BROKEN //_oObj.PropAdd(EActorArm.Fingers_Spread, "Fingers-Spread", 0, -100, 100, "", CProp.Hide); //_oObj.PropAdd(EActorArm.Fingers_ThumbPose, "Fingers-ThumbPose", typeof(EThumbPose), (int)EThumbPose.AlongsideFingers, "", CProp.Hide); //_oObj.PropAdd(EActorArm.UserControl, "User Control", 0, 0, 1, ""); _oObj.FinishInitialization(); _oHandTarget_RaycastPin = CActorArm.FindHandTarget(_oBody, EHandTargets.RaycastPin, _eBodySide == EBodySide.Right); // Find the raycast pin hand target as we use it heavily and it is reparented }
//--------------------------------------------------------------------------- INIT public override void OnDeserializeFromBlender() { base.OnDeserializeFromBlender(); transform.SetParent(_oBodyBase._oBody._oBodySkinnedMeshGO_HACK.transform); // Parent to our body's main skinned mesh ###WEAK#14: Crappy circumvent way of obtaining node we need early in init! _sNameSoftBody = GetType().Name.Substring(1); // Obtain the name of our detached body part ('Breasts', 'Penis', 'V****a') from a substring of our class name. Must match Blender!! ###WEAK? _sBlenderInstancePath_CSoftBody = ".oBody.aSoftBodies['" + _sNameSoftBody + "']"; // Simplify access to Blender CSoftBody instance _sBlenderInstancePath_CSoftBody_FullyQualfied = _oBodyBase._sBlenderInstancePath_CBodyBase + _sBlenderInstancePath_CSoftBody; // Simplify access to fully-qualified Blender CSoftBody instance (from CBody instance) _oBoneAnchor = _oBodyBase._oBody._oBodyBase.FindBone(_sNameBoneAnchor_HACK); //=== Set bounds to infinite so our dynamically-created mesh never has to recalculate bounds === _oMeshNow.bounds = CGame._oBoundsInfinite; //####IMPROVE: This can hurt performance ####OPT!! _oMeshNow.MarkDynamic(); // Docs say "Call this before assigning vertices to get better performance when continually updating mesh" //=== Create the managing object and related hotspot === _oObj = new CObject(this, 0, typeof(EFlexSoftBody), "SoftBody " + gameObject.name); //###IMPROVE: Name of soft body to GUI _oObj.PropGroupBegin("", "", true); _oObj.PropAdd(EFlexSoftBody.Volume, "Volume", 1.0f, 0.6f, 1.6f, ""); _oObj.PropAdd(EFlexSoftBody.Stiffness, "Stiffness", 1.0f, 0.001f, 1.0f, ""); //###IMPROVE: Log scale! _oObj.PropAdd(EFlexSoftBody.SoftBodyMass, "Mass", 1.0f, 0.0001f, 1000.0f, ""); _oObj.FinishInitialization(); if (GetType() != typeof(CBreastR)) //###HACK!: Right breast doesn't get hotspot (left breast gets it and manually broadcasts to right one) _oHotSpot = CHotSpot.CreateHotspot(this, _oBoneAnchor, "SoftBody", false, new Vector3(0, 0.10f, 0.08f)); //###IMPROVE!!! Position offset that makes sense for that piece of clothing (from center of its verts?) }