Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions .github/workflows/blender_extension.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: blender_extension

# Builds the COMPAS Blender extension packages (one per Blender version range and platform)
# and uploads each package as its own, unzipped workflow artifact.
# Called by the release workflow, which attaches the packages to the GitHub release,
# and run on pull requests that touch the Blender integration.

on:
workflow_call:
workflow_dispatch:
pull_request:
paths:
- "extensions/blender/**"
- "src/compas_blender/**"
- "requirements.txt"
- ".github/workflows/blender_extension.yml"

env:
# Any Blender >= 4.2 can build packages for all supported Blender versions.
BLENDER_VERSION: "5.2.4"

jobs:
build:
name: build (Blender ${{ matrix.blender }}, ${{ matrix.platform }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- { blender: "4.2-5.0", python: "3.11", platform: windows-x64 }
- { blender: "4.2-5.0", python: "3.11", platform: macos-arm64 }
- { blender: "4.2-5.0", python: "3.11", platform: macos-x64 }
- { blender: "4.2-5.0", python: "3.11", platform: linux-x64 }
- { blender: "5.1+", python: "3.13", platform: windows-x64 }
- { blender: "5.1+", python: "3.13", platform: windows-arm64 }
- { blender: "5.1+", python: "3.13", platform: macos-arm64 }
- { blender: "5.1+", python: "3.13", platform: linux-x64 }

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install Blender runtime libraries
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libx11-6 libxi6 libxxf86vm1 libxfixes3 libxrender1 libxkbcommon0 \
libsm6 libice6 libgl1 libegl1

- name: Cache Blender
id: cache-blender
uses: actions/cache@v4
with:
path: ~/blender
key: blender-${{ env.BLENDER_VERSION }}-linux-x64

- name: Download Blender
if: steps.cache-blender.outputs.cache-hit != 'true'
run: |
series="${BLENDER_VERSION%.*}"
curl -sSfL "https://download.blender.org/release/Blender${series}/blender-${BLENDER_VERSION}-linux-x64.tar.xz" | tar -xJ -C ~
mv ~/blender-${BLENDER_VERSION}-linux-x64 ~/blender

- name: Check Blender
run: ~/blender/blender --version

- name: Build extension package
run: python extensions/blender/build.py --blender ~/blender/blender --python ${{ matrix.python }} --platform ${{ matrix.platform }}

# Uploaded unzipped, so the artifact is the extension package itself (named after the file).
- uses: actions/upload-artifact@v7
with:
path: dist/blender/*.zip
archive: false
if-no-files-found: error
retention-days: 14

# Downloads the packages the same way the release workflow does, to catch problems before a release.
check:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v8
with:
pattern: compas-*.zip
path: dist/blender
merge-multiple: true
skip-decompress: true

- name: Check extension packages
run: |
ls -l dist/blender
count=0
for package in dist/blender/*.zip; do
unzip -l "$package" | grep -q " blender_manifest.toml$" || { echo "::error::$package is not an extension package"; exit 1; }
count=$((count + 1))
done
[ "$count" -eq 8 ] || { echo "::error::Expected 8 extension packages, found $count"; exit 1; }
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-24.04, macos-latest, windows-latest] # ubuntu-24.04 is the last image with Python 3.9
python: ["3.9", "3.10", "3.11", "3.12"]

steps:
Expand Down
24 changes: 23 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-24.04, macos-latest, windows-latest] # ubuntu-24.04 is the last image with Python 3.9
python: ["3.9", "3.10", "3.11", "3.12"]

steps:
Expand All @@ -33,3 +33,25 @@ jobs:
gh_source: src/compas_ghpython/components
gh_target: src/compas_ghpython/components/ghuser
release_name_prefix: COMPAS

blender_extension:
needs: build
uses: ./.github/workflows/blender_extension.yml

attach_blender_extension:
needs: [publish, blender_extension]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v8
with:
pattern: compas-*.zip
path: dist/blender
merge-multiple: true
skip-decompress: true

- name: Attach Blender extension packages to the release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release upload "${{ github.ref_name }}" dist/blender/*.zip --repo "${{ github.repository }}" --clobber
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Added `TOL.update()` method for explicit global state modification.
* Added `TOL.temporary()` context manager for scoped changes.
* Added missing implementation of `Brep.to_polygons()` in `compas_rhino.geometry.RhinoBrep`.
* Added COMPAS as a Blender extension (Blender 4.2+), with all dependencies bundled as wheels. Build it with `invoke build-blender-extension`.
* Added `blender_extension` workflow that builds the Blender extension packages and attaches them to GitHub releases.

### Changed

Expand All @@ -26,9 +28,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Changed `angle_vectors` to raise `ValueError` when one of the input vectors is a zero-length vector instead of returning 0.
* Changed `transformation_to_rhino` and `transformation_matrix_to_rhino` to assign the matrix components directly to the fields of `Rhino.Geometry.Transform` instead of looping over its indexer. About 11x faster per conversion, noticable when used inside an animation loop.
* Fixed the parameter names in the docstrings of `Shear.from_entries`, `Polyline.split_by_length` and `trimesh_gradient_numpy`.
* Fixed `compas_blender.redraw` raising `RuntimeError` when Blender runs in background mode.

### Removed

* Removed `compas_blender.install` and `compas_blender.print_python_path`. Install COMPAS in Blender as an extension instead.
* Removed `compas_blender.INSTALLABLE_PACKAGES`, `compas_blender.SUPPORTED_VERSIONS`, `compas_blender.DEFAULT_VERSION` and `compas_blender.INSTALLATION_ARGUMENTS`.
* Removed the `installable_blender_packages` and `after_blender_install` pluggables.


## [2.15.0] 2025-11-12

Expand Down
111 changes: 38 additions & 73 deletions docs/userguide/cad.blender.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,109 +10,74 @@ and :mod:`compas_blender` provides functionality for converting COMPAS objects t

.. note::

These instructions are for the current LTS versions of Blender (3.3, 3.6 and 4.2).
Other versions are currently not supported.

.. warning::

The installation procedure is a work in progress.
It has currently only been tested on macOS, and may change in the future.
COMPAS is distributed as a Blender extension for Blender 4.2 and newer.
Older versions of Blender are not supported.


Installation
============

The installation of COMPAS in Blender can be done in two ways:

* by installing COMPAS in Blender's Python environment using ``pip``, or
* by using the ``compas_blender.install`` command.

Using ``pip`` (recommended)
---------------------------
COMPAS is packaged as a `Blender extension <https://docs.blender.org/manual/en/latest/advanced/extensions/index.html>`_.
The extension is self-contained: it bundles COMPAS and its dependencies (except ``numpy``, which ships with Blender),
so there is no need to install anything into Blender's Python environment manually.

Blender comes with its own Python installation.
This procedure simply uses that Python installation and associated ``pip`` to install COMPAS.
The location of the executable is different on different platforms.
The default locations are:

* Windows: ``C:\Program Files\Blender Foundation\Blender 4.2\4.2\python\bin\python.exe``
* macOS: ``/Applications/Blender.app/Contents/Resources/4.2/python/bin/python3.10``
* Linux: ``/usr/share/blender/4.2/python/bin/python3.10`` (i think :)

.. note::
Blender ships different versions of Python, and some dependencies contain compiled code,
so there is one extension package per Blender version range and operating system:

If you already have an installation of COMPAS on your system, you can try finding the Blender Python executable by running the following in a terminal or command prompt:
========================= =======================================================
Blender Extension package
========================= =======================================================
4.2 to 5.0 ``compas-<version>-blender4.2-<platform>.zip``
5.1 and newer ``compas-<version>-blender5.1-<platform>.zip``
========================= =======================================================

.. code-block:: python
where ``<platform>`` is one of ``windows_x64``, ``windows_arm64`` (Blender 5.1+ only),
``macos_arm64``, ``macos_x64`` (Blender 4.2 to 5.0 only) or ``linux_x64``.

python -m compas_blender.print_python_path
Install from disk
-----------------

Update `pip`
~~~~~~~~~~~~
1. Download the extension package for your Blender version and operating system from the
`COMPAS releases <https://github.com/compas-dev/compas/releases>`_.
2. In Blender, open *Edit > Preferences > Get Extensions*.
3. In the drop-down menu in the top right corner, select *Install from Disk...* and pick the downloaded ``.zip`` file.

Before installing `compas` with `pip`, it is highly recommended that you update `pip` itself.
Alternatively, drag and drop the ``.zip`` file onto the Blender window,
or install it from the command line:

.. code-block:: bash

$ /Applications/Blender.app/Contents/Resources/4.2/python/bin/python3.10 -m pip install --upgrade pip
$ blender --command extension install-file -r user_default -e compas-<version>-blender5.1-macos_arm64.zip

Once the extension is enabled, ``compas`` and ``compas_blender`` can be imported in the Python console,
in scripts in the Text Editor, and from other add-ons.
To update COMPAS, install the package of the newer version in the same way.
To uninstall it, remove the extension from the *Get Extensions* panel.

Install from PyPI
~~~~~~~~~~~~~~~~~
Build from source
-----------------

For example on Mac:

.. code-block:: bash

$ /Applications/Blender.app/Contents/Resources/4.2/python/bin/python3.10 -m pip install compas


Install from Source
~~~~~~~~~~~~~~~~~~~
To build the extension packages from a checkout of the COMPAS repository,
you need a Python environment with ``pip`` and a Blender executable (4.2 or newer):

.. code-block:: bash

$ cd path/to/compas
$ /Applications/Blender.app/Contents/Resources/4.2/python/bin/python3.10 -m pip install -e .


Using ``compas_blender.install``
--------------------------------

.. warning::

This procedure will not install any of the dependencies required by COMPAS.
They have to already be present in the Blender Python environment.

The ``compas_blender.install`` command installs COMPAS in Blender's Python ``site-packages`` folder
by creating symlinks to COMPAS packages installed in an existing (``conda``) environment.
Therefore, before running the command below, you should activate the environment in which you have installed COMPAS.

.. code-block:: bash

$ python -m compas_blender.install

Optionally, you can specify the version of Blender using the ``-v`` flag.

.. code-block:: bash

$ python -m compas_blender.install -v 4.2

To remove all previously installed symlinks before installing new ones, use the ``--clean`` flag.

.. code-block:: bash
$ invoke build-blender-extension --blender /Applications/Blender.app/Contents/MacOS/Blender

$ python -m compas_blender.install --clean
This builds a ``compas`` wheel from the source, downloads the wheels of all dependencies for every supported
platform and Python version, and writes the extension packages to ``dist/blender``.
See ``extensions/blender/build.py`` for more options.


Verification
============

To test if the installation was successful, you can run the following on the Blender command line.
To test if the installation was successful, you can run the following on the Blender Python console.

>>> import compas
>>> print(compas.__version__)
'2.4.0'
'2.15.0'


Visualisation
Expand Down
14 changes: 14 additions & 0 deletions extensions/blender/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# COMPAS Blender extension

Source of the [Blender extension](https://docs.blender.org/manual/en/latest/advanced/extensions/getting_started.html) that distributes COMPAS for Blender 4.2 and newer.

* `addon/` contains the extension source: the add-on `__init__.py` and the source `blender_manifest.toml`.
* `build.py` builds the extension packages into `dist/blender`, one per Blender version range and platform,
bundling the `compas` wheel and all its dependencies (except `numpy`, which ships with Blender).

```bash
invoke build-blender-extension --blender /path/to/blender
```

The manifest `version` is kept in sync by `bump-my-version`; `blender_version_max`, `platforms` and `wheels`
are generated by `build.py` for each build.
41 changes: 41 additions & 0 deletions extensions/blender/addon/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# SPDX-License-Identifier: MIT
"""COMPAS for Blender.

This extension only bundles COMPAS and its dependencies as Python wheels.
Blender installs them into the extensions site-packages folder, so once the
extension is enabled, ``compas`` and ``compas_blender`` can be imported from
any script, the Python console, or other add-ons.
"""

import os

import bpy


class COMPAS_AddonPreferences(bpy.types.AddonPreferences):
bl_idname = __package__

def draw(self, context):
layout = self.layout
try:
import compas
except ImportError as error:
layout.label(text="COMPAS could not be imported: {}".format(error), icon="ERROR")
return

column = layout.column(align=True)
column.label(text="COMPAS {}".format(compas.__version__), icon="CHECKMARK")
column.label(text=os.path.dirname(os.path.dirname(compas.__file__)))


classes = (COMPAS_AddonPreferences,)


def register():
for cls in classes:
bpy.utils.register_class(cls)


def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)
Loading
Loading