Unity Instantiate along surface

 https://forum.unity.com/threads/how-to-procedurally-add-objects-to-surface-of-mesh.576814/


Your second option is by far the easier one: create a mesh collider, then raycast at it (probably from a random position to a point inside the mesh), and set the position to the raycast hit point, and use hit.normal to align it along the surface. This does mean that you'll be placing things only on places that get hit by the raycast, so if you have concave surfaces things won't be able to be randomly placed there.

The other option is a little more "complete", but will indeed involve getting nitty-gritty with the Mesh class. The basic idea will be:
1. pick a triangle from mesh.triangles[] at random (be sure to use something like Random.Range(0,mesh.triangles.Length/3)*3 since triangles is sets of 3 ints)
2. pick a point within that triangle. Getting this randomness to be evenly spaced will be tricky, but you could use an algorithm like this to pick a point within a "normalized triangle" (e.g. a triangle of (0,0), (1,0), (0,1) ), and then use that to find the position and normal.

Code (csharp):
  1. Mesh mesh = GetComponent<MeshFilter>().sharedMesh;
  2. int rndTriStart = Random.Range(0,mesh.triangles.Length/3)*3; //pick a triangle
  3. Vector2 rndNorm = new Vector2(Random.value, Random.value); //find random point in normalized square
  4. if (rndNorm.X + rndNorm.y >= 1f) {
  5. rndNorm = new Vector2(1f - rndNorm.x, 1f - rndNorm.y); //cut the square diagonally in half by reflecting points not in the normalized triangle
  6. }
  7. Vector3 position = mesh.vertices[rndTriStart+0] + (rndNorm.x * mesh.vertices[rndTriStart+1]) + (rndNorm.y * mesh.vertices[rndTriStart+2]);
  8. Vector3 normal = mesh.normals[rndTriStart+0] + (rndNorm.x * mesh.normals[rndTriStart+1]) + (rndNorm.y * mesh.normals[rndTriStart+2]);
  9. someNewObject.transform.position = position;
  10. someNewObject.transform.rotation = Quaternion.FromToRotation(Vector3.up, normal);

Be advised that this is complex and untested :)
One caveat with this technique is that it pretends all triangles are the same size, so the random distribution will appear to favor smaller triangles. If your triangles in your mesh are roughly the same size this is a non-issue, but if not, you may want to consider weighting the selection of rndTriStart somehow based on the triangles' surface area.


 found that the distribution of objects was skewed towards the center of the mesh since I was raycasting there and I really wanted a more uniform distribution. To do this I would need to raycast at random points on the mesh using collider.closestpoint... but that function didn't like CONCAVE mesh colliders which was a pain...

So to find a random point on any mesh, I used a modified version of the code posted above by StarManta and this formula to get a random point of a triangle in 3D space.
https://math.stackexchange.com/questions/538458/triangle-point-picking-in-3d ]

x = v1 + a(v2 − v1) + b(v3 − v1)
(x is the new vector, v1, v2, v3 are vertices and a, b are random nums between [0, 1])

Code (CSharp):
  1.  
  2. Vector3[] meshPoints = transform.GetComponent<MeshFilter>().mesh.vertices;
  3. int[] tris = transform.GetComponent<MeshFilter>().mesh.triangles;
  4. int triStart = Random.Range(0, meshPoints.Length / 3) * 3; // get first index of each triangle
  5.  
  6. float a = Random.value;
  7. float b = Random.value;
  8.          
  9. if(+ b >= 1){ // reflect back if > 1
  10.     a = 1 - a;
  11.     b = 1 - b;
  12. }
  13.  
  14. Vector3 newPointOnMesh = meshPoints[triStart] + (* (meshPoints[triStart + 1] - meshPoints[triStart])) + (* (meshPoints[triStart + 2] - meshPoints[triStart])); // apply formula to get new random point inside triangle
  15.  
  16. newPointOnMesh = transform.TransformPoint(newPointOnMesh); // convert back to worldspace
  17.  
  18. Vector3 rayOrigin = ((Random.onUnitSphere * r) + transform.position); // put the ray randomly around the transform
  19.  
  20. RaycastHit hitPoint;
  21. Physics.Raycast(rayOrigin, newPointOnMesh - rayOrigin, out hitPoint, 100f, layermask)

The results are much nicer distribution over all mesh shapes

댓글

이 블로그의 인기 게시물

About AActor!!! "UObject" has no member "BeginPlay"

UNREAL Android build information

C++ 생성자 위임 (delegating constructor)