Skip to content
Merged
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
82 changes: 82 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,85 @@ jobs:

- name: Build all applications and run regression tests
run: ./scripts/build-all.sh "${RUNNER_TEMP}/of_v0.12.1_osx_release"


linux-render:
name: Linux Mesa rendering
runs-on: ubuntu-24.04
timeout-minutes: 60
# A clean Jammy package set avoids dependency conflicts with SDKs preinstalled on hosted runners.
container:
image: ubuntu:22.04@sha256:2edbbc5dc405e9612ba3584ce95480277e3eb374407b5505fe26f17df77c7dbc
defaults:
run:
shell: bash

env:
OF_URL: https://github.com/openframeworks/openFrameworks/releases/download/0.12.1/of_v0.12.1_linux64_gcc6_release.tar.gz
OF_SHA256: d6c1dcab777665b2aa63e5e3d9122cc116f096b3421db3493f795a621b399c63
LIBGL_ALWAYS_SOFTWARE: "1"
GALLIUM_DRIVER: llvmpipe
DEBIAN_FRONTEND: noninteractive
TZ: Etc/UTC

steps:
- name: Bootstrap clean Ubuntu container
run: |
apt-get update
apt-get install --yes --no-install-recommends \
ca-certificates curl git sudo zstd lsb-release pkg-config
mkdir -p "${RUNNER_TEMP}/example-captures"
apt-cache policy libunwind-dev libunwind8 libgstreamer1.0-dev \
| tee "${RUNNER_TEMP}/example-captures/dependency-policy.log"
# Install the GStreamer prerequisite explicitly; fail here if package resolution breaks.
apt-get install --yes --no-install-recommends libunwind-dev

- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Cache openFrameworks 0.12.1
id: cache-openframeworks
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ runner.temp }}/of_v0.12.1_linux64_gcc6_release
key: openframeworks-0.12.1-jammy-container-2edbbc5dc405-${{ runner.arch }}-d6c1dcab7776-v1

- name: Download verified openFrameworks release
if: steps.cache-openframeworks.outputs.cache-hit != 'true'
shell: bash
run: |
OF_ARCHIVE="${RUNNER_TEMP}/of_v0.12.1_linux64_gcc6_release.tar.gz"
curl --fail --location --retry 3 --output "$OF_ARCHIVE" "$OF_URL"
echo "$OF_SHA256 $OF_ARCHIVE" | sha256sum --check
tar --extract --gzip --file "$OF_ARCHIVE" --directory "${RUNNER_TEMP}"

- name: Install official Ubuntu dependencies and software OpenGL
shell: bash
run: |
# This installer comes from the checksum-pinned release and supports Ubuntu 22.04.
sudo env DEBIAN_FRONTEND=noninteractive bash \
"${RUNNER_TEMP}/of_v0.12.1_linux64_gcc6_release/scripts/linux/ubuntu/install_dependencies.sh" -y
sudo apt-get install --yes --no-install-recommends xvfb xauth mesa-utils libgl1-mesa-dri

- name: Build all applications and run regression tests
run: ./scripts/build-all.sh "${RUNNER_TEMP}/of_v0.12.1_linux64_gcc6_release"

- name: Render all examples with Mesa OpenGL
shell: bash
run: |
mkdir -p "${RUNNER_TEMP}/example-captures"
xvfb-run --auto-servernum --server-args="-screen 0 1600x1000x24 +extension GLX -nolisten tcp" \
bash -euo pipefail -c '
glxinfo -B | tee "${RUNNER_TEMP}/example-captures/opengl-context.log"
grep -qi llvmpipe "${RUNNER_TEMP}/example-captures/opengl-context.log"
./scripts/smoke-all.sh "${RUNNER_TEMP}/example-captures"
'

- name: Keep rendering evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: openframeworks-rendering
path: ${{ runner.temp }}/example-captures
if-no-files-found: error
retention-days: 7
3 changes: 3 additions & 0 deletions LICENSES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ single combined work.
| `motion-visualization` | [MIT](motion-visualization/LICENSE) | Copyright (c) 2012 Atsushi Tadokoro |
| `marching-cubes` | [MIT](marching-cubes/LICENSE) | Copyright (c) 2012 Atsushi Tadokoro |
| `ofxBvh` | [MIT](ofxBvh/LICENSE) | Copyright (c) 2012 Daito Manabe; originally published under the Perfume Dev Team name |
| `example-motion-ribbons` | [MIT](example-motion-ribbons/LICENSE) | Copyright (c) 2026 Daito Manabe |
| `example-motion-field` | [MIT](example-motion-field/LICENSE) | Copyright (c) 2026 Daito Manabe |
| `shared` | [MIT](shared/LICENSE) | Copyright (c) 2026 Daito Manabe |
| `scripts` | [MIT](scripts/LICENSE) | Copyright (c) 2026 Daito Manabe |
| `tests/ofxBvh-boundary` | [MIT](tests/ofxBvh-boundary/LICENSE) | Copyright (c) 2026 Daito Manabe |
| `third_party/ofxMarchingCubes` | [LGPL-2.1-or-later](third_party/ofxMarchingCubes/LICENSE.txt) | Copyright (c) 2009 Rui Madeira; adapted by Greg Borenstein |
Expand Down
60 changes: 52 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,31 @@

[![Build openFrameworks 0.12.1](https://github.com/perfume-dev/example-openFrameworks/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/perfume-dev/example-openFrameworks/actions/workflows/build.yml)

This repository contains openFrameworks examples created around the 2012
Perfume “Global Site Project.” It is maintained for
[openFrameworks 0.12.1](https://openframeworks.cc/download/), the current
stable release. The original visual character and data formats are preserved
while the application lifecycle, APIs, project files, dependency handling, and
BVH playback safety have been updated.
Motion-capture studies for [openFrameworks 0.12.1](https://openframeworks.cc/download/).
The six examples from the 2012 Perfume “Global Site Project” now use the
programmable OpenGL 3.2 renderer, `ofApp`, member-owned state, and mesh-based
drawing. Two new shader studies turn the bundled motion into luminous ribbons
and animated contour fields.

## Start with the shader studies

| Example | What you see | What you learn |
| --- | --- | --- |
| [Motion Ribbons](example-motion-ribbons) | Fine luminous trails following the dancers | Vertex, geometry, and fragment shaders; expanding a line into a ribbon |
| [Motion Field](example-motion-field) | Contours and halos around moving joints | Passing motion to a full-screen fragment shader |

![Motion Ribbons rendered with its vertex, geometry, and fragment shaders](docs/images/motion-ribbons.png)

![Motion Field rendered with its full-screen fragment shader](docs/images/motion-field.png)

These are actual application captures, not concept images. The studies recenter
horizontal root travel to keep the three dancers legible; they show the recorded
poses rather than reconstructing the original stage formation.

Both use the existing bundled BVH samples and need no external addons or audio
downloads. The [shader guide](docs/shaders.md) explains the rendering stages and
where to start editing. Companion studies are available in the
[Processing repository](https://github.com/perfume-dev/example-processing).

## Stewardship

Expand Down Expand Up @@ -44,6 +63,8 @@ notices.
| `particle-motion-example` | Particle forces driven by tracked joints |
| `motion-visualization` | Long-exposure-style joint trajectories |
| `marching-cubes` | A metaball surface driven by skeletal endpoints |
| `example-motion-ribbons` | Geometry-shader ribbons following the bundled motion |
| `example-motion-field` | A joint-driven fragment-shader contour field |
| `ofxBvh` | The bundled BVH loader and player used by every example |

## Build with openFrameworks 0.12.1
Expand All @@ -60,7 +81,7 @@ cd "$OF_ROOT/apps/myApps/example-openFrameworks"
./scripts/build-all.sh "$OF_ROOT"
```

The script builds all six applications in Release mode and runs the `ofxBvh`
The script builds all eight applications in Release mode and runs the `ofxBvh`
boundary/malformed-input and marching-cubes lifecycle regression tests. An
individual application can be built with, for example:

Expand All @@ -69,6 +90,23 @@ make -C example-bvh Release OF_ROOT="$OF_ROOT"
open example-bvh/bin/example-bvh.app
```

To render every example in a hidden test window and save PNG evidence:

```sh
./scripts/smoke-all.sh /path/to/captures
```

The GitHub workflow builds and runs regression tests on macOS, then independently
builds and renders all eight examples in a clean, digest-pinned Ubuntu 22.04
container with Mesa llvmpipe and Xvfb. The container isolates OF dependencies
from the hosted runner's preinstalled compiler SDKs.
This supplies a real software OpenGL context where hosted macOS runners cannot
provide the required pixel format. The `openframeworks-rendering` artifact contains
screenshots, application logs and the OpenGL context report. Render failures fail
CI; the shader studies are captured at two motion timestamps to check that their
output changes. Local capture also requires a desktop OpenGL context, even though
the test windows stay hidden. The build/capture scripts support macOS and Linux.

The checked-in Xcode projects were regenerated from the openFrameworks 0.12.1
macOS template. They use relative paths and expect the repository layout shown
above. If you put the repository elsewhere, use the Makefiles with an explicit
Expand All @@ -77,7 +115,8 @@ above. If you put the repository elsewhere, use the Makefiles with an explicit
## Motion and audio data

`example-bvh` is ready to run with its bundled `A_test.bvh`, `B_test.bvh`, and
`C_test.bvh` files. The other five applications first look for the historical
`C_test.bvh` files. The two new shader studies read those same files. The other
five historical applications first look for the original
Perfume Global Site assets in each application's `bin/data` directory:

```text
Expand Down Expand Up @@ -106,3 +145,8 @@ the two examples by Atsushi Tadokoro retain their original copyright and MIT
license notices. See [LICENSES.md](LICENSES.md) for the component-by-component
license index; the repository does not apply one blanket license to every
directory.

The maintained example code uses GLM vectors and mesh drawing. `ofxBvh` retains
its older public vector/matrix types so existing addon consumers continue to
compile; its example rendering supports the programmable renderer. The vendored
marching-cubes dependency retains its upstream public interface and attribution.
Binary file added docs/images/motion-field.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/motion-ribbons.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions docs/shaders.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Motion as a shader input

The new studies share a small idea: read motion on the CPU, send a compact set
of positions to the GPU, and let the shader decide how that motion looks.
The BVH data remains the source of the animation.

## Motion Ribbons

Open [`example-motion-ribbons`](../example-motion-ribbons) first if you want to
learn the geometry stage.

1. The app samples joint positions over time and builds line segments.
2. The vertex shader transforms each position.
3. The geometry shader expands a segment into a narrow, camera-facing strip.
4. The fragment shader shapes its soft edge and luminous colour.

This keeps the C++ topology simple. Changing ribbon width or edge falloff does
not require a new BVH parser or a dense CPU-generated tube. Read the example's
README for its controls and shader filenames.

## Motion Field

[`example-motion-field`](../example-motion-field) starts with a full-screen
rectangle. The app projects selected joints and sends their positions to the
fragment shader. Each pixel evaluates its relationship to those moving sources,
producing contour lines and overlapping halos.

Start with the contour spacing, line softness, and colour constants. Keep
expensive work bounded: adding more source joints increases the work for every
pixel, while increasing the window size increases the number of pixels.

## openFrameworks and Processing

| Stage | openFrameworks studies | Processing studies |
| --- | --- | --- |
| Motion sampling | C++ and the bundled `ofxBvh` | Java/PDE and the bundled BVH parser |
| Ribbon topology | Geometry shader expands line segments | The sketch creates a triangle strip |
| Vertex shading | GLSL vertex shader | `PShader` vertex shader |
| Colour and soft edges | GLSL fragment shader | `PShader` fragment shader |
| Contour field | Full-screen fragment shader | Full-screen `PShader` |

Processing's standard `PShader` API exposes vertex and fragment shaders. Its
ribbon study therefore generates the strip in the sketch; it does not require
a custom OpenGL wrapper for a geometry stage. The openFrameworks study uses a
desktop OpenGL 3.2 context and GLSL 150, including a real geometry shader.

These examples target the stable releases checked for this update:
[openFrameworks 0.12.1](https://openframeworks.cc/download/) and
[Processing 4.5.6](https://github.com/processing/processing4/releases/tag/processing-1434-4.5.6).

References: [ofShader](https://openframeworks.cc/documentation/gl/ofShader/) and
[Processing PShader](https://processing.org/reference/PShader).
4 changes: 2 additions & 2 deletions example-bvh/example-bvh.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@
"fileEncoding": "4",
"isa": "PBXFileReference",
"lastKnownFileType": "sourcecode.cpp.h",
"name": "testApp.h",
"name": "ofApp.h",
"sourceTree": "<group>"
},
"4A8C997B-B3CE-4C44-BC3A-FA84012AB644": {
"fileEncoding": "4",
"isa": "PBXFileReference",
"lastKnownFileType": "sourcecode.cpp.cpp",
"name": "testApp.cpp",
"name": "ofApp.cpp",
"sourceTree": "<group>"
},
"524986E5-48D9-40CF-A1DE-1AD77A70D460": {
Expand Down
15 changes: 3 additions & 12 deletions example-bvh/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
#include "ofMain.h"
#include "testApp.h"
#include "ofApp.h"

//========================================================================
int main() {
ofGLWindowSettings settings;
settings.setSize(1024, 768);
settings.setGLVersion(2, 1);
settings.windowMode = OF_WINDOW;

auto window = ofCreateWindow(settings);
ofRunApp(window, std::make_shared<testApp>());
ofRunMainLoop();
int main(int argc, char** argv) {
return example::launch<ofApp>(argc, argv, "example-bvh");
}
27 changes: 27 additions & 0 deletions example-bvh/src/ofApp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "ofApp.h"

void ofApp::setup() {
runtime.setup();
ofBackground(0);
playback.load("example-bvh", true, runtime.isSmokeTest());
camera.setTarget(glm::vec3(0, 80, 0));
camera.setDistance(450);
}

void ofApp::update() {
playback.update(runtime.deltaSeconds());
}

void ofApp::draw() {
ofEnableDepthTest();
ofEnableBlendMode(OF_BLENDMODE_ALPHA);
camera.begin();
for (auto& motion : playback.motions) motion.draw();
camera.end();
ofDisableDepthTest();
if (!playback.ready) {
ofSetColor(255);
ofDrawBitmapString("Unable to load the bundled BVH files.", 20, 30);
}
runtime.finishFrame(playback.ready, "example-bvh", playback.motions.front().getNumJoints() * 48);
}
16 changes: 16 additions & 0 deletions example-bvh/src/ofApp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include "../../shared/ExampleRuntime.h"

class ofApp : public ofBaseApp {
public:
explicit ofApp(const example::RunOptions& options) : runtime(options) {}
void setup() override;
void update() override;
void draw() override;

private:
example::Runtime runtime;
example::MotionPlayback playback;
ofEasyCam camera;
};
Loading