[node] Adding color particle changes and a lot of comments

Many minor bug fixes and added the possibility to change the particle color of the rendering to let the user chose the clearest color in their case. Commented a lot of my code to make it readable to someone else that myself.
This commit is contained in:
Solal Depardieu 2021-05-21 21:36:46 +02:00 committed by Fabien Castan
parent 5701f8f578
commit 1e2aaff884

View file

@ -95,9 +95,6 @@ def main():
parser.print_help()
return
print(args.SFM_cam_path)
#Clear Current Scene
try:
for objects in bpy.data.objects:
@ -111,15 +108,21 @@ def main():
#Some of these info will be very useful in the next steps keep them in mind
number_of_frame = 0
offset = 0
image_name = ""
first_image_name = ""
try:
# In this part of the code we take the undistorted images and we process some info about them
# undis_imgs is the list of the images' names
# first_image_name says it all in the name
# The offset is important, it corresponds to the last part of the name of the first frame
# In most case it will hopefully be 0 but the sequence may start from another frame
files = os.listdir(args.undisto_images)
for f in files :
if f.endswith(".exr") and not f.__contains__("UVMap"):
undis_imgs.append({"name":f})
number_of_frame = len(undis_imgs)
image_name = undis_imgs[0]['name']
offset = int(re.search("_(.*).exr", image_name).group(1)[3:]) - 1
first_image_name = undis_imgs[0]['name']
offset = int(re.findall(r'\d+', first_image_name)[-1]) - 1
except:
print("Error: while importing the undistorted images.")
@ -127,9 +130,23 @@ def main():
#import abc (Animated Camera)
try:
# In this part of the code we import the alembic in the cam_path to get the animated camera
# We use cam_location and cam_obj to store information about this camera
# We look for a camera (of type 'Persp') with the name 'anim' (not to confuse them with previously imported cams)
# Such hard code is not a problem in this case because all imported cams come from previous nodes and are named specificaly
# Once the cam has been found we select is make it the main camera of the scene
# The rest of the code is setting up the display of the background image,
# Since it's not a simple image but an image Sequence, we have to use the offset and the number of frame
# Information taken from the previous block of code.
# The frame method is the one that align with the Cloud of Point althought this may change
# so feel free to try out the two other settings if something changes on previous nodes.
# We also have to make the scene render film transparent because we want to be able to display
# our background afterward in the next block of code
bpy.ops.wm.alembic_import(filepath=args.SFM_cam_path)
animated_cams = bpy.context.selected_editable_objects[:]
cam_scale = mathutils.Vector((0, 0, 0))
cam_location = mathutils.Vector((0, 0, 0))
cam_obj = None
for obj in animated_cams:
@ -137,13 +154,12 @@ def main():
bpy.context.scene.collection.objects.link(obj)
bpy.context.view_layer.objects.active = obj
bpy.context.scene.camera = obj
cam_scale = obj.scale
cam_location = obj.location
cam_obj = obj
bpy.ops.image.open(filepath=args.undisto_images + "/" + image_name, directory=args.undisto_images, files=undis_imgs, relative_path=True, show_multiview=False)
bpy.ops.image.open(filepath=args.undisto_images + "/" + first_image_name, directory=args.undisto_images, files=undis_imgs, relative_path=True, show_multiview=False)
bpy.data.cameras[obj.data.name].background_images.new()
bpy.data.cameras[obj.data.name].show_background_images = True
bpy.data.cameras[obj.data.name].background_images[0].image = bpy.data.images[image_name]
bpy.data.cameras[obj.data.name].background_images[0].image = bpy.data.images[first_image_name]
bpy.data.cameras[obj.data.name].background_images[0].frame_method = 'CROP'
bpy.data.cameras[obj.data.name].background_images[0].image_user.frame_offset = offset
bpy.data.cameras[obj.data.name].background_images[0].image_user.frame_duration = number_of_frame
@ -154,6 +170,23 @@ def main():
#Place the particle plane
try:
# This is a key step if you are displaying a cloud point.
# We are using a particle system later in the code to display the cloud point.
# To make it so, we need a model for the particle, a object that will be repeated a lot to make a shape.
# In order to do that we need a plane (one face only for optimisation purpose) that always face the camera.
# So we made a plane and made it a child (in the parenting system) of the camera. That way whenever the cam
# moves, the plane moves and turn accordingly.
# Bmesh creates the plane and put it into the mesh. We change the size of the plane according to
# the scale given in arguments. We need to adjust the plane's location because putting it at the
# exact location of the camera blocks the view. Then, the switcher give a RGBA color according to
# the given argument... This is where it gets harder. We have to use a material that uses 'Emission'
# otherwise the particle is going to react to lights and we don't really need that (the color wouldn't be clear).
# To do that we have to use the shader 'node_tree' we clear all links between nodes, create the emission node
# and connects it to the 'Material Output' node (which is what we will see in render).
# Finally we use the switcher to color the model.
plane = bpy.data.meshes.new('Plane')
objectsPlane = bpy.data.objects.new(name="Plane", object_data=plane)
bm = bmesh.new()
@ -165,36 +198,74 @@ def main():
objectsPlane.location = cam_location
bpy.context.scene.collection.objects.link(objectsPlane)
bpy.data.objects['Plane'].parent = cam_obj
bpy.context.view_layer.objects.active = objectsPlane
switcher={
'Grey':(0.2, 0.2, 0.2, 1),
'White':(1, 1, 1, 1),
'Red':(0.5, 0, 0, 1),
'Green':(0, 0.5, 0, 1),
'Magenta':(1.0, 0, 0.75, 1)
}
col = bpy.data.materials.new('Color')
objectsPlane.active_material = col
objectsPlane.active_material.use_nodes = True
objectsPlane.active_material.node_tree.links.clear()
objectsPlane.active_material.node_tree.nodes.new(type='ShaderNodeEmission')
objectsPlane.active_material.node_tree.links.new(objectsPlane.active_material.node_tree.nodes['Emission'].outputs['Emission'], objectsPlane.active_material.node_tree.nodes['Material Output'].inputs['Surface'])
objectsPlane.active_material.node_tree.nodes['Emission'].inputs[0].default_value = switcher.get(args.Particle_Color, 'Invalid Color')
except:
print("Error: while setting up the particle model.")
#import abc (Cloud Point)
if (args.SFM_Data.endswith('.abc')):
# This part is all about importing the Cloud Point and setting up the Particle System to make a good render
# After importing the alembic we look for a specific meshe in the file. Again the hard coded name would be a
# problem if the previous nodes hadn't name it specificaly that (.001 because a meshe with the same name has
# been imported with the animated camera).
try:
bpy.ops.wm.alembic_import(filepath=args.SFM_Data)
all_abc_info = bpy.context.selected_editable_objects[:]
for obj in all_abc_info:
if obj.name == 'mvgPointCloud.001':
bpy.context.scene.collection.objects.link(obj)
bpy.context.view_layer.objects.active = obj
obj.modifiers.new("ParticleSystem", "PARTICLE_SYSTEM")
particle_system = bpy.data.particles["ParticleSystem"]
particle_system.render_type = 'OBJECT'
particle_system.instance_object = bpy.data.objects["Plane"]
particle_system.emit_from = 'VERT'
# Once the cloud point has been found. We make it the active object (important for the node_tree later).
# Then, we create a particle system on it. Render_type set to object and the said object is the plane,
# thanks to that the particle format is set to repeat the plane. Emit_from 'vert' so the points of the
# cloud of point are the one rendering the particle.
# The count is the number of particle repeated on the cloud of point. We use the rate given as arguments
# to give a number. Most of the following settings are just formalities except use_rotation and use_rotation_instance
# those two make sure to use the same roation as the model which is vital to have the particle always facing the camera.
#import abc (Cloud Point)
try:
bpy.ops.wm.alembic_import(filepath=args.SFM_Data)
all_abc_info = bpy.context.selected_editable_objects[:]
for obj in all_abc_info:
if obj.name == 'mvgPointCloud.001': #May have a problem with such hard code
bpy.context.scene.collection.objects.link(obj)
bpy.context.view_layer.objects.active = obj
obj.modifiers.new("ParticleSystem", "PARTICLE_SYSTEM")
particle_system = bpy.data.particles["ParticleSystem"]
particle_system.render_type = 'OBJECT'
particle_system.instance_object = bpy.data.objects["Plane"]
particle_system.emit_from = 'VERT'
particle_system.count = int(args.Cloud_Point_Density * len(obj.data.vertices.values()))
particle_system.frame_end = 1.0
particle_system.use_emit_random = False
particle_system.particle_size = 0.02
particle_system.physics_type = 'NO'
particle_system.use_rotations = True
particle_system.use_rotation_instance = True
particle_system.rotation_mode = 'GLOB_X'
except:
print("Error: while importing the alembic file (Cloud Point).")
#Or import obj directly
elif (args.SFM_Data.endswith('.obj')):
bpy.ops.import_scene.obj(filepath=args.SFM_Data)
else:
print("SFM_Data isn't in the right format, alembics(.abc) and object(.obj) only are supported")
particle_system.count = int(args.Cloud_Point_Density * len(obj.data.vertices.values()))
particle_system.frame_end = 1.0
particle_system.use_emit_random = False
particle_system.particle_size = 0.02
particle_system.physics_type = 'NO'
particle_system.use_rotations = True
particle_system.use_rotation_instance = True
particle_system.rotation_mode = 'GLOB_X'
except:
print("Error: while importing the alembic file (Cloud Point).")
#WE HAVE TO USE THE GRAPH TO MAKE THE BACKGROUND IMAGE VISIBLE
@ -211,7 +282,7 @@ def main():
bpy.data.scenes["Scene"].node_tree.nodes["Image"].frame_offset = offset
bpy.data.scenes["Scene"].node_tree.nodes["Scale"].space = 'RENDER_SIZE'
bpy.data.scenes["Scene"].node_tree.nodes["Scale"].frame_method = 'CROP'
bpy.context.scene.node_tree.nodes["Image"].image = bpy.data.images[image_name]
bpy.context.scene.node_tree.nodes["Image"].image = bpy.data.images[first_image_name]
#LINKS THE NODES THAT NEEDS TO BE LINKED
bpy.context.scene.node_tree.links.new(bpy.context.scene.node_tree.nodes['Alpha Over'].outputs['Image'], bpy.context.scene.node_tree.nodes['Composite'].inputs['Image'])
@ -225,9 +296,12 @@ def main():
## Starts the rendering and launchs it with a blender animator player
try:
# Setup the render format and filepath
bpy.context.scene.render.image_settings.file_format = 'FFMPEG'
bpy.context.scene.render.filepath = args.output_path + '/render.mkv'
# Render everything on to the filepath
bpy.ops.render.render(animation=True)
# Starts a player automatically to play the output
bpy.ops.render.play_rendered_anim()
except:
print("Error: while rendering the scene.")