Skip to content
No description, website, or topics provided.
Java GLSL Processing Other
Branch: master
Clone or download
Latest commit 9429fca Sep 25, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.idea
data initial commit Sep 20, 2017
examples
lib frames -> nub Mar 3, 2019
resources Copyright notice updated Sep 22, 2019
src/nub Copyright notice updated Sep 22, 2019
style initial commit Sep 20, 2017
testing
web Shape has gone! Jan 14, 2019
.all-contributorsrc contributors updated Sep 13, 2019
.gitignore Interpolator setFrame() and addkeyFrame made more robust Jan 29, 2018
README.md
detached.md broken links fixed Sep 13, 2019
license.txt initial commit Sep 20, 2017

README.md

nubAll Contributors

Table of Contents

Description

nub is a simple, expressive, language-agnostic, and extensible (2D/3D) scene graph featuring interaction, visualization and animation frameworks and supporting advanced (onscreen/offscreen) rendering techniques, such as view frustum culling.

nub is meant to be coupled with third party real and non-real time renderers. Our current release supports all major Processing desktop renderers: 2D and 3D PGraphicsOpenGL (a.k.a. P2D and P3D, respectively), PGraphicsJava2D (a.k.a. JAVA2D) and PGraphicsFX2D (a.k.a. FX2D).

If looking for the API docs, check them here.

Readers unfamiliar with geometry transformations may first check the great Processing 2D transformations tutorial by J David Eisenberg and this presentation that discusses some related formal foundations.

Scene

Instantiate your on-screen scene at the setup():

Scene scene;
void setup() {
  scene = new Scene(this);
}

The Scene context() corresponds to the PApplet main PGraphics instance.

Off-screen scenes should be instantiated upon a PGraphics object:

Scene scene;
void setup() {
  scene = new Scene(this, createGraphics(500, 500, P3D));
  // or use the equivalent but simpler version:
  // scene = new Scene(this, P3D, 500, 500);
}

In this case, the Scene context() corresponds to the PGraphics instantiated with createGraphics() (which is of course different than the PApplet main PGraphics instance).

Nodes

A node may be translated, rotated and scaled (the order is important) and be rendered when it has a shape. Node instances define each of the nodes comprising a scene graph. To illustrate their use, suppose the following scene graph is being implemented:

 World
  ^
  |\
  1 eye
  ^
  |\
  2 3

To setup the scene hierarchy of attached nodes, i.e., nodes belonging to the scene, use code such as the following:

Scene scene;
Node n1, n2, n3;
void setup() {
  scene = new Scene(this);
  // To attach a leading-node (those whose parent is the world, such as n1)
  // the scene parameter is passed to the Node constructor:
  n1 = new Node(scene);
  // whereas for the remaining nodes we pass any constructor taking a
  // reference node paramater, such as Node(Node referenceNode)
  n2 = new Node(n1) {
    // immediate mode rendering procedure
    // defines n2 visual representation
    @Override
    public void graphics(PGraphics pg) {
      Scene.drawTorusSolenoid(pg);
    }
  };
  // retained-mode rendering PShape
  // defines n3 visual representation
  n3 = new Node(n1, createShape(BOX, 60));
}

Some advantages of using attached nodes are:

Interactivity

To set the scene tracked-node (the node the mouse should interact with) call setTrackedNode(Node) or update it using ray-casting with cast(), for example:

void mouseMoved() {
  // the tracked-node is updated using ray-casting from the set of scene attached nodes
  scene.cast();
}

To interact with a given node use any Scene method that takes a Node parameter, such as: spin(Node), translate(Node) or scale(float, Node) For example:

public void mouseDragged() {
  // spin n1
  if (mouseButton == LEFT)
    scene.spin(n1);
  // translate n3
  else if (mouseButton == RIGHT)
    scene.translate(n3);
  // scale n2
  else
    scene.scale(scene.mouseDX(), n2);
}

To interact with the default-node (which is either the tracked-node updated with the mouseMoved above or the scene eye when the tracked-node is null) use the nodeless versions of the above methods, e.g., spin(), translate() or scale(float). For example:

public void mouseDragged() {
  // spins the default-node (the eye or the node picked with a mouseMoved)
  if (mouseButton == LEFT)
    scene.spin();
  else if (mouseButton == RIGHT)
  // translates the default-node (the eye or the node picked with a mouseMoved)
    scene.translate();
  // scales the default-node (the eye or the node picked with a mouseMoved)
  else
    scene.scale(scene.mouseDX());
}

See the CajasOrientadas example.

Rendering

Render the node hierarchy onto context() with:

void draw() {
  // visits each shape drawing it
  scene.render();
}

observe that:

To bypass the render() algorithm use detached nodes, or cull the node (see cull(boolean) and isCulled()).

Drawing functionality

The Scene implements several static drawing functions that complements those already provided by Processing, such as: drawCylinder(PGraphics, int, float, float), drawHollowCylinder(PGraphics, int, float, float, Vector, Vector), drawCone(PGraphics, int, float, float, float, float), drawCone(PGraphics, int, float, float, float, float, float) and drawTorusSolenoid(PGraphics, int, int, float, float).

Drawing functions that take a PGraphics parameter (including the above static ones), such as beginHUD(PGraphics), endHUD(PGraphics), drawAxes(PGraphics, float), drawCross(PGraphics, float, float, float) and drawGrid(PGraphics) among others, can be used to set a node shape.

Another scene's eye (different than this one) can be drawn with drawEye(Graph). Typical usage include interactive minimaps and visibility culling visualization and debugging.

Interpolators

A node can be animated through a key-frame Catmull-Rom interpolator path. Use code such as the following:

Scene scene;
PShape pshape;
Node shape;
Interpolator interpolator;
void setup() {
  ...
  shape = new Node(scene, pshape);
  interpolator = new Interpolator(shape);
  for (int i = 0; i < random(4, 10); i++)
    interpolator.addKeyFrame(scene.randomNode());
  interpolator.start();
}

which will create a random interpolator path containing [4..10] key-frames. The interpolation is also started. The interpolator path may be drawn with code like this:

...
void draw() {
  scene.render();
  scene.drawPath(interpolator);
}

while render() will draw the animated shape(s) drawPath(Interpolator) will draw the interpolated path too. See the Interpolators example.

HIDs

Setting up a Human Interface Device (hid) (different than the mouse which is provided by default) such as a keyboard or a space-navigator, is a two step process:

  1. Define an hid tracked-node instance, using an arbitrary name for it (see setTrackedNode(String, Node)); and,
  2. Call any interactivity method that take an hid param (such as translate(String, float, float, float), rotate(String, float, float, float) or scale(String, float) following the name convention you defined in 1.

See the SpaceNavigator example.

Observations:

  1. An hid tracked-node (see trackedNode(String)) defines in turn an hid default-node (see defaultNode(String)) which simply returns the tracked-node or the scene eye when the hid tracked-node is null
  2. The hid interactivity methods are implemented in terms of the ones defined previously by simply passing the hid defaultNode(String) to them.
  3. The default hid is defined with a null String parameter (e.g., scale(float) simply calls scale(null, delta)). The Scene default mouse hid presented in the Nodes section is precisely implemented is this manner.
  4. To update an hid tracked-node using ray-casting call track(String, Point, Node[]) (detached or attached nodes), track(String, Point) (only attached nodes) or cast(String, Point) (only for attached nodes too). While track(String, Point, Node[]) and track(String, Point) update the hid tracked-node synchronously (i.e., they return the hid tracked-node immediately), cast(String, Point) updates it asynchronously (i.e., it optimally updates the hid tracked-node during the next call to the render() algorithm).

Control

Application control (aka as Post-WIMP interaction styles) refers to interfaces “containing at least one interaction technique not dependent on classical 2D widgets” [van Dam], such as: tangible interaction, or perceptual and affective computing.

Implementing an application control for a node is a two step process:

  1. Override the node method interact(Object...) to parse the gesture into a custom (application) control.
  2. Send gesture data to the node by calling one of the following scene methods: defaultHIDControl(Object...), control(String, Object...) or control(Node, Object...).

See the ApplicationControl example.

Installation

Import/update it directly from your PDE. Otherwise download your release and extract it to your sketchbook libraries folder.

Contributors

Thanks goes to these wonderful people (emoji key):

Jean Pierre Charalambos
Jean Pierre Charalambos

📝 🐛 💻 🎨 📖 📋 💡 💵 🔍 🤔 📦 🔌 💬 👀 📢 ⚠️ 📹

This project follows the all-contributors specification. Contributions of any kind welcome!

You can’t perform that action at this time.