[nodes/blender] update documentation

This commit is contained in:
Loïc Vital 2023-05-30 11:07:59 +02:00
parent 3eaea1ff6f
commit 1e74c00d8b
2 changed files with 36 additions and 31 deletions

View file

@ -10,9 +10,11 @@ class RenderAnimatedCamera(desc.CommandLineNode):
category = 'Visualization'
documentation = '''
This node makes a rendering of the sfmData scene through an animated camera using the Blender rendering engine.
It supports both Point Clouds (.abc) and Meshes (.obj).
'''
This node uses Blender to visualize a 3D model from a given set of cameras.
The cameras must be a SfMData file in JSON format.
For the 3D model it supports both point clouds in Alembic format and meshes in OBJ format.
One frame per viewpoint will be rendered, and the undistorted views can optionally be used as background.
'''
inputs = [
desc.File(
@ -25,7 +27,7 @@ class RenderAnimatedCamera(desc.CommandLineNode):
),
desc.File(
name='script',
label='Script Path',
label='Script',
description='Path to the internal script for rendering in Blender',
value=os.path.join(currentDir, 'scripts' ,'renderAnimatedCameraInBlender.py'),
uid=[],
@ -34,15 +36,15 @@ class RenderAnimatedCamera(desc.CommandLineNode):
),
desc.File(
name='cameras',
label='SfmData with Animated Camera',
description='SfmData with the animated camera to render (in json format)',
label='Cameras',
description='SfmData with the views, poses and intrinsics to use (in JSON format)',
value='',
uid=[0],
),
desc.File(
name='model',
label='Model',
description='Point Cloud or Mesh to render',
description='Point cloud (.abc) or mesh (.obj) to render',
value='',
uid=[0],
),
@ -55,8 +57,8 @@ class RenderAnimatedCamera(desc.CommandLineNode):
),
desc.File(
name='undistortedImages',
label='Undistorted Images Folder',
description='Input folder with the undistorted images',
label='Undistorted Images',
description='Folder containing the undistorted images',
value='',
uid=[0],
enabled=lambda node: node.useBackground.value,
@ -66,12 +68,12 @@ class RenderAnimatedCamera(desc.CommandLineNode):
label="Point Cloud Settings",
group=None,
enabled=lambda node: node.model.value.lower().endswith('.abc'),
description="Settings of the render if we use a Point Cloud",
description="Settings for point cloud rendering",
groupDesc=[
desc.FloatParam(
name='particleSize',
label='Particle Size',
description='Scale of particles used to show the point cloud',
description='Scale of particles used for the point cloud',
value=0.01,
range=(0.01, 1.0, 0.01),
uid=[0],
@ -79,12 +81,11 @@ class RenderAnimatedCamera(desc.CommandLineNode):
desc.ChoiceParam(
name='particleColor',
label='Particle Color',
description='Color of particles used to show the point cloud',
description='Color of particles used for the point cloud',
value='Red',
values=['Grey', 'White', 'Red', 'Green', 'Magenta'],
exclusive=True,
uid=[0],
joinChar=',',
),
]
),
@ -93,7 +94,7 @@ class RenderAnimatedCamera(desc.CommandLineNode):
label="Mesh Settings",
group=None,
enabled=lambda node: node.model.value.lower().endswith('.obj'),
description="Setting of the render if we use a Mesh",
description="Setting for mesh rendering",
groupDesc=[
desc.ChoiceParam(
name='shading',
@ -107,7 +108,7 @@ class RenderAnimatedCamera(desc.CommandLineNode):
desc.ChoiceParam(
name='edgeColor',
label='Edge Color',
description='Color of the edges of the rendered object',
description='Color of the mesh edges',
value='Red',
values=['Grey', 'White', 'Red', 'Green', 'Magenta'],
exclusive=True,
@ -120,17 +121,17 @@ class RenderAnimatedCamera(desc.CommandLineNode):
outputs = [
desc.File(
name='output',
label='Output Folder',
description='Output Folder',
label='Output',
description='Output folder',
value=desc.Node.internalFolder,
uid=[],
),
desc.File(
name='render',
label='Render',
name='frames',
label='Frames',
description='Frames rendered in Blender',
semantic='image',
value=desc.Node.internalFolder + '<VIEW_ID>.png',
value=desc.Node.internalFolder + '<VIEW_ID>.jpg',
uid=[],
group='',
),

View file

@ -9,6 +9,7 @@ import glob
def createParser():
'''Create command line interface.'''
# When --help or no args are given, print this help
usage_text = (
"Run blender in background mode with this script:"
@ -67,10 +68,10 @@ def parseSfMCameraFile(filepath):
return views, intrinsics, poses
def getFromId(data, key, id):
def getFromId(data, key, identifier):
'''Utility function to retrieve view, intrinsic or pose using their IDs.'''
for item in data:
if item[key] == id:
if item[key] == identifier:
return item
return None
@ -109,14 +110,16 @@ def setupCamera(intrinsic, pose):
def initScene():
'''Initialize Blender scene.'''
# Clear current scene (keep default camera)
bpy.data.objects.remove(bpy.data.objects['Cube'])
bpy.data.objects.remove(bpy.data.objects['Light'])
# Set output format
bpy.context.scene.render.image_settings.file_format = 'JPEG'
def initCompositing():
'''Initialize Blender compositing graph for adding background image to render.'''
bpy.context.scene.render.image_settings.file_format = 'PNG'
bpy.context.scene.render.film_transparent = True
bpy.context.scene.use_nodes = True
bpy.context.scene.node_tree.nodes.new(type="CompositorNodeAlphaOver")
@ -135,11 +138,11 @@ def initCompositing():
def setupRender(view, intrinsic, pose, outputDir):
'''Setup rendering in Blender for a given view.'''
setupCamera(intrinsic, pose)
bpy.context.scene.render.filepath = os.path.abspath(outputDir + '/' + view['viewId'] + '.png')
bpy.context.scene.render.filepath = os.path.abspath(outputDir + '/' + view['viewId'] + '.jpg')
def setupBackground(view, folderUndistorted):
'''TODO'''
'''Retrieve undistorted image corresponding to view and use it as background.'''
baseImgName = os.path.splitext(os.path.basename(view['path']))[0]
undistortedImgPath = glob.glob(folderUndistorted + '/*' + baseImgName + "*")[0]
bpy.ops.image.open(filepath=undistortedImgPath)
@ -147,8 +150,8 @@ def setupBackground(view, folderUndistorted):
bpy.context.scene.node_tree.nodes["Image"].image = bpy.data.images[undistortedImgName]
def loadScene(filename):
'''TODO'''
def loadModel(filename):
'''Load model in Alembic of OBJ format. Make sure orientation matches camera orientation.'''
if filename.lower().endswith('.obj'):
bpy.ops.import_scene.obj(filepath=filename, axis_forward='Y', axis_up='Z')
return bpy.data.objects['mesh'], bpy.data.meshes['mesh']
@ -160,7 +163,7 @@ def loadScene(filename):
def setupWireframeShading(mesh, color):
'''TODO'''
'''Setup material for wireframe shading.'''
# Initialize wireframe material
material = bpy.data.materials.new('Wireframe')
material.use_backface_culling = True
@ -191,7 +194,7 @@ def setupWireframeShading(mesh, color):
def setupLineArtShading(obj, mesh, color):
'''TODO'''
'''Setup materials and Solidify modifier for line art shading.'''
# Transparent filling material
matFill = bpy.data.materials.new('Fill')
matFill.use_backface_culling = True
@ -225,7 +228,7 @@ def setupLineArtShading(obj, mesh, color):
def setupPointCloudShading(obj, color, size):
'''TODO'''
'''Setup material and geometry nodes for point cloud shading.'''
# Colored filling material
material = bpy.data.materials.new('PointCloud_Mat')
material.use_nodes = True
@ -278,6 +281,7 @@ def main():
parser.print_help()
return -1
# Color palette (common for point cloud and mesh visualization)
palette={
'Grey':(0.2, 0.2, 0.2, 1),
'White':(1, 1, 1, 1),
@ -297,7 +301,7 @@ def main():
views, intrinsics, poses = parseSfMCameraFile(args.cameras)
print("Load scene objects")
sceneObj, sceneMesh = loadScene(args.model)
sceneObj, sceneMesh = loadModel(args.model)
print("Setup shading")
if args.model.lower().endswith('.obj'):