void UpdateParams() { Flex.Params prms = new Flex.Params(); Flex.GetParams(m_solverHandle, ref prms); prms.numIterations = m_iterationCount; prms.gravity = m_gravity; prms.radius = m_radius; prms.solidRestDistance = m_solidRest; prms.fluidRestDistance = m_fluidRest; prms.staticFriction = m_staticFriction; prms.dynamicFriction = m_dynamicFriction; prms.particleFriction = m_particleFriction; prms.restitution = m_restitution; prms.adhesion = m_adhesion; prms.sleepThreshold = m_sleepThreshold; prms.maxSpeed = m_maxSpeed; prms.maxAcceleration = m_maxAcceleration; prms.shockPropagation = m_shockPropagation; prms.dissipation = m_dissipation; prms.damping = m_damping; prms.wind = m_wind; prms.drag = m_drag; prms.lift = m_lift; //prms.fluid = m_fluid; prms.cohesion = m_cohesion; prms.surfaceTension = m_surfaceTension; prms.viscosity = m_viscosity; prms.vorticityConfinement = m_vorticityConfinement; prms.anisotropyScale = m_anisotropyScale; prms.anisotropyMin = m_anisotropyMin; prms.anisotropyMax = m_anisotropyMax; prms.smoothing = m_smoothing; prms.solidPressure = m_solidPressure; prms.freeSurfaceDrag = m_freeSurfaceDrag; prms.buoyancy = m_buoyancy; prms.diffuseThreshold = m_diffuseThreshold; prms.diffuseBuoyancy = m_diffuseBuoyancy; prms.diffuseDrag = m_diffuseDrag; prms.diffuseBallistic = m_diffuseBallistic; //prms.diffuseSortAxis = m_diffuseSortAxis; prms.diffuseLifetime = m_diffuseLifetime; //prms.plasticThreshold = m_plasticThreshold; //prms.plasticCreep = m_plasticCreep; prms.collisionDistance = m_collisionDistance; prms.particleCollisionMargin = m_particleCollisionMargin; prms.shapeCollisionMargin = m_shapeCollisionMargin; prms.numPlanes = m_planes.Length; prms.plane0 = m_planes.Length > 0 ? m_planes[0] : Vector4.zero; prms.plane1 = m_planes.Length > 1 ? m_planes[1] : Vector4.zero; prms.plane2 = m_planes.Length > 2 ? m_planes[2] : Vector4.zero; prms.plane3 = m_planes.Length > 3 ? m_planes[3] : Vector4.zero; prms.plane4 = m_planes.Length > 4 ? m_planes[4] : Vector4.zero; prms.plane5 = m_planes.Length > 5 ? m_planes[5] : Vector4.zero; prms.plane6 = m_planes.Length > 6 ? m_planes[6] : Vector4.zero; prms.plane7 = m_planes.Length > 7 ? m_planes[7] : Vector4.zero; prms.relaxationMode = m_relaxationMode; prms.relaxationFactor = m_relaxationFactor; Flex.SetParams(m_solverHandle, ref prms); }
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); }
public void TestSetSpringConstraints() { float DELTA_T = 0.016f; float INTERACTION_DISTANCE = 0.5f; float SOLID_REST_DISTANCE = 0.2f; float SPRING_LENGTH = 1.0f; 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 indices = CreateBuffer(lib, 2, 1, new int[] { 0, 1 }); Flex.Buffer lengths = CreateBuffer(lib, 1, 1, new float[] { SPRING_LENGTH }); Flex.Buffer stiffness = CreateBuffer(lib, 1, 1, new float[] { 1.0f }); Flex.SetSprings(solver, indices, lengths, stiffness, 1); 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(SPRING_LENGTH, Vector3.Distance(new Vector3(values[0], values[1], values[2]), new Vector3(values[4], values[5], values[6])), 0.001f); Flex.FreeBuffer(particles); Flex.FreeBuffer(indices); Flex.FreeBuffer(lengths); Flex.FreeBuffer(stiffness); Flex.FreeBuffer(active); Flex.DestroySolver(solver); Flex.Shutdown(lib); }
public void TestSetGetParticlesVelocities() { Vector3 GRAVITY = new Vector3(1, 2, 3); float DELTA_T = 0.016f; 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.gravity = GRAVITY; Flex.SetParams(solver, ref prms); Flex.Buffer particles = CreateBuffer(lib, 1, 4, new float[] { 0.0f, 0.0f, 0.0f, 1.0f, }); Flex.SetParticles(solver, particles); Flex.Buffer velocities = CreateBuffer(lib, 1, 3, new float[] { 0.0f, 0.0f, 0.0f, }); Flex.SetVelocities(solver, velocities); Flex.SetActiveCount(solver, 1); Flex.Buffer active = CreateBuffer(lib, 1, 1, new int[] { 0 }); Flex.SetActive(solver, active); Flex.UpdateSolver(solver, DELTA_T, 1); Flex.GetVelocities(solver, velocities); float[] values; ReadBuffer(lib, velocities, 1, 3, out values); Assert.AreEqual(GRAVITY * DELTA_T, new Vector3(values[0], values[1], values[2])); Flex.FreeBuffer(particles); Flex.FreeBuffer(velocities); Flex.FreeBuffer(active); Flex.DestroySolver(solver); Flex.Shutdown(lib); }
public void TestParamsPlaneCollision() { float DELTA_T = 0.016f; float INTERACTION_DISTANCE = 0.5f; float SOLID_REST_DISTANCE = 0.2f; Vector3 GRAVITY = new Vector3(0, -9.81f, 0); Flex.Library lib = Flex.Init(Flex.FLEX_VERSION, ErrorCallback); Flex.SolverDesc desc = default(Flex.SolverDesc); Flex.SetSolverDescDefaults(ref desc); desc.maxParticles = 1000; desc.maxDiffuseParticles = 0; 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; prms.gravity = GRAVITY; prms.plane0 = new Vector4(0.0f, 1.0f, 0.0f, 0.0f); prms.numPlanes = 1; Flex.SetParams(solver, ref prms); Flex.Buffer particles = CreateBuffer(lib, 1, 4, new float[] { 0.0f, 2.0f, 0.0f, 1.0f }); Flex.SetParticles(solver, particles); Flex.SetActiveCount(solver, 1); Flex.Buffer active = CreateBuffer(lib, 1, 1, new int[] { 0 }); Flex.CopyDesc cpyDsc; cpyDsc.srcOffset = cpyDsc.dstOffset = 0; cpyDsc.elementCount = 1; Flex.SetActive(solver, active, ref cpyDsc); for (int i = 0; i < 100; ++i) { Flex.UpdateSolver(solver, DELTA_T, 1); } Flex.GetParticles(solver, particles); float[] values; ReadBuffer(lib, particles, 1, 4, out values); Assert.AreEqual(0, values[1], 0.001f); Flex.FreeBuffer(active); Flex.FreeBuffer(particles); Flex.DestroySolver(solver); Flex.Shutdown(lib); }
// Start is called before the first frame update void Start() { _rayMarcher = Camera.main.GetComponent <RayMarcher>(); Flex.Params param = new Flex.Params(); param.radius = 10.0f; param.fluidRestDistance = 1.0f; param.gravity = new Vector3(0.0f, -9.81f, 0.0f); //param.viscosity = 10.0f; Flex.SetParams(_solver, ref param); // Map buffers for reading / writing. particles = Flex.Map(_particleBuffer); velocities = Flex.Map(_velocityBuffer); phases = Flex.Map(_phaseBuffer); // Spawn particles. spawnParticles(particles, velocities, phases); }
public void TestSetGetParams() { Vector3 GRAVITY = new Vector3(1, 2, 3); 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); Assert.AreNotEqual(GRAVITY, prms.gravity); prms.gravity = GRAVITY; Flex.SetParams(solver, ref prms); Assert.AreEqual(GRAVITY, prms.gravity); Flex.DestroySolver(solver); Flex.Shutdown(lib); }
protected override void SolveInstance(IGH_DataAccess DA) { //CONTINUE HERE!!!! UpdateTask = new Task <int>(() => Update()); FlexParams param = new FlexParams(); FlexCollisionGeometry geom = new FlexCollisionGeometry(); List <FlexForceField> forceFields = new List <FlexForceField>(); List <FlexScene> scenes = new List <FlexScene>(); List <ConstraintSystem> constraints = new List <ConstraintSystem>(); FlexSolverOptions options = new FlexSolverOptions(); bool reset = false; bool go = false; DA.GetData(6, ref reset); DA.GetData(7, ref go); if (reset) { //reset everything related to time tracking counter = 0; totalTimeMs = 0; totalUpdateTimeMs = 0; sw.Stop(); sw.Reset(); outInfo = new List <string>(); //retrieve relevant data DA.GetData(0, ref param); DA.GetData(1, ref geom); DA.GetDataList(2, forceFields); DA.GetDataList(3, scenes); DA.GetDataList(4, constraints); DA.GetData(5, ref options); sceneTimeStamps = new List <int>(); forceFieldTimeStamps = new List <int>(); //destroy old Flex instance if (flex != null) { flex.Destroy(); } //Create new instance and assign everything flex = new Flex(); flex.SetParams(param); flex.SetCollisionGeometry(geom); flex.SetForceFields(forceFields); foreach (FlexForceField f in forceFields) { forceFieldTimeStamps.Add(f.TimeStamp); } FlexScene scene = new FlexScene(); foreach (FlexScene s in scenes) { scene.AppendScene(s); sceneTimeStamps.Add(s.TimeStamp); } foreach (ConstraintSystem c in constraints) { scene.RegisterCustomConstraints(c.AnchorIndices, c.ShapeMatchingIndices, c.ShapeStiffness, c.SpringPairIndices, c.SpringStiffnesses, c.SpringTargetLengths, c.TriangleIndices, c.TriangleNormals); constraintTimeStamps.Add(c.TimeStamp); } flex.SetScene(scene); flex.SetSolverOptions(options); } else if (go && flex != null && flex.IsReady()) { DA.GetData(5, ref options); if (options.TimeStamp != optionsTimeStamp) { flex.SetSolverOptions(options); } if (options.SceneMode == 0 || options.SceneMode == 1) { //update params if timestamp expired DA.GetData(0, ref param); if (param.TimeStamp != paramsTimeStamp) { flex.SetParams(param); paramsTimeStamp = param.TimeStamp; } //update geom if timestamp expired if (DA.GetData(1, ref geom)) { if (geom.TimeStamp != geomTimeStamp) { flex.SetCollisionGeometry(geom); geomTimeStamp = geom.TimeStamp; } } else if (geom != null) { flex.SetCollisionGeometry(new FlexCollisionGeometry()); } //update forcefields where timestamp expired DA.GetDataList(2, forceFields); bool needsUpdate = false; for (int i = forceFieldTimeStamps.Count; i < forceFields.Count; i++) { forceFieldTimeStamps.Add(forceFields[i].TimeStamp); needsUpdate = true; } for (int i = 0; i < forceFields.Count; i++) { if (forceFields[i].TimeStamp != forceFieldTimeStamps[i]) { needsUpdate = true; forceFieldTimeStamps[i] = forceFields[i].TimeStamp; } } if (needsUpdate) { flex.SetForceFields(forceFields); } //update scenes where timestamp expired DA.GetDataList(3, scenes); for (int i = sceneTimeStamps.Count; i < scenes.Count; i++) { sceneTimeStamps.Add(scenes[i].TimeStamp); } for (int i = 0; i < scenes.Count; i++) { if (scenes[i].TimeStamp != sceneTimeStamps[i]) { if (options.SceneMode == 0) { flex.SetScene(flex.Scene.AlterScene(scenes[i], false)); } else { flex.SetScene(flex.Scene.AppendScene(scenes[i])); } sceneTimeStamps[i] = scenes[i].TimeStamp; } } DA.GetDataList(4, constraints); for (int i = constraintTimeStamps.Count; i < constraints.Count; i++) { constraintTimeStamps.Add(constraints[i].TimeStamp); } for (int i = 0; i < constraints.Count; i++) { ConstraintSystem c = constraints[i]; if (c.TimeStamp != constraintTimeStamps[i]) { if (!flex.Scene.RegisterCustomConstraints(c.AnchorIndices, c.ShapeMatchingIndices, c.ShapeStiffness, c.SpringPairIndices, c.SpringStiffnesses, c.SpringTargetLengths, c.TriangleIndices, c.TriangleNormals)) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Custom constraint indices exceeded particle count. No constraints applied!"); } flex.SetScene(flex.Scene); constraintTimeStamps[i] = constraints[i].TimeStamp; } } } //Add timing info outInfo = new List <string>(); counter++; outInfo.Add(counter.ToString()); long currentTickTimeMs = sw.ElapsedMilliseconds; sw.Restart(); totalTimeMs += currentTickTimeMs; outInfo.Add(totalTimeMs.ToString()); outInfo.Add(currentTickTimeMs.ToString()); float avTotalTickTime = ((float)totalTimeMs / (float)counter); outInfo.Add(avTotalTickTime.ToString()); //start update UpdateTask.Start(); //Add solver timing info int tickTimeSolver = UpdateTask.Result; totalUpdateTimeMs += tickTimeSolver; float ratUpdateTime = ((float)totalUpdateTimeMs / (float)counter); outInfo.Add(tickTimeSolver.ToString()); outInfo.Add(ratUpdateTime.ToString()); } if (go && options.FixedTotalIterations < 1) { ExpireSolution(true); } else if (flex != null && UpdateTask.Status == TaskStatus.Running) { UpdateTask.Dispose(); } if (flex != null) { DA.SetData(0, flex); } DA.SetDataList(1, outInfo); }
void Start() { if (m_cntr == null) { m_cntr = GetComponent <FlexContainer>(); } if (m_diffuseParticles == null) { m_diffuseParticles = GetComponent <FlexDiffuseParticles>(); } if (m_parameters == null) { m_parameters = GetComponent <FlexParameters>(); } if (m_colliders == null) { m_colliders = GetComponent <FlexColliders>(); } m_errorCallback = new Flex.ErrorCallback(this.ErrorCallback); m_timers = new Flex.Timers(); Flex.Error flexErr = Flex.Init(100, m_errorCallback, -1); Debug.Log("NVidia FleX v" + Flex.GetVersion()); if (flexErr != Flex.Error.eFlexErrorNone) { Debug.LogError("FlexInit: " + flexErr); } if (m_diffuseParticles) { m_solverPtr = Flex.CreateSolver(m_cntr.m_maxParticlesCount, m_diffuseParticles.m_maxDiffuseParticlesCount, m_maxNeighboursCount); } else { m_solverPtr = Flex.CreateSolver(m_cntr.m_maxParticlesCount, 0, m_maxNeighboursCount); } m_parameters.GetParams(ref m_params); Flex.SetParams(m_solverPtr, ref m_params); m_cntr.UpdateContainer(); m_processors = FindObjectsOfType <FlexProcessor>(); foreach (FlexProcessor fp in m_processors) { fp.FlexStart(this, m_cntr, m_parameters); } PushParticlesToGPU(m_solverPtr, m_cntr, Flex.Memory.eFlexMemoryHost); PushConstraintsToGPU(m_solverPtr, m_cntr, Flex.Memory.eFlexMemoryHost); if (m_colliders) { m_colliders.ProcessColliders(m_solverPtr, Flex.Memory.eFlexMemoryHost); } //Flex.SetShapes(m_solverPtr, m_cnt.shapeGeometry, shapeGeometry.Length, shapeAabbMin, shapeAabbMax, shapeStarts, shapePositions, shapeRotations, // shapePrevPositions, shapePrevRotations, shapeFlags, shapeStarts.Length, Flex.Memory.eFlexMemoryHost); }
void Update() { //get the data from the GPU PullParticlesFromGPU(m_solverPtr, m_cntr, Flex.Memory.eFlexMemoryHostAsync); if (m_diffuseParticles && m_diffuseParticles.m_maxDiffuseParticlesCount > 0) { m_diffuseParticles.m_diffuseParticlesCount = Flex.GetDiffuseParticles(m_solverPtr, m_diffuseParticles.m_diffuseParticlesHndl.AddrOfPinnedObject(), m_diffuseParticles.m_diffuseVelocitiesHndl.AddrOfPinnedObject(), m_diffuseParticles.m_sortedDepthHndl.AddrOfPinnedObject(), Flex.Memory.eFlexMemoryHostAsync); } //update solver parameters //TODO check impact on performance m_parameters.GetParams(ref m_params); Flex.SetParams(m_solverPtr, ref m_params); //ensure memory transfers have finished Flex.SetFence(); Flex.WaitFence(); //for (int i = 0; i < m_cntr.m_particlesCount; i++) //{ // print("index:" + i + "velocity:" + m_cntr.m_velocities[i]); //} if (Input.GetKeyDown(KeyCode.Space)) { Debug.Log("uFlex Scene Reset"); for (int i = 0; i < m_cntr.m_particlesCount; i++) { m_cntr.m_particles[i] = m_cntr.m_restParticles[i]; m_cntr.m_velocities[i] = new Vector3(); } } //copy data to instances UpdateGameObjects(); //do the custom processing on flex gameobjects m_processors = FindObjectsOfType <FlexProcessor>(); foreach (FlexProcessor fp in m_processors) { fp.PreContainerUpdate(this, m_cntr, m_parameters); } //update container if (m_dynamic) { m_cntr.UpdateContainer(); } //do the custom processing on the container foreach (FlexProcessor fp in m_processors) { fp.PostContainerUpdate(this, m_cntr, m_parameters); } //copy the processed data back to the GPU PushParticlesToGPU(m_solverPtr, m_cntr, Flex.Memory.eFlexMemoryHostAsync); if (m_dynamic) { //Async transfers on unpinned arrays!? //PushConstraintsToGPU(m_solverPtr, m_cntr, Flex.Memory.eFlexMemoryHostAsync); //m_colliders.UpdateColliders(m_solverPtr, Flex.Memory.eFlexMemoryHostAsync); PushConstraintsToGPU(m_solverPtr, m_cntr, Flex.Memory.eFlexMemoryHost); m_colliders.UpdateColliders(m_solverPtr, Flex.Memory.eFlexMemoryHost); } //do not wait here for memory transfers to finish //Flex.SetFence(); //Flex.WaitFence(); //Debug.Log("Total Time: "+m_timers.mTotal); }
public void TestSetRigidsGetTransforms() { float DELTA_T = 0.016f; float INTERACTION_DISTANCE = 0.5f; float SOLID_REST_DISTANCE = 0.2f; Vector3 GRAVITY = new Vector3(1, 2, 3); 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; prms.gravity = GRAVITY; Flex.SetParams(solver, ref prms); Flex.Buffer particles = CreateBuffer(lib, 8, 4, new float[] { 0.1f, 0.1f, 0.1f, 1.0f, -0.1f, 0.1f, 0.1f, 1.0f, -0.1f, -0.1f, 0.1f, 1.0f, 0.1f, -0.1f, 0.1f, 1.0f, 0.1f, 0.1f, -0.1f, 1.0f, -0.1f, 0.1f, -0.1f, 1.0f, -0.1f, -0.1f, -0.1f, 1.0f, 0.1f, -0.1f, -0.1f, 1.0f, }); Flex.SetParticles(solver, particles); Flex.Buffer active = CreateBuffer(lib, 8, 1, new int[] { 0, 1, 2, 3, 4, 5, 6, 7 }); Flex.SetActive(solver, active); Flex.Buffer offsets = CreateBuffer(lib, 2, 1, new int[] { 0, 8 }); Flex.Buffer indices = CreateBuffer(lib, 8, 1, new int[] { 0, 1, 2, 3, 4, 5, 6, 7 }); Flex.Buffer positions = CreateBuffer(lib, 8, 3, new float[] { 0.1f, 0.1f, 0.1f, -0.1f, 0.1f, 0.1f, -0.1f, -0.1f, 0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 0.1f, -0.1f, -0.1f, 0.1f, -0.1f, -0.1f, -0.1f, -0.1f, 0.1f, -0.1f, -0.1f, }); const float N = 0.57735026918962576450914878050196f; // 1 / sqrt(3) Flex.Buffer normals = CreateBuffer(lib, 8, 4, new float[] { N, N, N, 0, -N, N, N, 0, -N, -N, N, 0, N, -N, N, 0, N, N, -N, 0, -N, N, -N, 0, -N, -N, -N, 0, N, -N, -N, 0, }); Flex.Buffer stiffness = CreateBuffer(lib, 1, 1, new float[] { 1.0f }); Flex.Buffer thresholds = CreateBuffer(lib, 1, 1, new float[] { 1.0f }); Flex.Buffer creeps = CreateBuffer(lib, 1, 1, new float[] { 1.0f }); Flex.Buffer rotations = CreateBuffer(lib, 1, 4, new float[] { 0.0f, 0.0f, 0.0f, 1.0f }); Flex.Buffer translations = CreateBuffer(lib, 1, 3, new float[] { 0.0f, 0.0f, 0.0f }); Flex.SetRigids(solver, offsets, indices, positions, normals, stiffness, thresholds, creeps, rotations, translations, 1, 8); Flex.UpdateSolver(solver, DELTA_T, 1); Flex.Buffer nullBuffer = default(Flex.Buffer); Flex.GetRigids(solver, nullBuffer, nullBuffer, nullBuffer, nullBuffer, nullBuffer, nullBuffer, nullBuffer, rotations, translations); float[] values; ReadBuffer(lib, translations, 1, 3, out values); Vector3 expectedPosition = GRAVITY * DELTA_T * DELTA_T; Vector3 currentPosition = new Vector3(values[0], values[1], values[2]); Assert.AreEqual(expectedPosition.magnitude, currentPosition.magnitude, 0.001f); Flex.FreeBuffer(translations); Flex.FreeBuffer(rotations); Flex.FreeBuffer(creeps); Flex.FreeBuffer(thresholds); Flex.FreeBuffer(stiffness); Flex.FreeBuffer(normals); Flex.FreeBuffer(positions); Flex.FreeBuffer(indices); Flex.FreeBuffer(offsets); Flex.FreeBuffer(active); Flex.FreeBuffer(particles); Flex.DestroySolver(solver); Flex.Shutdown(lib); }