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); }
public override void OnDeserializeFromBlender() { base.OnDeserializeFromBlender(); // Call important base class first to serialize rim, pinned particle mesh, etc //=== Create the collision mesh from Blender === _oMeshFlexCollider = CBMesh.Create(null, _oBodyBase, _sBlenderInstancePath_CSoftBody + ".oMeshFlexCollider", typeof(CBMesh)); // Also obtain the Unity2Blender mesh call above created. _oMeshFlexCollider.GetComponent<MeshRenderer>().enabled = false; // Collider does not render... only for Flex definition! _oMeshFlexCollider.transform.SetParent(transform); //=== Construct the Flex solid body to obtain the particles that need further processing Blender for pinning === CFlex.CreateFlexObject(gameObject, _oMeshNow, _oMeshFlexCollider._oMeshNow, uFlex.FlexBodyType.Soft, uFlex.FlexInteractionType.SelfCollideFiltered, CGame.INSTANCE.nMassSoftBody, Color.red); //=== Obtain references to the components we'll need at runtime === _oFlexParticles = GetComponent<uFlex.FlexParticles>(); //###WEAK: Owned by base class, defined here _oFlexParticlesRenderer = GetComponent<uFlex.FlexParticlesRenderer>(); _oFlexShapeMatching = GetComponent<uFlex.FlexShapeMatching>(); _oFlexGeneratedSMR = GetComponent<SkinnedMeshRenderer>(); //=== Ask Blender to create a 'Unity2Blender' mesh of the right number of verts so we can upload our Tetramesh to Blender for processing there === int nVertTetras = _oFlexParticles.m_particlesCount; CGame.gBL_SendCmd("CBody", _sBlenderInstancePath_CSoftBody_FullyQualfied + ".CreateMesh_Unity2Blender(" + nVertTetras.ToString() + ")"); // Our softbody instance will now have its 'oMeshUnity2Blender' member populated with a temporary mesh of exactly nVertTetras verts //=== Obtain the Unity2Blender mesh so we can pass particles to Blender for processing there === CBMesh oMesh_Unity2Blender = CBMesh.Create(null, _oBodyBase, _sBlenderInstancePath_CSoftBody + ".oMeshUnity2Blender", typeof(CBMesh), true); // Also obtain the Unity2Blender mesh call above created. // Keep link to Blender mesh open so we can upload our verts //###IMPROVE: When/where to release?? oMesh_Unity2Blender.transform.SetParent(transform); //###IMPROVE#13: Set parent in Create() above? //=== Upload our particles to Blender so it can select those that are pinned and skin them === for (int nVertTetra = 0; nVertTetra < nVertTetras; nVertTetra++) oMesh_Unity2Blender._memVerts.L[nVertTetra] = _oFlexParticles.m_particles[nVertTetra].pos; //###LEARN: For some reason this is safe to do while still copying back to Blender... why? oMesh_Unity2Blender.UpdateVertsToBlenderMesh(); // Blender now has our particles. It can now find the particles near the rim and skin them //=== Create and retrieve the softbody rim mesh responsible to pin softbody to skinned body === float nDistSoftBodyParticlesFromBackmesh = CGame.INSTANCE.particleSpacing * CGame.INSTANCE.nDistSoftBodyParticlesFromBackmeshMult; CGame.gBL_SendCmd("CBody", _sBlenderInstancePath_CSoftBody_FullyQualfied + ".FindPinnedFlexParticles(" + nDistSoftBodyParticlesFromBackmesh.ToString() + ")"); // Ask Blender select the particles near the rim and skin them Destroy(oMesh_Unity2Blender); // We're done with Unity2Blender mesh after FindPinnedFlexParticles... delete oMesh_Unity2Blender = null; //=== Retreive the pinned particles skinned mesh so we can manually set the position of the pinned particles to the appropriate position on the skinned main body (so softbody doesn't float into space) === _oMeshPinnedParticles = (CBSkinBaked)CBMesh.Create(null, _oBodyBase, _sBlenderInstancePath_CSoftBody + ".oMeshPinnedParticles", typeof(CBSkinBaked)); // Retrieve the skinned softbody rim mesh Blender just created so we can pin softbody at runtime _oMeshPinnedParticles.transform.SetParent(transform); ////=== Obtain the map of pinned particles in skinned mesh to softbody particles in whole softbody mesh === List<ushort> aMapPinnedParticles = CByteArray.GetArray_USHORT("'CBody'", _sBlenderInstancePath_CSoftBody_FullyQualfied + ".aMapPinnedParticles.Unity_GetBytes()"); // Read the particle traversal map from our CSoftBody instance //=== 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, _oMeshPinnedParticles); //=== Create our baked-recipient mesh === _oFlexGeneratedSMR_BakedMesh = new Mesh(); // The mesh baked at every frame by _oFlexGeneratedSMR }