**Edit - I'm willing to pay a $15USD bounty via Paypal for the accepted answer to this question.
I have a script which generates random points on the surface of a sphere and then places cone objects at each point.
emitter.closest_point_on_mesh call I can get the surface normal from the sphere at a spot very close to the generated point and then apply that normal to the rotation of the cone object, thereby pointing the cone out from the surface of the sphere at an angle that very closely approximates the normal from the sphere surface.
However this only works when the sphere is at the world origin point. When I move the sphere, it no longer works. The cones no longer point away from the sphere surface at the normal direction.
I've tried different techniques involved multiplying the sphere's
matrix_world value by the normal, but I can't seem to find the right combo to make it work.
Any help would be GREATLY appreciated!
import bpy from mathutils.bvhtree import BVHTree import mathutils import math import bpy_extras from bpy_extras import mesh_utils import timeit from random import random from math import radians from mathutils import Vector import bmesh scn = bpy.context.scene objs = bpy.data.objects def DeletePreviousParticles(): for o in bpy.data.objects: if o.name.startswith("particle"): objs.remove(o, True) #select sphere to update window sphere = bpy.data.objects['Sphere'] bpy.context.scene.objects.active = sphere def PlaceParticle(emitter,src_obj, point): dupCount = 0 maxObjectDimension = 2 new_obj = src_obj.copy() new_obj.data = src_obj.data.copy() scn.objects.link(new_obj) new_obj.animation_data_clear() new_obj.location=point new_obj.location=point new_obj.location=point new_obj.name = "particle_" + str(dupCount) dupCount+=1 #calculate normal from surface of emitter partLoc = new_obj.location surfaceNormal = emitter.closest_point_on_mesh( partLoc ) print('surfaceNormal' + str(surfaceNormal)) #the following line does not work when emitter object is not at world origin point new_obj.rotation_euler = surfaceNormal.to_track_quat('Z', 'Y').to_euler() def Main(): emitter = bpy.data.objects['Sphere'] src_obj = bpy.data.objects['sourceParticle'] print("starting------------------------------------------------------------") DeletePreviousParticles() me = emitter.data me.calc_tessface() # recalculate tessfaces tessfaces_select = me.tessfaces #[f for f in me.tessfaces if f.select] pointList = bpy_extras.mesh_utils.face_random_points(1, tessfaces_select) totalPoints = 20 pointCounter = 0 for p in pointList: if(pointCounter<totalPoints): mat1 = emitter.matrix_world adjPoints = mat1 * p PlaceParticle(emitter, src_obj, adjPoints) pointCounter +=1 else: break print("done") Main()
Here's the source file: