Skip to content

Commit

Permalink
upgraded blender artists
Browse files Browse the repository at this point in the history
  • Loading branch information
tomvanmele committed Sep 17, 2023
1 parent c6132d7 commit 08e61fd
Show file tree
Hide file tree
Showing 21 changed files with 948 additions and 1,327 deletions.
4 changes: 4 additions & 0 deletions src/compas_blender/artists/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from compas.geometry import Frame
from compas.geometry import Line
from compas.geometry import Point
from compas.geometry import Pointcloud
from compas.geometry import Polygon
from compas.geometry import Polyhedron
from compas.geometry import Polyline
Expand All @@ -36,6 +37,7 @@
from .meshartist import MeshArtist
from .networkartist import NetworkArtist
from .pointartist import PointArtist
from .pointcloudartist import PointcloudArtist
from .polygonartist import PolygonArtist
from .polyhedronartist import PolyhedronArtist
from .polylineartist import PolylineArtist
Expand Down Expand Up @@ -70,6 +72,7 @@ def register_artists():
Artist.register(Mesh, MeshArtist, context="Blender")
Artist.register(Network, NetworkArtist, context="Blender")
Artist.register(Point, PointArtist, context="Blender")
Artist.register(Pointcloud, PointcloudArtist, context="Blender")
Artist.register(Polygon, PolygonArtist, context="Blender")
Artist.register(Polyhedron, PolyhedronArtist, context="Blender")
Artist.register(Polyline, PolylineArtist, context="Blender")
Expand All @@ -95,6 +98,7 @@ def register_artists():
"MeshArtist",
"NetworkArtist",
"PointArtist",
"PointcloudArtist",
"PolygonArtist",
"PolyhedronArtist",
"PolylineArtist",
Expand Down
216 changes: 180 additions & 36 deletions src/compas_blender/artists/artist.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from typing import Union
from typing import Optional
from typing import Any

import bpy # type: ignore
import compas_blender

from compas.colors import Color
from compas.artists import Artist
from compas_blender.conversions import color_to_blender_material

from compas_blender import conversions


class BlenderArtist(Artist):
Expand All @@ -28,70 +27,215 @@ class BlenderArtist(Artist):
"""

def __init__(self, collection: Optional[Union[str, bpy.types.Collection]] = None, **kwargs: Any):
def __init__(self, **kwargs: Any):
# Initialize collection before even calling super because other classes depend on that
self._collection = None
self.collection = collection
super().__init__(**kwargs)
self.objects = []

@property
def collection(self) -> bpy.types.Collection:
return self._collection
# many of the methods below will be added to a general scene object in the future
# to make them universaly accessible they are added here for now

@collection.setter
def collection(self, value: Union[str, bpy.types.Collection]):
if isinstance(value, bpy.types.Collection):
self._collection = value
elif isinstance(value, str):
self._collection = compas_blender.create_collection(value)
else:
raise Exception("Collection must be of type `str` or `bpy.types.Collection`.")
# =============================================================================
# Objects
# =============================================================================

def link_object(self, obj: bpy.types.Object):
"""Link an object to the collection of this artist.
def create_object(self, geometry, name=None):
"""Add an object to the Blender scene.
Parameters
----------
obj : :class:`bpy.types.Object`
The Blender object to link.
geometry : :blender:`bpy.types.Mesh` | :blender:`bpy.types.Curve`
The Blender object data.
name : str, optional
The name of the object.
Returns
-------
:blender:`bpy.types.Object`
The Blender object.
"""
self.unlink_object(obj)
self.collection.objects.link(obj)
obj = bpy.data.objects.new(name, geometry)
self.objects.append(obj)
return obj

def unlink_object(self, obj: bpy.types.Object):
"""Unlink an object from the collection of this artist.
def update_object(self, obj, name=None, color=None, collection=None, transformation=None, show_wire=False):
"""Update an object in the Blender scene.
Parameters
----------
obj : :class:`bpy.types.Object`
The Blender object to unlink.
obj : :blender:`bpy.types.Object`
The Blender object data.
name : str, optional
The name of the object.
color : rgb1 | rgb255 | :class:`compas.colors.Color`, optional
The color specification.
collection : str | :blender:`bpy.types.Collection`, optional
The collection to which the object should be added.
transformation : :class:`compas.geometry.Transformation`, optional
The transformation to apply to the object.
show_wire : bool, optional
Show the wireframe of the object.
Returns
-------
None
"""
for c in obj.users_collection:
c.objects.unlink(obj)
if show_wire:
obj.show_wire = True

if name:
obj.name = name

def assign_object_color(self, obj: bpy.types.Object, color: Color):
"""Assign a color to a Blender object.
self.set_object_tranformation(obj, transformation)
self.add_object_to_collection(obj, collection)
self.set_object_color(obj, color)

def add_object_to_collection(self, obj, name=None, do_unlink=True):
"""Add an object to a collection.
Parameters
----------
obj : :blender:`bpy.types.Object`
The Blender object.
name : str, optional
The name of the collection to which the object should be added.
Returns
-------
:blender:`bpy.types.Collection`
"""
if name:
collection = self.create_collection(name)
else:
collection = bpy.context.scene.collection

if do_unlink:
for c in obj.users_collection:
c.objects.unlink(obj)

collection.objects.link(obj)
return collection

def set_object_color(self, obj, color):
"""Set the color of a Blender object.
Parameters
----------
obj : :class:`bpy.types.Object`
The Blender object.
color : str | tuple, optional
color : rgb1 | rgb255 | :class:`compas.colors.Color`
The color specification.
Returns
-------
:class:`bpy.types.Material`
The Blender color material assigned to the object.
None
"""
material = color_to_blender_material(color)
color = Color.coerce(color)
if not color:
return

material = conversions.color_to_blender_material(color)
obj.color = color.rgba
if obj.data.materials:
obj.data.materials[0] = material
else:
obj.data.materials.append(material)
obj.active_material = material
return material

def set_object_tranformation(self, obj, transformation):
"""Set the transformation of a Blender object.
Parameters
----------
obj : :class:`bpy.types.Object`
The Blender object.
transformation : :class:`compas.geometry.Transformation`
The transformation.
Returns
-------
None
"""
if transformation:
if self.transformation:
transformation = self.transformation * transformation
obj.matrix_world = conversions.transformation_to_blender(transformation)
elif self.transformation:
obj.matrix_world = conversions.transformation_to_blender(self.transformation)

# =============================================================================
# Collections
# =============================================================================

def create_collection(self, name: str) -> bpy.types.Collection:
"""Create a collection with the given name.
Parameters
----------
name : str
The name of the collection.
parent : bpy.types.Collection, optional
A parent collection.
Returns
-------
:blender:`bpy.types.Collection`
"""
parts = name.split("::")
parent = bpy.context.scene.collection
collection = None
for index, name in enumerate(parts):
if index > 0:
name = f"{parent.name}::{name}"
if name not in bpy.data.collections:
collection = bpy.data.collections.new(name)
parent.children.link(collection)
else:
collection = bpy.data.collections[name]
parent = collection
return collection

def clear_collection(self, name: str, include_children: bool = True):
"""Clear the objects in a collection.
Parameters
----------
name : str
The name of the collection to clear.
include_children : bool, optional
Clear the children collections as well.
Returns
-------
None
"""
if name not in bpy.data.collections:
return
compas_blender.clear_collection(name)
if include_children:
collection = bpy.data.collections.get(name)
for child in collection.children:
self.clear_collection(child.name)

def delete_collection(self, name: str):
"""Delete a collection.
Parameters
----------
name : str
The name of the collection to delete.
Returns
-------
None
"""
self.clear_collection(name)
bpy.data.collections.remove(bpy.data.collections[name])
Loading

0 comments on commit 08e61fd

Please sign in to comment.