public override void GenerateDistribution() { distribution.Clear(); if (particleSize <= 0 || mesh == null) { return; } // Calculate voxel size so that no more than 32^3 points are created: Vector3 boundsSize = Vector3.Scale(mesh.bounds.size, Vector3.one); float voxelSize = Mathf.Max(boundsSize.x / 32.0f, boundsSize.y / 32.0f, boundsSize.z / 32.0f, particleSize); // Voxelize mesh: MeshVoxelizer voxelizer = new MeshVoxelizer(mesh, voxelSize); voxelizer.Voxelize(Vector3.one); MeshVoxelizer.Voxel[,,] voxels = voxelizer.voxels; // Create one distribution point at the center of each volume/surface voxel: for (int x = 0; x < voxels.GetLength(0); ++x) { for (int y = 0; y < voxels.GetLength(1); ++y) { for (int z = 0; z < voxels.GetLength(2); ++z) { if (voxels[x, y, z] != MeshVoxelizer.Voxel.Outside) { Vector3 pos = new Vector3(voxelizer.Origin.x + x + 0.5f, voxelizer.Origin.y + y + 0.5f, voxelizer.Origin.z + z + 0.5f) * voxelSize; distribution.Add(new ObiEmitterShape.DistributionPoint(pos, Vector3.forward)); } } } } }
protected override IEnumerator Initialize() { if (inputMesh == null || !inputMesh.isReadable) { // TODO: return an error in the coroutine. Debug.LogError("The input mesh is null, or not readable."); yield break; } ClearParticleGroups(); List <Vector3> particles = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); // Calculate voxel size so that no more than 32^3 particles are created: Vector3 boundsSize = Vector3.Scale(inputMesh.bounds.size, Vector3.one); float voxelSize = Mathf.Max(boundsSize.x / 32.0f, boundsSize.y / 32.0f, boundsSize.z / 32.0f, particleRadius * 2 * (1 - particleOverlap)); // Voxelize mesh and calculate discrete distance field: MeshVoxelizer voxelizer = new MeshVoxelizer(inputMesh, voxelSize); VoxelDistanceField df = new VoxelDistanceField(voxelizer); voxelizer.Voxelize(scale); df.JumpFlood(); MeshVoxelizer.Voxel[,,] voxels = voxelizer.voxels; for (int x = 0; x < voxels.GetLength(0); ++x) { for (int y = 0; y < voxels.GetLength(1); ++y) { for (int z = 0; z < voxels.GetLength(2); ++z) { if (voxels[x, y, z] != MeshVoxelizer.Voxel.Outside) { particles.Add(new Vector3(voxelizer.Origin.x + x + 0.5f, voxelizer.Origin.y + y + 0.5f, voxelizer.Origin.z + z + 0.5f) * voxelSize); normals.Add(df.distanceField[x, y, z] - new Vector3Int(x, y, z)); } } } } positions = new Vector3[particles.Count]; orientations = new Quaternion[particles.Count]; restPositions = new Vector4[particles.Count]; restOrientations = new Quaternion[particles.Count]; velocities = new Vector3[particles.Count]; angularVelocities = new Vector3[particles.Count]; invMasses = new float[particles.Count]; invRotationalMasses = new float[particles.Count]; principalRadii = new Vector3[particles.Count]; phases = new int[particles.Count]; colors = new Color[particles.Count]; m_ActiveParticleCount = particles.Count; for (int i = 0; i < particles.Count; ++i) { // Perform ellipsoid fitting: Vector3 avgNormal = Vector3.zero; List <Vector3> neighbourVertices = new List <Vector3>(); Vector3 centroid = particles[i]; Quaternion orientation = Quaternion.LookRotation(normals[i]); Vector3 principalValues = Vector3.one * voxelSize * (0.5f + particleOverlap); invRotationalMasses[i] = invMasses[i] = 1.0f; positions[i] = Vector3.Lerp(particles[i], centroid, shapeSmoothing); restPositions[i] = positions[i]; orientations[i] = orientation; restOrientations[i] = orientation; restPositions[i][3] = 1; // activate rest position. principalRadii[i] = principalValues; phases[i] = ObiUtils.MakePhase(1, 0); //Oni.MakePhase(1, (selfCollisions ? Oni.ParticlePhase.SelfCollide : 0) | (oneSided ? Oni.ParticlePhase.OneSided : 0)); colors[i] = Color.white; if (i % 100 == 0) { yield return(new CoroutineJob.ProgressInfo("ObiSoftbody: generating particles...", i / (float)particles.Count)); } } IEnumerator sc = CreateShapeMatchingConstraints(particles); while (sc.MoveNext()) { yield return(sc.Current); } // Initialize pin constraints: pinConstraintsData = new ObiPinConstraintsData(); ObiPinConstraintsBatch pinBatch = new ObiPinConstraintsBatch(); pinConstraintsData.AddBatch(pinBatch); }