• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
4
Question by Caiuse · Mar 14, 2011 at 12:08 PM · instantiatemeshprefab

Instantiate a Prefab along the surface of a Mesh

alt text

var prefab : GameObject;

function spawn() { var position = Random.onUnitSphere*2.5000; var spawnPreferences = Instantiate(prefab, position, Quaternion.identity); spawnPreferences.transform.eulerAngles.y = Random.Range(0, 360); }

I've managed to create a simple script to instantiate a prefab along the surface of a sphere, but i'm trying to use the same principle but create the instances along the surface of a mesh.

Any suggestions on how to do this. Sadly onUnitMesh doesn't exist!

Cheers - C

Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image AngryOldMan · Mar 14, 2011 at 12:20 PM 2
Share

again loving the diagram. Very helpful to explain what you want. I believe as a last resort you can put several spheres together to make the mesh on the left then restrict instantiation along the bits of each sphere. This is quite time consuming and fiddley as you need to make sure you have the random range set right for each seperate sphere so that you don't instantiate things inside the mesh. If you cant find an easier method this one atleast works with the script you already have (aslong as you configure the random.range)

avatar image Caiuse · Mar 14, 2011 at 12:24 PM 0
Share

Thanks @Bobadebob that sounds like a nice quick fix solution, which I'm going to use for now. Although I am looking for a solution for the long-run, planning of using a variety of different shaped meshes. Once again cheers.

2 Replies

· Add your reply
  • Sort: 
avatar image
7
Best Answer

Answer by Bunny83 · Mar 14, 2011 at 02:36 PM

The easiest way to get a random point on the surface of an irregular mesh in Unity would be to cast a random ray against the mesh. Every collider have a dedicated Raycast function to test only against this collider.

Both functions are not tested yet

function GetPointOnMesh() : RaycastHit{
    var length : float = 100.0;
    var direction : Vector3 = Random.onUnitSphere;
    var ray : Ray = Ray(transform.position + direction*length,-direction);
    var hit : RaycastHit;
    collider.Raycast (ray, hit, length*2);
    return hit;
}

The function returns a RaycastHit with all information on the point.

Another way would be to calculate a random triangle index and random barycentric coordinates and calculate the world position from this information.

function GetPointOnMesh() : RaycastHit{ var hit : RaycastHit; var mesh : Mesh = GetComponent.<MeshFilter>().mesh; hit.triangleIndex = Random.Range(0,mesh.triangles.Length/3); var BC : Vector3; BC.x = Random.Range(0.0,1.0); BC.y = Random.Range(0.0,1.0-BC.x); BC.z = Random.Range(0.0,1.0-BC.x-BC.y); hit.barycentricCoordinate = BC;

 var P1 : Vector3 = mesh.vertices[mesh.triangles[hit.triangleIndex + 0]];
 var P2 : Vector3 = mesh.vertices[mesh.triangles[hit.triangleIndex + 1]];
 var P3 : Vector3 = mesh.vertices[mesh.triangles[hit.triangleIndex + 2]];
 hit.point = transform.TransformPoint(P1*BC.x + P2*BC.y + P3*BC.z);

 // Interpolated vertex normal
 var N1 : Vector3 = mesh.normals[mesh.triangles[hit.triangleIndex + 0]];
 var N2 : Vector3 = mesh.normals[mesh.triangles[hit.triangleIndex + 1]];
 var N3 : Vector3 = mesh.normals[mesh.triangles[hit.triangleIndex + 2]];
 hit.normal = N1*BC.x + N2*BC.y + N3*BC.z;

 return hit;

}

If you need the face normal instead of the interpolated vertex normal you have to calculate it.

[...] var P1 : Vector3 = mesh.vertices[mesh.triangles[hit.triangleIndex + 0]]; var P2 : Vector3 = mesh.vertices[mesh.triangles[hit.triangleIndex + 1]]; var P3 : Vector3 = mesh.vertices[mesh.triangles[hit.triangleIndex + 2]]; hit.point = P1*BC.x + P2*BC.y + P3*BC.z;

 // Face normal
 hit.normal = Vector3.Cross((P1-P2),(P3-P2)).normalized;
 [...]

Both functions returns a RaycastHit structure. Keep in mind that the second method doesn't set all fields of hit.

If your mesh is more or less convex but with very different triangle sizes, the better point distribution you will get with the first function.
If the mesh have almost equal sized triangles but a very custom non convex shape the second would be better.

The first one is like a spherical projection onto the mesh. The second will covers all mesh triangles, even when they are hidden be other parts of the mesh.

To use this function do something like that:

var prefab : GameObject;

function spawn() { var randomPoint = GetPointOnMesh(); var spawnPreferences = Instantiate(prefab, randomPoint.point, Quaternion.identity); spawnPreferences.transform.eulerAngles.y = Random.Range(0, 360); }

You can use hit.normal with Quaternion.LookRotation to align the spawned object to the surface if you want but the axis that will point away from the surface have to be z in this case.

Comment
Add comment · Show 7 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Caiuse · Mar 14, 2011 at 05:19 PM 0
Share

Bunny83 thats an extremely informative answer, absolutely brilliant, I'm going to use the first method as I understand it better. Also the added information on using Quaternion.LookRotation is brilliant, I've been using a sperate LookAt script, not very practical. cheers +rep

avatar image Bunny83 · Mar 14, 2011 at 06:53 PM 0
Share

It's a very good and common question (way better than a lots of questions just asking for help on their own specific problems). I'm glad I could help. ;)

avatar image Argenex · Apr 29, 2011 at 01:50 AM 0
Share

" hit.triangleIndex = Random.Range(0,mesh.triangles.Length/3);" Returns: BCE0053: Property 'UnityEngine.RaycastHit.triangleIndex' is read only.

avatar image Bunny83 · Apr 29, 2011 at 02:08 AM 0
Share

Hmm, well, i've not checked the members of RaycastHit. I thought because it's a struct it's not a problem to setup your own RaycastHit but unfortunately the public members are all properties and some of them are read only. I'm not sure if they changed that recently or if they always have been properties. Anyways it's just a struct to return some information. If there's no way around that just use your own, custom struct/class. I don't see any good reason for a pure data holding structure to have readonly members...

avatar image Argenex · Apr 29, 2011 at 02:22 AM 0
Share

Yea thanks I found this to be a really good read as I am just simply instancing objects on a plane and restricting them to its surface. Thanks for the indepth answer!

Show more comments
avatar image
3

Answer by ScienceFiction · Jan 12, 2014 at 08:25 PM

You could also instantiate on the vertices of the mesh itself, picking from them randomly.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image kamyflex · Apr 11, 2020 at 06:15 PM 0
Share

Works fine in my case, Thanks.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.



Follow this Question

Answers Answers and Comments

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Combining Meshes? 1 Answer

Find prefab from Instantiation 2 Answers

my object keeps cloning is self i want it to clone once 2 Answers

Prefab Materials and Meshes being deleted, How can I stop this 0 Answers

Instatiating an object. Altering that new object causes prefab to be altered. 2 Answers

  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges