2
$\begingroup$

I have a particle system and I wanted to see which face each particle was in. Is there a way to check it? I have tried to check x, y, and z coordinates separately but that would not work. Also is there a way to see which vertices a face has?

These are the faces and the particles:

I would like to check which face each particle is in so that I can find probabilities.

$\endgroup$
  • $\begingroup$ If a face generates a particle would you like change the particle material based on that info? Is the question location related? If so ..... May we ask what you will do will do if a particle is within a certain distance of a (XYZ) location ? For example would you like to you change the material of the particle? $\endgroup$ – atomicbezierslinger Dec 15 '15 at 21:49
  • $\begingroup$ I would simply have the information stored and collect it for each particle. $\endgroup$ – user2888499 Dec 17 '15 at 0:32
  • $\begingroup$ Sometimes knowing how the information will be used in Blender allows suggestions in Blender. I respect privacy. Perhaps an image submitted by you would help. $\endgroup$ – atomicbezierslinger Dec 17 '15 at 16:57
3
+50
$\begingroup$

Using the particles location vector, and the closest_point_on_mesh method. The particle location is in global coords. We can see this by moving the emitter in the UI, the particles remain in their world position and need to be re(bake)calculated.

As pointed out in https://blender.stackexchange.com/a/40979/15543 you need to put the location passed to closest_point_on_mesh into the objects local space, otherwise it will give unexpected results once the object's matrix_world is no longer the identity matrix.

The particle location is multiplied by the inverse matrix world of the emmitter object, to put it into that objects local coordinates.

I'm using a build of 2.76.4 and it appears closest_point_on_mesh has a new return value,

>>> C.object.closest_point_on_mesh((0,0,0))
(True, Vector((0.9999996423721313, -2.980232238769531e-07, 0.0)), Vector((1.0, 0.0, 3.2782557468635787e-07)), 2)

The first being success of operation, the others: location vector of closest point; normal vector; and face index.

The script below prints how many particles are closest to each face.

import bpy
context = bpy.context
obj = context.object

mwi = obj.matrix_world.inverted()

ps = obj.particle_systems.active
facelist = []
new_version = bpy.app.version == (2, 76, 4)

print("-" * 72)
print("Obj: %s Particle System: %s" % (obj.name, ps.name))
print("-" * 72)

for i, p in enumerate(ps.particles):    
    v1 = p.location # global particle location
    localPos = mwi * v1  # particle in obj local space
    if new_version:
        (found, loc, norm, face_index) = obj.closest_point_on_mesh(localPos)
        if not found:
            continue
    else:
        (loc, norm, face_index) = obj.closest_point_on_mesh(localPos)

    facelist.append(face_index)

mesh = obj.data        
for fi in set(facelist):
    vertstr = str([v for v in mesh.polygons[fi].vertices])
    print("face %d,  verts: %s particle count:%d" % (fi, vertstr, facelist.count(fi)))

Sample result default cube, default particle system

------------------------------------------------------------------------
Obj: Cube Particle System: ParticleSystem
------------------------------------------------------------------------
face 0,  verts: [0, 1, 2, 3] particle count:180
face 1,  verts: [4, 7, 6, 5] particle count:168
face 2,  verts: [0, 4, 5, 1] particle count:161
face 3,  verts: [1, 5, 6, 2] particle count:169
face 4,  verts: [2, 6, 7, 3] particle count:150
face 5,  verts: [4, 0, 3, 7] particle count:172
| improve this answer | |
$\endgroup$
1
$\begingroup$

This will work for hair type particle systems (not sure how to do this for a non-hair PS at the moment). Copy to a new text file, select the object that has the particle system and press "Run Script".

import bpy, bmesh

o = bpy.context.object
ps = o.particle_systems[0]

bm = bmesh.new()

bm.from_mesh( o.data )
bm.faces.ensure_lookup_table()
bm.verts.ensure_lookup_table()

for p in ps.particles:
    co = p.hair_keys[0].co
    fIdx = o.closest_point_on_mesh( co )[2]
    print( "Face Index: ", fIdx )

    print( "Face Vertices: ", [ v.index for v in bm.faces[fIdx].verts ] )
| improve this answer | |
$\endgroup$
1
$\begingroup$

Each particle system has a list of it's particles which have a location. This location can be passed to object.closest_point_on_mesh() to find the index of the closest face. We can then get the vertex indices used to build the face.

The following will assign a material to the faces touched by a particle then print the vertex indices for each face.

import bpy

obj = bpy.context.object
obj_polys = obj.data.polygons

for pidx, ps in enumerate(obj.particle_systems):
    for p in ps.particles:
        face = obj_polys[obj.closest_point_on_mesh(p.location)[2]]
        face.material_index = pidx + 1
        print('Face',face.index,'uses verts -', end=' ')
        for vidx in face.vertices:
            # vertex is obj.data.vertices[vidx]
            print(vidx,end=' ')
        print()
| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.