Commit 754c5154 authored by Breno Rilho Lemos's avatar Breno Rilho Lemos 💬
Browse files

Merge branch 'pcad'

parents 2f801f9c 0c763e7b
......@@ -20,28 +20,46 @@ The whole process is a lot more user-friendly than it may seem at first glance;
This project was developed in Ubuntu 18.04 version of Linux, therefore this is the recommended OS for running it.
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 somehow referenced along the process, as explained further.
First, create a directory to keep everything:
The software used for animating events 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/
```bash
$ mkdir -p ~/alice
```
Enter this directory:
Before starting, you must also clone this repository:
```bash
mkdir -p ~/alice
cd ~/alice
git clone https://git.cta.if.ufrgs.br/ALICE-open-data/alice-blender-animation.git
$ cd ~/alice
```
If you haven't yet, clone the project's repository:
```bash
$ 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:
Make sure the repository is inside the `alice` directory you created.
1) Installing Aliroot;
2) Getting an ESD file;
3) Running script to process ESD data and generate Blender animations using its results.
It is then time to download Blender, a free and open source software that is used for animating events. Stick to version 2.79b, or there is no
guarantee the code will work.
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.
```bash
$ wget https://download.blender.org/release/Blender2.79/blender-2.79b-linux-glibc219-x86_64.tar.bz2
```
## Step 1 - Installing Aliroot
Extract files from package:
Here is the sequence of steps for installing Aliroot, CERN's official software for ALICE physics analysis, so you are able to process the relevant information for the project.
```bash
$ tar -jxvf blender-2.79b-linux-glibc219-x86_64.tar.bz2
```
The next step is to install Aliroot, which is CERN's official software for ALICE physics analysis, so you are able to process the relevant information
for the events.
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.
Here is the sequence of steps for installing Aliroot:
1) Install aliBuild. Follow instructions on https://alice-doc.github.io/alice-analysis-tutorial/building/custom.html
......@@ -61,49 +79,140 @@ $ aliDoctor AliPhysics
aliBuild build AliPhysics --defaults user -z aliroot5
```
## Step 2 - Getting an ESD file
After that, you are ready to pick an ESD file at CERN's Open Data Portal. ESD files regarding the ALICE experiment can be found on
http://opendata.cern.ch/search?page=1&size=20&experiment=ALICE. You can either manually download your ESD file and save it in the
project's repository directory (in the same path as this `README.md` file), under the name `AliESDs.root`, or have your ESD be downloaded automatically, as explained
further.
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.
Once you're all set, all there is left to do is run the `workflow_sketch.sh` script through your terminal. Don't forget to access the project's repository
directory first:
Here, there are two options from which you can choose:
### Manual Download
Manually download your ESD file and save it in the `alice-blender-animation` directory, which was cloned from the git repository. Make sure you save it on the same path as this `README.md` file and the `workflow_sketch.sh` script, not inside the "aliRoot" or "animate" directories. Also make sure the file is named `AliESDs.root`.
```bash
$ cd ~/alice/alice-blender-animation
```
### Automatic Download
Have your ESD be downloaded automatically; just copy the URL for the chosen ESD file (the address you would access to download it) so you can paste it on the command line when you run the script that generates the animation, according to the next section.
The script offers several options in order to personalize the output. For example, in order to set the number of frames per second (fps) to 24 and the video
time duration to 8 seconds, one should run the command like this:
## Step 3 - Generating animation
```bash
./workflow_sketch.sh --fps 24 -t 8
```
Once you are all set, all there is left to do is run the `workflow_sketch.sh` script through your terminal. This script offers several options regarding parameters such as animation time duration and resolution. For more information, run it as
As you can see, options are either preceded by double dashes (as in `--fps 24`) or by a single dash (as in `-t 8`). The option's value should follow
the option's name, also separated by a space. Some options, such as the `--download` option, don't expect arguments. When any available option is not called, it runs
the code with its standard value. See below for a detailed list of all the available options, which can also be checked out by entering:
```bash
./workflow_sketch.sh --help
```
Standard values to all these parameters are set so the minimum code required is simply
In case you have chosen the automatic ESD download option, run the code as:
```bash
./workflow_sketch.sh
./workflow_sketch.sh --url <URL> --download
```
If you have chosen the automatic ESD download option above, the code becomes
where ``<URL>`` is the URL address for the chosen ESD file. Of course, you can add other options as well, if you wish. Here's another working example, including
the download option:
```bash
./workflow_sketch.sh --url <URL> --download
./workflow_sketch.sh --url http://opendata.cern.ch/record/1103/files/assets/alice/2010/LHC10h/000139173/ESD/0004/AliESDs.root --download -t 4 --cameras Overview,Forward
```
where ``<URL>`` is the copied ESD URL.
---------------------------------------------------------------------------------------------------------------------
Option Entry Action Standard Value
------------------- ------------------------- ------------------------------------------------------ ----------------
-h or --help none Shows a list with all possible using options. -
-d or
--download none Informs to download the ESD file, rather than trying -
to find one locally
-u or --url ESD file URL Informs ESD file URL, in case download option is -
called
-m ou Positive integer Sets the maximum number of particles allowed in the 1000
--maxparticles events to be animated.
--minparticles Positive integer Sets the minimum number of particles allowed in the 0
events to be animated.
-n or Non-negative integer Sets number of events to be animated inside chosen 10
--numberofevents ESD file
--minavgpz Positive number Gets only events for which the absolute value of 0
average momentum in the z direction is greater than
or equal to the specified value, in GeV/c. Useful
for animating events with 'boosts' of particles to
the same side.
--minavgpt Positive number Get only events for which the average transversal 0
momentum is greater than or equal to the specified
value, in GeV/c. Useful for animating events with
'boosts' of particles on the xy plane.
-t or
--duration Positive integer Sets animation duration, in seconds 10
-r ou --radius Positive number Scales the particle's radius to the informed value 1
--resolution Whole number from Sets animation resolution percentage. 100
1 to 100
--fps Positive integer Sets animation number of frames per second 24
--transparency Positive number Sets detector transparency, where zero is full 1
transparency and 1 is standard transparency
-c ou --cameras Comma-separated list Sets cameras to animate events with Overview
(with no spaces) of
cameras. Options:
Barrel, Forward,
Overview, Side,
Moving1, Moving2,
Moving3, Moving4
--mosaic none Makes animations in four different cameras (Barrel, -
Forward, Overview and Moving1) and combines them
into a single 2x2 clip containing all four
perspectives.
--picpct Whole number from Informs percentage of animation to take HD picture, 80
1 to 100 saved along with the clip.
--bgshade Number from 0 to 1 Set background shade of black to VALUE, where 0 is 0
totally black and 1 is totally white.
-a ou --sample none Creates a sample Blender animation of Event 2 from -
URL http://opendata.cern.ch/record/1102/files/asset
s/alice/2010/LHC10h/000139038/ESD/0001/AliESDs.root
--its none Removes ITS detector from animation -
--detailedtpc none Includes a more detailed version of the TPC -
geometry, made by researcher Stefan Rossegger
(stefan.rossegger@gmail.com)
--tpc none Removes TPC detector from animation -
--trd none Removes TRD detector from animation -
--emcal none Removes EMCal detector from animation -
--blendersave none Saves Blender file along with animation clip -
-----------------------------------------------------------------------
After running the script, it may take a long time to generate all the animations, but as soon as it is done, they will be available inside a new directory uniquely identified according to the chosen ESD file. Each clip is also identified by event number. Enjoy!
After running the script, it may take a long time to generate all the animations, but as soon as it is done, they will be available inside a new directory uniquely
identified according to the chosen ESD file. Each clip is also identified by event number. Enjoy!
# Default Animation
For generating a default animation, simply run the script `workflow_sketch.sh` in your terminal as below:
For generating a default animation, simply run the script `workflow_sketch.sh` in your terminal as below, from inside the project's repository directory:
```bash
./workflow_sketch.sh -a
```
After this, a single default animation should be ready. It will be available inside the `blender` directory, in *.mp4* format. Enjoy!
After this, a single default animation should be ready. It will be available inside the `blender` directory, in *.mp4* format. Enjoy! You may want to check the table
above for information on the using options.
......@@ -2,9 +2,10 @@
# animate_particles.py - Animate HEP events
#
# For console only rendering (example):
# $ blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=1 -cameras="BarrelCamera OverviewCamera" \
# -datafile="esd-detail.dat" -n_event=0 -simulated_t=0.02 -fps=24 -resolution=100 -transparency=1.2 \
# -stamp_note="Texto no canto" -its=1 -tpc=0 -trd=1 -detailed_tpc=1 -emcal=0 -blendersave=0 -picpct=5 -tpc_blender_path="/home/files/blender"
# $ blender -noaudio --background -P animate_particles.py -- -radius=1.2 -duration=1 \
# -datafile="esd-detail.dat" -n_event=0 -simulated_t=0.02 -fps=24 -resolution=100 -transparency=1.2 -stamp_note="Texto no canto"\
# -its=1 -tpc=0 -trd=1 -detailed_tpc=1 -emcal=0 -blendersave=0 -tpc_blender_path="/home/files/blender"\
# -output_path="/tmp/blender" -bgshade=0.05
#
import os
......@@ -30,7 +31,6 @@ parser = ArgumentParserForBlender()
parser.add_argument('-radius','--r_part')
parser.add_argument('-duration','--duration')
parser.add_argument('-cameras','--render_cameras')
parser.add_argument('-datafile','--datafile')
parser.add_argument('-simulated_t','--simulated_t')
parser.add_argument('-fps','--fps')
......@@ -43,9 +43,10 @@ parser.add_argument('-tpc','--tpc')
parser.add_argument('-trd','--trd')
parser.add_argument('-emcal','--emcal')
parser.add_argument('-blendersave','--blendersave')
parser.add_argument('-picpct','--picpct')
parser.add_argument('-bgshade','--bgshade')
parser.add_argument('-tpc_blender_path','--tpc_blender_path')
parser.add_argument('-detailed_tpc','--detailed_tpc')
parser.add_argument('-output_path','--output_path')
args = parser.parse_args()
bpy.context.user_preferences.view.show_splash = False
......@@ -54,7 +55,7 @@ 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
r_part = float(args.r_part) # Particle radius scale
n_event = str(args.n_event) # Event number for video name
simulated_t = float(args.simulated_t) # in microsseconds
duration = int(args.duration) # in seconds
......@@ -65,59 +66,37 @@ transp_par = float(args.transp_par)
datafile = str(args.datafile)
detectors = [int(args.its),int(args.tpc),int(args.trd),int(args.emcal),int(args.detailed_tpc)] # Array that stores which detectors to build
blendersave = int(args.blendersave) # 1 (save Blender file) or 0 (don't)
picpct = int(args.picpct) # percentage of animation to take picture
bgshade = float(args.bgshade)
tpc_blender_path = str(args.tpc_blender_path) # path to 'animate' directory, where .blend file for detailed TPC is saved
# Create array with cameras:
cams_string = str(args.render_cameras)
cams_list = []
j=0
last_space=0
for digit in range(0,len(cams_string)):
if cams_string[digit] == ' ':
cam = ""
for i in range(j,digit):
cam += cams_string[i]
cams_list.append(cam)
j=digit+1
cam = ""
for i in range(j,len(cams_string)):
cam += cams_string[i]
cams_list.append(cam)
#configure output
outputPath = "/tmp/alice_blender/"
# Configure Output
outputPath = str(args.output_path)+"/"
fileIdentifier = "PhysicalTrajectories_"
renderAnimation = True # True
saveBlenderFile = blendersave # 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(cams_list, duration, fps, simulated_t, outputPath, fileIdentifier, resolution_percent)
driver.configure(duration, fps, simulated_t, outputPath, fileIdentifier, resolution_percent)
"""
# Create and configure animation driver
driver = dataDriver("AlirootFileGenerator",n_event,datafile) # Simple dataDriver
driver.configure(cams_list, duration, fps, simulated_t, outputPath, fileIdentifier, resolution_percent)
driver.configure(duration, fps, simulated_t, outputPath, fileIdentifier, resolution_percent)
### Build scene
init(stamp_note,transp_par,detectors,tpc_blender_path) # Cleanup, addCameras, addALICE_TPC
init(stamp_note,transp_par,detectors,tpc_blender_path,bgshade) # Cleanup, addCameras, addALICE_TPC, Set background
particles = driver.getParticles()
blender_particles, blender_tracks = createSceneParticles(particles,createTracks = True) # Create blender objects - one sphere per particle
blender_particles, blender_tracks = createSceneParticles(particles,r_part,createTracks = True) # Create blender objects - one sphere per particle
#Animate scene using driver
animate(blender_particles,particles,driver)
animate_tracks(blender_tracks,particles,driver)
animate_camera(driver)
bpy.context.scene.frame_current = 24
## Save blender file
if saveBlenderFile: bpy.ops.wm.save_as_mainfile(filepath=outputPath+fileIdentifier+"AlirootFileGenerator_"+datafile+"_Event_"+n_event+".blend")
# Render animation
if renderAnimation: driver.render(picpct)
#exit()
......@@ -11,8 +11,7 @@ exec(compile(open(filename).read(), filename, 'exec'))
class animationDriver:
def __init__(self,name):
self.name = name
def configure(self, renderCameras, duration, fps, simulated_t, outputPath, fileIdentifier, resolution_percent=100):
self.renderCameras=renderCameras # array with cameras to render animation with
def configure(self, duration, fps, simulated_t, outputPath, fileIdentifier, resolution_percent=100):
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)
......@@ -26,25 +25,6 @@ class animationDriver:
bcs.frame_start = 0
bcs.frame_end = self.N_frames
def render(self,pic_pct):
bcs = bpy.context.scene
self.output_prefix=[]
for c in range(0,len(self.renderCameras)):
# Set specific output info
self.output_prefix.append(self.fileIdentifier+str(self.xpixels)+"px_"+self.name+self.renderCameras[c])
bcs.render.filepath = "/tmp/alice_blender/"+self.output_prefix[c]
bcs.camera = bpy.data.objects[self.renderCameras[c]]
# Take picture of animation
bcs.frame_current = int(bcs.frame_end * pic_pct/100)
bpy.ops.render.render()
bpy.data.images['Render Result'].save_render(filepath=bcs.render.filepath+".png")
# Render actual animation
bpy.ops.render.render(animation=True)
def configureOutput(self):
# Configure Output
bcsr = bpy.context.scene.render
......
# -*- coding: utf-8 -*-
# animate_particles.py - Animate HEP events
#
# For console only rendering (example):
# $ blender -noaudio --background -P animate_particles.py -- -cam "OverviewCamera" -datafile "Run139038_Orbit7548473_BunchCross1534_2.dat" \
# -n_event 2 -pic_pct 30 -output_path "/home"
#
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('-cam','--render_cam')
parser.add_argument('-datafile','--datafile')
parser.add_argument('-n_event','--n_event')
parser.add_argument('-pic_pct','--pic_pct')
parser.add_argument('-output_path','--output_path')
args = parser.parse_args()
render_cam = str(args.render_cam)
datafile = str(args.datafile)
n_event = str(args.n_event)
pic_pct = int(args.pic_pct)
outputPath = str(args.output_path)+"/"
fileIdentifier = "PhysicalTrajectories_"
bpy.ops.wm.open_mainfile(filepath=outputPath+fileIdentifier+"AlirootFileGenerator_"+datafile+"_Event_"+n_event+".blend")
bcs = bpy.context.scene
# Set specific output info
output_prefix = "PhysicalTrajectories_1920px_AlirootFileGenerator_"+datafile+"_Event_"+n_event+"_"+render_cam
bcs.render.filepath = outputPath+output_prefix
bcs.camera = bpy.data.objects[render_cam]
# Take picture of animation
bcs.frame_current = int(bcs.frame_end * pic_pct/100)
bpy.ops.render.render()
bpy.data.images['Render Result'].save_render(filepath=bcs.render.filepath+".png")
# Render actual animation
bpy.ops.render.render(animation=True)
import math
# Import Blender functions
filename = os.path.join(os.path.basename(bpy.data.filepath), "blender_functions.py")
exec(compile(open(filename).read(), filename, 'exec'))
def init(unique_id,transp_par,detectors,blender_path):
def init(unique_id,transp_par,detectors,blender_path,bgshade):
bcs = bpy.context.scene
# Configure Environment
bcs.world.light_settings.use_environment_light = False
bcs.world.light_settings.environment_energy = 0.1
bpy.context.scene.world.horizon_color = (bgshade,bgshade,bgshade)
# Configure Stamp
bcsr = bpy.context.scene.render
......@@ -21,6 +24,8 @@ def init(unique_id,transp_par,detectors,blender_path):
bcsr.use_stamp_filename = False
bcsr.stamp_note_text = unique_id
bcsr.use_stamp_note = True
bcsr.stamp_font_size = 40
# Cleanup
bpy.data.objects.remove(bpy.data.objects['Cube'])
......@@ -58,7 +63,7 @@ def addALICE_ITS(transp_par,rgb_v):
# ADD ITS INNER BARREL
# Material
createMaterial("innerITS",R=rgb_v[2],G=0,B=rgb_v[2],shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.7,emit=0,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("innerITS",R=rgb_v[2],G=0,B=rgb_v[2],shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*1.4,emit=0,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
# Add Inner ITS
bpy.ops.mesh.primitive_cylinder_add(radius=0.0421, depth=0.271, view_align=False, enter_editmode=False, location=(0, 0, 0))
......@@ -73,7 +78,7 @@ def addALICE_ITS(transp_par,rgb_v):
# ADD ITS OUTER BARREL
# Material
createMaterial("outerITS",R=rgb_v[3],G=0,B=rgb_v[3],shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.4,emit=0.8,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("outerITS",R=rgb_v[3],G=0,B=rgb_v[3],shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.8,emit=0.8,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
# ADD ITS MIDDLE LAYERS
......@@ -122,7 +127,7 @@ def addALICE_ITS(transp_par,rgb_v):
def addALICE_TPC(transp_par,rgb_v):
# Material
createMaterial("tpc",R=0,G=rgb_v[0],B=0,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.2,emit=0.3,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("tpc",R=0,G=rgb_v[0],B=0,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.4,emit=0.3,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
# Add TPC
bpy.ops.mesh.primitive_cylinder_add(radius=2.461, depth=5.1, view_align=False, enter_editmode=False, location=(0, 0, 0)) #bigger cylinder
......@@ -136,10 +141,10 @@ def addALICE_TPC(transp_par,rgb_v):
def importALICE_detailed_TPC(transp_par,blender_path):
# Materials
createMaterial("tpc_part_1",R=0,G=1,B=0,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.2,emit=0.3,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("tpc_part_2",R=1,G=1,B=0,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.2,emit=0.3,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("tpc_part_3",R=1,G=0,B=0,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.2,emit=0.3,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("tpc_part_4",R=0,G=1,B=1,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.2,emit=0.3,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("tpc_part_1",R=0,G=1,B=0,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.4,emit=0.3,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("tpc_part_2",R=1,G=1,B=0,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.4,emit=0.3,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("tpc_part_3",R=1,G=0,B=0,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.4,emit=0.3,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("tpc_part_4",R=0,G=1,B=1,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.4,emit=0.3,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
# Import detailed TPC
#
......@@ -159,7 +164,7 @@ def importALICE_detailed_TPC(transp_par,blender_path):
def addALICE_TRD(transp_par,rgb_v):
# Material
createMaterial("TRD",R=rgb_v[3],G=0,B=rgb_v[3],shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.15,emit=0.8,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("TRD",R=rgb_v[3],G=0,B=rgb_v[3],shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.3,emit=0.8,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
# Add "hole" to subtract from the middle
bpy.ops.mesh.primitive_cylinder_add(radius=2.9, depth=6, vertices=18, view_align=False, enter_editmode=False, location=(0, 0, 0)) #smaller cylinder
......@@ -213,7 +218,7 @@ def addALICE_TRD(transp_par,rgb_v):
def addALICE_EMCal(transp_par,rgb_v):
# Material
createMaterial("emcal",R=rgb_v[1],G=rgb_v[1],B=0,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.05,emit=1.5,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
createMaterial("emcal",R=rgb_v[1],G=rgb_v[1],B=0,shadows=False,cast_shadows=False,transparency=True,alpha=transp_par*0.1,emit=1.5,specular_alpha=0,fresnel_factor=5,fresnel=0.3)
# Add cylinder for EMCal
bpy.ops.mesh.primitive_cylinder_add(radius=4.7, depth=5.1, vertices=19, view_align=False, enter_editmode=False, location=(0, 0, 0))
......@@ -276,9 +281,29 @@ def addCameras():
bpy.context.object.name = "SideCamera"
bpy.context.object.data.lens = 9
# Moving Camera 1
bpy.ops.object.camera_add()
bpy.context.object.name = "Moving1Camera"
bpy.context.object.data.lens = 26
# Moving Camera 2
bpy.ops.object.camera_add()
bpy.context.object.name = "Moving2Camera"
bpy.context.object.data.lens = 26
# Moving Camera 3
bpy.ops.object.camera_add()
bpy.context.object.name = "Moving3Camera"
bpy.context.object.data.lens = 26
# Moving Camera 4
bpy.ops.object.camera_add()
bpy.context.object.name = "Moving4Camera"
bpy.context.object.data.lens = 26
# Function that creates Blender Objects from input list of particles.
## Returns a list of blender objects
def createSceneParticles(particles, createTracks = False):
def createSceneParticles(particles, r_part=1, createTracks = False):
# Associate particles and colors
particle_types = ["Electron","Pion","Muon","Proton","Kaon","Unknown"]
clRed = (1, 0, 0)
......@@ -286,7 +311,7 @@ def createSceneParticles(particles, createTracks = False):
clBlue = (0, 0, 1)
clMagenta = (0.75, 0, 1)
clYellow = (1, 1, 0)
clWhite = (255, 255, 255)
clWhite = (0.8, 0.8, 0.8)
particle_colors = {"Electron":clRed, "Pion":clGreen, "Muon":clBlue, "Proton":clMagenta, "Kaon": clYellow, "Unknown": clWhite}
# Create Materials
......@@ -301,6 +326,13 @@ def createSceneParticles(particles, createTracks = False):
# Create blender spheres (particles)
blender_particles=[]
n_particles=len(particles)
# Define particle radius based on multiplicity
if n_particles > 15000:
r_part=0.01*r_part
else:
r_part=0.05-(0.04/15000)*n_particles*r_part
for particle in particles:
this_type=particle.p_type
print("Adding Sphere - Particle " + str(len(blender_particles)+1)+" of "+str(n_particles)+" - "+this_type)
......@@ -327,7 +359,7 @@ def createSceneParticles(particles, createTracks = False):
curveTrack.resolution_u = 2
curveTrack.fill_mode = 'FULL'
curveTrack.bevel_depth = 0.02
curveTrack.bevel_depth = 0.4*r_part # Tracks are 40% the thickness of particles
curveTrack.bevel_resolution = 3
......@@ -349,12 +381,83 @@ def createSceneParticles(particles, createTracks = False):
return blender_particles, blender_tracks
def animate_camera(driver):
bcs = bpy.context.scene
# Animate Moving Camera 1
for f in range(bcs.frame_end):
theta = f/bcs.frame_end*math.pi/2
bcs.frame_current = f
print("Configuring Moving1Camera in frame: "+str(f)+" of "+str(bcs.frame_end))
bcs.objects.active=bpy.data.objects['Moving1Camera']
x_cam=15*math.sin(theta)
y_cam=7
z_cam=15*math.cos(theta)
x_rot_cam=-0.427606
y_rot_cam=theta
z_rot_cam=0
bpy.context.object.location=(x_cam,y_cam,z_cam)
bpy.context.object.keyframe_insert(data_path='location')
bpy.context.object.rotation_euler=(x_rot_cam,y_rot_cam,z_rot_cam)
bpy.context.object.keyframe_insert(data_path='rotation_euler')
# Animate Moving Camera 2
for f in range(bcs.frame_end):
theta = f/bcs.frame_end*math.pi/2+math.pi/5
bcs.frame_current = f
print("Configuring Moving2Camerara in frame: "+str(f)+" of "+str(bcs.frame_end))
bcs.objects.active=bpy.data.objects['Moving2Camera']
x_cam=15*math.sin(theta)
y_cam=7
z_cam=-15*math.cos(theta)
x_rot_cam=-0.427606
y_rot_cam=math.pi-theta
z_rot_cam=0
bpy.context.object.location=(x_cam,y_cam,z_cam)
bpy.context.object