cadquery-freecad-module/ThirdParty/cqparts/display/material.py

234 lines
6.3 KiB
Python

from ..params import NonNullParameter
# Templates (may be used optionally)
COLOR = {
# primary colours
'red': (255, 0, 0),
'green': (0, 255, 0),
'blue': (0, 0, 255),
'cyan': (0, 255, 255),
'magenta': (255, 0, 255),
'yellow': (255, 255, 0),
# woods
'wood_light': (235, 152, 78),
'wood': (235, 152, 78), # == wood_light
'wood_dark': (169, 50, 38),
# metals
'aluminium': (192, 192, 192),
'aluminum': (192, 192, 192), # == aluminium
'steel': (84, 84, 84),
'steel_blue': (35, 107, 142),
'copper': (184, 115, 51),
'silver': (230, 232, 250),
'gold': (205, 127, 50),
}
TEMPLATE = dict(
(k, {'color': v, 'alpha': 1})
for (k, v) in COLOR.items()
)
TEMPLATE.update({
'default': {'color': COLOR['aluminium'], 'alpha': 1.0},
'glass': {'color': (200, 200, 255), 'alpha': 0.2},
})
# -------------------- Parameter(s) --------------------
class RenderProps(object):
"""
Properties for rendering.
This class provides a :class:`RenderParam` instance
as a :class:`Parameter <cqparts.params.Parameter>` for a
:class:`ParametricObject <cqparts.params.ParametricObject>`.
.. doctest::
>>> from cqparts.params import ParametricObject
>>> from cqparts.display.material import RenderParam, TEMPLATE, COLOR
>>> class Thing(ParametricObject):
... _render = RenderParam(TEMPLATE['red'], doc="render params")
>>> thing = Thing()
>>> thing._render.color
(255, 0, 0)
>>> thing._render.alpha
1.0
>>> thing = Thing(_render={'color': COLOR['green'], 'alpha': 0.5})
>>> thing._render.color
(0, 255, 0)
>>> thing._render.alpha
0.5
>>> thing._render.dict
{'color': (0, 255, 0), 'alpha': 0.5}
The ``TEMPLATE`` and ``COLOR`` dictionaries provide named templates to
display your creations quickly, but you can also provide custom properties.
"""
def __init__(self, color=(200, 200, 200), alpha=1):
"""
:param color: 3-tuple of RGB in the bounds: ``{0 <= val <= 255}``
:type color: :class:`tuple`
:param alpha: object alpha in the range ``{0 <= alpha <= 1}``
where ``0`` is transparent, and ``1`` is opaque
:type alpha: :class:`float`
"""
self.color = tuple(color)
self.alpha = max(0., min(float(alpha), 1.))
@property
def dict(self):
"""
Return a :class:`dict` of this instance.
Can be used to set a property based on the property of another.
:return: dict of render attributes
:rtype: :class:`dict`
"""
return {
'color': self.color,
'alpha': self.alpha,
}
def __hash__(self):
hash(frozenset(self.dict.items()))
def __eq__(self, other):
return self.dict == other.dict
def __ne__(self, other):
return self.dict != other.dict
@property
def transparency(self):
"""
:return: transparency value, 1 is invisible, 0 is opaque
:rtype: :class:`float`
"""
return 1. - self.alpha
@property
def rgb(self):
"""
Red, Green, Blue
:return: red, green, blue values
:rtype: :class:`tuple`
synonym for ``color``
"""
return self.color
@property
def rgba(self):
"""
Red, Green, Blue, Alpha
:return: red, green, blue, alpha values
:rtype: :class:`tuple`
.. doctest::
>>> from cqparts.display import RenderProps
>>> r = RenderProps(color=(1,2,3), alpha=0.2)
>>> r.rgba
(1, 2, 3, 0.2)
"""
return self.color + (self.alpha,)
@property
def rgbt(self):
"""
Red, Green, Blue, Transparency
:return: red, green, blue, transparency values
:rtype: :class:`tuple`
.. doctest::
>>> from cqparts.display import RenderProps
>>> r = RenderProps(color=(1,2,3), alpha=0.2)
>>> r.rgbt
(1, 2, 3, 0.8)
"""
return self.color + (self.transparency,)
@property
def gltf_material(self):
"""
:return: `glTF Material <https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materials>`_
:rtype: :class:`dict`
"""
# There's a lot of room for improvement here
return {
"pbrMetallicRoughness": {
"baseColorFactor": [round(val / 255., 4) for val in self.rgb] + [self.alpha],
"metallicFactor": 0.1,
"roughnessFactor": 0.7,
},
'alphaMode': 'BLEND',
'alphaCutoff': 1.0,
#"name": "red",
}
class RenderParam(NonNullParameter):
_doc_type = "kwargs for :class:`RenderProps <cqparts.display.material.RenderProps>`"
def type(selv, value):
return RenderProps(**value)
# Serialize / Deserialize
@classmethod
def serialize(cls, value):
return value.dict
def render_props(**kwargs):
"""
Return a valid property for cleaner referencing in :class:`Part <cqparts.Part>`
child classes.
:param template: name of template to use (any of ``TEMPLATE.keys()``)
:type template: :class:`str`
:param doc: description of parameter for sphinx docs
:type doc: :class:`str`
:return: render property instance
:rtype: :class:`RenderParam`
.. doctest::
>>> import cadquery
>>> from cqparts.display import render_props
>>> import cqparts
>>> class Box(cqparts.Part):
... # let's make semi-transparent aluminium (it's a thing!)
... _render = render_props(template='aluminium', alpha=0.8)
>>> box = Box()
>>> box._render.rgba
(192, 192, 192, 0.8)
The tools in :mod:`cqparts.display` will use this colour and alpha
information to display the part.
"""
# Pop named args
template = kwargs.pop('template', 'default')
doc = kwargs.pop('doc', "render properties")
params = {}
# Template parameters
if template in TEMPLATE:
params.update(TEMPLATE[template])
# override template with any additional params
params.update(kwargs)
# return parameter instance
return RenderParam(params, doc=doc)