scene_functions.py 16.7 KB
Newer Older
1
2
import math

3
4
5
# Import Blender functions
filename = os.path.join(os.path.basename(bpy.data.filepath), "blender_functions.py")
exec(compile(open(filename).read(), filename, 'exec'))
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
6

7
def init(unique_id,transp_par,detectors,blender_path,bgshade):
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
8
9
10
    bcs = bpy.context.scene

    # Configure Environment
11
    bcs.world.light_settings.use_environment_light = False
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
12
    bcs.world.light_settings.environment_energy = 0.1
13
    bpy.context.scene.world.horizon_color = (bgshade,bgshade,bgshade)
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
14
15

    # Configure Stamp
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
16
17
18
19
20
21
22
23
24
25
26
    bcsr = bpy.context.scene.render
    bcsr.use_stamp = True
    bcsr.use_stamp_time = False
    bcsr.use_stamp_date = False
    bcsr.use_stamp_render_time = False
    bcsr.use_stamp_frame = False
    bcsr.use_stamp_scene = False
    bcsr.use_stamp_camera = False
    bcsr.use_stamp_filename = False
    bcsr.stamp_note_text = unique_id
    bcsr.use_stamp_note = True
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
27
28
29
30

    # Cleanup
    bpy.data.objects.remove(bpy.data.objects['Cube'])
    bpy.data.objects.remove(bpy.data.objects['Camera'])
31
    bpy.data.objects.remove(bpy.data.objects['Lamp'])
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
32
33
34

    # Basic Objects
    addCameras() # Add cameras
35
    addLamps() # Add Lamps
36

37
    addALICE_Geometry(False,transp_par,detectors,blender_path)
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
38

39
def addALICE_Geometry(bright_colors=False, transp_par=1.0, detectors=[1,1,1,1,0], blender_path="/home/"):
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
40

41
    if bright_colors: # Defining sequence of RGB values to fill 'createMaterial' functions below
42
        rgb_v = [13,13,25,10] # Colors for brighter detector
43
    else:
44
        rgb_v = [0.5,0.9,1,0.2] # Colors for standard geometry
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
45

Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
46

47
    if detectors[0]:
48
49
50
51
52
53
54
55
56
57
        addALICE_ITS(transp_par,rgb_v)
    if detectors[4]:
        importALICE_detailed_TPC(transp_par,blender_path)
    else:
        if detectors[1]:
            addALICE_TPC(transp_par,rgb_v)
    if detectors[2]:
        addALICE_TRD(transp_par,rgb_v)
    if detectors[3]:
        addALICE_EMCal(transp_par,rgb_v)
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
58

59
def addALICE_ITS(transp_par,rgb_v):
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
60

61
    # ADD ITS INNER BARREL
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
62

63
    # Material
64
    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)
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
65

66
67
68
69
    # 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))
    inner_TPC = bpy.context.object
    inner_TPC.name = "innerITS"
70

71
72
73
    # Set Material
    inner_TPC.data.materials.clear()
    inner_TPC.data.materials.append(bpy.data.materials["innerITS"])
74
75


76
    # ADD ITS OUTER BARREL
77

78
    # Material
79
    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)
80

81
    # ADD ITS MIDDLE LAYERS
82

83
84
85
86
    # Add "hole" to subtract from the middle
    bpy.ops.mesh.primitive_cylinder_add(radius=0.1944, depth=0.9, view_align=False, enter_editmode=False, location=(0, 0, 0)) #smaller cylinder
    middle_ITS_hole = bpy.context.object
    middle_ITS_hole.name = "Hole"
87

88
89
90
91
    # Add actual middle layer ITS part
    bpy.ops.mesh.primitive_cylinder_add(radius=0.247, depth=0.843, view_align=False, enter_editmode=False, location=(0, 0, 0)) #bigger cylinder
    middle_ITS = bpy.context.object
    middle_ITS.name = "middleITS"
92

93
94
    # Subtract hole from main TPC part
    subtract(middle_ITS_hole,middle_ITS)
95

96
97
98
    # Set material
    middle_ITS.data.materials.clear()
    middle_ITS.data.materials.append(bpy.data.materials["outerITS"])
99
100


101
    # ADD ITS OUTER LAYERS
102

103
104
105
106
    # Add "hole" to subtract from the middle
    bpy.ops.mesh.primitive_cylinder_add(radius=0.3423, depth=1.5, view_align=False, enter_editmode=False, location=(0, 0, 0)) #smaller cylinder
    outer_ITS_hole = bpy.context.object
    outer_ITS_hole.name = "Hole"
107

108
109
110
111
    # Add actual outer layer ITS part
    bpy.ops.mesh.primitive_cylinder_add(radius=0.3949, depth=1.475, view_align=False, enter_editmode=False, location=(0, 0, 0)) #bigger cylinder
    outer_ITS = bpy.context.object
    outer_ITS.name = "outerITS"
112

113
114
115
116
117
118
    # Subtract hole from main ITS part
    subtract(outer_ITS_hole,outer_ITS)

    # Set material
    outer_ITS.data.materials.clear()
    outer_ITS.data.materials.append(bpy.data.materials["outerITS"])
119

120
121
122
123
    # Make ITS middle and outer layers a single object
    joinObjects([middle_ITS,outer_ITS])
    Outer_ITS = bpy.context.object
    Outer_ITS.name = "OuterITS"
124

125
def addALICE_TPC(transp_par,rgb_v):
126

127
    # Material
128
    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)
129

130
131
132
133
134
135
136
137
138
139
140
141
    # 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
    TPC = bpy.context.object
    TPC.name = "TPC"

    # Set material
    TPC.data.materials.clear()
    TPC.data.materials.append(bpy.data.materials["tpc"])

def importALICE_detailed_TPC(transp_par,blender_path):

    # Materials
142
143
144
145
    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)
146
147

    # Import detailed TPC
148
149
150
151
    #
    # File was provided by CERN's researcher Stefan Rossegger
    # Email: stefan.rossegger@gmail.com
    #
152
153
154
155
156
    for i in range(1,5):
        bpy.ops.wm.append(filename="tpc_part"+str(i), directory=blender_path+"/Detailed_TPC.blend/Object/")
        bpy.context.scene.objects.active = bpy.data.objects["tpc_part"+str(i)]
        TPC_part = bpy.context.object
        TPC_part.name = "TPC_part_"+str(i)
157

158
        # Set material
159
160
        TPC_part.data.materials.clear()
        TPC_part.data.materials.append(bpy.data.materials["tpc_part_"+str(i)])
161

162
def addALICE_TRD(transp_par,rgb_v):
163

164
    # Material
165
    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)
166

167
168
169
170
    # 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
    TRD_hole = bpy.context.object
    TRD_hole.name = "Hole"
171

172
173
174
175
    # Add actual TRD part
    bpy.ops.mesh.primitive_cylinder_add(radius=3.7, depth=5.1, vertices=18, view_align=False, enter_editmode=False, location=(0, 0, 0)) #bigger cylinder
    TRD = bpy.context.object
    TRD.name = "TRD"
176

177
178
    # Subtract hole from main TRD part
    subtract(TRD_hole,TRD)
179

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
    # Set material
    TRD.data.materials.clear()
    TRD.data.materials.append(bpy.data.materials["TRD"])

    # Add 'slices' to subtract from TRD structure
    bpy.ops.mesh.primitive_cube_add(radius=1, location=(2.855942,0.50358,0))
    slice = bpy.context.object
    slice.name = "slice"
    bpy.ops.transform.resize(value=(1,0.03,4))
    bpy.context.object.rotation_euler[2] = 0.174533
    subtract(slice,TRD)

    def rad(theta): # Convert degrees to radians
        return theta * math.pi / 180

    xn = 2.9 * math.cos(rad(10))
    yn = 2.9 * math.sin(rad(10))

    for n in range(1,18):

        dx = -2 * 2.9 * math.sin(rad(10)) * math.sin(rad(n * 20))
        xn += dx
202

203
204
205
206
207
208
        dy = 2 * 2.9 * math.sin(rad(10)) * math.cos(rad(n * 20))
        yn += dy

        rotat = rad(10 + n*20)

        bpy.ops.mesh.primitive_cube_add(radius=1, location=(xn,yn,0))
209
210
211
        slice = bpy.context.object
        slice.name = "slice"
        bpy.ops.transform.resize(value=(1,0.03,4))
212
        bpy.context.object.rotation_euler[2] = rotat
213

214
        subtract(slice,TRD)
215

216
def addALICE_EMCal(transp_par,rgb_v):
217

218
    # Material
219
    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)
220

221
222
223
224
    # 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))
    EMCal = bpy.context.object
    EMCal.name = "EMCal"
225

226
227
228
229
    # Add cylinder to be removed from center
    bpy.ops.mesh.primitive_cylinder_add(radius=4.35, depth=5.2, vertices=19, view_align=False, enter_editmode=False, location=(0, 0, 0))
    emcal_hole = bpy.context.object
    emcal_hole.name = "Hole"
230

231
    subtract(emcal_hole,EMCal);
232

233
234
235
236
237
    # Adds rotated cube to be removed from EMCal so that there's a 7.3° angle with top y axis, clockwise
    bpy.ops.mesh.primitive_cube_add(location=(2.85,2.2,0), rotation=(0,0,-0.1274), radius=2.55)
    bpy.ops.transform.resize(value=(1.5,1.5,1.5), constraint_axis=(False,False,True))
    cube1 = bpy.context.object # first quadrant
    subtract(cube1,EMCal)
238

239
240
241
242
243
    # Adds rotated cube to be removed from EMCal so that there's a 9.7° angle with left x axis, anticlockwise
    bpy.ops.mesh.primitive_cube_add(location=(-2.08,-2.95,0), rotation=(0,0,0.1693), radius=2.55)
    bpy.ops.transform.resize(value=(1.5,1.5,1.5), constraint_axis=(False,False,True))
    cube3 = bpy.context.object # third quadrant
    subtract(cube3,EMCal)
244

245
246
247
248
249
    #Adds cube with right angle in fourth quadrant to be removed from EMCal
    bpy.ops.mesh.primitive_cube_add(location=(2.55,-2.55,0), radius=2.55)
    bpy.ops.transform.resize(value=(1.5,1.5,1.5), constraint_axis=(False,False,True))
    cube4 = bpy.context.object # fourth quadrant
    subtract(cube4,EMCal)
250

251
252
253
    # Set Material
    EMCal.data.materials.clear()
    EMCal.data.materials.append(bpy.data.materials["emcal"])
254

255

256
def addLamps():
257
    bpy.ops.object.lamp_add(type='POINT', location=(4,1,6))
258
    bpy.ops.object.lamp_add(type='POINT', location=(0,0,-8))
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
259

Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
260
261
def addCameras():
    # ForwardCamera
262
    bpy.ops.object.camera_add(location = (0,0.5,20), rotation = (0, 0, 0))
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
263
264
265
    bpy.context.object.name = "ForwardCamera"
    camera_forward=bpy.data.objects['ForwardCamera']
    camera_forward.data.type = 'ORTHO'
266
    camera_forward.data.ortho_scale = 18
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
267
268

    # OverviewCamera
269
    bpy.ops.object.camera_add(location = (23.27182, 10.3968, 22.754), rotation = (-0.071558, 0.879645, 0.305433))
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
270
271
272
273
274
275
276
    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.name = "BarrelCamera"

277
278
279
280
281
    # Side Camera
    bpy.ops.object.camera_add(location = (6, 0, 0), rotation = (0, 1.5708, 0))
    bpy.context.object.name = "SideCamera"
    bpy.context.object.data.lens = 9

282
283
284
285
286
    # Moving Camera
    bpy.ops.object.camera_add(location = (0, 7, 15), rotation = (-0.427606,0,0))
    bpy.context.object.name = "MovingCamera"
    bpy.context.object.data.lens = 26

Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
287
288
# Function that creates Blender Objects from input list of particles.
## Returns a list of blender objects
289
def createSceneParticles(particles, r_part=1, createTracks = False):
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
290
291
292
293
294
295
296
297
298
299
    # 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}

300
    # Create Materials
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
301
302
303
    for type in particle_types:
        bpy.data.materials.new(name=type)
        #bpy.context.object.active_material = (1, 0, 0)
304
        bpy.data.materials[type].emit = 0.05
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
305
306
307
308
309
310
311
        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)
312
313
314
315
316
317
318

    # 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

Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
319
320
    for particle in particles:
        this_type=particle.p_type
321
        print("Adding Sphere - Particle " + str(len(blender_particles)+1)+" of "+str(n_particles)+" - "+this_type)
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
322
        bpy.ops.mesh.primitive_uv_sphere_add()
323
        bpy.ops.object.shade_smooth()
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
324
325
326
327
328
329
330
331
332
333
334
335
        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:
336
337
                this_type=track.p_type
                print("Adding Curve - Track " + str(len(blender_tracks)+1)+" of "+str(n_particles)+" - "+this_type)
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
338
339
340
341
342
343
344

                # create the Curve Datablock
                curveTrack = bpy.data.curves.new('CurveTrack', type='CURVE')
                curveTrack.dimensions = '3D'
                curveTrack.resolution_u = 2

                curveTrack.fill_mode = 'FULL'
345
                curveTrack.bevel_depth = 0.4*r_part # Tracks are 40% the thickness of particles
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
                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

367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
def animate_camera(driver):
    bcs = bpy.context.scene

    #Animate particles
    for f in range(bcs.frame_end):
        theta = f/bcs.frame_end*math.pi
        bcs.frame_current = f
        print("Configuring moving camera in frame: "+str(f)+" of "+str(bcs.frame_end))
        bcs.objects.active=bpy.data.objects['MovingCamera']
        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')


Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
388
389
390
391
392
# Function that animates the scene using the particle propagator class
def animate(objects, particles, driver):
    bcs = bpy.context.scene

    #Animate particles
393
    for f in range(bcs.frame_end):
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
394
395
396
397
398
399
400
401
402
403
404
405
406
        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
407
408
    for f in range(bcs.frame_end):
        t = driver.delta_t*(f+1) # choosing (f+1) instead of (f) removes gap between track and particle
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
409
410
        bcs.frame_current = f
        print("Configuring tracks in frame: "+ str(f) +" of "+ str(bcs.frame_end))
411
        for point in range(f,bcs.frame_end+1):
Breno Rilho Lemos's avatar
Breno Rilho Lemos committed
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
            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