Commit a8fca691 authored by Breno Rilho Lemos's avatar Breno Rilho Lemos 💬

Pair up with origin/master

parents e0a8309d 4af60d57
......@@ -4,49 +4,135 @@
This project has the purpose of generating a 3D animation of an ALICE particle collision event, inside the LHC, using data obtained from CERN's Open Data Portal, which makes ESDs - Event Summary Data files, that contain information about such events - open and available for analysis.
ESD files regarding the ALICE experiment can be found on http://opendata.cern.ch/search?page=1&size=20&experiment=ALICE, and they should be processed using the Aliroot software, as indicated in the AliESD_Example git repository: https://git.cta.if.ufrgs.br/ALICE-open-data/AliESD_Example/tree/Blender_animation
ESD files regarding the ALICE experiment can be found on http://opendata.cern.ch/search?page=1&size=20&experiment=ALICE, and they should be processed using the Aliroot software, as indicated in the 'Aliroot' section below.
The software that makes the animation is Blender, which is free and open source. Blender's 2.79b version should be downloaded for this project, and can be found on https://www.blender.org/download/releases/2-79/
Before starting, you must also clone this repository:
```bash
mkdir -p ~/alice
cd ~/alice
git init
git clone https://git.cta.if.ufrgs.br/ALICE-open-data/alice-blender-animation.git
```
The animation making can be summarized in three basic steps:
1) Downloading of an ESD file (for example, any file on this list: http://opendata.cern.ch/record/1102);
2) Processing of ESD file using Aliroot macros;
3) Run code to generate Blender animation using the ESD processing results.
1) Downloading an ESD file;
2) Installing aliRoot and running macros;
3) Run bash to generate Blender animation using the ESD processing results.
In case you are not conCERNed about the data being used for the animation and only wish to generate a standard one, skip to the Default Animation section below. For detailed steps on how to make the animation from ESDs, as described above, read the following sections.
## Step 1 - Downloading ESD files
ESD files regarding the ALICE experiment can be found on http://opendata.cern.ch/search?page=1&size=20&experiment=ALICE. If you have doubts on which file to pick for a test, you can select any file on this list: http://opendata.cern.ch/record/1102.
You must save your ESD file inside the 'aliRoot' directory, which is obtained by cloning this repository as mentioned above.
## Step 2 - Installing aliRoot
Here is the sequence of steps for installing aliRoot, so you are able to process the relevant information for the project.
1) Install aliBuild. Follow instructions on https://alice-doc.github.io/alice-analysis-tutorial/building/custom.html
2) Initialize AliPhysics
```bash
cd ~/alice
aliBuild init AliPhysics@master
```
3) Verify dependencies (Optional)
```bash
$ aliDoctor AliPhysics
```
4) Build AliPhysics with aliroot5 (this may take a long time)
```bash
aliBuild build AliPhysics --defaults user -z aliroot5
```
5) Enter AliPhysics environment
```bash
alienv enter AliPhysics/latest-aliroot5-user
```
6) Run the macro
```bash
cd ~/alice/alice-blender-animation/aliRoot
aliroot runAnalysis.C
```
With the last step, ESD analysis results will be saved on three text files:
- `s-esd-detail.dat`, for an event with a 'small' number of tracks (between 15 and 30 tracks);
- `m-esd-detail.dat`, for an event with a 'medium' number of tracks (between 100 and 300 tracks);
- `l-esd-detail.dat`, for an event with a 'very large' number of tracks (between 5000 and 50000 tracks).
You must then move those three files into the 'animate' folder, where the Blender scripts are.
## Step 3 - Generating animation
Go inside the 'animate' directory:
```bash
cd ~/alice/alice-blender-animation/animate
```
Run the python script `animate_particles.py` as in the example below:
```bash
blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=10 -camera="BarrelCamera" -datafile="s-esd-detail.dat" -simulated_t=0.02 -fps=24 -resolution=100
```
where everything that follows the double dashes are input arguments for generating the animation. Here is what each argument means:
-radius:
particle radius; must be a number; type float
-duration:
animation duration, in seconds; must be a number; type int
-camera:
defines animation point of view; must be a string; available options: "OverviewCamera", "BarrelCamera", "ForwardCamera"
-datafile:
filename for event data file; must be a string; must be one of your text files: "s-esd-detail.dat", "m-esd-detail.dat", "l-esd-detail.dat"
## Requirements
-simulated_t:
* Blender 2.79b
simulated time of event, in microsseconds; must be a number; type float
## Run
Run animation example:
`blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=1 -camera="BarrelCamera" -datafile="esd-detail.dat" -simulated_t=0.02 -fps=24 -resolution=100`
-fps:
frames per second; must be a number; type int
In the example above, argument 'radius' has value 0.05, 'duration' has value 10 and so on.
*-radius*:
particle radius; must be a number; type float
-resolution:
*-duration*:
animation duration; must be a number; type int
animation resolution percent; must be a number; type int
*-camera*:
defines animation view; must be a string; available options: OverviewCamera, BarrelCamera, ForwardCamera
*-datafile*:
filename for event data file; must be a string
After running the script, your Blender animation should be ready! It will be saved in format .mp4 on the address `/tmp/blender`. Enjoy!
*-simulated_t*:
simulated time of event; must be a number; type float
*-fps*:
frames per second; must be a number; type int
# Default Animation
*-resolution*:
animation resolution percent; must be a number; type int
For generating a default animation, simply run the animation python code inside the 'animate' folder, using the `d-esd-detail.dat` file (where 'd' is for 'default') as the input file, as showed below:
Implement command line arguments:
https://blender.stackexchange.com/questions/6817/how-to-pass-command-line-arguments-to-a-blender-python-script
```bash
cd ~/alice/alice-blender-animation/animate
blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=10 -camera="BarrelCamera" -datafile="d-esd-detail.dat" -simulated_t=0.02 -fps=24 -resolution=100
```
After running the script, your Blender animation should be ready! It will be saved in format .mp4 on the address `/tmp/blender`. Enjoy!
# Project Description
This project has the purpose of generating a 3D animation of an ALICE particle collision event, inside the LHC, using data obtained from CERN's Open Data Portal, which makes ESDs - Event Summary Data files, that contain information about such events - open and available for analysis.
ESD files regarding the ALICE experiment can be found on http://opendata.cern.ch/search?page=1&size=20&experiment=ALICE, and they should be processed using the Aliroot software, as indicated by the Instructions section below
The software that makes the animation is Blender, which is free and open source. Blender's 2.79b version should be downloaded for this project, and can be found on https://www.blender.org/download/releases/2-79/
The animation making can be summarized in three basic steps:
1) Downloading of an ESD file (for example, any file on this list: http://opendata.cern.ch/record/1102);
2) Processing of ESD file using Aliroot macros (as indicated further);
3) Run code to generate Blender animation using the ESD processing results.
The code for step 3 can be found in the Blender_animation repository: https://git.cta.if.ufrgs.br/ALICE-open-data/alice-blender-animation/tree/ParticleTypes
# Sample macros for processing AliESDs from CERN Open Data Portal
## Requirements
Execute with aliroot5. Place `AliESDs.root` files in reach of the `chain->Add("AliESDs.root");` line on `runAnalysis.C` and execute.
## Instructions
1) Install aliBuild. Follow instructions on https://alice-doc.github.io/alice-analysis-tutorial/building/custom.html
2) Initialize AliPhysics
```bash
mkdir -p ~/alice
cd ~/alice
aliBuild init AliPhysics@master
```
3) Verify dependencies (Optional)
```bash
$ aliDoctor AliPhysics
```
4) Build AliPhysics with aliroot5 (this may take a long time)
```bash
aliBuild build AliPhysics --defaults user -z aliroot5
```
5) Enter AliPhysics environment
```bash
alienv enter AliPhysics/latest-aliroot5-user
```
6) Run the macro
```bash
aliroot runAnalysis.C
```
Results will be saved on three text files: `s-esd-detail.dat`, for an event with a 'small' number of tracks; `m-esd-detail.dat`, for an event with a medium number of tracks; `l-esd-detail.dat`, for an event with a very large number of tracks.
## Credits
The code used here is based on the ALICE analysis tutorial by Redmer A. Bertens.
# ALICE Open Data Blender animation
## Project Description
This project has the purpose of generating a 3D animation of an ALICE particle collision event, inside the LHC, using data obtained from CERN's Open Data Portal, which makes ESDs - Event Summary Data files, that contain information about such events - open and available for analysis.
ESD files regarding the ALICE experiment can be found on http://opendata.cern.ch/search?page=1&size=20&experiment=ALICE, and they should be processed using the Aliroot software, as indicated in the 'Aliroot' section below.
// AliESD_Example git repository: https://git.cta.if.ufrgs.br/ALICE-open-data/AliESD_Example/tree/Blender_animation
The software that makes the animation is Blender, which is free and open source. Blender's 2.79b version should be downloaded for this project, and can be found on https://www.blender.org/download/releases/2-79/
Before starting, you must also clone this repository:
```bash
mkdir -p ~/alice
cd ~/alice
git init
git clone https://git.cta.if.ufrgs.br/ALICE-open-data/alice-blender-animation.git
```
The animation making can be summarized in three basic steps:
1) Downloading an ESD file;
2) Installing aliRoot and running macros;
3) Run bash to generate Blender animation using the ESD processing results.
## Step 1 - Downloading ESD files
ESD files regarding the ALICE experiment can be found on http://opendata.cern.ch/search?page=1&size=20&experiment=ALICE. If you have doubts on which file to pick for a test, you can select any file on this list: http://opendata.cern.ch/record/1102.
You must save your ESD file inside the 'aliRoot' directory, which is obtained by cloning this repository as mentioned above.
## Step 2 - Installing aliRoot
1) Install aliBuild. Follow instructions on https://alice-doc.github.io/alice-analysis-tutorial/building/custom.html
2) Initialize AliPhysics
```bash
cd ~/alice
aliBuild init AliPhysics@master
```
3) Verify dependencies (Optional)
```bash
$ aliDoctor AliPhysics
```
4) Build AliPhysics with aliroot5 (this may take a long time)
```bash
aliBuild build AliPhysics --defaults user -z aliroot5
```
5) Enter AliPhysics environment
```bash
alienv enter AliPhysics/latest-aliroot5-user
```
6) Run the macro
```bash
cd ~/alice/alice-blender-animation/aliRoot
aliroot runAnalysis.C
```
Results will be saved on three text files: `s-esd-detail.dat`, for an event with a 'small' number of tracks; `m-esd-detail.dat`, for an event with a 'medium' number of tracks; `l-esd-detail.dat`, for an event with a 'very large' number of tracks. You must then move those three files to the 'animate' folder, where the Blender scripts are.
## Step 3 - Generating animation
Run the script animate_particles.py as in the example below:
blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=1 -camera="BarrelCamera" -datafile="esd-detail.dat" -simulated_t=0.02 -fps=24 -resolution=100
In the example above, argument 'radius' has value 0.05, 'duration' has value 10 and so on.
-radius:
particle radius; must be a number; type float
-duration:
animation duration; must be a number; type int
-camera:
defines animation view; must be a string; available options: OverviewCamera, BarrelCamera, ForwardCamera
-datafile:
filename for event data file; must be a string; must be one of your text files: `s-esd-detail.dat`, `m-esd-detail.dat`, `l-esd-detail.dat`
-simulated_t:
simulated time of event; must be a number; type float
-fps:
frames per second; must be a number; type int
-resolution:
animation resolution percent; must be a number; type int
Animation will be saved in format .mp4 on the address `/tmp/blender`
-6.30213e-05 0.00165968 -0.0095511 0.105658 1 0.563826 -1.72644 -0.721978
-6.30213e-05 0.00165968 -0.0095511 0.105658 1 -0.53665 0.847315 0.521594
-6.30213e-05 0.00165968 -0.0095511 0.493677 -1 -0.330079 0.580633 0.332982
......
# -*- coding: utf-8 -*-
# animate_particles.py - Animate HEP events
#
# For console only rendering (example):
# $ blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=1 -camera="BarrelCamera" -datafile="esd-detail.dat" -simulated_t=0.02 -fps=24 -resolution=100 -stamp_note="Texto no canto"
#
import os
import bpy
import argparse
import sys
# Pass on command line arguments to script:
class ArgumentParserForBlender(argparse.ArgumentParser):
def _get_argv_after_doubledash(self):
try:
idx = sys.argv.index("--")
return sys.argv[idx+1:] # the list after '--'
except ValueError as e: # '--' not in the list:
return []
# overrides superclass
def parse_args(self):
return super().parse_args(args=self._get_argv_after_doubledash())
parser = ArgumentParserForBlender()
parser.add_argument('-radius','--r_part')
parser.add_argument('-duration','--duration')
parser.add_argument('-camera','--render_camera')
parser.add_argument('-datafile','--datafile')
parser.add_argument('-simulated_t','--simulated_t')
parser.add_argument('-fps','--fps')
parser.add_argument('-resolution','--resolution_percent')
parser.add_argument('-stamp_note','--stamp_note')
args = parser.parse_args()
bpy.context.user_preferences.view.show_splash = False
# Import Drivers, partiles and scence functions:
filename = os.path.join(os.path.basename(bpy.data.filepath), "drivers.py")
exec(compile(open(filename).read(), filename, 'exec'))
# Set animation parameters
r_part = float(args.r_part) # Particle radius
simulated_t = float(args.simulated_t) # in microsseconds
duration = int(args.duration) # in seconds
fps = int(args.fps)
resolution_percent = int(args.resolution_percent)
#configure output
outputPath = "/tmp/blender/"
fileIdentifier = "PhysicalTrajectories_"
## RenderCameras: ["ForwardCamera", "OverviewCamera", "BarrelCamera"]
renderCamera= args.render_camera
renderAnimation = True # True
saveBlenderFile = False # False
"""
# Create and configure animation driver
n_particles = 100 # Event Multiplicity
driver = genDriver("GaussianGenerator",n_particles,3.0) # Simple genDriver takes two parameters: number of particles and Gaussian width
driver.configure(renderCamera, duration, fps, simulated_t, outputPath, fileIdentifier, resolution_percent)
"""
# Create and configure animation driver
driver = dataDriver("AlirootFileGenerator",args.datafile) # Simple dataDriver takes one parameters: filename
driver.configure(renderCamera, duration, fps, simulated_t, outputPath, fileIdentifier, resolution_percent)
### Build scene
init(args.stamp_note) # Cleanup, addCameras, addALICE_TPC
particles = driver.getParticles()
blender_particles, blender_tracks = createSceneParticles(particles,createTracks = True) # Create blender objects - one sphere per particle
#Animate scene using driver
animate(blender_particles,particles,driver)
animate_tracks(blender_tracks,particles,driver)
bpy.context.scene.frame_current = 24
## Save blender file
if saveBlenderFile: bpy.ops.wm.save_as_mainfile(filepath=outputPath+fileIdentifier+".blend")
# Render animation
if renderAnimation: driver.render()
#exit()
# -*- coding: utf-8 -*-
# Import Particle class
filename = os.path.join(os.path.basename(bpy.data.filepath), "particle.py")
exec(compile(open(filename).read(), filename, 'exec'))
# Import scene functions
filename = os.path.join(os.path.basename(bpy.data.filepath), "scene_functions.py")
exec(compile(open(filename).read(), filename, 'exec'))
class animationDriver:
def __init__(self,name):
self.name = name
def configure(self, renderCamera, duration, fps, simulated_t, outputPath, fileIdentifier, resolution_percent=100):
self.renderCamera=renderCamera
self.duration=duration # total video duration in seconds
self.fps=fps
self.simulated_t=simulated_t # total simulated time in microseconds. (0.01 -> light travels ~ 3 m)
self.N_frames=duration*fps
self.delta_t=self.simulated_t/self.N_frames # time elapsed per frame
self.outputPath = outputPath
self.fileIdentifier = fileIdentifier
self.resolution_percent = resolution_percent
self.configureOutput()
bcs = bpy.context.scene
bcs.frame_start = 0
bcs.frame_end = self.N_frames
def render(self):
bpy.context.scene.camera = bpy.data.objects[self.renderCamera]
bpy.ops.render.render(animation=True)
def configureOutput(self):
# Configure Output
bcsr = bpy.context.scene.render
bcsr.fps=self.fps
bcsr.resolution_percentage = self.resolution_percent
bcsr.image_settings.file_format = 'FFMPEG'
bcsr.ffmpeg.format = "MPEG4"
bcsr.ffmpeg.codec = "H264"
bcsr.ffmpeg.use_max_b_frames = False
bcsr.ffmpeg.video_bitrate = 6000
bcsr.ffmpeg.maxrate = 9000
bcsr.ffmpeg.minrate = 0
bcsr.ffmpeg.buffersize = 224 * 8
bcsr.ffmpeg.packetsize = 2048
bcsr.ffmpeg.muxrate = 10080000
xpixels = int(bcsr.resolution_percentage * bcsr.resolution_x / 100)
output_prefix=fileIdentifier+str(xpixels)+"px_"+self.name
bcsr.filepath = "/tmp/blender/"+output_prefix
class genDriver(animationDriver): # A driver for particle generators
def __init__(self,name,N_particles, par1):
self.name = name+"_N"+str(n_particles)+"_"
self.N_particles = N_particles
self.par1 = par1
def getParticles(self, x = 0, y = 0, z = 0): # Create particles at given position and return them in a list
particles=[]
#loop over particles
for i in range(0, self.N_particles):
charge = random.choice([+1,-1])
mass = random.choice([0.000510999, 0.13957, 0.105658, 0.938272, 0.493677]) # Available mass values
part = ParticlePropagator(i,x,y,z,charge,mass)
part.SetType()
part.SetMagneticField()
part.SetProperties(random.gauss(0,self.par1),random.gauss(0,self.par1),random.gauss(0,self.par1))
particles.append(part)
return particles;
class dataDriver(animationDriver): # A driver for data from files.
def __init__(self,name,datafile):
self.name = name+"_"+datafile+"_"
self.datafile = datafile
def getParticles(self): # Create particles acording to parameters from file
# Count number of lines in file = number of particles
detail_file = open(self.datafile, 'r')
lines = detail_file.readlines()
N_particles = len(lines)
# Create particles list
particles=[]
#loop over particles and get information from data file
for i in range(0, N_particles):
x = lines[i].split(' ')[0]
y = lines[i].split(' ')[1]
z = lines[i].split(' ')[2]
mass = lines[i].split(' ')[3]
charge = lines[i].split(' ')[4]
Px = lines[i].split(' ')[5]
Py = lines[i].split(' ')[6]
Pz = lines[i].split(' ')[7]
part = ParticlePropagator(i,float(x),float(y),float(z),float(charge),float(mass))
part.SetType()
part.SetMagneticField(0.5)
part.SetProperties(float(Px),float(Py),float(Pz))
particles.append(part)
detail_file.close()
return particles;
# -*- coding: utf-8 -*-
# Sample Particle class and function that creates N particles, returning a list of particles
import math
import random
# Basic particle class to store bascic information
class Particle:
def __init__(self, index, x = 0, y = 0, z = 0, charge = 1, mass=0.94):
self.iDx=index
self.x=x
self.y=y
self.z=z
self.charge=charge
self.mass = mass
def SetType(self):
p_mass = {"Electron":0.000510999, "Pion":0.13957, "Muon":0.105658, "Proton":0.938272, "Kaon":0.493677}
self.p_type = "Unknown"
for p_type in p_mass:
if p_mass[p_type] == self.mass:
self.p_type = p_type
def PrintPosition(self):
print(str(self.x) + " ; " + str(self.y) + " ; " + str(self.z))
def GetPosition(self):
return self.x, self.y, self.z
# Derived class to computes the time evolution particle positions
class ParticlePropagator(Particle):
def SetMagneticField(self, B = 0.5):
self.B = B
def SetProperties(self, Px, Py, Pz):
self.Px = Px # unit: Gev/c
self.Py = Py # unit: Gev/c
self.Pz = Pz # unit: Gev/c
self.Velocity = 1/math.sqrt(1+self.mass*self.mass/(Px*Px+Py*Py+Pz*Pz)) # unit: []c
self.LorentzFactor = 1 / math.sqrt( 1 - self.Velocity * self.Velocity )
self.Vz = 300 * Pz / self.LorentzFactor / self.mass # unit: meters/micro seconds
def Propagate(self, time):
Rx = self.Px / (self.charge * self.B) * 3.335641 # unit conversion to meters
Ry = self.Py / (self.charge * self.B) * 3.335641 # unit conversion to meters
omega = self.charge * self.B / ( self.LorentzFactor * self.mass ) * 89.876 # Angular frequency (unit: radians/micro seconds)
Xprop = self.x + Rx * math.sin(omega*time) - Ry * ( math.cos(omega*time) - 1 )
Yprop = self.y + Ry * math.sin(omega*time) + Rx * ( math.cos(omega*time) - 1 )
Zprop = self.z + self.Vz * time
return Xprop, Yprop, Zprop
def init(unique_id):
bcs = bpy.context.scene
# Configure Environment
bcs.world.light_settings.use_environment_light = False
bcs.world.light_settings.environment_energy = 0.1
# Configure Stamp
bpy.context.scene.render.use_stamp = True
bpy.context.scene.render.use_stamp_time = False
bpy.context.scene.render.use_stamp_date = False
bpy.context.scene.render.use_stamp_render_time = False
bpy.context.scene.render.use_stamp_frame = False
bpy.context.scene.render.use_stamp_scene = False
bpy.context.scene.render.use_stamp_camera = False
bpy.context.scene.render.use_stamp_filename = False
bpy.context.scene.render.stamp_note_text = unique_id
bpy.context.scene.render.use_stamp_note = True
# Cleanup
bpy.data.objects.remove(bpy.data.objects['Cube'])
bpy.data.objects.remove(bpy.data.objects['Camera'])
# Basic Objects
addCameras() # Add cameras
addALICE_TPC() # ALICE TPC
def addALICE_TPC():
print("Adding ALICE TPC")
bpy.data.materials.new(name="TPC")
bpy.data.materials["TPC"].diffuse_color = (0, 0.635632, 0.8)
bpy.data.materials["TPC"].use_shadows = False
bpy.data.materials["TPC"].use_cast_shadows = False
bpy.data.materials["TPC"].use_transparency = True
bpy.data.materials["TPC"].alpha = 1
bpy.data.materials["TPC"].specular_alpha = 0
bpy.data.materials["TPC"].raytrace_transparency.fresnel_factor = 5
bpy.data.materials["TPC"].raytrace_transparency.fresnel = 0.3
bpy.ops.mesh.primitive_cylinder_add(radius=2.5, depth=5, view_align=False, enter_editmode=False, location=(0, 0, 0))
TPC = bpy.context.object
TPC.name = "TPC"
TPC.data.materials.clear()
TPC.data.materials.append(bpy.data.materials["TPC"])
def addCameras():
# ForwardCamera
bpy.ops.object.camera_add(location = (0,0,20), rotation = (0, 0, 0))
bpy.context.object.name = "ForwardCamera"
camera_forward=bpy.data.objects['ForwardCamera']
camera_forward.data.type = 'ORTHO'
camera_forward.data.ortho_scale = 10
# OverviewCamera
bpy.ops.object.camera_add(location = (6.98591, -19.7115, 23.9696), rotation = (-0.281366, 0.683857, -1.65684))
bpy.context.object.name = "OverviewCamera"
bpy.context.object.data.lens = 66.78
# Barrel Camera
bpy.ops.object.camera_add(location = (6, 0, 0), rotation = (0, 1.5708, 0))
#bpy.context.object.rotation_euler[1] = 1.5708
bpy.context.object.name = "BarrelCamera"
# Function that creates Blender Objects from input list of particles.
## Returns a list of blender objects
def createSceneParticles(particles, createTracks = False):
# Associate particles and colors
particle_types = ["Electron","Pion","Muon","Proton","Kaon","Unknown"]
clRed = (1, 0, 0)
clGreen = (0, 1, 0)
clBlue = (0, 0, 1)
clMagenta = (0.75, 0, 1)
clYellow = (1, 1, 0)
clWhite = (255, 255, 255)
particle_colors = {"Electron":clRed, "Pion":clGreen, "Muon":clBlue, "Proton":clMagenta, "Kaon": clYellow, "Unknown": clWhite}
#Create Materials
for type in particle_types:
bpy.data.materials.new(name=type)
#bpy.context.object.active_material = (1, 0, 0)
bpy.data.materials[type].diffuse_color = particle_colors[type]
bpy.data.materials[type].use_shadows = False
bpy.data.materials[type].use_cast_shadows = False
# Create blender spheres (particles)
blender_particles=[]
n_particles=len(particles)
for particle in particles:
this_type=particle.p_type
print("Adding Sphere - Particle " + str(len(blender_particles))+" of "+str(n_particles-1)+" - "+this_type)
bpy.ops.mesh.primitive_uv_sphere_add()
this_particle = bpy.context.object
this_particle.name = "part"+str(particle.iDx)
this_particle.location = ((particle.x,particle.y,particle.z))
this_particle.delta_scale = (r_part,r_part,r_part)
this_particle.data.materials.clear()
this_particle.data.materials.append(bpy.data.materials[this_type])
blender_particles.append(this_particle)
# Create blender curves (tracks)
blender_tracks=[]
if createTracks:
for track in particles:
this_type=track.p_type #TO DO: make this not random, but according to file data
print("Adding Curve - Track " + str(len(blender_tracks))+" of "+str(n_particles-1)+" - "+this_type)
# create the Curve Datablock
curveTrack = bpy.data.curves.new('CurveTrack', type='CURVE')
curveTrack.dimensions = '3D'
curveTrack.resolution_u = 2
curveTrack.fill_mode = 'FULL'
curveTrack.bevel_depth = 0.02
curveTrack.bevel_resolution = 3
# map coords to spline
bcs = bpy.context.scene
polyline = curveTrack.splines.new('NURBS')
polyline.points.add(bcs.frame_end) # Add one point per frame
for i in range(bcs.frame_end):
polyline.points[i].co = (particle.x,particle.y,particle.z, 1)
# create Object
trackOB = bpy.data.objects.new('Track', curveTrack)
trackOB.data.materials.clear()
trackOB.data.materials.append(bpy.data.materials[this_type])
scn = bpy.context.scene
scn.objects.link(trackOB)
blender_tracks.append(trackOB)
return blender_particles, blender_tracks
# Function that animates the scene using the particle propagator class
def animate(objects, particles, driver):
bcs = bpy.context.scene
#Animate particles
for f in range(1, bcs.frame_end):
t = driver.delta_t*f
bcs.frame_current = f
print("Configuring particles in frame: "+str(f)+" of "+str(bcs.frame_end))
for i in range(0, len(objects)):
bcs.objects.active=objects[i]
objects[i].location=(particles[i].Propagate(t))
objects[i].keyframe_insert(data_path='location')
# Function that animates particle tracks using the particle propagator class
def animate_tracks(tracks, particles, driver):
bcs = bpy.context.scene
#Animate tracks
for f in range(1, bcs.frame_end):
t = driver.delta_t*f
bcs.frame_current = f
print("Configuring tracks in frame: "+ str(f) +" of "+ str(bcs.frame_end))
for point in range(f,bcs.frame_end):
for i in range(0, len(particles)):
#bcs.objects.active=tracks[i]
tracks[i].data.splines[0].points[point].keyframe_insert(data_path="co", frame = f)
x, y, z = particles[i].Propagate(t)
tracks[i].data.splines[0].points[point].co = (x, y, z, 1)
##polyline = curveTrack.splines.new('NURBS')
##polyline.points.add(len(coords))
##for i, coord in enumerate(coords):
## x,y,z = coord
## polyline.points[i].co = (x, y, z, 1)
#curve = bpy.data.objects["Track"]
#curve.data.splines[0].points[1].co
#point.keyframe_insert(data_path="co", frame = i)
# https://blender.stackexchange.com/questions/73630/animate-curves-by-changing-spline-data-using-a-python-script
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment