Table of Contents
Cam Z-Up is a Java-based library for the creative coding environment Processing. Cam Z-Up flips Processing's default projection so that the positive z axis, (0.0, 0.0, 1.0), is the world up axis; the positive y axis, (0.0, 1.0, 0.0), is forward. The world origin, (0.0, 0.0, 0.0), is placed at the center of a sketch.
This library supports two- and three-dimensional graphics. In 2D, if the camera is imagined to be above the sketch looking down, the positive y axis is forward. If the camera is imagined to be looking from a sideview, the y axis is up.
If you can flip the y axis by either
- supplying -1.0 to scale's y parameter or
- supplying (0.0, -1.0, 0.0) to the final parameters of camera
without negative impact to your sketch, chances are you don't need this library.
While Cam Z-Up can help with more complex sketches, it is a general purpose library. It aims to make a number of small tasks easier than in vanilla Processing. It will not be as effective as specialist libraries.
Cam Z-Up is tested with Processing version 4.x. It's been around for a while, so it was overhauled to use the accepted library template on March 19, 2025, this commit.
For more thorough information, please refer to the documentation included within the distribution. For examples, see the examples directory.
If you're not familiar with git and want to acquire this library from Github,
- Click on the green
Codebutton in the upper right corner of this repository. - Select
Download ZIPto start the download in your browser. - Unzip the download.
- Navigate through the directory
build\libs\until you find ajarfile. - Drag and drop the
jaronto an open Processing sketch.
Cam Z-Up is split into two packages: core and friendly. The friendly package contains code compatible with Processing's API. Inside it, you'll find four graphics renderers:
Yup3, which extendsPGraphicsOpenGL, similar toP3D;Zup3, which also extendsPGraphicsOpenGL;YupJ2, which extendsPGraphicsJava2D, a.k.a.JAVA2D, the default Processing renderer based on the Java AWT library;Yup2, which extendsPGraphicsOpenGL, similar toP2D, a "2.5D" renderer;
The FX2D renderer, based on Java FX, is not distributed with Processing, so it's not supported here. The Yup3 renderer treats the positive y axis, (0.0, 1.0, 0.0), as world up.
This library's core package includes basic utilities that were used to modify the Processing renderer. In this package, you'll find classes such as Vec2, Vec3 and Quaternion. The division between friendly and core is a protective measure. The aim is to retain the library's usefulness even as bugs in friendly, or changes to the underlying Processing library, cause trouble.
With the library installed, you can set up your Processing sketch like so:
// Import the library
import com.behreajj.camzup.friendly.*;
void settings() {
// Supply the renderer's path to size as the
// third argument.
size(128, 128, YupJ2.PATH_STR);
}More experienced coders may wish to use createGraphics and/or getGraphics to access the renderers directly.
import com.behreajj.camzup.core.*;
import com.behreajj.camzup.friendly.*;
YupJ2 graphics;
void settings() {
size(128, 128, YupJ2.PATH_STR);
}
void setup() {
// For OpenGL on Macs.
frameRate(60.0);
// Cast from PGraphics to your renderer.
graphics = (YupJ2)getGraphics();
}Both createGraphics and getGraphics return PGraphics; the result needs to be cast to the specific renderer. The benefit of accessing Cam Z-Up renderers directly, rather than through PApplet, is that the renderers offer additional conveniences. For example, in the following snippet,
graphics.beginDraw();
graphics.background();
graphics.stroke();
graphics.ellipse(new Vec2(), new Vec2(25.0, 25.0));
graphics.endDraw();background and stroke use default colors, while ellipse and image support Vec2 arguments.
Flipping the y axis changes the default rotational direction of a positive angle from clockwise to counter-clockwise.
This can be crucial when working with signed angles, such as those returned from Vec2.headingSigned or Utils.atan2, as it's important to understand the relationship between polar coordinates and the four quadrants of the Cartesian coordinate plane.
Signed angles can be converted to unsigned angles with floor modulo, mod. This should not be confused with truncation modulo, fmod. In Processing's Java mode, % is truncation modulo; in Python mode, % is floor modulo.
Vertex winding is also affected. Below, a piecewise Bezier curve is used to approximate a circle. The central contour uses the opposite (clockwise) vertex winding.
A renderer's vertex winding rule will dictate the fill of contours with the same winding. For more information, see the non-zero and the even-odd rule.
In 3D, the orientation of a spherical coordinate system depends on the up axis. For z-up, the equator of a spherical system rests on the camera's horizon; for y-up, the poles rest on the camera's horizon. The image below shows z-up.
Negative inclinations, in the range [-PI / 2.0, 0.0] will fall beneath the equator; positive inclinations, in the range [0.0, PI / 2.0], will fall above the equator. An inclination of -PI / 2.0 will return the South pole; an inclination of PI / 2.0 will return the North pole. A positive azimuth will head East from the prime meridian; a negative azimuth will head West.
In OpenGL renderers, texture coordinates default to NORMAL textureMode. IMAGE is not supported. This is for three reasons: (1.) the belief that IMAGE is harder, not easier, to understand; (2.) recognition that NORMAL is standard; (3.) methods in PGraphicsOpenGL interfere with textureWrap REPEAT and cannot be overidden by this library. That aside, as per usual, texture coordinates begin at (0.0, 0.0) in the top-left corner and end at (1.0, 1.0) in the bottom-right corner of the image.
I am not versed in color science, nor do I pretend to be. However, vanilla Processing's approach to color can't not be addressed, so I've introduced enough to allow users to get the job done, namely an Rgb and Gradient class. Color is not the central focus of this library and I'm not interested in debating the "correct" way to mix it. Do not use this library for advanced or photorealistic color work.
The Gradient class allows you to create color ramps, including the following:
Viridis and Magma are color palettes used in data visualizations. Sepia and cyanotype replicate older photographic printing processes.
RYB color is included above because popular tutorials on "Color Harmony" (or "Color Theory") often assume a subtractive red-yellow-blue color model, even in the context of digital media. Processing defaults to additive sRGB, where cyan (#00ffff) is the complement of red (#ff0000), not green. This holds regardless of whether you use the HSB or the RGB colorMode.
This RYB wheel's limitations should be apparent from the above. Oranges are dilated while blues are compressed. Brighter greens, cyans and magentas are not achievable. Blues and greens are desaturated. This tutorial on harmonies is one of the better I've found.
A quick heuristic to decide if you are blending colors as you prefer is to take two complementary colors - typically red and green - which you predict will yield an ugly blend and sample them.
Here is a brief list of issues with this library and differences which may be unexpected. Some are unresolved bugs, some arise from the design philosophy of the library.
- Support for high density pixel displays may be lost; I cannot test this at the moment, so please report issues with
image. - The arc implementation has been changed to
modthe start and stop angles. It no longer responds to ellipseMode;RADIUSis the default behavior. When given nonuniform scales, the minimum is taken. - The PShape class has numerous problems stemming from both its implementation and its design. I encourage using
CurveEntityandMeshEntityobjects excepting the case where high poly countPShapeOpenGLs are more performant. - shapeMode is not supported.
- textMode
SHAPEis not supported. However you can retrieve glyph outlines from a PFont with theTextShapeclass from thepfriendlypackage. (Reminder: thePFontneeds to be loaded with createFont). - Color methods no longer promote
ints in[0, 255]to gray colors. Usefloats orRgbobjects instead. - Aside from the default blend, blendMode is no longer supported. The very concept of blending color in gamma-encoded standard RGB is flawed. See instead the
Imgclass, which blends in LAB color space. - The miter and bevel strokeJoin are not supported in the OpenGL-based renderer.
- The
imagefunction forPGraphicsJava2Dis ineffective, both in terms of frame rate and appearance. I recommend that an OpenGL renderer be used instead. Alternatively, rescale images to display size and tint them in a raster image editor. I have made an image function which removes some of the padding around the native renderer's image function in cases where aPImagecan be converted to ajava.awt.Imageinsetup. - As a consequence of how
imagefunction works above, dynamictinting is no longer supported inYupJ2. - Using
YupJ2'srotateorrotateZwill cause shapes with strokes to jitter. CORNERis supported for rectMode,ellipseModeand imageMode. However it is less intuitive with this library. For that reason,CENTERis the default alignment.- OpenGL renderers do not recognize contours in meshes and curves.
- Neither 3D primitive, sphere and box, are supported; use
MeshEntity3s instead. - A
Mesh3material may not have both a fill and a stroke due to flickering in perspective cameras.
Many core Processing functions are marked final, meaning they cannot be extended and modified by classes in this library; many fields are marked private meaning they cannot be accessed and/or mutated. This is the one of the reasons for the limitations above.
null-checks excepted, the goal of this library is not to throw exceptions, but to create. For that reason some liberties have been taken with mathematics.
acosandasinclamp the input value to the range-1.0to1.0so as to avoid exceptions.- As with Python, JavaScript and OSL,
x != 0istrue;trueis1andfalseis0. - Where possible,
Vec2,Vec3andVec4parallel GLSL'sbvec. Examples include:Vec2 c = Vec2.lt(new Vec2(false, true), new Vec2(true, true));andboolean d = Vec2.any(c);. - As with shader languages, I try to protect against divide-by-zero errors when possible. Though mathematically incorrect,
div(x, 0.0) = 0.0; in consequencefmod(x, 0.0)andmod(x, 0.0)returnx. - Unlike GLSL,
fractis defined asx - trunc(x), notx - floor(x). This library refers to the latter asmod1. - The linear interpolation (
lerp) method in this library uses the formula(1.0 - t) * a + t * b, nota + t * (b - a). Processing uses the latter. Furthermore, Processing'slerpis unclamped by default. This library Includes a clamped and unclamped version oflerp; clamped is assumed to be the default. - The step provided to easing functions is always a scalar (a
float). There are nostep,smoothstepandlinearstepfunctions which generate the step to be supplied tomix.mixis, however, is defined in relevant classes. - A quaternion's real component is assumed to be its first element,
{ w, x, y, z }. Its imaginary components are stored in a vector. This is in contrast to other APIs, such as Unity's. - The convention established by Java's
indexOffunction is to return-1when an array or collection does not contain a query. Some collections in this library, particularlyMeshs andCurves, match Pythonic idiom insofar as they accept negative indices togetfunctions. For example,curve.get(-1)will return the lastKnotin a curve, provided that it is aclosedLoop. As a consequence, the reciprocity between Java'sindexOfandgetis broken. For example:curve.get(curve.knots.indexOf(elmNotInCurve)) != elmNotInCurve. For this reason,containsshould always be preferred overindexOf, and no customcontainsmethod should depend onindexOfunlessgets definition is guaranteed. - Between two vectors, the Hadamard product, is the default multiplication associated with the
*operator.
🇹🇼 🇺🇦






