glitch3d 0.2.2.3 → 0.2.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b4f2f6d21ae96e8105a1c6da16f6e1fb2838f1d9
4
- data.tar.gz: d9860cd506ad2b7c87ea43f3da5527a0282402c1
3
+ metadata.gz: a15b6ba339b081828a44dfb59587d73745cecfbc
4
+ data.tar.gz: 4b7d71946ca52bf70a562a9ec457b9a72cbdded8
5
5
  SHA512:
6
- metadata.gz: d980c45b765663cd5aa61736b6f79b82b9d75993efec48806e668e800077ab41ec513a4b99ee2b6be7d3a4d21b6df0d6c33bc803992995e24e4b23084e685c7c
7
- data.tar.gz: 1db6e37de5e965a3ea6ff0526c4bdfb0be99d1c7782f39668c8c9ea876985ff02ded591c2ec76f5cf3378e0d76e7cbc0065c376b914c1e47e70546331abef6e8
6
+ metadata.gz: c5c5fd02a892349daf3b9fa218d9782a79804e1b8feb26d92a56903bb4a821d2aaef940d5c304ed35df34adcca3fde11708898c37f99b71b8a277cc5b77402a5
7
+ data.tar.gz: 6fa00d4f1fd9ada772c01a6a145e42348ca23717c4497c74539d3d9766895284240acc52bdb6768316d743a9e445ea40e40c51eb48fd3471a30bfcf5ebec3aa7
data/fixtures/dude.jpg ADDED
Binary file
@@ -0,0 +1,73 @@
1
+ # Load props
2
+ bpy.ops.import_scene.obj(filepath = os.path.join(FIXTURES_FOLDER_PATH + 'm4a1.obj'), use_edges=True)
3
+ m4a1 = bpy.data.objects['m4a1']
4
+ m4a1.location = rand_location()
5
+ m4a1.scale = (0.5, 0.5, 0.5)
6
+ props.append(m4a1)
7
+
8
+ # Add props
9
+ rand_primitive = random.choice(PRIMITIVES)
10
+ build_composite_object(rand_primitive, 4, 1)
11
+
12
+ # Set up virtual displays
13
+ bpy.ops.mesh.primitive_grid_add(x_subdivisions=100, y_subdivisions=100, location=(0, 6, 2))
14
+ display1 = bpy.data.objects['Grid']
15
+ bpy.ops.mesh.primitive_grid_add(x_subdivisions=100, y_subdivisions=100, location=(6, 0, 2))
16
+ display2 = bpy.data.objects['Grid.001']
17
+
18
+ bpy.data.groups.new('Displays')
19
+ bpy.data.groups['Displays'].objects.link(display1)
20
+ bpy.data.groups['Displays'].objects.link(display2)
21
+
22
+ display1.rotation_euler.x += math.radians(90)
23
+ display1.rotation_euler.z -= math.radians(90)
24
+ display2.rotation_euler.x += math.radians(90)
25
+ display2.rotation_euler.y += math.radians(90)
26
+ display2.rotation_euler.z += math.radians(120)
27
+
28
+ for display in bpy.data.groups['Displays'].objects:
29
+ display.rotation_euler.x += math.radians(90)
30
+ display.scale = DISPLAY_SCALE
31
+ texture_object(display)
32
+ make_texture_object_transparent(display)
33
+ unwrap_model(display)
34
+ glitch(display)
35
+
36
+ glitch(m4a1)
37
+ make_object_gradient_fabulous(m4a1, rand_color(), rand_color())
38
+
39
+ # Make floor
40
+ bpy.ops.mesh.primitive_plane_add(location=(0, 0, -2))
41
+ floor = last_added_object('PLANE')
42
+ bpy.data.groups['Plane'].objects.link(floor)
43
+ floor.scale = (20,20,20)
44
+ subdivide(floor, 8)
45
+ displace(floor)
46
+ texture_object(floor)
47
+
48
+ OCEAN = add_ocean(10, 20)
49
+
50
+ # Create lines as backdrop
51
+ bpy.data.groups.new('Lines')
52
+ for j in range(0,20):
53
+ for i in range(0, 20):
54
+ new_line = create_line('line' + str(uuid.uuid1()), series(30), 0.003, (j, -10, 2))
55
+ new_line.location.z += i / 3
56
+
57
+ # Add flying letters, lmao
58
+ for index in range(1, len(WORDS)):
59
+ new_object = spawn_text()
60
+ props.append(new_object)
61
+ text_scale = random.uniform(0.75, 3)
62
+ make_object_glossy(new_object, rand_color(), 0.0)
63
+ new_object.scale = (text_scale, text_scale, text_scale)
64
+ new_object.location = rand_location()
65
+ # pivot text to make it readable by camera
66
+ new_object.rotation_euler.x += math.radians(90)
67
+ new_object.rotation_euler.z += math.radians(90)
68
+
69
+ for plane in bpy.data.groups['Plane'].objects:
70
+ unwrap_model(plane)
71
+
72
+ for obj in WIREFRAMES:
73
+ wireframize(obj)
@@ -1,29 +1,18 @@
1
- import bpy
2
- import argparse
3
- import datetime
4
- import bmesh
5
- import random
6
- import code
7
- import math
8
- import mathutils
9
- import random
10
- import uuid
11
- import sys
12
- import logging
13
- import string
14
- import colorsys
15
- import numpy
16
-
17
- REFLECTOR_SCALE = random.uniform(4, 6)
18
- REFLECTOR_STRENGTH = random.uniform(8, 12)
19
- REFLECTOR_LOCATION_PADDING = random.uniform(10, 12)
20
- WIREFRAME_THICKNESS = random.uniform(0.008, 0.01)
21
- DISPLACEMENT_AMPLITUDE = random.uniform(0.06, 0.08)
22
- REPLACE_TARGET = '6'
23
- REPLACEMENT = '2'
24
- ORIGIN = (0,0,0)
25
- NUMBER_OF_FRAMES = 100
1
+ # DISCLAIMER: all of this could be done in a much more intelligent way (with more Python knowledge)
2
+ # This is just what works for now for the needs of my current project
26
3
 
4
+ REFLECTOR_SCALE = random.uniform(5, 8)
5
+ REFLECTOR_STRENGTH = random.uniform(10, 15)
6
+ REFLECTOR_LOCATION_PADDING = random.uniform(10, 12)
7
+ WIREFRAME_THICKNESS = random.uniform(0.006, 0.02)
8
+ DISPLACEMENT_AMPLITUDE = random.uniform(0.02, 0.1)
9
+ REPLACE_TARGET = str(random.uniform(0, 9))
10
+ REPLACEMENT = str(random.uniform(0, 9))
11
+ ORIGIN = (0,0,2)
12
+ NUMBER_OF_FRAMES = 400
13
+ SCATTER_INTENSITY = 0.015
14
+ ABSORPTION_INTENSITY = 0.25
15
+ DISPLAY_SCALE = (2, 2, 2)
27
16
  PRIMITIVES = ['PYRAMID', 'CUBE']
28
17
  props = []
29
18
  YELLOW = (1, 0.7, 0.1, 1)
@@ -32,39 +21,40 @@ BLUE = (0.1, 0.1, 0.8, 1)
32
21
  PINK = (0.8, 0.2, 0.7, 1.0)
33
22
  WORDS = string.ascii_lowercase
34
23
  WIREFRAMES = []
35
-
36
- context = bpy.context
24
+ VORONOIED = []
37
25
 
38
26
  def debug():
39
27
  code.interact(local=dict(globals(), **locals()))
40
28
  sys.exit("Aborting execution")
41
29
 
42
30
  # Helper methods
43
- def look_at(camera_object, point):
44
- location_camera = camera_object.matrix_world.to_translation()
45
- location_point = point.matrix_world.to_translation()
46
- direction = location_point - location_camera
31
+ def look_at(object):
32
+ location_camera = CAMERA.matrix_world.to_translation()
33
+ location_object = object.matrix_world.to_translation()
34
+ direction = location_object - location_camera
47
35
  rot_quat = direction.to_track_quat('-Z', 'Y')
48
- camera_object.rotation_euler = rot_quat.to_euler()
36
+ CAMERA.rotation_euler = rot_quat.to_euler()
49
37
 
50
38
  def empty_materials():
51
39
  for material in bpy.data.materials.keys():
52
40
  bpy.data.materials.remove(object.data.materials[material])
53
41
 
54
- def shoot(animate, camera, model_object, filepath):
42
+ def shoot(model_object, filepath):
55
43
  directory = os.path.dirname('./renders')
56
44
  if not os.path.exists(directory):
57
45
  os.makedirs(directory)
58
- look_at(camera, model_object)
59
- print('Camera now at location: ' + camera_location_string(camera) + ' / rotation: ' + camera_rotation_string(camera))
46
+ look_at(model_object)
47
+ print('Camera now at location: ' + camera_location_string(CAMERA) + ' / rotation: ' + camera_rotation_string(CAMERA))
60
48
  bpy.context.scene.render.filepath = filepath
61
49
  if animate:
62
- bpy.context.scene.render.filepath = './renders/animation-' + str(uuid.uuid1()) + '/'
63
50
  return bpy.ops.render.render(animation=animate)
64
51
  bpy.ops.render.render(write_still=True)
65
52
 
66
53
  def output_name(index, model_path):
67
- return './renders/' + os.path.splitext(model_path)[0].split('/')[-1] + '_' + str(index) + '_' + str(datetime.date.today()) + '_' + str(mode) + '.png'
54
+ if animate == True:
55
+ return './renders/' + os.path.splitext(model_path)[0].split('/')[-1] + '_' + str(index) + '_' + str(datetime.date.today()) + '_' + str(mode) + '.avi'
56
+ else:
57
+ return './renders/' + os.path.splitext(model_path)[0].split('/')[-1] + '_' + str(index) + '_' + str(datetime.date.today()) + '_' + str(mode) + '.png'
68
58
 
69
59
  def rotate(model_object, index):
70
60
  model_object.rotation_euler[2] = math.radians(index * (360.0 / shots_number))
@@ -80,7 +70,7 @@ def rand_rotation():
80
70
  return (rand_rotation_value(), rand_rotation_value(), rand_rotation_value())
81
71
 
82
72
  def rand_rotation_value():
83
- return round(random.uniform(0, 1), 10)
73
+ return round(math.radians(random.uniform(0, 60), 10))
84
74
 
85
75
  def rand_rotation():
86
76
  return (random.uniform(0, 20), random.uniform(0, 20), random.uniform(0, 20))
@@ -106,20 +96,6 @@ def unwrap_model(obj):
106
96
  bpy.ops.uv.unwrap()
107
97
  bpy.ops.object.mode_set(mode='OBJECT')
108
98
 
109
- def get_args():
110
- parser = argparse.ArgumentParser()
111
- # get all script args
112
- _, all_arguments = parser.parse_known_args()
113
- double_dash_index = all_arguments.index('--')
114
- script_args = all_arguments[double_dash_index + 1: ]
115
- # add parser rules
116
- parser.add_argument('-f', '--file', help="obj file to render")
117
- parser.add_argument('-n', '--shots-number', help="number of shots desired")
118
- parser.add_argument('-m', '--mode', help="quality mode: low | high")
119
- parser.add_argument('-p', '--path', help="root path of assets")
120
- parsed_script_args, _ = parser.parse_known_args(script_args)
121
- return parsed_script_args
122
-
123
99
  def camera_rotation_string(camera):
124
100
  return str(int(camera.rotation_euler.x)) + ' ' + str(int(camera.rotation_euler.y)) + ' ' + str(int(camera.rotation_euler.z))
125
101
 
@@ -161,13 +137,12 @@ def mix_nodes(material, node1, node2):
161
137
  material.node_tree.links.new(mix.inputs[2], node2.outputs[0])
162
138
  assign_node_to_output(material, mix)
163
139
 
164
- def make_object_glossy(obj, color):
140
+ def make_object_glossy(obj, color = (PINK), roughness = 0.2):
165
141
  material = bpy.data.materials.new('Glossy Material - ' + str(uuid.uuid1()))
166
142
  material.use_nodes = True
167
143
  glossy_node = material.node_tree.nodes.new('ShaderNodeBsdfGlossy')
168
144
  glossy_node.inputs[0].default_value = color
169
- # roughness
170
- glossy_node.inputs[1].default_value = 0.2
145
+ glossy_node.inputs[1].default_value = roughness
171
146
  assign_node_to_output(material, glossy_node)
172
147
  assign_material(obj, material)
173
148
 
@@ -175,13 +150,16 @@ def make_object_reflector(obj):
175
150
  obj.scale = (REFLECTOR_SCALE, REFLECTOR_SCALE, REFLECTOR_SCALE)
176
151
  make_object_emitter(obj, REFLECTOR_STRENGTH)
177
152
 
178
- def make_object_transparent(obj, color):
179
- material = bpy.data.materials.new('Transparent Material - ' + str(uuid.uuid1()))
180
- material.use_nodes = True
181
- node = material.node_tree.nodes.new('ShaderNodeBsdfTransparent')
182
- node.inputs[0].default_value = color
183
- assign_node_to_output(material, node)
184
- assign_material(obj, material)
153
+ def make_texture_object_transparent(obj, color = (1,1,1,0.5), intensity = 0.25):
154
+ material = obj.data.materials[-1]
155
+ emission_node = material.node_tree.nodes['Emission']
156
+ trans = material.node_tree.nodes.new('ShaderNodeBsdfTransparent')
157
+ add = material.node_tree.nodes.new('ShaderNodeMixShader')
158
+ material.node_tree.links.new(emission_node.outputs[0], add.inputs[0])
159
+ material.node_tree.links.new(trans.outputs[0], add.inputs[1])
160
+ material.node_tree.links.new(emission_node.outputs[0], add.inputs[0])
161
+ add.inputs[0].default_value = intensity
162
+ trans.inputs[0].default_value = color
185
163
 
186
164
  def make_object_emitter(obj, emission_strength):
187
165
  emissive_material = bpy.data.materials.new('Emissive Material #' + str(uuid.uuid1()))
@@ -209,6 +187,14 @@ def make_object_gradient_fabulous(obj, color1, color2):
209
187
  mixer_node.inputs['Color1'].default_value = color1
210
188
  mixer_node.inputs['Color2'].default_value = color2
211
189
 
190
+ def voronoize(obj, scale = 5.0):
191
+ material = obj.data.materials[-1]
192
+ texture_node = material.node_tree.nodes.new('ShaderNodeTexVoronoi')
193
+ material.node_tree.links.new(texture_node.outputs['Color'], material.node_tree.nodes['Glossy BSDF'].inputs['Color'])
194
+ texture_node.coloring = 'CELLS'
195
+ texture_node.inputs[1].default_value = scale
196
+ VORONOIED.append(obj)
197
+
212
198
  def texture_object(obj):
213
199
  new_material = create_cycles_material()
214
200
  assign_texture_to_material(new_material, random_texture())
@@ -258,8 +244,8 @@ def series(length):
258
244
  return list(map(lambda x: (0, x, math.cos(x)), numpy.arange(0.0, length, 0.1)))
259
245
 
260
246
  def randomize_reflectors_colors():
261
- reflector1.data.materials[-1].node_tree.nodes['Emission'].inputs[0].default_value = rand_color()
262
- reflector2.data.materials[-1].node_tree.nodes['Emission'].inputs[0].default_value = rand_color()
247
+ for r in bpy.data.groups['Plane'].objects:
248
+ r.data.materials[-1].node_tree.nodes['Emission'].inputs[0].default_value = rand_color()
263
249
 
264
250
  def add_object(obj, x, y, z, radius):
265
251
  infer_primitive(obj, location=(x, y, z), radius=radius)
@@ -314,8 +300,8 @@ def displace_vector(vector):
314
300
  return mathutils.Vector((vector.x + random.uniform(-DISPLACEMENT_AMPLITUDE, DISPLACEMENT_AMPLITUDE), vector.y + random.uniform(-DISPLACEMENT_AMPLITUDE, DISPLACEMENT_AMPLITUDE), vector.z + random.uniform(-DISPLACEMENT_AMPLITUDE, DISPLACEMENT_AMPLITUDE)))
315
301
 
316
302
  # Replace vertex coordinate everywhere
317
- def find_and_replace(vector):
318
- return mathutils.Vector((float(str(vector.x).replace(REPLACE_TARGET, REPLACEMENT)), float(str(vector.y).replace(REPLACE_TARGET, REPLACEMENT)), float(str(vector.z).replace(REPLACE_TARGET, REPLACEMENT))))
303
+ def find_and_replace(vector, target = random.uniform(0,9), replacement = random.uniform(0,9)):
304
+ return mathutils.Vector((float(str(vector.x).replace(target, replacement)), float(str(vector.y).replace(target, replacement)), float(str(vector.z).replace(target, replacement))))
319
305
 
320
306
  def glitch(object):
321
307
  bpy.ops.object.mode_set(mode='OBJECT')
@@ -360,7 +346,7 @@ def add_ocean(spatial_size, resolution):
360
346
  wireframize(shadow)
361
347
  shadow.name = 'ocean'
362
348
  ocean.name = 'ocean'
363
- return ocean
349
+ return [ocean, shadow]
364
350
 
365
351
  # Delete current objects
366
352
  def flush_all_objects():
@@ -400,14 +386,31 @@ def build_pyramid(width=random.uniform(1,3), length=random.uniform(1,3), height=
400
386
  faces.append([3,0,4])
401
387
  return create_mesh('Pyramid ' + str(uuid.uuid1()), verts, faces, location)
402
388
 
403
- def dance_routine():
404
- camera_object.location.x = INITIAL_CAMERA_LOCATION[0] + round(random.uniform(-2, 2), 10)
405
- camera_object.location.y = INITIAL_CAMERA_LOCATION[1] + round(random.uniform(-2, 2), 10)
389
+ def move_ocean(ocean):
390
+ ocean.modifiers['Ocean'].time += 1.5
391
+ ocean.modifiers['Ocean'].random_seed = round(random.uniform(0, 100))
392
+ ocean.modifers['Ocean'].choppiness += 0.3
393
+
394
+ def camera_path(pitch):
395
+ res = []
396
+ initial_z = INITIAL_CAMERA_LOCATION[2]
397
+ initial_x = INITIAL_CAMERA_LOCATION[0]
398
+ for y in numpy.arange(initial_x, -initial_x, pitch):
399
+ res.append((initial_x, y, initial_z))
400
+ for x in numpy.arange(initial_x, -initial_x, pitch):
401
+ res.append((x,-initial_x, initial_z))
402
+ for y in numpy.arange(-initial_x, initial_x, pitch):
403
+ res.append((-initial_x, y, initial_z))
404
+ for x in numpy.arange(-initial_x, initial_x, pitch):
405
+ res.append((x, initial_x, initial_z))
406
+ return res
407
+
408
+ def still_routine():
409
+ CAMERA.location.x = INITIAL_CAMERA_LOCATION[0] + round(random.uniform(-2, 2), 10)
410
+ CAMERA.location.y = INITIAL_CAMERA_LOCATION[1] + round(random.uniform(-2, 2), 10)
406
411
  randomize_reflectors_colors()
407
- OCEAN.modifiers['Ocean'].time += 1
408
- OCEAN.modifiers['Ocean'].random_seed = round(random.uniform(0, 100))
409
- make_object_glossy(OCEAN, rand_color())
410
- OCEAN.modifiers['Ocean'].choppiness += 0.3
412
+ map(move_ocean, OCEAN)
413
+ map(make_object_glossy, OCEAN)
411
414
  rotate(model_object, index)
412
415
  for l in bpy.data.groups['Lines'].objects:
413
416
  rotation = rand_rotation()
@@ -416,13 +419,31 @@ def dance_routine():
416
419
  prop.location = rand_location()
417
420
  prop.rotation_euler = rand_rotation()
418
421
  for obj in WIREFRAMES:
419
- rotate(obj, index)
420
- obj.location.z += round(random.uniform(-1, 1), 10)
421
- obj.rotation_euler.z += math.radians(round(random.uniform(0, 90)))
422
+ obj.location = rand_location()
423
+ obj.rotation_euler = rand_rotation()
422
424
  for display in bpy.data.groups['Displays'].objects:
423
425
  display.location = rand_location()
424
426
  rotate(display, index)
425
427
 
428
+ def animation_routine(frame):
429
+ assert len(camera_path) >= NUMBER_OF_FRAMES
430
+ CAMERA.location = camera_path[frame]
431
+ randomize_reflectors_colors()
432
+ map(move_ocean, OCEAN)
433
+ map(make_object_glossy, OCEAN)
434
+ glitch(model_object)
435
+ model_object.rotation_euler.z += math.radians(4)
436
+ for l in bpy.data.groups['Lines'].objects:
437
+ l.rotation_euler.x += math.radians(5)
438
+ l.rotation_euler.z += math.radians(5)
439
+ for prop in props:
440
+ prop.rotation_euler.x += math.radians(5)
441
+ for obj in WIREFRAMES:
442
+ obj.location.z += 0.1
443
+ obj.rotation_euler.z += math.radians(5)
444
+ for display in bpy.data.groups['Displays'].objects:
445
+ display.rotation_euler.x += math.radians(3)
446
+
426
447
  def create_line(name, point_list, thickness = 0.002, location = (0, -10, 0)):
427
448
  # setup basic line data
428
449
  line_data = bpy.data.curves.new(name=name,type='CURVE')
@@ -435,8 +456,30 @@ def create_line(name, point_list, thickness = 0.002, location = (0, -10, 0)):
435
456
  for idx in range(len(point_list)):
436
457
  polyline.points[idx].co = (point_list[idx])+(1.0,)
437
458
  # create an object that uses the linedata
438
- line = bpy.data.objects.new('LineOne', line_data)
459
+ line = bpy.data.objects.new('line' + str(uuid.uuid1()), line_data)
439
460
  bpy.context.scene.objects.link(line)
440
461
  line.location = location
441
462
  make_object_emitter(line, 0.8)
442
463
  return line
464
+
465
+ def add_spotlight(location, intensity, radians):
466
+ bpy.ops.object.lamp_add(type='SPOT', radius=1.0, view_align=False, location=location)
467
+ spot = last_added_object('Spot')
468
+ spot.data.node_tree.nodes['Emission'].inputs[1].default_value = intensity
469
+ spot.data.spot_size = radians
470
+ return spot
471
+
472
+ def make_world_volumetric(world, scatter_intensity = SCATTER_INTENSITY, absorption_intensity = ABSORPTION_INTENSITY):
473
+ assert world.use_nodes == True
474
+ output = world.node_tree.nodes['World Output']
475
+ bg_node = world.node_tree.nodes.new('ShaderNodeBackground')
476
+ absorption_node = world.node_tree.nodes.new('ShaderNodeVolumeAbsorption')
477
+ scatter_node = world.node_tree.nodes.new('ShaderNodeVolumeScatter')
478
+ add_shader = world.node_tree.nodes.new('ShaderNodeAddShader')
479
+ world.node_tree.links.new(add_shader.outputs[0], output.inputs['Volume'])
480
+ world.node_tree.links.new(bg_node.outputs['Background'], output.inputs['Surface'])
481
+ world.node_tree.links.new(scatter_node.outputs[0], add_shader.inputs[0])
482
+ world.node_tree.links.new(absorption_node.outputs[0], add_shader.inputs[1])
483
+ scatter_node.inputs['Density'].default_value = SCATTER_INTENSITY
484
+ absorption_node.inputs['Density'].default_value = ABSORPTION_INTENSITY
485
+ bg_node.inputs[0].default_value = rand_color()
@@ -0,0 +1,32 @@
1
+ def let_there_be_light(scene):
2
+ add_spotlight((0, 0, 12), 14000, math.radians(60))
3
+ spot1 = add_spotlight((0, 8, 4), 8000, math.radians(60))
4
+ spot2 = add_spotlight((0, -8, 4), 8000, math.radians(60))
5
+ spot1.rotation_euler.x -= math.radians(90)
6
+ spot2.rotation_euler.x += math.radians(90)
7
+
8
+ bpy.ops.mesh.primitive_plane_add(location=(0,8 + REFLECTOR_LOCATION_PADDING, 0))
9
+ bpy.ops.mesh.primitive_plane_add(location=(8 + REFLECTOR_LOCATION_PADDING,0,0))
10
+ bpy.ops.mesh.primitive_plane_add(location=(0, 0, 30))
11
+
12
+ reflector1 = bpy.data.objects['Plane']
13
+ reflector2 = bpy.data.objects['Plane.001']
14
+ reflector3 = bpy.data.objects['Plane.002']
15
+
16
+ bpy.data.groups.new('Plane')
17
+ bpy.data.groups['Plane'].objects.link(reflector1)
18
+ bpy.data.groups['Plane'].objects.link(reflector2)
19
+ bpy.data.groups['Plane'].objects.link(reflector3)
20
+
21
+ reflector2.rotation_euler.x += math.radians(90)
22
+ reflector1.rotation_euler.x += math.radians(90)
23
+ reflector2.rotation_euler.z += math.radians(90)
24
+
25
+ make_object_reflector(reflector1)
26
+ make_object_reflector(reflector2)
27
+ make_object_reflector(reflector3)
28
+
29
+ world = bpy.data.worlds.new('A Brave New World')
30
+ world.use_nodes = True
31
+ make_world_volumetric(world)
32
+ scene.world = world
@@ -0,0 +1,135 @@
1
+ # Rendering script
2
+ # Run by calling the blender executable with -b -P <script_name>
3
+ # Use `debug()` to pry into the script
4
+
5
+ import argparse
6
+
7
+ DEBUG=False
8
+
9
+ def get_args():
10
+ parser = argparse.ArgumentParser()
11
+ # get all script args
12
+ _, all_arguments = parser.parse_known_args()
13
+ double_dash_index = all_arguments.index('--')
14
+ script_args = all_arguments[double_dash_index + 1: ]
15
+ # add parser rules
16
+ parser.add_argument('-f', '--file', help="obj file to render")
17
+ parser.add_argument('-n', '--shots-number', help="number of shots desired")
18
+ parser.add_argument('-m', '--mode', help="quality mode: low | high")
19
+ parser.add_argument('-p', '--path', help="root path of assets")
20
+ parser.add_argument('-a', '--animate', help="render animation") # bool
21
+ parsed_script_args, _ = parser.parse_known_args(script_args)
22
+ return parsed_script_args
23
+
24
+ args = get_args()
25
+ file = args.file
26
+ mode = args.mode
27
+ path = str(args.path)
28
+ animate = (args.animate == 'True')
29
+ shots_number = int(args.shots_number)
30
+
31
+ import os
32
+ import bpy
33
+ import datetime
34
+ import bmesh
35
+ import random
36
+ import math
37
+ import mathutils
38
+ import random
39
+ import uuid
40
+ import sys
41
+ import logging
42
+ import string
43
+ import colorsys
44
+ import numpy
45
+ import code
46
+
47
+ # DEBUG = True
48
+ if DEBUG:
49
+ shots_number = 2
50
+ import os
51
+ mode = 'low'
52
+ animate = False
53
+ file = "/Users/pascal/dev/glitch3d/fixtures/skull.obj"
54
+ path = "/Users/pascal/dev/glitch3d/lib/"
55
+
56
+ exec(open(os.path.join(path + '/glitch3d/bpy', 'helpers.py')).read())
57
+ exec(open(os.path.join(path + '/glitch3d/bpy', 'render_settings.py')).read())
58
+ exec(open(os.path.join(path + '/glitch3d/bpy', 'lighting.py')).read())
59
+
60
+ DEBUG = False
61
+ FISHEYE = True
62
+ COLORS = rand_color_palette(5)
63
+ INITIAL_CAMERA_LOCATION = (4, 4, 1)
64
+ FIXTURES_FOLDER_PATH = path + '/../fixtures/'
65
+ TEXTURE_FOLDER_PATH = FIXTURES_FOLDER_PATH + 'textures/'
66
+
67
+ # Scene
68
+ context = bpy.context
69
+ new_scene = bpy.data.scenes.new("Automated Render Scene")
70
+ bpy.ops.scene.delete() # Delete old scene
71
+ context.screen.scene = new_scene # selects the new scene as the current one
72
+
73
+ flush_all_objects()
74
+
75
+ camera_data = bpy.data.cameras['Camera']
76
+ bpy.data.objects.new('Camera', object_data=camera_data)
77
+ CAMERA = bpy.data.objects['Camera']
78
+ new_scene.objects.link(CAMERA)
79
+ context.scene.camera = CAMERA
80
+ CAMERA.location = INITIAL_CAMERA_LOCATION
81
+
82
+ if FISHEYE:
83
+ CAMERA.data.type = 'PANO'
84
+ CAMERA.data.cycles.panorama_type = 'FISHEYE_EQUISOLID'
85
+ CAMERA.data.cycles.fisheye_lens = 12
86
+ CAMERA.data.cycles.fisheye_fov = 2.5
87
+ CAMERA.data.sensor_width = 20
88
+ CAMERA.data.sensor_height = 20
89
+
90
+ render_settings(context.scene, animate, mode)
91
+
92
+ # Initialize groups
93
+ for primitive in PRIMITIVES:
94
+ bpy.data.groups.new(primitive.lower().title())
95
+
96
+ # Load model
97
+ model_path = os.path.join(file)
98
+ bpy.ops.import_scene.obj(filepath = model_path, use_edges=True)
99
+ model_object = bpy.data.objects[1]
100
+ model_object.select = True
101
+ bpy.ops.object.origin_set(type="ORIGIN_CENTER_OF_MASS")
102
+ model_object.location = ORIGIN
103
+ make_object_glossy(model_object, YELLOW, 0.1)
104
+ voronoize(model_object)
105
+
106
+ let_there_be_light(context.scene)
107
+
108
+ exec(open(os.path.join(path + '/glitch3d/bpy/canvas', 'dreamatorium.py')).read())
109
+
110
+ print('Rendering images with resolution: ' + str(context.scene.render.resolution_x) + ' x ' + str(context.scene.render.resolution_y))
111
+
112
+ if animate:
113
+ print('ANIMATION RENDERING BEGIN')
114
+ context.scene.frame_start = 0
115
+ context.scene.frame_end = NUMBER_OF_FRAMES
116
+ bpy.ops.screen.frame_jump(end=False)
117
+ camera_path = camera_path(0.08)
118
+
119
+ for frame in range(0, NUMBER_OF_FRAMES):
120
+ bpy.context.scene.frame_set(frame)
121
+ animation_routine(frame - 1)
122
+ for ob in context.scene.objects:
123
+ ob.keyframe_insert(data_path="location", index=-1)
124
+ bpy.ops.screen.frame_jump(end=False)
125
+ shoot(model_object, output_name(index, model_path))
126
+
127
+ else:
128
+ print('STILL RENDERING BEGIN')
129
+ for index in range(0, int(shots_number)):
130
+ print("-------------------------- " + str(index) + " --------------------------")
131
+ still_routine()
132
+ shoot(model_object, output_name(index, model_path))
133
+
134
+
135
+ print('FINISHED ¯\_(ツ)_/¯')
@@ -0,0 +1,26 @@
1
+ def render_settings(scene, animate, mode):
2
+ scene.render.resolution_x = 2000
3
+ scene.render.resolution_y = 2000
4
+ scene.render.engine = 'CYCLES'
5
+ scene.render.resolution_percentage = 25
6
+
7
+ # bpy.scene.cycles.device = 'GPU'
8
+ scene.render.image_settings.compression = 0
9
+ scene.cycles.samples = 25
10
+ scene.cycles.max_bounces = 1
11
+ scene.cycles.min_bounces = 1
12
+ scene.cycles.caustics_reflective = False
13
+ scene.cycles.caustics_refractive = False
14
+ scene.render.tile_x = 32
15
+ scene.render.tile_y = 32
16
+ scene.render.image_settings.color_mode ='RGBA'
17
+
18
+ if animate:
19
+ scene.render.image_settings.file_format='H264'
20
+ else:
21
+ scene.render.image_settings.file_format='PNG'
22
+
23
+ if mode == 'high':
24
+ scene.render.image_settings.compression = 90
25
+ scene.cycles.samples = 400
26
+ scene.render.resolution_percentage = 100
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Glitch3d
3
- VERSION = '0.2.2.3'
3
+ VERSION = '0.2.2.5'
4
4
  end
data/lib/glitch3d.rb CHANGED
@@ -15,7 +15,7 @@ module Glitch3d
15
15
  CHUNK_SIZE=20
16
16
 
17
17
  BLENDER_EXECUTABLE_PATH = ENV['BLENDER_EXECUTABLE_PATH'].freeze
18
- RENDERING_SCRIPT_PATH = File.dirname(__FILE__) + '/glitch3d/bpy/rendering.py'
18
+ RENDERING_SCRIPT_PATH = File.dirname(__FILE__) + '/glitch3d/bpy/main.py'
19
19
 
20
20
  def clean_model(source_file)
21
21
  self.class.include Glitch3d::None
@@ -28,7 +28,7 @@ module Glitch3d
28
28
  # @param String source_file, 3d model file to take as input
29
29
  # @param Hash args, parameters { 'stuff' => 'shit' }
30
30
  def process_model(source_file, args = nil)
31
- source_file = File.dirname(__FILE__) + '/../fixtures/cube.obj' if source_file.nil?
31
+ source_file = random_fixture if source_file.nil?
32
32
  args = Hash[ARGV.join(' ').scan(/--?([^=\s]+)(?:=(\S+))?/)] if args.nil?
33
33
  return clean_model(source_file) if args['clean']
34
34
 
@@ -37,6 +37,12 @@ module Glitch3d
37
37
  return nil
38
38
  end
39
39
 
40
+ if args.has_key?('animate')
41
+ args['animate'] = 'true'
42
+ else
43
+ args['animate'] = 'false'
44
+ end
45
+
40
46
  raise 'Set Blender executable path in your env variables before using glitch3d' if BLENDER_EXECUTABLE_PATH.nil?
41
47
  self.class.include infer_strategy(args['mode'] || 'default')
42
48
  @quality = args['quality'] || 'low'
@@ -45,7 +51,17 @@ module Glitch3d
45
51
  model_name = File.basename(source_file, '.obj')
46
52
  target_file = base_file_name + '_glitched.obj'
47
53
  create_glitched_file(glitch(read_source(source_file)), target_file, model_name)
48
- render(target_file, args['shots-number'] || 6) unless args['no-render']
54
+ render(args, target_file, args['shots-number'] || 6) unless args['no-render']
55
+ end
56
+
57
+ def random_fixture
58
+ @fixtures_path = File.dirname(__FILE__) + '/../fixtures'
59
+ fixtures = []
60
+ Dir.foreach(@fixtures_path) do |item|
61
+ next if item == '.' or item == '..' or item.end_with?('_glitched.obj') or !item.end_with?('.obj')
62
+ fixtures << @fixtures_path + '/' + item
63
+ end
64
+ fixtures.sample
49
65
  end
50
66
 
51
67
  def infer_strategy(mode)
@@ -135,7 +151,8 @@ module Glitch3d
135
151
  boundaries.flatten.map(&:abs).max.abs > BOUNDARY_LIMIT
136
152
  end
137
153
 
138
- def render(file_path, shots_number)
154
+ def render(initial_args, file_path, shots_number)
155
+ raise 'Animation arg not boolean' unless eval(initial_args['animate']).is_a?(FalseClass) || eval(initial_args['animate']).is_a?(TrueClass)
139
156
  args = [
140
157
  BLENDER_EXECUTABLE_PATH,
141
158
  '-b',
@@ -149,7 +166,9 @@ module Glitch3d
149
166
  '-m',
150
167
  @quality,
151
168
  '-p',
152
- File.dirname(__FILE__).to_s
169
+ File.dirname(__FILE__).to_s,
170
+ '-a',
171
+ initial_args['animate'].capitalize
153
172
  ]
154
173
  raise 'Make sure Blender is correctly installed' unless system(*args)
155
174
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glitch3d
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2.3
4
+ version: 0.2.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - pskl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-29 00:00:00.000000000 Z
11
+ date: 2017-10-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -88,7 +88,7 @@ files:
88
88
  - bin/setup
89
89
  - fixtures/brain.obj
90
90
  - fixtures/cube.obj
91
- - fixtures/demo.png
91
+ - fixtures/dude.jpg
92
92
  - fixtures/face.obj
93
93
  - fixtures/m4a1.obj
94
94
  - fixtures/male_head.obj
@@ -106,8 +106,11 @@ files:
106
106
  - fixtures/textures/vapor.jpg
107
107
  - glitch3d.gemspec
108
108
  - lib/glitch3d.rb
109
+ - lib/glitch3d/bpy/canvas/dreamatorium.py
109
110
  - lib/glitch3d/bpy/helpers.py
110
- - lib/glitch3d/bpy/rendering.py
111
+ - lib/glitch3d/bpy/lighting.py
112
+ - lib/glitch3d/bpy/main.py
113
+ - lib/glitch3d/bpy/render_settings.py
111
114
  - lib/glitch3d/objects/face.rb
112
115
  - lib/glitch3d/objects/vertex.rb
113
116
  - lib/glitch3d/strategies/default.rb
data/fixtures/demo.png DELETED
Binary file
@@ -1,236 +0,0 @@
1
- # Rendering script
2
- # Run by calling the blender executable with -b -P <script_name>
3
- # Disclaimer: I never did Python before so this is mostly hacks
4
- #
5
- # process:
6
- # 1) Load model given as a parameter
7
- # 2) Create emitting surfaces to act as lamps
8
- # 3) Create camera
9
- # 4) Rotate model and shoot image at each step
10
- #
11
- # Use `debug()` to pry into the script
12
- import os
13
- exec(open(os.path.join(os.path.dirname(__file__), 'helpers.py')).read())
14
-
15
- # Arguments parsing
16
- args = get_args()
17
- file = args.file
18
- mode = args.mode
19
- path = str(args.path)
20
- shots_number = int(args.shots_number)
21
-
22
- FIXTURES_FOLDER_PATH = path + '/../fixtures/'
23
-
24
- DEBUG = False
25
- FISHEYE = True
26
- COLORS = rand_color_palette(5)
27
- INITIAL_CAMERA_LOCATION = (4, 4, 1)
28
- ANIMATE = False
29
-
30
- # DEBUG = True
31
- if DEBUG:
32
- shots_number = 2
33
- import os
34
- mode = 'low'
35
- file = "/Users/pascal/dev/glitch3d/fixtures/skull.obj"
36
- FIXTURES_FOLDER_PATH = "/Users/pascal/dev/glitch3d/fixtures/"
37
-
38
- TEXTURE_FOLDER_PATH = FIXTURES_FOLDER_PATH + 'textures/'
39
-
40
- # Scene
41
- new_scene = bpy.data.scenes.new("Automated Render Scene")
42
- bpy.ops.scene.delete() # Delete old scene
43
- context.screen.scene = new_scene # selects the new scene as the current one
44
-
45
- # Initialize groups
46
- for primitive in PRIMITIVES:
47
- bpy.data.groups.new(primitive.lower().title())
48
-
49
- # Render settings
50
- context.scene.render.resolution_x = 2000
51
- context.scene.render.resolution_y = 2000
52
- context.scene.render.engine = 'CYCLES'
53
- context.scene.render.resolution_percentage = 25
54
- # uncomment if GPU
55
- # bpy.context.scene.cycles.device = 'GPU'
56
- context.scene.render.image_settings.compression = 0
57
- context.scene.cycles.samples = 25
58
- context.scene.render.image_settings.color_mode ='RGBA'
59
- context.scene.render.image_settings.file_format='PNG'
60
-
61
- if mode == 'high':
62
- context.scene.render.image_settings.compression = 90
63
- context.scene.cycles.samples = 400
64
- context.scene.render.resolution_percentage = 100
65
-
66
- # Add background to world
67
-
68
- # This shit doesnt work in v 2.76
69
- # bpy.data.worlds.remove(bpy.data.worlds[0])
70
- world = bpy.data.worlds.new('A Brave New World')
71
- world.use_nodes = True
72
- world_node_tree = world.node_tree
73
- context.scene.world = world
74
-
75
- # Clean slate
76
- flush_all_objects()
77
-
78
- # Load model
79
- model_path = os.path.join(file)
80
-
81
- bpy.ops.import_scene.obj(filepath = model_path, use_edges=True)
82
- model_object = bpy.data.objects[0]
83
-
84
- # Load props
85
- bpy.ops.import_scene.obj(filepath = os.path.join(FIXTURES_FOLDER_PATH + 'm4a1.obj'), use_edges=True)
86
- m4a1 = bpy.data.objects['m4a1']
87
- m4a1.location = rand_location()
88
- m4a1.scale = (0.5, 0.5, 0.5)
89
- props.append(m4a1)
90
-
91
- # Use center of mass to center object
92
- model_object.select = True
93
- bpy.ops.object.origin_set(type="ORIGIN_CENTER_OF_MASS")
94
- model_object.location = ORIGIN
95
- make_object_glossy(model_object, YELLOW)
96
-
97
- # Add props
98
- rand_primitive = random.choice(PRIMITIVES)
99
- build_composite_object(rand_primitive, 4, 1)
100
-
101
- # --------------
102
- # Create camera
103
- # --------------
104
- camera_data = bpy.data.cameras.new('Camera')
105
- bpy.data.objects.new('Camera', object_data=camera_data)
106
- camera_object = bpy.data.objects['Camera']
107
- new_scene.objects.link(camera_object)
108
- camera_object.location = INITIAL_CAMERA_LOCATION
109
-
110
- if FISHEYE:
111
- camera_object.data.type = 'PANO'
112
- camera_object.data.cycles.panorama_type = 'FISHEYE_EQUISOLID'
113
- camera_object.data.cycles.fisheye_lens = 12
114
- camera_object.data.cycles.fisheye_fov = 2.5
115
- camera_object.data.sensor_width = 20
116
- camera_object.data.sensor_height = 20
117
-
118
- # Add reflectors
119
- bpy.ops.mesh.primitive_plane_add(location=(0,8 + REFLECTOR_LOCATION_PADDING, 0))
120
- bpy.ops.mesh.primitive_plane_add(location=(8 + REFLECTOR_LOCATION_PADDING,0,0))
121
- bpy.ops.mesh.primitive_plane_add(location=(0, 0, 20))
122
- bpy.ops.mesh.primitive_plane_add(location=(0, 0, -2))
123
-
124
- reflector1 = bpy.data.objects['Plane']
125
- reflector2 = bpy.data.objects['Plane.001']
126
- reflector3 = bpy.data.objects['Plane.002']
127
-
128
- bpy.data.groups.new('Plane')
129
- bpy.data.groups['Plane'].objects.link(reflector1)
130
- bpy.data.groups['Plane'].objects.link(reflector2)
131
- bpy.data.groups['Plane'].objects.link(reflector3)
132
-
133
- reflector2.rotation_euler.x += math.radians(90)
134
- reflector1.rotation_euler.x += math.radians(90)
135
- reflector2.rotation_euler.z += math.radians(90)
136
-
137
- make_object_reflector(reflector1)
138
- make_object_reflector(reflector2)
139
- make_object_reflector(reflector3)
140
-
141
- # Set up virtual displays
142
- bpy.ops.mesh.primitive_grid_add(x_subdivisions=100, y_subdivisions=100, location=(0, 6, 2))
143
- display1 = bpy.data.objects['Grid']
144
- bpy.ops.mesh.primitive_grid_add(x_subdivisions=100, y_subdivisions=100, location=(6, 0, 2))
145
- display2 = bpy.data.objects['Grid.001']
146
-
147
- bpy.data.groups.new('Displays')
148
- bpy.data.groups['Displays'].objects.link(display1)
149
- bpy.data.groups['Displays'].objects.link(display2)
150
-
151
- display1.rotation_euler.x += math.radians(90)
152
- display1.rotation_euler.z -= math.radians(90)
153
- display2.rotation_euler.x += math.radians(90)
154
- display2.rotation_euler.y += math.radians(90)
155
- display2.rotation_euler.z += math.radians(120)
156
-
157
- for display in bpy.data.groups['Displays'].objects:
158
- display.rotation_euler.x += math.radians(90)
159
- display.scale = (3,3,3)
160
- texture_object(display)
161
- unwrap_model(display)
162
- glitch(display)
163
-
164
- glitch(m4a1)
165
- make_object_gradient_fabulous(m4a1, rand_color(), rand_color())
166
-
167
- # Adjust camera
168
- context.scene.camera = camera_object
169
- look_at(camera_object, model_object)
170
-
171
- # Make floor
172
- floor = bpy.data.objects['Plane.003']
173
- bpy.data.groups['Plane'].objects.link(floor)
174
- floor.scale = (20,20,20)
175
- subdivide(floor, 8)
176
- displace(floor)
177
- texture_object(floor)
178
-
179
- OCEAN = add_ocean(10, 20)
180
-
181
- # Create lines
182
- bpy.data.groups.new('Lines')
183
- for i in range(0, 20):
184
- new_line = create_line('line' + str(uuid.uuid1()), series(30))
185
- new_line.location.z += i / 6
186
-
187
- for index in range(1, len(WORDS)):
188
- new_object = spawn_text()
189
- props.append(new_object)
190
- text_scale = random.uniform(0.75, 2)
191
- make_object_glossy(new_object, GREY)
192
- new_object.scale = (text_scale, text_scale, text_scale)
193
- new_object.location = rand_location()
194
- # pivot text to make it readable by camera
195
- new_object.rotation_euler.x += math.radians(90)
196
- new_object.rotation_euler.z += math.radians(90)
197
-
198
- for plane in bpy.data.groups['Plane'].objects:
199
- unwrap_model(plane)
200
-
201
- for obj in WIREFRAMES:
202
- wireframize(obj)
203
-
204
- look_at(camera_object, model_object)
205
- model_object.location.z += 2
206
-
207
- # ------
208
- # Shoot
209
- # ------
210
- print('Rendering images with resolution: ' + str(context.scene.render.resolution_x) + ' x ' + str(context.scene.render.resolution_y))
211
-
212
- if ANIMATE:
213
- print('ANIMATION RENDERING BEGIN')
214
- context.scene.frame_start = 0
215
- context.scene.frame_end = NUMBER_OF_FRAMES
216
- bpy.ops.screen.frame_jump(end=False)
217
-
218
- for frame in range(1, NUMBER_OF_FRAMES):
219
- bpy.context.scene.frame_set(frame)
220
-
221
- dance_routine()
222
-
223
- for ob in context.scene.objects:
224
- ob.keyframe_insert(data_path="location", index=-1)
225
-
226
- bpy.ops.screen.frame_jump(end=False)
227
- shoot(True, camera_object, model_object, output_name(index, model_path))
228
- else:
229
- print('STILL RENDERING BEGIN')
230
- for index in range(0, int(shots_number)):
231
- print("-------------------------- " + str(index) + " --------------------------")
232
- shoot(False, camera_object, model_object, output_name(index, model_path))
233
- dance_routine()
234
-
235
-
236
- print('FINISHED ¯\_(ツ)_/¯')