Outils pour utilisateurs

Outils du site


blender

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
blender [2017/10/18 17:34]
jcombier
blender [2017/12/15 15:50] (Version actuelle)
jcombier
Ligne 121: Ligne 121:
  
 =====Rendu depuis un script python==== =====Rendu depuis un script python====
 +Les commandes pythons correspondantes aux actions en cours dans la GUI sont affichées dans la console python intégrée: https://www.youtube.com/watch?v=K0yb4sZ7B4g
 +
 +
 +https://wiki.blender.org/index.php/Doc:FR/2.4/Manual/Extensions/Python/Example
 +
 +Exemple de rendu avec caméra fisheye: https://blender.stackexchange.com/questions/32848/script-for-rendering-a-simple-scene
 +====Execution d'un script====
 +
 Utiliser l’interpréteur python intégré à blender depuis la ligne de commande Utiliser l’interpréteur python intégré à blender depuis la ligne de commande
  
Ligne 188: Ligne 196:
   ./blender   ./blender
      
-Utiliser l'option -b pour désactiver le rendu openGL. Par exemple pour éxecuter un script python:+Utiliser l'option -b pour désactiver le rendu openGL. Par exemple pour exécuter un script python:
    ./blender --python test.py -b    ./blender --python test.py -b
 Pour lancer le rendu à distance:    Pour lancer le rendu à distance:   
Ligne 194: Ligne 202:
 Copier la clef publique rsa pour ne pas avoir à saisir le mot de passe à chaque connexion Copier la clef publique rsa pour ne pas avoir à saisir le mot de passe à chaque connexion
  
 +==== Blender et le ray-tracing ====
 +Blender a deux modes de rendu possible : le mode par défaut "blender render" et le mode ray-tracing nommé "cycles". Les documentations associées sont :
 +  * Blender Render : [[https://docs.blender.org/manual/en/dev/render/blender_render/index.html]]
 +  * Cycles : [[https://docs.blender.org/manual/en/dev/render/cycles/index.html]]
  
-==== script python détaillé ====+Lien fournissant une comparaison entre les deux moteurs de rendu : 
 + 
 +[[https://blender.stackexchange.com/questions/5820/how-is-cycles-different-from-blender-internal]] 
 +   
 +Notions à connaître : ray-tracing et anti-aliasing (cours) : 
 + 
 +[[https://www.cs.cmu.edu/afs/cs/academic/class/15462-s09/www/lec/13/lec13.pdf]] 
 +   
 +Ray-tracing (et anti-aliasing) du moteur de rendu Cycles : 
 + 
 +[[https://docs.blender.org/manual/en/dev/render/cycles/settings/scene/render/integrator.html]] 
 +[[https://docs.blender.org/manual/en/dev/render/cycles/settings/scene/render/light_paths.html]] 
 +   
 +Anti-aliasing du moteur de rendu Blender (par défaut) : 
 + 
 +[[https://docs.blender.org/manual/en/dev/render/blender_render/settings/antialiasing.html]] 
 + 
 +==== Script python détaillé pour le moteur de rendu Blender (par défaut) ====
 Le script suit les étapes suivantes : Le script suit les étapes suivantes :
   * Sélection de l'outil GPU : Il faudra vérifier au préalable le type de votre carte graphique. "compute_device_type" peut être "CUDA", "OpenCL", "NONE" et "device" peut être "CPU" ou "GPU" voir [[https://docs.blender.org/manual/en/dev/render/cycles/gpu_rendering.html]].   * Sélection de l'outil GPU : Il faudra vérifier au préalable le type de votre carte graphique. "compute_device_type" peut être "CUDA", "OpenCL", "NONE" et "device" peut être "CPU" ou "GPU" voir [[https://docs.blender.org/manual/en/dev/render/cycles/gpu_rendering.html]].
Ligne 206: Ligne 235:
   * Rendu   * Rendu
  
-<file python sample_code_complete.py >+<file python sample_code_blender_render.py >
  
 import bpy import bpy
Ligne 277: Ligne 306:
 #****** ADD MATERIALS ********* #****** ADD MATERIALS *********
 # create material # create material
-plane_material = bpy.data.materials.new("skin_material") # new material+plane_material = bpy.data.materials.new("plane_material") # new material
 plane_material_texture = plane_material.texture_slots.add() # add texture slot to material plane_material_texture = plane_material.texture_slots.add() # add texture slot to material
 plane_material.specular_intensity = 0.0 plane_material.specular_intensity = 0.0
Ligne 352: Ligne 381:
  
 </file> </file>
 +
 +==== Script python détaillé pour le moteur de rendu Cycles (photo-réalistique) ====
 +Le moteur de rendu doit être changé avec la variable "bpy.context.scene.render.engine". Avec le rendu Cycles certaines choses changent :
 +  * Les matériaux ne sont plus définis de la même façon. On doit déclarer des noeuds pour les matériaux. Ici, les coordonnées des textures sont "Generated" au lieu de "UV", sinon l'image n'est plus visible sur le plan.
 +  * La lampe est remplacée par "SUN" au lieu de "POINT". En Cycles, la lampe "POINT" n'éclaire plus assez.
 +
 +<file python sample_code_cycles_render.py >
 +import bpy
 +import numpy as np
 +import os
 +import sys
 +
 +
 +#****** CREATE DIRECTORY WHERE TO SAVE IMAGES ***********
 +img_dir = '/tmp/images/'
 +if not os.path.exists(img_dir):
 +    os.makedirs(img_dir)
 +    
 +#****** SELECT RENDERING MODE (by default blender render) ***********
 +bpy.context.scene.render.engine = 'CYCLES'
 +print(bpy.context.scene.render.engine)
 +# Other parameters
 +#bpy.context.scene.cycles.progressive = 'PATH'
 +#bpy.context.scene.cycles.samples = 50
 +#bpy.context.scene.cycles.max_bounces = 1
 +#bpy.context.scene.cycles.min_bounces = 1
 +#bpy.context.scene.cycles.glossy_bounces = 1
 +#bpy.context.scene.cycles.transmission_bounces = 1
 +#bpy.context.scene.cycles.volume_bounces = 1
 +#bpy.context.scene.cycles.transparent_max_bounces = 1
 +#bpy.context.scene.cycles.transparent_min_bounces = 1
 +#bpy.context.scene.cycles.use_progressive_refine = True
 +#bpy.context.scene.render.tile_x = 64
 +#bpy.context.scene.render.tile_y = 64
 +
 +
 +#****** SET GPU AS DEVICE ***********
 +# Before check your gpu compute device type
 +ver = bpy.app.version[0]*1000 + bpy.app.version[1]*10 + bpy.app.version[2]
 +if ver < 2782 :
 +# Before blender 2.78b
 + bpy.context.scene.cycles.device = 'GPU'
 + bpy.context.user_preferences.system.compute_device_type = 'CUDA'
 +else :
 +# Since blender 2.78b
 + sysp = bpy.context.user_preferences.addons['cycles'].preferences
 + sysp.compute_device_type = 'CUDA'
 + bpy.context.scene.cycles.device = 'GPU'
 +
 +
 +#****** INITIALIZE THE BLENDER 3D WORLD ********
 +# gather list of items of interest.
 +candidate_list = [item.name for item in bpy.data.objects if item.type == "MESH" or item.type == "LAMP" or item.type == "CAMERA"]
 +
 +# select them only.
 +for object_name in candidate_list:
 +    bpy.data.objects[object_name].select = True
 +
 +# remove all selected.
 +bpy.ops.object.delete()
 +
 +# remove the meshes, they have no users anymore.
 +for item in bpy.data.meshes:
 +    bpy.data.meshes.remove(item)
 +    
 +# delete all materials
 +for i in bpy.data.materials.values():
 +    bpy.data.materials.remove(i)
 +
 +# delete all textures
 +for i in bpy.data.textures.values():
 +    bpy.data.textures.remove(i)
 +
 +# delete all images 
 +for i in bpy.data.images.values():
 +    # delete image path, this is only possible without a user
 +    i.user_clear()
 +    # delete all, except »Render Result«
 +    if i.name != "Render Result":
 +        bpy.data.images.remove(i)
 +        
 +
 +#************* INIT NODE COMPOSITOR FOR DEPTH RENDERING ***********
 +# switch on nodes
 +bpy.context.scene.use_nodes = True
 +tree = bpy.context.scene.node_tree
 +links = tree.links
 +  
 +# clear default nodes
 +for n in tree.nodes:
 +    tree.nodes.remove(n)
 +  
 +# create input render layer node
 +rl = tree.nodes.new('CompositorNodeRLayers'     
 +rl.location = 185,285
 +
 +# create output node for color image
 +out_c_node = tree.nodes.new('CompositorNodeOutputFile')
 +out_c_node.location = 600, 200
 +out_c_node.format.file_format = 'PNG'
 +
 +# create output node for z map
 +out_z_node = tree.nodes.new('CompositorNodeOutputFile')
 +out_z_node.location = 600, 400
 +out_z_node.format.file_format = 'OPEN_EXR'
 +
 +#links
 +links.new(rl.outputs[2], out_z_node.inputs[0])  # render node to output file for Z image
 +links.new(rl.outputs[0], out_c_node.inputs[0])  # render node to output file for color image
 +
 +
 +#****** ADD OBJECTS ********
 +# Add a mesh
 +bpy.ops.mesh.primitive_plane_add(location=(0,0,0), radius=1.75)
 +plane = bpy.data.objects['Plane']
 +
 +# Add a camera
 +bpy.ops.object.camera_add( location = ( 1.5, 0, 5), rotation = ( 0,0.3,0 ) )
 +
 +# Add a lamp
 +bpy.ops.object.lamp_add( location = ( 1.0, -1.0, 6.0 ), type = 'SUN' );
 +
 +
 +#****** ADD MATERIALS *********
 +# Create material
 +plane_material = bpy.data.materials.new("plane_material") # new material
 +
 +# Activate nodes for materials
 +plane_material.use_nodes = True
 +plane_nt = plane_material.node_tree
 +plane_nodes = plane_nt.nodes
 +plane_links = plane_nt.links
 +
 +# clear previous materials nodes
 +while(plane_nodes): plane_nodes.remove(plane_nodes[0])
 +
 +# Add nodes for materials
 +plane_output  = plane_nodes.new("ShaderNodeOutputMaterial")
 +plane_diffuse = plane_nodes.new("ShaderNodeBsdfDiffuse")
 +plane_texture = plane_nodes.new("ShaderNodeTexImage")
 +plane_texcoord   = plane_nodes.new("ShaderNodeTexCoord")
 +
 +# edit texture and texture coordinates
 +plane_image_path = os.path.expanduser('ton_image.jpg') # get image (needs the lib os)
 +plane_texture.image = bpy.data.images.load(plane_image_path) # load image
 +
 +# Links materials nodes
 +plane_links.new( plane_output.inputs['Surface'], plane_diffuse.outputs['BSDF'])
 +plane_links.new(plane_diffuse.inputs['Color'],   plane_texture.outputs['Color'])
 +plane_links.new(plane_texture.inputs['Vector'],    plane_texcoord.outputs['Generated'])
 +
 +# Distribute nodes along the x axis
 +for index, node in enumerate((plane_texcoord, plane_texture, plane_diffuse, plane_output)):
 +    node.location.x = 200.0 * index
 +
 +# Link material to object
 +plane.data.materials.append(plane_material)
 +
 +
 +#************* RENDER AND SAVE IMAGES ***********
 +# Define image resolution for rendering
 +bpy.data.scenes["Scene"].render.resolution_x = 250
 +bpy.data.scenes["Scene"].render.resolution_y = 250
 +# resolution percentage : have to be 100% to have the whole image resolution defined earlier
 +bpy.context.scene.render.resolution_percentage = 100
 +
 +# Activate which camera will be used for rendering
 +# (if more than one camera are defined, the rendering have to be repeated for each camera)
 +bpy.context.scene.camera = bpy.data.objects["Camera"]
 +
 +# Define path where to save images
 +str4 = img_dir + "image"
 +out_c_node.base_path = str4 + "000"
 +out_z_node.base_path = str4 +"_Z_"+ "000"
 +
 +# Render
 +bpy.ops.render.render()#write_still=True)
 +
 +#************* EXIT BLENDER  ***********
 +sys.exit(0)
 +</file>
 +
 +
 +==== Ajout de modules python externes ====
 +Blender est livré avec son propre python. On le trouve à l'emplacement suivant : "chemin_vers_le_dossier_blender/blender-2.79-linux-glibc219-x86_64/2.79/python/lib/python3.5/". Votre version de blender (ici 2.79) et de python (ici 3.5) sera à adapter à votre configuration. On retrouve à l'emplacement "python3.5/site-packages" les modules "numpy" et "requests" déjà présent dans blender.
 +
 +Pour importer de nouveaux modules dans mes scripts, j'ai appliqué la solution suivante :
 +  * faire en sorte que la version de python installé et celle de blender coïncide. Télécharger la dernière version de blender dont le python intégré a la bonne version.
 +  * télécharger les modules voulus sur le python3 installé dans /usr/local/ (l'adresse dépend de votre installation)
 +  * ajouter dans le script python les chemins vers les modules externes recherchés : sys.path.append('/usr/local/lib/python3.5/site-packages/') et sys.path.append('/usr/local/lib/python3.5/lib-dynload/') pour tkinter utilisé par matplotlib. Les chemins doivent être ajouté avant d'inclure les modules avec "import".
 +  * ajouter sys.path.append('chemin_vers_le_dossier_contenant_le_script') et lancer la commande ./chemin_vers_blender/blender -P mon_script.py, si le script n'est pas à emplacement de l'exécutable python
 +
 +Si la version de numpy de blender ne coïncide pas avec celle utilisée par les modules externes, renommez le numpy de blender (par exemple en 'numpy_1.10.1'). Le script utilisera alors le numpy installé dans /usr/local/.
 +
 +Pour voir la version de numpy, entrer dans la console python :
 +  >>> import numpy
 +  >>> numpy.version.version
 +
 +
 +=====Animation modèle de visage=====
 +
 +charger la scène Swirski-EyeModel.blend
 +
 +Mode d'affichage default
 +
 +Développer l'arbre Armature Head->the rig->Pose_head.002->eyetargetparent
 +
 +à droite, choisir mode Bone (OS)
 +
 +en bas, chosir Pose Mode
 +
 +à droite dans  transform->Location, changer x,y,z pour spécifier la cible visée par l'oeil
 +
 +passer en mode scripting
 +
 +recliquer sur Bone et changer  transform->Location, la commande python correspondante apparait dans la console:
 +  bpy.context.object.pose.bones["eyetargetparent"].location[0] = -0.113456
 +
 +bpy.context dépend de l'objet actuellement selectionné dans la GUI, pour modifier dans le script, il faut retrouver dans l'arborescence de la scene (s'aider de l'auto complétion avec CTRL+SPACE)
 +  scene = bpy.context.scene
 +  armature = bpy.data.objects['Armature Head']
 +  armature.pose.bones['eyetargetparent'].location[0] = -0.113456
 +
 +
 +  ./blender-2.74-linux-glibc211-x86_64/blender --python ./Swirski-EyeModel.py -b
 +
 +<file python Swirski-EyeModel.py>
 +import bpy
 +import math
 +import mathutils
 +import os
 +import sys
 +import numpy as np
 +#lancer avec  ./blender-2.74-linux-glibc211-x86_64/blender --python ./Swirski-EyeModel.py -b 
 +
 +
 +
 +#****** CREATE DIRECTORY WHERE TO SAVE IMAGES ***********
 +img_dir = '/tmp/images/'
 +if not os.path.exists(img_dir):
 +    os.makedirs(img_dir)
 +
 +
 +
 +bpy.ops.wm.open_mainfile(filepath="/media/HD500GO/blender/Swirski-EyeModel.blend")
 +
 +scene = bpy.context.scene
 +armature = bpy.data.objects['Armature Head']
 +camera_obj = bpy.data.objects['Camera']
 +camera = bpy.data.cameras['Camera']
 +
 +eyeL = bpy.data.objects['eye.L']
 +pupilGroup = eyeL.vertex_groups['eyepulpex.L']
 +pupilVertices = [v for v in eyeL.data.vertices if pupilGroup.index in [g.group for g in v.groups]]
 +
 +pupil_base_radius = max((v1.co - v2.co).length for v1 in pupilVertices for v2 in pupilVertices) * eyeL.scale[1]
 +
 +eyeLbone = armature.pose.bones['def_eye.L']
 +pupilLbone = armature.pose.bones['eyepulpex.L']
 +
 +def strVec(vec):
 +    return "({},{},{})".format(vec[0], vec[1], vec[2])
 +
 +datafilepath = os.path.join(os.path.dirname(bpy.data.filepath), "render_eye_data.txt")
 +
 +
 +
 +# switch on nodes
 +scene.use_nodes = True
 +tree = scene.node_tree
 +links = tree.links
 + 
 +# clear default nodes
 +for n in tree.nodes:
 +    tree.nodes.remove(n)
 + 
 +# create input render layer node
 +rl = tree.nodes.new('CompositorNodeRLayers'     
 +rl.location = 185,285
 + 
 +# create output node
 +v = tree.nodes.new('CompositorNodeViewer'  
 +v.location = 750,210
 +v.use_alpha = False
 + 
 +# create output node
 +of_c_node = tree.nodes.new('CompositorNodeOutputFile')
 +of_c_node.location = 600, 200
 +#of_node.base_path = 
 +of_c_node.format.file_format = 'PNG'
 + 
 +# Links
 +links.new(rl.outputs[0], v.inputs[0])  # link Image output to Viewer input
 +links.new(rl.outputs[0], of_c_node.inputs[0])
 + 
 +# Define path where to save image
 +base_path = "/tmp/images" #"./images_test_png"
 + 
 +
 +
 +
 +with open(datafilepath, "w") as datafile:
 +    #for frame in range(scene.frame_end+1):
 +    for frame in range(2):
 +        scene.frame_set(frame)
 +        #modification position de visée de l'oeil
 +        print('Jessica et Bertrand sont passés par la');
 +        armature.pose.bones['eyetargetparent'].location[0] = -0.113456
 +
 +        camera_mat = camera_obj.matrix_world * mathutils.Matrix([[1,0,0,0],[0,-1,0,0],[0,0,-1,0],[0,0,0,1]])
 +        
 +        camera_invmat = camera_mat.inverted()
 +        armature_mat = armature.matrix_world
 +        
 +        head_world = armature_mat*eyeLbone.head
 +        tail_world = armature_mat*eyeLbone.tail
 +        
 +        head_cam = camera_invmat*head_world
 +        tail_cam = camera_invmat*tail_world
 +        
 +        eye_centre = head_cam
 +        eye_radius = eyeLbone.bone.length
 +        pupil_gaze = (tail_cam - head_cam).normalized()
 +        pupil_radius = pupilLbone.scale[0] * pupil_base_radius
 +        pupil_centre = eye_centre + eye_radius*pupil_gaze
 +        
 +        #framestr = "{} | head_world: {} | tail_world: {} | vec_world: {} | head_cam: {} | tail_cam: {} | vec_cam {}".format(
 +        #       frame, *[strVec(x) for x in [head_world,tail_world,vec_world,head_cam,tail_cam,vec_cam]])
 +        framestr = "{} {} {} {} {} {}".format(
 +            frame,
 +            strVec(eye_centre),
 +            eye_radius,
 +            strVec(pupil_centre),
 +            strVec(pupil_gaze),
 +            pupil_radius
 +            )
 +        print(framestr)
 +        print(framestr, file=datafile)
 +        #************* RENDER AND SAVE IMAGES ***********
 +# Define image resolution for rendering
 +        scene.render.resolution_x = 250
 +        scene.render.resolution_y = 250
 +# resolution percentage : have to be 100% to have the whole image resolution defined earlier
 +        scene.render.resolution_percentage = 100
 + 
 +# Activate which camera will be used for rendering
 +# (if more than one camera are defined, the rendering have to be repeated for each camera)
 +        scene.camera = bpy.data.objects["Camera"]
 + 
 + 
 +# get viewer pixels directly
 +        #pixels = bpy.data.images['Viewer Node'].pixels
 +        #print(len(pixels)) # size is always width * height * 4 (rgba)
 + 
 +# copy buffer to numpy array for faster manipulation
 +#       arr = np.array(pixels[:])
 +#        print('one pixel \n',arr[100:104])
 + 
 +
 +# Define path where to save images
 +        str4 = base_path + "/image"
 +        of_c_node.base_path = str4 + "000"
 +        #out_z_node.base_path = str4 +"_Z_"+ "000"
 + 
 +# Render
 +        bpy.ops.render.render()#write_still=True)
 + 
 +#************* EXIT BLENDER  ***********
 +        sys.exit(0)
 +
 +</file>
 +
 +
 +{{http://homepages.laas.fr/bvandepo/files/oeil.png}}
 +
 +
 +
 +
 +==== Accélérer le rendu ====
 +
 +Plusieurs astuces existent pour accelérer le rendu. Ces astuces diffèrent suivant si on est en "Blender render" ou en "Cycle render".
 +
 +Lien pour le "Cycle render":
 +  * [[https://www.blenderguru.com/articles/4-easy-ways-to-speed-up-cycles]]
 +  * [[http://boundlessblending.com/blender-fast-rendering/]]
 +
 +Lien pour "Blender render":
 +  * [[https://www.blenderguru.com/articles/13-ways-to-reduce-render-times]]
 +
 +Pour le calcul de Blender occupe 100% du CPU il faut indiquer le bon nombre de threads et la bonne taille de tuile ("Tile size") : [[https://blenderartists.org/forum/showthread.php?410469-Why-Blender-Cycles-Rendering-Not-Using-100-CPU]]
 +
blender.1508340877.txt.gz · Dernière modification: 2017/10/18 17:34 de jcombier