2
$\begingroup$

My goal is to get a rendered image of an PLY mesh from command line. I wrote this script:

import os
import bpy
import sys
from math import pi

filename = 'web.ply'
in_dir = os.path.join('J:\\', 'aa')
item = os.path.join(in_dir, filename)
out_dir = os.path.join(in_dir, 'out')
os.makedirs(out_dir, exist_ok=True)     


bpy.ops.object.delete()
bpy.ops.import_mesh.ply(filepath=os.path.join(item))
bpy.ops.object.lamp_add(type='SUN', radius=100, view_align=False, location=(0, 0, 0), layers=(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
bpy.ops.object.select_all(action='DESELECT')
for ob in bpy.data.objects:
  print (ob.type, ob.name)
  if ob.type == 'MESH':
    bpy.context.scene.objects.active = ob
    ob.select = True
  elif ob.type == 'CAMERA':
    ob.data.clip_end = 1000000
    ob.data.clip_start = 0.01
    ob.select = False
  else:
    ob.select = False


bpy.ops.transform.rotate(value=pi/2, axis=(True, False, False))
bpy.context.scene.render.resolution_x = 692
bpy.context.scene.render.resolution_y = 900
bpy.context.scene.render.alpha_mode = 'TRANSPARENT'

bpy.ops.object.mode_set(mode='VERTEX_PAINT')

for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':
        ctx = bpy.context.copy()
        ctx['area'] = area
        ctx['region'] = area.regions[-1]
        bpy.ops.view3d.view_selected(ctx)
        bpy.ops.view3d.camera_to_view_selected(ctx)

bpy.context.scene.render.image_settings.file_format = 'PNG'
bpy.context.scene.render.image_settings.quality = 100
bpy.context.scene.render.filepath = os.path.join(out_dir, filename+'-preview.jpg')
bpy.ops.render.render(write_still=True)

It works, but not properly renders colors. The output image is in gray scale colors! I think that the issue is bpy.ops.object.mode_set(mode='VERTEX_PAINT') and the position inside the script. Something is wrong. Any tips? Here a PLY example file: http://156.54.99.175/3d/a.ply

$\endgroup$
3
  • $\begingroup$ which render engine would you prefer? Cycles or Blender Internal. $\endgroup$
    – zeffii
    Commented Sep 2, 2015 at 10:16
  • $\begingroup$ Blender Internal, thankyou @zeffii your script works like a sharm! And great explanation, you are my guru. $\endgroup$
    – sborfedor
    Commented Sep 2, 2015 at 13:13
  • $\begingroup$ Your script was very close already - hopefully this cleared up some details. $\endgroup$
    – zeffii
    Commented Sep 2, 2015 at 13:32

2 Answers 2

2
$\begingroup$

If you used bpy.ops.screen.screenshot(ctx, filepath=destination, full=False) in the correct context it would save a screenshot of what you see in the viewport, but render.render() isn't the same as doing a screenshot.

I think you're getting something like this? enter image description here

You need to set up a material to pipe the Vertex Color Layer to the material diffuse colour. Right now you are rendering the object with the default material, which doesn't know anything about the Vertex Color layer. The .ply importer doesn't assign a material to your object.

Blender Internal materials.

enter image description here

# assuming there is a material assigned to the object.
obj.data.materials[0].use_vertex_color_paint = True

else it's something like

obj = bpy.data.objects['a']
mat = bpy.data.materials.new('material_1')
obj.active_material = mat
mat.use_vertex_color_paint = True

maybe stick some ambient occlusion on it:

enter image description here

bpy.data.worlds["World"].light_settings.use_ambient_occlusion = True

For cycles materials

via the UI it's pretty easy

enter image description here

Which makes a node setup like this:

enter image description here

If you wanted to script that, that's another matter.

Your script adjusted (expects Blender Internal)

import os
import bpy
import sys
from math import pi

# filename = 'web.ply'
# in_dir = os.path.join('J:\\', 'aa')
filename = 'a.ply'
in_dir = "/home/zeffii/Desktop"
item = os.path.join(in_dir, filename)
out_dir = os.path.join(in_dir, 'out')
os.makedirs(out_dir, exist_ok=True)


bpy.ops.object.delete()
bpy.ops.import_mesh.ply(filepath=item)
bpy.ops.object.lamp_add(
    type='SUN', radius=100,
    view_align=False, location=(0, 0, 0),
    layers=tuple(i == 0 for i in range(20))
)
bpy.ops.object.select_all(action='DESELECT')

for ob in bpy.data.objects:
    print(ob.type, ob.name)
    if ob.type == 'MESH':
        bpy.context.scene.objects.active = ob
        ob.select = True
        mat = bpy.data.materials.new('material_1')
        ob.active_material = mat
        mat.use_vertex_color_paint = True
    elif ob.type == 'CAMERA':
        ob.data.clip_end = 1000000
        ob.data.clip_start = 0.01
        ob.select = False
    else:
        ob.select = False

bpy.ops.transform.rotate(value=pi / 2, axis=(True, False, False))
scn = bpy.context.scene
scn.render.resolution_x = 692
scn.render.resolution_y = 900
scn.render.alpha_mode = 'TRANSPARENT'
bpy.data.worlds["World"].light_settings.use_ambient_occlusion = True


for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':
        ctx = bpy.context.copy()
        ctx['area'] = area
        ctx['region'] = area.regions[-1]
        bpy.ops.view3d.view_selected(ctx)
        bpy.ops.view3d.camera_to_view_selected(ctx)

scn.render.image_settings.file_format = 'PNG'
scn.render.image_settings.quality = 100
scn.render.filepath = os.path.join(out_dir, filename + '-preview.jpg')
bpy.ops.render.render(write_still=True)

outputs this:

enter image description here

$\endgroup$
1
$\begingroup$

This is an update to the original script by @zeffii for Blender 2.8x:

import os
import bpy
import sys
from math import pi

dataset_name = "hotel_0"
item = "/media/DATA/dataset/environments/Replica-Dataset/"+dataset_name+"/mesh.ply"
out_dir = "/tmp/blender_hotel0/"
os.makedirs(out_dir, exist_ok=True)

# https://blender.stackexchange.com/q/36897/89335

bpy.ops.object.delete()
bpy.ops.import_mesh.ply(filepath=item)
bpy.ops.object.light_add(
    type='SUN', radius=100,
    align='VIEW', location=(0, 0, 0)
)
bpy.ops.object.select_all(action='DESELECT')

for ob in bpy.data.objects:
    print(ob.type, ob.name)
    if ob.type == 'MESH':
        bpy.context.view_layer.objects.active = ob
        ob.select_set(True)
        mat = bpy.data.materials.new('material_1')
        ob.active_material = mat
        # https://blender.stackexchange.com/a/160069
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        mat_links = mat.node_tree.links
        bsdf = nodes.get("Principled BSDF")
        assert(bsdf) # make sure it exists to continue
        vcol = nodes.new(type="ShaderNodeVertexColor")
        # vcol.layer_name = "VColor" # the vertex color layer name
        vcol.layer_name = "Col"
        mat_links.new(vcol.outputs['Color'], bsdf.inputs['Base Color'])
    elif ob.type == 'CAMERA':
        ob.data.clip_end = 1000000
        ob.data.clip_start = 0.01
        ob.select_set(False)
    else:
        ob.select_set(False)

bpy.ops.transform.rotate(value=pi / 2, orient_axis='X')
scn = bpy.context.scene
scn.render.resolution_x = 692
scn.render.resolution_y = 900
scn.render.film_transparent = True
bpy.data.worlds["World"].light_settings.use_ambient_occlusion = True


for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':
        ctx = bpy.context.copy()
        ctx['area'] = area
        ctx['region'] = area.regions[-1]
        bpy.ops.view3d.view_selected(ctx)
        bpy.ops.view3d.camera_to_view_selected(ctx)

scn.render.image_settings.file_format = 'PNG'
scn.render.image_settings.quality = 100
scn.render.filepath = os.path.join(out_dir, dataset_name + '-preview.jpg')
bpy.ops.render.render(write_still=True)
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .