private void GenerateMesh(out Mesh mesh, out Mesh meshDebug) { mesh = new Mesh(); meshDebug = new Mesh { vertices = carrierMesh.vertices, triangles = carrierMesh.triangles, uv = carrierMesh.uv }; Vector3 particleAverageNormal = Vector3.zero; for (int i = 0; i < particleMesh.vertexCount; i++) { particleAverageNormal += particleMesh.normals[i]; } particleAverageNormal.Normalize(); var numTriangles = carrierMesh.triangles.Length / 3; CombineInstance[] combine = new CombineInstance[numParticles]; for (int i = 0; i < numParticles; i++) { var particle = new Mesh { vertices = particleMesh.vertices, triangles = particleMesh.triangles, colors = particleMesh.colors, normals = particleMesh.normals, tangents = particleMesh.tangents, uv = particleMesh.uv, }; int triangleIndex = carrierSampling == CarrierSampling.Random ? Random.Range(0, numTriangles) : (int)Mathf.Lerp(0, numTriangles, i / (float)numParticles); var vertexIndex0 = carrierMesh.triangles[triangleIndex * 3 + 0]; var vertexIndex1 = carrierMesh.triangles[triangleIndex * 3 + 1]; var vertexIndex2 = carrierMesh.triangles[triangleIndex * 3 + 2]; var a = carrierMesh.vertices[vertexIndex0]; var b = carrierMesh.vertices[vertexIndex1]; var c = carrierMesh.vertices[vertexIndex2]; var p = GetRandomPositionWithinTriangle(a, b, c); p = Vector3.Scale(p, carrierScale); var triangleNormal = (carrierMesh.normals[vertexIndex0] + carrierMesh.normals[vertexIndex1] + carrierMesh.normals[vertexIndex2]).normalized; var triangleTangent = (carrierMesh.tangents[vertexIndex0] + carrierMesh.tangents[vertexIndex1] + carrierMesh.tangents[vertexIndex2]).normalized; if (Random.value <= offsetAlongNormalFraction) { p += triangleNormal * offsetAlongNormal; } var up = Vector3.Cross(triangleNormal, triangleTangent); var rotation = Quaternion.LookRotation(-triangleNormal, up); // Random rotation for particle clouds. rotation = Quaternion.RotateTowards(rotation, Random.rotationUniform, particleRotationRange); // Rotation bias for billboard meshes. var biasTowards = Quaternion.Euler(biasTowardRotation); rotation = Quaternion.RotateTowards(rotation, biasTowards, 180f * particleRotationBias); // Give the particle a random forward rotation. rotation *= Quaternion.AngleAxis(360f * Random.value, particleAverageNormal); var scaleVariance = Random.Range(1f - particleScaleVariance, 1f); var particleTransform = Matrix4x4.Translate(p) * Matrix4x4.Rotate(rotation) * Matrix4x4.Scale(particleScale * scaleVariance) * Matrix4x4.identity; var combineInstance = new CombineInstance { mesh = particle, transform = particleTransform }; combine[i] = combineInstance; } mesh.CombineMeshes(combine, true, true); // Calculate normals. { var normals = new Vector3[mesh.vertexCount]; for (int i = 0; i < normals.Length; i++) { int vertexIndex = oneNormalPerParticle ? i - i % particleMesh.vertexCount : i; var v = mesh.vertices[vertexIndex].normalized; Vector3 noise = Vector3.zero; if (noiseEnabled) { var nv = v * noiseFrequency; var nx = NoiseUtil.Fbm(Hash.Float(noiseSeed, 0u, -1000, 1000), nv.x, noiseOctaves); var ny = NoiseUtil.Fbm(Hash.Float(noiseSeed, 1u, -1000, 1000), nv.y, noiseOctaves); var nz = NoiseUtil.Fbm(Hash.Float(noiseSeed, 2u, -1000, 1000), nv.z, noiseOctaves); noise = Vector3.Scale(new Vector3(nx, ny, nz), noiseScale) / 0.75f * noiseAmplitude; } normals[i] = (v + noise).normalized; } mesh.normals = normals; } }