What about a gradient texture in Z?
could work, not slope tho
True, it would be just height
Hi colleagues, letĀ“s see if you can help me,
following this great page I have been able to control the positions of a particle system using python, and it works perfectly and wonderfully
The problem comes when I want to render an animation that contains this. It will simply not take the positions that Im setting with python.
If in the timeline I select one frame, and then move to next frame and then render a single frame then it works. But If I render the entire animation it will not show the positions I set with python.
And if I render frames one by one from python same problem, it will simply not show them.
How can I make sure that when rendering the entire animation, 200 frames or similar, the positions of the particles will be the ones Im setting in python,
as I say, in the viewport all works perfect, the positions are taken from the python script and all works perfect
Im using your particlesetter code:
def particleSetter(self):
particle_systems = object.evaluated_get(degp).particle_systems
particles = particle_systems[0].particles
totalParticles = len(particles)
scene = bpy.context.scene
cFrame = scene.frame_current
sFrame = scene.frame_start
# at start-frame, clear the particle cache
if cFrame == sFrame:
psSeed = object.particle_systems[0].seed
object.particle_systems[0].seed = psSeed
f=cFrame
c=0
c2=1
totalData=20
data = np.zeros(shape=(totalParticles,3))
for i in range(totalParticles):
if (c2==(totalData)):
c2=1
x=easeInOutExpo(float(f), float(cxa[c]),float(cxb[c2])-float(cxa[c]),frange)
y=easeInOutExpo(float(f), float(cya[c]),float(cyb[c2])-float(cya[c]),frange)
z=easeInOutExpo(float(f), float(cza[c]),float(czb[c2])-float(cza[c]),frange)
data[c]= np.array([x, y, z])
c=c+1
c2=c2+1
flatList = data.ravel()
# Set the location of all particle locations to flatList
particles.foreach_set("location", flatList)
this is great and works perfectly for me,
but how do you make it so that when you render the animation the coordinates are taken from the script, because for me all works and behaves perfectly on the viewport, and also if I render a single frame (after moving from the previous one though), but if I try to render the entire 200 frames as an animation, (or frame by frame from python), it just wont work, it wont take then the position coordinates from the python script (Im using your same code), any tips? thank you
Hi Javier!
I only utilized the solution provided by 3DSinghVFX, saw that positions were properly set for viewport and could render a single frame. However, I have not tried rendering animations from it.
(For the moment Iāve actually reverted to 2.79 because I couldnāt get this to work for hair particles. Seems like this depsgraph-thing is still evolving. When itās stable and easy to set particle positions explicitly Iāll return to 2.8x).
Good luck!
^An update to my earlier issue with the Python API ā by changing from Hair to Emitter mode, and then changing the Frame Start and End properties both to 1, Iām able to export the static scene that I wanted.
Still not sure whether there was something I could have done in my Python script to access the actual state of the (not-animated) scene, while staying in Hair mode. It seems like a bug to me, but Iām still not sure.
@javismiles Not sure if youāre still interested, but I thought Iād post this for anyone coming here from Google (as I did).
This answer came from john-l on blender.chat, apparently you should use the depsgraph given to the frame_change_post callback instead of creating your own, as externally created depsgraphs are always for āVIEWPORTā instead of āRENDERā. Also, youāll need at least 2.81, as frame_change_post doesnāt give its depsgraph in 2.80.
Hereās the code from @3DSinghVFX with john-lās updates:
import bpy
import numpy as np
object = bpy.data.objects["Cube"]
def particleSetter(scene, degp):
particle_systems = object.evaluated_get(degp).particle_systems
particles = particle_systems[0].particles
totalParticles = len(particles)
cFrame = scene.frame_current
sFrame = scene.frame_start
#at start-frame, clear the particle cache
if cFrame == sFrame:
psSeed = object.particle_systems[0].seed
object.particle_systems[0].seed = psSeed
# sin function as location of particles
data = 5.0*np.sin(cFrame/20.0)
flatList = [data]*(3*totalParticles)
# additionally set the location of all particle locations to flatList
particles.foreach_set("location", flatList)
#clear the post frame handler
bpy.app.handlers.frame_change_post.clear()
#run the function on each frame
bpy.app.handlers.frame_change_post.append(particleSetter)
Hello,
Have anyone found a way to set hair_keys coordinates (not only locations)? Iāve tried solution from here, based on one of code snippets from this forum thread, but it didnāt work for me.
Thanks for code snippets presented
@bdax Iāve implemented your attached code but it doesnāt seem to work for me.Iām not sure if thereās change in API since your answer but code doesnāt give any error so i assume that is not the case. When I render animation it doesnāt take new locations into account. While in View-port it work fine. Any way to render the animation. Iām using blender 2.82 on windows.
You can try a little script along these lines:
class CM_OT_RenderAnimation(bpy.types.Operator):
bl_idname = "cm_audio.render_animation"
bl_label = "Render Animation"
@classmethod
def poll(cls, context):
cm_node = context.node
return cm_node.render_dir not in ["", "//"]
def execute(self, context):
scene = context.scene
cm_node = context.node
path = bpy.path.abspath(cm_node.render_dir)
scene.render.filepath = path
bpy.context.scene.frame_current = cm_node.strt_frame
for i in range(cm_node.strt_frame, cm_node.stop_frame + 1):
scene.frame_set(i)
scene.render.filepath = f"{path}render{i}"
bpy.ops.render.render(write_still = True)
return {"FINISHED"}
This one runs as an operator on a node, in essence you just need to feed your script with a file path variable and start & stop frames, here is my node:
You can run this as a script in Text Editor, or in the UI, or wherever you like. This produces a png file for each frame, which you assemble in VSE (just add the whole lot in one go).
Works Like Charms Thanks a lot @clockmender . I thought of rendering each frame using python but i hesitated to do it thinking that it will probably not work. I have to keep in mind not to hesitate of trying next time.
Iāve attached the script when executed it will render every frame from strat frame to end frame and store in folder named āRenderā. This folder will be at blend file location.
import bpy
scene = bpy.context.scene
fr_start = scene.frame_start
fr_end = scene.frame_end
for i in range(fr_start,fr_end+1):
scene.frame_set(i)
scene.render.filepath = "//Render/" + str(i)
bpy.ops.render.render(write_still =True)
Hey, has anyone gotten motion blur working for particles set from Python? Iāve tried to set āvelocityā and āprev_velocityā but so far no motion blur for particlesā¦
I do not have an emitter, but I have particles inside a container. Kindly help me on how to determine their locations.
Hello,
What I am trying to achieve is to spawn particles on an object and then have them there rest statically.
But there is a problemā¦ I do this by appending this function in my script:
bpy.app.handlers.frame_change_pre.append(particleSetter)
but with this function you canāt run it on multiple objects with different particle positions and sizes.
Is there any better way to spawn instanced objects (with custom scale and rotation) as fast as particles or does one know how to come around with the particles on multiple objects.
I hope I explained my problem well enough for one to understand it at least.
This is part of the code Iām using which I found on this thread:
def particleSetter(scene, degp):
particle_object = bpy.data.objects.get(MainObject.name)
scene = bpy.context.scene
particles.foreach_set("size", sizes)
particles.foreach_set("location", locations)
The problem comes when I clear the cache with this line:
bpy.app.handlers.frame_change_post.clear() <ā This line then clears particles of other objects, which makes it unusable on multiple objects and without this line the script starts giving errors since the function is unable to set the particles for 2 objects at once.
bpy.app.handlers.frame_change_pre.append(particleSetter)
bpy.app.handlers.frame_change_post.append(particleSetter)
Maybe there is a better approach to all of this that I am unfamiliar of?
My main reason for using particles is their speed.
Thanks in advance for any help.