void Start() { _oFlexShapeMatching = GetComponent<uFlex.FlexShapeMatching>(); _oFlexParticles = GetComponent<uFlex.FlexParticles>(); _vecSizeParticles = new Vector3(_SizeParticles, _SizeParticles, _SizeParticles); _vecSizeShapes = new Vector3(_SizeShapes, _SizeShapes, _SizeShapes); //=== Create new nodes to render all particles === _aVisParticles = new CVisualizeParticle[_oFlexParticles.m_particlesCount]; for (int nParticle = 0; nParticle < _oFlexParticles.m_particlesCount; nParticle++) { GameObject oTemplateGO = Resources.Load("Prefabs/CVisualizeParticle", typeof(GameObject)) as GameObject; GameObject oParticleGO = Instantiate(oTemplateGO) as GameObject; CVisualizeParticle oVisParticle = CUtility.FindOrCreateComponent(oParticleGO, typeof(CVisualizeParticle)) as CVisualizeParticle; _aVisParticles[nParticle] = oVisParticle; oVisParticle.Initialize(this, nParticle); } //=== Create new nodes to render all shapes === _aVisShapes = new CVisualizeShape[_oFlexShapeMatching.m_shapesCount]; for (int nShape = 0; nShape < _oFlexShapeMatching.m_shapesCount; nShape++){ GameObject oTemplateGO = Resources.Load("Prefabs/CVisualizeShape", typeof(GameObject)) as GameObject; GameObject oParticleGO = Instantiate(oTemplateGO) as GameObject; CVisualizeShape oVisShape = CUtility.FindOrCreateComponent(oParticleGO, typeof(CVisualizeShape)) as CVisualizeShape; _aVisShapes[nShape] = oVisShape; oVisShape.Initialize(this, nShape); } GetComponent<MeshRenderer>().enabled = false; // Hide the soft body renderer out of convenience so we see inside ###IMPROVE: Set transparent? }
uFlex.FlexSprings _oFlexSprings; // Reference to spring component we're modifying to make pinning possible #endregion Fields #region Methods public void Initialize(ref List<ushort> aMapPinnedParticles, CBSkinBaked oMeshSoftBodyPinnedParticles) { //=== Obtain reference to the objects we'll need at every game frame === _aMapPinnedParticles = aMapPinnedParticles; _nNumMappingsSkinToSim = _aMapPinnedParticles.Count / 2; // Each mapping takes two slots in _aMapPinnedParticles _oMeshSoftBodyPinnedParticles = oMeshSoftBodyPinnedParticles; _oFlexParticles = CUtility.FindOrCreateComponent(gameObject, typeof(uFlex.FlexParticles)) as uFlex.FlexParticles; // Find or create these necessary compoenent from our parent _oFlexSprings = CUtility.FindOrCreateComponent(gameObject, typeof(uFlex.FlexSprings)) as uFlex.FlexSprings; //=== Create extra particles and springs for our parent's Flex objects === ushort nStartOfExtraParticles = (ushort)_oFlexParticles.m_particlesCount; // Remeber the split point between our parent's Flex particles/springs and the new ones we're adding ushort nStartOfExtraSprings = (ushort)_oFlexSprings.m_springsCount; _oFlexParticles.m_particlesCount += _nNumMappingsSkinToSim; // Add just the number of particles and springs we need (have a 1:1 relationship) _oFlexSprings. m_springsCount += _nNumMappingsSkinToSim; Array.Resize<uFlex.Particle> (ref _oFlexParticles.m_particles, _oFlexParticles.m_particlesCount); Array.Resize<bool> (ref _oFlexParticles.m_particlesActivity, _oFlexParticles.m_particlesCount); Array.Resize<Vector3> (ref _oFlexParticles.m_velocities, _oFlexParticles.m_particlesCount); Array.Resize<float> (ref _oFlexParticles.m_densities, _oFlexParticles.m_particlesCount); Array.Resize<Color> (ref _oFlexParticles.m_colours, _oFlexParticles.m_particlesCount); Array.Resize<int> (ref _oFlexSprings.m_springIndices, _oFlexSprings.m_springsCount * 2); Array.Resize<float> (ref _oFlexSprings.m_springRestLengths, _oFlexSprings.m_springsCount); Array.Resize<float> (ref _oFlexSprings.m_springCoefficients, _oFlexSprings.m_springsCount); //=== Define the extra particles and springs between the skinned portion and the simulated portion === ushort nNextPinnedParticle = nStartOfExtraParticles; ushort nNextSpring = nStartOfExtraSprings; for (ushort nMapping = 0; nMapping < _nNumMappingsSkinToSim; nMapping++) { //###F ###BUG??? Assumes all skinned particles are used? ###CHECK! ushort nMappingX2 = (ushort)(nMapping * 2); //ushort nParticleSkinned = _aMapPinnedParticles[nMappingX2 + 0]; // The index of the skinned particle in this mapping (sparsely populated) ushort nParticleSimulatedMoving = _aMapPinnedParticles[nMappingX2 + 1]; // The index of the simulated particle in this mapping (moves as usual but has a spring to nParticleSimulatedPinned pinned particle) ushort nParticleSimulatedPinned = nNextPinnedParticle++; // The ordinal of the (new) pinned Flex-simulated particle is the next ordinal. ushort nSpring = nNextSpring++; _aMapPinnedParticles[nMappingX2 + 1] = nParticleSimulatedPinned; // We never need to address the moving particle after this loop... so re-use the map to point to the pinned particle we'll need to move everyframe instead. _oFlexParticles.m_particles[nParticleSimulatedPinned].invMass = 0; // The extra particle is always the skinned one which we drive so it gets infinite mass to not be simulated _oFlexParticles.m_particles[nParticleSimulatedPinned].pos = _oFlexParticles.m_particles[nParticleSimulatedMoving].pos; _oFlexParticles.m_colours[nParticleSimulatedPinned] = Color.gray; //###TODO: Standardize Flex colors! _oFlexParticles.m_particlesActivity[nParticleSimulatedPinned] = true; _oFlexSprings.m_springRestLengths [nSpring] = 0.0f; // Springs between (master) skinned particle and (slave) simulated one is always zero... (we want simulated particle to stick as close to where it should be!) _oFlexSprings.m_springCoefficients[nSpring] = 1.0f; //###TUNE: Make as stiff as possible for a given Flex iteration count. ###IMPROVE: Enable game-time setting of this! ###F _oFlexSprings.m_springIndices[nSpring * 2 + 0] = nParticleSimulatedPinned; // Create the link between the two simulated particles (pinned and moving) _oFlexSprings.m_springIndices[nSpring * 2 + 1] = nParticleSimulatedMoving; } }
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); }
void FlexObjects_Destroy() { //=== Destroy all configure-time Flex objects for performance. They will have to be re-created upon re-entry into configure mode === GameObject.DestroyImmediate(_oMeshMorphResult.gameObject.GetComponent<uFlex.FlexParticlesRenderer>()); //###LEARN: DestroyImmediate is needed to avoid CUDA errors with regular Destroy()! GameObject.DestroyImmediate(_oMeshMorphResult.gameObject.GetComponent<uFlex.FlexProcessor>()); GameObject.DestroyImmediate(_oFlexParticles); _oFlexParticles = null; }
void FlexObjects_Create() { //=== Define Flex particles from Blender mesh made for Flex === int nParticles = _aVertsFlexCollider.Count; _oFlexParticles = CUtility.CreateFlexObjects(_oMeshMorphResult.gameObject, this, nParticles, uFlex.FlexInteractionType.SelfCollideFiltered, Color.green); //###TODO#14: Flex Colors! for (int nParticle = 0; nParticle < nParticles; nParticle++) { int nVertWholeMesh = _aVertsFlexCollider[nParticle]; // Lookup the vert index in the full mesh from the Blender-supplied array that isolates which verts participate in the Flex collider //_oFlexParticles.m_particles[nParticle].pos = _oMeshMorphResult._memVerts.L[nVertWholeMesh]; // Don't position here to insure only one place positions to avoid bugs / confusion. (in PreContainerUpdate()) _oFlexParticles.m_particles[nParticle].invMass = 0; // We're a static collider with every particle moved by this code at every morph... (e.g. All particles are not Flex simulated) _oFlexParticles.m_colours[nParticle] = _oFlexParticles.m_colour; _oFlexParticles.m_particlesActivity[nParticle] = true; } _bParticlePositionsUpdated = true; // Flag Flex to perform an update of its particle positions. }