protected virtual void CreateInstance() { if (m_currentContainer && m_currentContainer.handle && m_currentAsset && m_currentAsset.handle) { int group = m_particleGroup < 0 ? ++sm_nextGroup : m_particleGroup; Flex.Phase flags = Flex.Phase.Default; if (m_selfCollide) { flags |= Flex.Phase.SelfCollide; } if (m_selfCollideFilter) { flags |= Flex.Phase.SelfCollideFilter; } if (m_fluid) { flags |= Flex.Phase.Fluid; } m_phase = Flex.MakePhase(group, flags); m_instanceHandle = m_currentContainer.CreateInstance(m_currentAsset.handle, transform.localToWorldMatrix, Vector3.zero, m_phase, m_massScale); if (m_instanceHandle) { FlexExt.Instance instance = m_instanceHandle.instance; m_indices = new int[m_currentAsset.maxParticles]; m_indexCount = instance.numParticles; if (m_indexCount > 0) { FlexUtils.FastCopy(instance.particleIndices, 0, ref m_indices[0], 0, sizeof(int) * m_indexCount); } } } }
private void ProcessParticles(bool countChanged) { for (int iId = 0; iId < m_flexGameObjects.Count && iId < m_activeInstacesCount; iId++) { Transform tr = m_flexGameObjects[iId].transform; FlexParticles particles = m_flexGameObjects[iId]; if (particles && particles.enabled) { if (m_flexGameObjects[iId].m_initialized) //if initialized just update some arrays { Array.Copy(particles.m_particles, 0, m_particles, particles.m_particlesIndex, particles.m_particlesCount); Array.Copy(particles.m_restParticles, 0, m_restParticles, particles.m_particlesIndex, particles.m_particlesCount); Array.Copy(particles.m_velocities, 0, m_velocities, particles.m_particlesIndex, particles.m_particlesCount); Array.Copy(particles.m_particlesActivity, 0, m_particlesActivity, particles.m_particlesIndex, particles.m_particlesCount); particles.m_collisionGroup = particles.m_collisionGroup == -1 ? iId : particles.m_collisionGroup; int phase = Flex.MakePhase(particles.m_collisionGroup, (int)particles.m_interactionType); for (int pId = 0; pId < particles.m_particlesCount; pId++) { m_phases[pId + particles.m_particlesIndex] = phase; } //needs to update this if the flex game object is changing position in the containcer (i.e. iId) //particles.m_collisionGroup = particles.m_collisionGroup == -1 ? iId : particles.m_collisionGroup; //int phase = Flex.MakePhase(particles.m_collisionGroup, (int)particles.m_interactionType); //for (int pId = 0; pId < particles.m_particlesCount; pId++) //{ // m_phases[pId + particles.m_particlesIndex] = phase; //} } else // do the full init { //if group is -1 set the consecutive bodyId, else use a user defined number particles.m_collisionGroup = particles.m_collisionGroup == -1 ? iId : particles.m_collisionGroup; int phase = Flex.MakePhase(particles.m_collisionGroup, (int)particles.m_interactionType); float invMass = particles.m_mass == 0 ? 0.0f : 1.0f / particles.m_mass; for (int pId = 0; pId < particles.m_particlesCount; pId++) { m_particles[pId + particles.m_particlesIndex].pos = tr.TransformPoint(particles.m_particles[pId].pos); m_particles[pId + particles.m_particlesIndex].invMass = particles.m_overrideMass ? invMass : particles.m_particles[pId].invMass; m_restParticles[pId + particles.m_particlesIndex] = particles.m_restParticles[pId]; //m_velocities[pId + particles.m_particlesIndex] = particles.m_velocities[pId]; m_velocities[pId + particles.m_particlesIndex] = particles.m_initialVelocity; m_colors[pId + particles.m_particlesIndex] = particles.m_colours[pId]; m_phases[pId + particles.m_particlesIndex] = phase; m_particlesActivity[pId + particles.m_particlesIndex] = particles.m_particlesActivity[pId]; } m_flexGameObjects[iId].m_initialized = true; } } } //m_particlesCount = UpdateActiveSet(); m_activeParticlesCount = UpdateActiveSet(); }
public void TestSetParticlesPhases() { float DELTA_T = 0.016f; float INTERACTION_DISTANCE = 0.5f; float SOLID_REST_DISTANCE = 0.2f; Flex.Library lib = Flex.Init(Flex.FLEX_VERSION, ErrorCallback); Flex.SolverDesc desc = default(Flex.SolverDesc); Flex.SetSolverDescDefaults(ref desc); desc.maxParticles = 1000; desc.maxDiffuseParticles = 1000; Flex.Solver solver = Flex.CreateSolver(lib, ref desc); Flex.Params prms = new Flex.Params(); Flex.GetParams(solver, ref prms); prms.radius = INTERACTION_DISTANCE; prms.solidRestDistance = SOLID_REST_DISTANCE; Flex.SetParams(solver, ref prms); Flex.Buffer particles = CreateBuffer(lib, 2, 4, new float[] { -0.001f, 0.0f, 0.0f, 1.0f, 0.001f, 0.0f, 0.0f, 1.0f, }); Flex.SetParticles(solver, particles); Flex.Buffer phases = CreateBuffer(lib, 2, 1, new int[] { Flex.MakePhase(1, Flex.Phase.SelfCollide), Flex.MakePhase(1, Flex.Phase.SelfCollide), }); Flex.SetPhases(solver, phases); Flex.SetActiveCount(solver, 2); Flex.Buffer active = CreateBuffer(lib, 2, 1, new int[] { 0, 1, }); Flex.SetActive(solver, active); Flex.UpdateSolver(solver, DELTA_T, 1); Flex.GetParticles(solver, particles); float[] values; ReadBuffer(lib, particles, 2, 4, out values); Assert.AreEqual(SOLID_REST_DISTANCE, Vector3.Distance(new Vector3(values[0], values[1], values[2]), new Vector3(values[4], values[5], values[6]))); Flex.FreeBuffer(particles); Flex.FreeBuffer(phases); Flex.FreeBuffer(active); Flex.DestroySolver(solver); Flex.Shutdown(lib); }
void spawnParticles(IntPtr particles, IntPtr velocities, IntPtr phases) { Vector4 particle; Vector3 velocity; int phase = Flex.MakePhase(0, Flex.Phase.SelfCollide | Flex.Phase.Fluid); unsafe { Vector4 *particlesPtr = (Vector4 *)particles; Vector3 *velocitiesPtr = (Vector3 *)velocities; int * phasesPtr = (int *)phases; for (int i = 0; i < 28; ++i) { particlesPtr[i] = new Vector4(UnityEngine.Random.Range(-10.0f, 10.0f), -3.5f, 13.0f, 1.0f); velocitiesPtr[i] = new Vector3(0.0f, 0.0f, 0.0f); phasesPtr[i] = phase; } } }
public void TestCreateDestroyInstance() { Flex.Library lib = Flex.Init(Flex.FLEX_VERSION, ErrorCallback); Flex.SolverDesc slvDsc = default(Flex.SolverDesc); Flex.SetSolverDescDefaults(ref slvDsc); slvDsc.maxParticles = 1000; Flex.Solver solver = Flex.CreateSolver(lib, ref slvDsc); FlexExt.Container container = FlexExt.CreateContainer(lib, solver, 1000); FlexExt.Asset.Handle asset = CreateTestClothAsset(); FlexExt.ParticleData data = FlexExt.MapParticleData(container); Matrix4x4 transform = Matrix4x4.identity; FlexExt.Instance.Handle instance = FlexExt.CreateInstance(container, ref data, asset, ref transform, 1.0f, 1.0f, 1.0f, Flex.MakePhase(1, Flex.Phase.Default), 1.0f); Assert.AreEqual(asset.asset.numParticles, instance.instance.numParticles); FlexExt.DestroyInstance(container, instance); FlexExt.UnmapParticleData(container); FlexExt.DestroyAsset(asset); FlexExt.DestroyContainer(container); Flex.DestroySolver(solver); Flex.Shutdown(lib); }
void OnGUI() { bool hasFlexComponent = false; GUILayout.Label("uFlex v0.5 - Developer Utils", EditorStyles.whiteLargeLabel); EditorGUILayout.HelpBox("This window is for advanced users. Improper use may break the uFlex objects.", MessageType.Warning); if (Selection.activeGameObject) { GUILayout.Label(Selection.activeGameObject.name, EditorStyles.boldLabel); FlexParticles particles = Selection.activeGameObject.GetComponent <FlexParticles>(); if (particles) { EditorGUILayout.Separator(); GUILayout.Label("Particles", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); m_mass = EditorGUILayout.FloatField("Particles Masses: ", m_mass); if (GUILayout.Button("Set ")) { Debug.Log("Mass Set To " + m_mass); float invMass = 1.0f / m_mass; for (int i = 0; i < particles.m_particlesCount; i++) { //skip locked particles if (particles.m_particles[i].invMass == 0) { continue; } particles.m_particles[i].invMass = invMass; } SceneView.RepaintAll(); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Apply Color")) { for (int i = 0; i < particles.m_particlesCount; i++) { particles.m_colours[i] = particles.m_colour; } SceneView.RepaintAll(); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } if (GUILayout.Button("Randomize Colors")) { for (int i = 0; i < particles.m_particlesCount; i++) { // particles.m_colours[i] = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value, 1.0f); particles.m_colours[i] = UnityEngine.Random.ColorHSV(0.0f, 1.0f, 0.0f, 1.0f, 0.5f, 1.0f); } SceneView.RepaintAll(); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } EditorGUILayout.EndHorizontal(); if (GUILayout.Button("Randomize Spacing")) { for (int i = 0; i < particles.m_particlesCount; i++) { particles.m_particles[i].pos += new Vector3(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value) * 0.1f; } SceneView.RepaintAll(); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } if (GUILayout.Button("Activate All")) { particles.m_particlesActivity = new bool[particles.m_particlesCount]; for (int i = 0; i < particles.m_particlesCount; i++) { particles.m_particlesActivity[i] = true; } SceneView.RepaintAll(); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } if (GUILayout.Button("Deactivate All")) { particles.m_particlesActivity = new bool[particles.m_particlesCount]; for (int i = 0; i < particles.m_particlesCount; i++) { particles.m_particlesActivity[i] = false; } SceneView.RepaintAll(); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } //if (GUILayout.Button("Deactivate Half")) //{ // particles.m_particlesActivity = new bool[particles.m_particlesCount]; // for (int i = 0; i < particles.m_particlesCount / 2; i++) // { // particles.m_particlesActivity[i] = true; // } // for (int i = particles.m_particlesCount / 2; i < particles.m_particlesCount; i++) // { // particles.m_particlesActivity[i] = false; // } // SceneView.RepaintAll(); // EditorUtility.SetDirty(particles); //} if (GUILayout.Button("Upgrade to v0.5")) { particles.m_densities = new float[particles.m_maxParticlesCount]; particles.m_velocities = new Vector3[particles.m_maxParticlesCount]; particles.m_phases = new int[particles.m_maxParticlesCount]; particles.m_restParticles = new Particle[particles.m_maxParticlesCount]; particles.m_smoothedParticles = new Particle[particles.m_maxParticlesCount]; particles.m_particlesActivity = new bool[particles.m_maxParticlesCount]; int phase = Flex.MakePhase(particles.m_collisionGroup, (int)particles.m_interactionType); for (int i = 0; i < particles.m_particlesCount; i++) { particles.m_velocities[i] = particles.m_initialVelocity; particles.m_particlesActivity[i] = true; particles.m_phases[i] = phase; particles.m_restParticles[i] = particles.m_particles[i]; particles.m_smoothedParticles[i] = particles.m_particles[i]; } SceneView.RepaintAll(); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } if (GUILayout.Button("Add FlexRopeMesh")) { FlexRopeMesh frm = Selection.activeGameObject.AddComponent <FlexRopeMesh>(); frm.m_particles = particles; frm.InitRope(particles.m_particlesCount); MeshFilter meshFilter = Selection.activeGameObject.AddComponent <MeshFilter>(); meshFilter.sharedMesh = frm.m_mesh; MeshRenderer rend = Selection.activeGameObject.AddComponent <MeshRenderer>(); Material mat = new Material(Shader.Find("Diffuse")); mat.name = "RopeMat"; mat.color = Color.yellow; rend.material = mat; SceneView.RepaintAll(); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } hasFlexComponent = true; } FlexSprings springs = Selection.activeGameObject.GetComponent <FlexSprings>(); if (springs) { EditorGUILayout.Separator(); GUILayout.Label("Springs", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Add Long Range Attachments to Rope")) { int ropeSegments = particles.m_particlesCount - 1; float restLength = Vector3.Distance(particles.m_particles[0].pos, particles.m_particles[1].pos); //distance + bend + tether (long range attachments) int springsCount = ropeSegments + (ropeSegments - 1) + ropeSegments; springs.m_springsCount = springsCount; Array.Resize <int>(ref springs.m_springIndices, springsCount * 2); Array.Resize <float>(ref springs.m_springCoefficients, springsCount); Array.Resize <float>(ref springs.m_springRestLengths, springsCount); for (int i = 0; i < ropeSegments; i++) { springs.m_springIndices[(ropeSegments + ropeSegments - 1) * 2 + i * 2 + 0] = 0; springs.m_springIndices[(ropeSegments + ropeSegments - 1) * 2 + i * 2 + 1] = i + 1; //negative stiffness means tether constraints //(i.e. prevents spring stretch but not its compression) springs.m_springCoefficients[(ropeSegments + ropeSegments - 1) + i] = -0.001f; springs.m_springRestLengths[(ropeSegments + ropeSegments - 1) + i] = i * restLength; } } EditorGUILayout.EndHorizontal(); } FlexShapeMatching shapes = Selection.activeGameObject.GetComponent <FlexShapeMatching>(); if (shapes) { EditorGUILayout.Separator(); GUILayout.Label("Shapes", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); m_clusterStiffness = EditorGUILayout.FloatField("Clusters Stiffness: ", m_clusterStiffness); if (GUILayout.Button("Set")) { for (int i = 0; i < shapes.m_shapesCount; i++) { shapes.m_shapeCoefficients[i] = m_clusterStiffness; } Debug.Log("Clusters Ks Set To " + m_clusterStiffness); SceneView.RepaintAll(); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Separator(); GUILayout.Label("Skinning"); EditorGUILayout.BeginHorizontal(); m_skinFalloff = EditorGUILayout.FloatField("Falloff: ", m_skinFalloff); m_skinMaxDist = EditorGUILayout.FloatField("Max Distance: ", m_skinMaxDist); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); inputMesh = EditorGUILayout.ObjectField(new GUIContent("Input Mesh", "The input mesh"), inputMesh, typeof(Mesh), true) as Mesh; if (GUILayout.Button("Generate Skinning") && inputMesh) { Vector3[] vertices = inputMesh.vertices; float[] skinWeights = new float[inputMesh.vertexCount * 4]; int[] skinIndices = new int[inputMesh.vertexCount * 4]; FlexExt.flexExtCreateSoftMeshSkinning(vertices, inputMesh.vertexCount, shapes.m_shapeCenters, shapes.m_shapesCount, m_skinFalloff, m_skinMaxDist, skinWeights, skinIndices); Mesh mesh = new Mesh(); mesh.name = this.inputMesh.name + "FlexMesh"; mesh.vertices = this.inputMesh.vertices; mesh.triangles = this.inputMesh.triangles; mesh.normals = this.inputMesh.normals; mesh.uv = this.inputMesh.uv; Transform[] bones = new Transform[shapes.m_shapesCount]; BoneWeight[] boneWeights = new BoneWeight[this.inputMesh.vertexCount]; Matrix4x4[] bindPoses = new Matrix4x4[shapes.m_shapesCount]; Vector3[] rigidRestPoses = new Vector3[shapes.m_shapesCount]; for (int i = 0; i < shapes.m_shapesCount; i++) { rigidRestPoses[i] = shapes.m_shapeCenters[i]; bones[i] = new GameObject("FlexShape_" + i).transform; bones[i].parent = Selection.activeGameObject.transform; bones[i].localPosition = shapes.m_shapeCenters[i]; bones[i].localRotation = Quaternion.identity; bindPoses[i] = bones[i].worldToLocalMatrix * Selection.activeGameObject.transform.localToWorldMatrix; } for (int i = 0; i < this.inputMesh.vertexCount; i++) { boneWeights[i].boneIndex0 = skinIndices[i * 4 + 0]; boneWeights[i].boneIndex1 = skinIndices[i * 4 + 1]; boneWeights[i].boneIndex2 = skinIndices[i * 4 + 2]; boneWeights[i].boneIndex3 = skinIndices[i * 4 + 3]; boneWeights[i].weight0 = skinWeights[i * 4 + 0]; boneWeights[i].weight1 = skinWeights[i * 4 + 1]; boneWeights[i].weight2 = skinWeights[i * 4 + 2]; boneWeights[i].weight3 = skinWeights[i * 4 + 3]; } mesh.bindposes = bindPoses; mesh.boneWeights = boneWeights; mesh.RecalculateNormals(); mesh.RecalculateBounds(); AssetDatabase.CreateAsset(mesh, "Assets/uFlex/Meshes/" + this.inputMesh.name + "FlexMesh.asset"); AssetDatabase.SaveAssets(); FlexSkinnedMesh skin = Selection.activeGameObject.AddComponent <FlexSkinnedMesh>(); skin.m_bones = bones; skin.m_boneWeights = boneWeights; skin.m_bindPoses = bindPoses; SkinnedMeshRenderer rend = Selection.activeGameObject.AddComponent <SkinnedMeshRenderer>(); rend.sharedMesh = mesh; // rend.sharedMesh = this.inputMesh; rend.updateWhenOffscreen = true; rend.quality = SkinQuality.Bone4; rend.bones = bones; SceneView.RepaintAll(); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } EditorGUILayout.EndHorizontal(); if (GUILayout.Button("Upgrade to v0.5")) { int shapeIndex = 0; int shapeIndexOffset = 0; shapes.m_shapeTranslations = new Vector3[shapes.m_shapesCount]; shapes.m_shapeRotations = new Quaternion[shapes.m_shapesCount]; shapes.m_shapeRestPositions = new Vector3[shapes.m_shapeIndicesCount]; int shapeStart = 0; for (int s = 0; s < shapes.m_shapesCount; s++) { shapes.m_shapeTranslations[s] = new Vector3(); shapes.m_shapeRotations[s] = Quaternion.identity; // int indexOffset = shapeIndexOffset; //m_shapeOffsets[shapeIndex + 1] = shapes.m_shapeOffsets[s] + indexOffset; //m_shapeCoefficients[shapeIndex] = shapes.m_shapeCoefficients[s]; //m_shapeTranslations[shapeIndex] = shapes.m_shapeTranslations[s]; //m_shapeRotations[shapeIndex] = shapes.m_shapeRotations[s]; shapeIndex++; int shapeEnd = shapes.m_shapeOffsets[s]; for (int i = shapeStart; i < shapeEnd; ++i) { int p = shapes.m_shapeIndices[i]; // remap indices and create local space positions for each shape Vector3 pos = particles.m_particles[p].pos; shapes.m_shapeRestPositions[shapeIndexOffset] = pos - shapes.m_shapeCenters[s]; // m_shapeIndices[shapeIndexOffset] = shapes.m_shapeIndices[i] + particles.m_particlesIndex; shapeIndexOffset++; } shapeStart = shapeEnd; } SceneView.RepaintAll(); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } hasFlexComponent = true; } } if (!hasFlexComponent) { GUILayout.Label("Select GameObject with Flex Components", EditorStyles.boldLabel); } }