[Blender Export] Now can be used as renderer
- Tested with kikit_present and populate - Also added `auto_crop`
This commit is contained in:
parent
fce9a2d581
commit
e16086ca70
|
|
@ -201,6 +201,7 @@ Notes:
|
|||
|
||||
[**ImageMagick**](https://imagemagick.org/) [](https://imagemagick.org/) [](https://packages.debian.org/bullseye/imagemagick) 
|
||||
- Optional to:
|
||||
- Automatically crop images for `blender_export`
|
||||
- Create outputs preview for `navigate_results`
|
||||
- Create monochrome prints and scaled PNG files for `pcb_print`
|
||||
- Create JPG and BMP images for `pcbdraw`
|
||||
|
|
@ -1608,10 +1609,14 @@ Notes:
|
|||
- **`samples`**: [number=10] How many samples we create. Each sample is a raytracing render.
|
||||
Use 1 for a raw preview, 10 for a draft and 100 or more for the final render.
|
||||
- **`transparent_background`**: [boolean=false] Make the background transparent.
|
||||
- `auto_crop`: [boolean=false] When enabled the image will be post-processed to remove the empty space around the image.
|
||||
In this mode the `background2` is changed to be the same as `background1`.
|
||||
- `background1`: [string='#66667F'] First color for the background gradient.
|
||||
- `background2`: [string='#CCCCE5'] Second color for the background gradient.
|
||||
- *height*: Alias for resolution_y.
|
||||
- `resolution_x`: [number=1280] Width of the image.
|
||||
- `resolution_y`: [number=720] Height of the image.
|
||||
- *width*: Alias for resolution_x.
|
||||
- `add_default_light`: [boolean=true] Add a default light when none specified.
|
||||
The default light is located at (-size*3.33, size*3.33, size*5) where size is max(width, height) of the PCB.
|
||||
- `camera`: [dict] Options for the camera.
|
||||
|
|
|
|||
|
|
@ -209,10 +209,14 @@ outputs:
|
|||
view: 'top'
|
||||
# [dict] Controls how the render is done for the `render` output type
|
||||
render_options:
|
||||
# [boolean=false] When enabled the image will be post-processed to remove the empty space around the image.
|
||||
# In this mode the `background2` is changed to be the same as `background1`
|
||||
auto_crop: false
|
||||
# [string='#66667F'] First color for the background gradient
|
||||
background1: '#66667F'
|
||||
# [string='#CCCCE5'] Second color for the background gradient
|
||||
background2: '#CCCCE5'
|
||||
# `height` is an alias for `resolution_y`
|
||||
# [number=1280] Width of the image
|
||||
resolution_x: 1280
|
||||
# [number=720] Height of the image
|
||||
|
|
@ -222,6 +226,7 @@ outputs:
|
|||
samples: 10
|
||||
# [boolean=false] Make the background transparent
|
||||
transparent_background: false
|
||||
# `width` is an alias for `resolution_x`
|
||||
# BoardView:
|
||||
# This format allows simple pads and connections navigation, mainly for circuit debug.
|
||||
# The output can be loaded using Open Board View (https://openboardview.org/)
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ KICAD5_SVG_SCALE = 116930/297002200
|
|||
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0'
|
||||
# Text used to disable 3D models
|
||||
DISABLE_3D_MODEL_TEXT = '_Disabled_by_KiBot'
|
||||
RENDERERS = ['pcbdraw', 'render_3d']
|
||||
RENDERERS = ['pcbdraw', 'render_3d', 'blender_export']
|
||||
PCB_GENERATORS = ['pcb_variant', 'panelize']
|
||||
KIKIT_UNIT_ALIASES = {'millimeters': 'mm', 'inches': 'inch', 'mils': 'mil'}
|
||||
|
||||
|
|
|
|||
|
|
@ -468,38 +468,6 @@ class Optionable(object):
|
|||
def color_str_to_rgb(self, color):
|
||||
return self.color_to_rgb(self.parse_one_color(color))
|
||||
|
||||
def save_renderer_options(self):
|
||||
""" Save the current renderer settings """
|
||||
options = self._renderer.options
|
||||
self.old_filters_to_expand = options._filters_to_expand
|
||||
self.old_show_components = options.show_components
|
||||
self.old_highlight = options.highlight
|
||||
self.old_output = options.output
|
||||
self.old_dir = self._renderer.dir
|
||||
self.old_done = self._renderer._done
|
||||
if self._renderer_is_pcbdraw:
|
||||
self.old_bottom = options.bottom
|
||||
self.old_add_to_variant = options.add_to_variant
|
||||
else: # render_3D
|
||||
self.old_view = options.view
|
||||
self.old_show_all_components = options._show_all_components
|
||||
|
||||
def restore_renderer_options(self):
|
||||
""" Restore the renderer settings """
|
||||
options = self._renderer.options
|
||||
options._filters_to_expand = self.old_filters_to_expand
|
||||
options.show_components = self.old_show_components
|
||||
options.highlight = self.old_highlight
|
||||
options.output = self.old_output
|
||||
self._renderer.dir = self.old_dir
|
||||
self._renderer._done = self.old_done
|
||||
if self._renderer_is_pcbdraw:
|
||||
options.bottom = self.old_bottom
|
||||
options.add_to_variant = self.old_add_to_variant
|
||||
else: # render_3D
|
||||
options.view = self.old_view
|
||||
options._show_all_components = self.old_show_all_components
|
||||
|
||||
|
||||
class BaseOptions(Optionable):
|
||||
""" A class to validate and hold output options.
|
||||
|
|
|
|||
|
|
@ -990,6 +990,32 @@ class VariantOptions(BaseOptions):
|
|||
self._sub_pcb = self.variant._sub_pcb
|
||||
self._comps = comps
|
||||
|
||||
# The following 3 members are used by 2D and 3D renderers
|
||||
def setup_renderer(self, components, active_components):
|
||||
""" Setup the options to use it as a renderer """
|
||||
self._show_all_components = False
|
||||
self._filters_to_expand = False
|
||||
self.highlight = self.solve_kf_filters([c for c in active_components if c])
|
||||
self.show_components = [c for c in components if c]
|
||||
if self.show_components:
|
||||
self.show_components = self.solve_kf_filters(self.show_components)
|
||||
|
||||
def save_renderer_options(self):
|
||||
""" Save the current renderer settings """
|
||||
self.old_filters_to_expand = self._filters_to_expand
|
||||
self.old_show_components = self.show_components
|
||||
self.old_highlight = self.highlight
|
||||
self.old_dir = self._parent.dir
|
||||
self.old_done = self._parent._done
|
||||
|
||||
def restore_renderer_options(self):
|
||||
""" Restore the renderer settings """
|
||||
self._filters_to_expand = self.old_filters_to_expand
|
||||
self.show_components = self.old_show_components
|
||||
self.highlight = self.old_highlight
|
||||
self._parent.dir = self.old_dir
|
||||
self._parent._done = self.old_done
|
||||
|
||||
|
||||
class PcbMargin(Optionable):
|
||||
""" To adjust each margin """
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ Dependencies:
|
|||
- from: Blender
|
||||
role: mandatory
|
||||
version: 3.4.0
|
||||
- from: ImageMagick
|
||||
role: Automatically crop images
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
|
|
@ -122,14 +124,21 @@ class BlenderRenderOptions(Optionable):
|
|||
Use 1 for a raw preview, 10 for a draft and 100 or more for the final render """
|
||||
self.resolution_x = 1280
|
||||
""" Width of the image """
|
||||
self.width = None
|
||||
""" {resolution_x} """
|
||||
self.resolution_y = 720
|
||||
""" Height of the image """
|
||||
self.height = None
|
||||
""" {resolution_y} """
|
||||
self.transparent_background = False
|
||||
""" *Make the background transparent """
|
||||
self.background1 = "#66667F"
|
||||
""" First color for the background gradient """
|
||||
self.background2 = "#CCCCE5"
|
||||
""" Second color for the background gradient """
|
||||
self.auto_crop = False
|
||||
""" When enabled the image will be post-processed to remove the empty space around the image.
|
||||
In this mode the `background2` is changed to be the same as `background1` """
|
||||
self._unkown_is_error = True
|
||||
|
||||
|
||||
|
|
@ -154,6 +163,7 @@ class BlenderPointOfViewOptions(Optionable):
|
|||
""" String to diferentiate the name of this view.
|
||||
When empty we use the `view` """
|
||||
self._unkown_is_error = True
|
||||
self._file_id = ''
|
||||
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
|
|
@ -190,6 +200,38 @@ class PCB3DExportOptions(Base3DOptionsWithHL):
|
|||
p._expand_ext = cur_ext
|
||||
return out_name
|
||||
|
||||
def setup_renderer(self, components, active_components, bottom, name):
|
||||
super().setup_renderer(components, active_components)
|
||||
self._pov.view = 'Z' if bottom else 'z'
|
||||
# Expand the name using .PNG
|
||||
cur_ext = self._expand_ext
|
||||
self._expand_ext = 'png'
|
||||
o_name = self.expand_filename_both(name, is_sch=False)
|
||||
self._expand_ext = cur_ext
|
||||
self._out.output = o_name
|
||||
return o_name
|
||||
|
||||
def save_renderer_options(self):
|
||||
""" Save the current renderer settings """
|
||||
p = self._parent
|
||||
# We are an option inside another option
|
||||
self._parent = self._parent._parent
|
||||
super().save_renderer_options()
|
||||
self._parent = p
|
||||
self.old_show_all_components = self._show_all_components
|
||||
self.old_view = self._pov.view
|
||||
self.old_output = self._out.output
|
||||
|
||||
def restore_renderer_options(self):
|
||||
""" Restore the renderer settings """
|
||||
p = self._parent
|
||||
self._parent = self._parent._parent
|
||||
super().restore_renderer_options()
|
||||
self._parent = p
|
||||
self._show_all_components = self.old_show_all_components
|
||||
self._pov.view = self.old_view
|
||||
self._out.output = self.old_output
|
||||
|
||||
|
||||
class Blender_ExportOptions(BaseOptions):
|
||||
def __init__(self):
|
||||
|
|
@ -222,9 +264,12 @@ class Blender_ExportOptions(BaseOptions):
|
|||
def config(self, parent):
|
||||
super().config(parent)
|
||||
# Check we at least have a name for the source output
|
||||
if isinstance(self.pcb3d, type) or (isinstance(self.pcb3d, str) and not self.pcb3d):
|
||||
if isinstance(self.pcb3d, str) and not self.pcb3d:
|
||||
raise KiPlotConfigurationError('You must specify the name of the output that'
|
||||
' generates the PCB3D file or its options')
|
||||
if isinstance(self.pcb3d, type):
|
||||
self.pcb3d = PCB3DExportOptions()
|
||||
self.pcb3d.config(self)
|
||||
# Do we have outputs?
|
||||
if isinstance(self.outputs, type):
|
||||
self.outputs = []
|
||||
|
|
@ -409,6 +454,10 @@ class Blender_ExportOptions(BaseOptions):
|
|||
return
|
||||
# Make sure Blender is available
|
||||
command = self._pcb3d.ensure_tool('Blender')
|
||||
if self.render_options.auto_crop:
|
||||
# Avoid a gradient
|
||||
self.render_options.background2 = self.render_options.background1
|
||||
convert_command = self.ensure_tool('ImageMagick')
|
||||
# Create a JSON with the scene information
|
||||
with NamedTemporaryFile(mode='w', suffix='.json') as f:
|
||||
scene = {}
|
||||
|
|
@ -473,6 +522,13 @@ class Blender_ExportOptions(BaseOptions):
|
|||
cmd.append(pcb3d_file)
|
||||
# Execute the command
|
||||
run_command(cmd)
|
||||
if self.render_options.auto_crop:
|
||||
for pov in self.point_of_view:
|
||||
for o in self.outputs:
|
||||
if o.type != 'render':
|
||||
continue
|
||||
name = self.get_output_filename(o, self._parent.output_dir, pov)
|
||||
run_command([convert_command, name, '-trim', '+repage', '-trim', '+repage', name])
|
||||
|
||||
|
||||
@output_class
|
||||
|
|
@ -501,6 +557,25 @@ class Blender_Export(Base3D):
|
|||
files.extend(self.options.pcb3d.list_models())
|
||||
return files
|
||||
|
||||
def get_renderer_options(self):
|
||||
""" Where are the options for this output when used as a 'renderer' """
|
||||
ops = self.options
|
||||
out = next(filter(lambda x: x.type == 'render', ops.outputs), None)
|
||||
res = None
|
||||
if out is not None:
|
||||
if isinstance(ops.pcb3d, str):
|
||||
# We can't configure it
|
||||
out = None
|
||||
else:
|
||||
res = ops.pcb3d
|
||||
res._pov = ops.point_of_view[0]
|
||||
res._out = out
|
||||
return res if out is not None else None
|
||||
|
||||
def get_extension(self):
|
||||
# Used when we are a renderer
|
||||
return 'png'
|
||||
|
||||
@staticmethod
|
||||
def get_conf_examples(name, layers, templates):
|
||||
if not GS.check_tool(name, 'Blender'):
|
||||
|
|
|
|||
|
|
@ -122,23 +122,19 @@ class PresentBoards(Optionable):
|
|||
return self.name, self.comment, self.pcb_file, self.front_image, self.back_image, self.gerbers
|
||||
|
||||
def generate_image(self, back, tmp_name):
|
||||
self.save_renderer_options()
|
||||
options = self._renderer.options
|
||||
options = self._renderer.get_renderer_options()
|
||||
if options is None:
|
||||
raise KiPlotConfigurationError('No suitable renderer ({})'.format(self._renderer))
|
||||
# Memorize the current options
|
||||
options.save_renderer_options()
|
||||
logger.debug('Starting renderer with back: {}, name: {}'.format(back, tmp_name))
|
||||
# Configure it according to our needs
|
||||
options._filters_to_expand = False
|
||||
options.show_components = None if self._renderer_is_pcbdraw else []
|
||||
options.highlight = []
|
||||
options.output = tmp_name
|
||||
options.setup_renderer([], [], back, tmp_name)
|
||||
self._renderer.dir = self._parent._parent.dir
|
||||
self._renderer._done = False
|
||||
if self._renderer_is_pcbdraw:
|
||||
options.add_to_variant = False
|
||||
options.bottom = back
|
||||
else: # render_3D
|
||||
options.view = 'Z' if back else 'z'
|
||||
options._show_all_components = False
|
||||
run_output(self._renderer)
|
||||
self.restore_renderer_options()
|
||||
# Restore the options
|
||||
options.restore_renderer_options()
|
||||
|
||||
def do_compress(self, tmp_name, out):
|
||||
tree = {'name': '_temporal_compress_gerbers',
|
||||
|
|
@ -202,7 +198,6 @@ class PresentBoards(Optionable):
|
|||
format(out, RENDERERS))
|
||||
config_output(out)
|
||||
self._renderer = out
|
||||
self._renderer_is_pcbdraw = out.type == 'pcbdraw'
|
||||
tmp_name = _get_tmp_name(out.get_extension())
|
||||
self.temporals.append(tmp_name)
|
||||
self.generate_image(back, tmp_name)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020-2022 Salvador E. Tropea
|
||||
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
|
||||
# Copyright (c) 2020-2023 Salvador E. Tropea
|
||||
# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial
|
||||
# License: GPL-3.0
|
||||
# Project: KiBot (formerly KiPlot)
|
||||
"""
|
||||
|
|
@ -322,6 +322,29 @@ class PcbDrawOptions(VariantOptions):
|
|||
self._expand_id = 'bottom' if self.bottom else 'top'
|
||||
self._expand_ext = self.format
|
||||
|
||||
def setup_renderer(self, components, active_components, bottom, name):
|
||||
super().setup_renderer(components, active_components)
|
||||
self.add_to_variant = False
|
||||
self.bottom = bottom
|
||||
self.output = name
|
||||
if not self.show_components:
|
||||
self.show_components = None
|
||||
return self.expand_filename_both(name, is_sch=False)
|
||||
|
||||
def save_renderer_options(self):
|
||||
""" Save the current renderer settings """
|
||||
super().save_renderer_options()
|
||||
self.old_bottom = self.bottom
|
||||
self.old_add_to_variant = self.add_to_variant
|
||||
self.old_output = self.output
|
||||
|
||||
def restore_renderer_options(self):
|
||||
""" Restore the renderer settings """
|
||||
super().restore_renderer_options()
|
||||
self.bottom = self.old_bottom
|
||||
self.add_to_variant = self.old_add_to_variant
|
||||
self.output = self.old_output
|
||||
|
||||
def expand_filtered_components(self, components):
|
||||
""" Expands references to filters in show_components """
|
||||
if not components or not self._filters_to_expand:
|
||||
|
|
@ -530,6 +553,10 @@ class PcbDraw(BaseOutput): # noqa: F821
|
|||
files.append(self.options.style)
|
||||
return files
|
||||
|
||||
def get_renderer_options(self):
|
||||
""" Where are the options for this output when used as a 'renderer' """
|
||||
return self.options
|
||||
|
||||
@staticmethod
|
||||
def get_conf_examples(name, layers, templates):
|
||||
outs = []
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2022 Salvador E. Tropea
|
||||
# Copyright (c) 2022 Instituto Nacional de Tecnología Industrial
|
||||
# Copyright (c) 2022-2023 Salvador E. Tropea
|
||||
# Copyright (c) 2022-2023 Instituto Nacional de Tecnología Industrial
|
||||
# License: GPL-3.0
|
||||
# Project: KiBot (formerly KiPlot)
|
||||
"""
|
||||
|
|
@ -82,33 +82,22 @@ class PopulateOptions(VariantOptions):
|
|||
img_dir = os.path.dirname(self._parent.expand_filename(out_dir, self.imgname))
|
||||
return [self._parent.expand_filename(out_dir, self.get_out_file_name()), img_dir]
|
||||
|
||||
def generate_image(self, side, components, active_components, name):
|
||||
options = self._renderer.options
|
||||
def generate_image(self, side, components, active_components, name, options):
|
||||
logger.debug('Starting renderer with side: {}, components: {}, high: {}, image: {}'.
|
||||
format(side, components, active_components, name))
|
||||
# Configure it according to our needs
|
||||
options._filters_to_expand = False
|
||||
options.show_components = [c for c in components if c]
|
||||
if not options.show_components:
|
||||
options.show_components = None if self._renderer_is_pcbdraw else []
|
||||
else:
|
||||
options.show_components = options.solve_kf_filters(options.show_components)
|
||||
options.highlight = options.solve_kf_filters([c for c in active_components if c])
|
||||
options.output = name
|
||||
o_name = options.setup_renderer(components, active_components, side.startswith("back"), name)
|
||||
self._renderer.dir = self._parent.dir
|
||||
self._renderer._done = False
|
||||
if self._renderer_is_pcbdraw:
|
||||
options.add_to_variant = False
|
||||
options.bottom = side.startswith("back")
|
||||
else: # render_3D
|
||||
options.view = 'Z' if side.startswith("back") else 'z'
|
||||
options._show_all_components = False
|
||||
run_output(self._renderer)
|
||||
return options.expand_filename_both(name, is_sch=False)
|
||||
return o_name
|
||||
|
||||
def generate_images(self, dir_name, content):
|
||||
options = self._renderer.get_renderer_options()
|
||||
if options is None:
|
||||
raise KiPlotConfigurationError('No suitable renderer ({})'.format(self._renderer))
|
||||
# Memorize the current options
|
||||
self.save_renderer_options()
|
||||
options.save_renderer_options()
|
||||
dir = os.path.dirname(os.path.join(dir_name, self.imgname))
|
||||
if not os.path.exists(dir):
|
||||
os.makedirs(dir)
|
||||
|
|
@ -119,9 +108,9 @@ class PopulateOptions(VariantOptions):
|
|||
for x in item["steps"]:
|
||||
counter += 1
|
||||
filename = self.imgname.replace('%d', str(counter))
|
||||
x["img"] = self.generate_image(x["side"], x["components"], x["active_components"], filename)
|
||||
x["img"] = self.generate_image(x["side"], x["components"], x["active_components"], filename, options)
|
||||
# Restore the options
|
||||
self.restore_renderer_options()
|
||||
options.restore_renderer_options()
|
||||
return content
|
||||
|
||||
def run(self, dir_name):
|
||||
|
|
@ -140,7 +129,6 @@ class PopulateOptions(VariantOptions):
|
|||
if out.type not in RENDERERS:
|
||||
raise KiPlotConfigurationError('The `renderer` must be {} type, not {}'.format(RENDERERS, out.type))
|
||||
self._renderer = out
|
||||
self._renderer_is_pcbdraw = out.type == 'pcbdraw'
|
||||
# Load the input content
|
||||
try:
|
||||
_, content = load_content(self.input)
|
||||
|
|
|
|||
|
|
@ -176,6 +176,26 @@ class Render3DOptions(Base3DOptionsWithHL):
|
|||
self.view = view
|
||||
self._expand_id += '_'+self._rviews.get(self.view)
|
||||
|
||||
def setup_renderer(self, components, active_components, bottom, name):
|
||||
super().setup_renderer(components, active_components)
|
||||
self.view = 'Z' if bottom else 'z'
|
||||
self.output = name
|
||||
return self.expand_filename_both(name, is_sch=False)
|
||||
|
||||
def save_renderer_options(self):
|
||||
""" Save the current renderer settings """
|
||||
super().save_renderer_options()
|
||||
self.old_show_all_components = self._show_all_components
|
||||
self.old_view = self.view
|
||||
self.old_output = self.output
|
||||
|
||||
def restore_renderer_options(self):
|
||||
""" Restore the renderer settings """
|
||||
super().restore_renderer_options()
|
||||
self._show_all_components = self.old_show_all_components
|
||||
self.view = self.old_view
|
||||
self.output = self.old_output
|
||||
|
||||
def add_step(self, cmd, steps, ops):
|
||||
if steps:
|
||||
cmd.extend([ops, str(steps)])
|
||||
|
|
@ -265,6 +285,10 @@ class Render_3D(Base3D): # noqa: F821
|
|||
""" *[dict] Options for the `render_3d` output """
|
||||
self._category = 'PCB/3D'
|
||||
|
||||
def get_renderer_options(self):
|
||||
""" Where are the options for this output when used as a 'renderer' """
|
||||
return self.options
|
||||
|
||||
@staticmethod
|
||||
def get_conf_examples(name, layers, templates):
|
||||
outs = []
|
||||
|
|
|
|||
|
|
@ -250,17 +250,24 @@ deps = '{\
|
|||
],\
|
||||
"extra_deb": null,\
|
||||
"help_option": "--version",\
|
||||
"importance": 4,\
|
||||
"importance": 5,\
|
||||
"in_debian": true,\
|
||||
"is_kicad_plugin": false,\
|
||||
"is_python": false,\
|
||||
"name": "ImageMagick",\
|
||||
"no_cmd_line_version": false,\
|
||||
"no_cmd_line_version_old": false,\
|
||||
"output": "navigate_results",\
|
||||
"output": "blender_export",\
|
||||
"plugin_dirs": null,\
|
||||
"pypi_name": "ImageMagick",\
|
||||
"roles": [\
|
||||
{\
|
||||
"desc": "Automatically crop images",\
|
||||
"mandatory": false,\
|
||||
"max_version": null,\
|
||||
"output": "blender_export",\
|
||||
"version": null\
|
||||
},\
|
||||
{\
|
||||
"desc": "Create outputs preview",\
|
||||
"mandatory": false,\
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ outputs:
|
|||
mode: local
|
||||
comment: This is a comment
|
||||
name: Light control
|
||||
back_image: Raytraced
|
||||
# back_image: Raytraced
|
||||
back_image: Blender
|
||||
repository: 'https://github.com/INTI-CMNB/KiBot/'
|
||||
|
||||
- name: PcbDraw
|
||||
|
|
@ -37,6 +38,18 @@ outputs:
|
|||
rotate_z: -2
|
||||
ray_tracing: true
|
||||
|
||||
- name: Blender
|
||||
type: blender_export
|
||||
run_by_default: false
|
||||
options:
|
||||
outputs:
|
||||
- type: render
|
||||
render_options:
|
||||
transparent_background: true
|
||||
auto_crop: true
|
||||
# width: 640
|
||||
# height: 480
|
||||
|
||||
- name: 'gerbers'
|
||||
comment: "Gerbers for the Gerber god"
|
||||
type: gerber
|
||||
|
|
|
|||
Loading…
Reference in New Issue