ViewFrustum #
Treegl allows you to visualize the volume that a camera is rendering through a frustum. This frustum shows the position of the screen and the camera, the render distance and the shape it has.
Params #
Name | PropType | description |
---|---|---|
fbo | p5.RendererGL or p5.Graphics | The renderer to be shown by the frustum. |
bits | number | Bitmask to choose which planes to draw. |
viewer | function | Callback that allows to draw a visual representation of the fbo’s position. |
Bitmask #
The bits parameter which planes to show. Even though this param is a number, it works as a Bitmask (Similar chmod’s numerical permissions in GNU/Linux). This bitmask allows different options to be chosen in a sigle parameter. p5.treegl
adds the Tree
object which allows easy access to all the necesary bits to mark different options. Each option is ordered as follows:
Description | Value in Tree | Binary |
---|---|---|
Draws the far plane | Tree.NEAR | 0000001 |
Draws the near plane | Tree.FAR | 0000010 |
Draws the left boundary | Tree.LEFT | 0000100 |
Draws the right boundary | Tree.RIGHT | 0001000 |
Draws the bottom boundary | Tree.BOTTOM | 0010000 |
Draws the top boundary | Tree.TOP | 0100000 |
Draws the frustum’s body | Tree.BODY | 1000000 |
Orthographic Projection #
In orthographic projection, the camera that is rendering the scene does not identify depth. This means that no matter how far away an object is from the camera, it will retain its size. It’s often used for schematics, architectural drawings, 3D software when lining up vertices and mesuring distances as they also remain constant.
Click and drag to move the camera arround!
code #
sketch.js
'use strict';
let fbo1, fbo2;
let cam1, cam2;
let height = 600;
let boxes;
let persp = true;
var left = 300;
var right = 300;
var frustum_width = 200;
var bottom = 300;
var topa = 300;
var frustum_height = 200;
var far = 500;
var viewer = ['axes', 'arrow'];
var gui;
function setup() {
createCanvas(400, 700);
fbo1 = createGraphics(400, 350, WEBGL);
fbo2 = createGraphics(400, 350, WEBGL);
fbo1.ortho(-fbo1.width / 2, fbo1.width / 2, -fbo1.height / 2, fbo1.height / 2, 1, 500);
// FBOs cams
cam1 = new Dw.EasyCam(fbo1._renderer, { distance: 200 });
cam1.setZoomScale(false);
let state1 = cam1.getState();
cam1.attachMouseListeners(this._renderer);
cam1.state_reset = state1; // state to use on reset (double-click/tap)
cam1.setViewport([0, 0, width / 2, height]);
cam2 = new Dw.EasyCam(fbo2._renderer, { rotation: [0.94, 0.33, 0, 0] });
cam2.setZoomScale(false);
cam2.attachMouseListeners(this._renderer);
let state2 = cam2.getState();
cam2.state_reset = state2; // state to use on reset (double-click/tap)
cam2.setViewport([width / 2, 0, width / 2, height]);
document.oncontextmenu = function () {
return false;
};
// scene
colorMode(RGB, 1);
boxes = [];
for (let i = 0; i < 5; i++){
for (let j = 0; j < 5; j++) {
boxes.push({
position: createVector(i * 40 - 70, 0, j * 40 - 70),
size: 20,
color: color(random(), random(), random()),
});
}
}
print(fbo1.bounds());
gui = createGui('Double click to close').setPosition(30, 350);
gui.addGlobals('frustum_width', 'frustum_height', 'far', 'viewer');
}
function draw() {
fbo1.ortho(-frustum_width/2, frustum_width/2, -frustum_height/2, frustum_height/2, 1, far);
fbo1.background(175, 125, 115);
fbo1.reset();
fbo1.axes({ size: 100, bits: Tree.X | Tree.YNEG });
fbo1.grid();
scene(fbo1);
beginHUD();
image(fbo1, 0, 0);
endHUD();
fbo2.background(130);
fbo2.reset();
fbo2.axes();
fbo2.grid();
scene(fbo2);
fbo2.push();
fbo2.strokeWeight(3);
fbo2.stroke('magenta');
fbo2.fill(color(1, 0, 1, 0.3));
let selectedViewer;
if(viewer === 'arrow'){
selectedViewer = () => {
fbo2.push();
fbo2.stroke('#0803FF');
fbo2.arrow({height: 50});
fbo2.pop();
};
} else {
selectedViewer = () => fbo2.axes({ size: 50, bits: Tree.X | Tree._X | Tree.Y | Tree._Y | Tree.Z | Tree._Z });
}
fbo2.viewFrustum({ fbo: fbo1, bits: Tree.NEAR | Tree.FAR, viewer: selectedViewer });
fbo2.pop();
beginHUD();
image(fbo2, 0, 350);
endHUD();
}
function scene(graphics) {
boxes.forEach(box => {
graphics.push();
graphics.fill(box.color);
graphics.translate(box.position);
graphics.box(box.size);
graphics.pop();
});
}
Perspective Projection #
This projection is the most similar to the human eye. In perspective projection, the camera gives a sense of depth. The further away an object is from the camera, the smaller it appears.
Click and drag to move the camera arround!
code #
sketch.js
'use strict';
let fbo1, fbo2;
let cam1, cam2;
let height = 600;
let boxes;
let persp = true;
var far = 500;
var vertical_fov = 100;
var viewer = ['axes', 'arrow'];
var gui;
function setup() {
createCanvas(400, 700);
fbo1 = createGraphics(400, 350, WEBGL);
fbo2 = createGraphics(400, 350, WEBGL);
// FBOs cams
cam1 = new Dw.EasyCam(fbo1._renderer, { distance: 200 });
cam1.setZoomScale(false);
let state1 = cam1.getState();
cam1.attachMouseListeners(this._renderer);
cam1.state_reset = state1; // state to use on reset (double-click/tap)
cam1.setViewport([0, 0, width / 2, height]);
cam2 = new Dw.EasyCam(fbo2._renderer, { rotation: [0.94, 0.33, 0, 0] });
cam2.setZoomScale(false);
cam2.attachMouseListeners(this._renderer);
let state2 = cam2.getState();
cam2.state_reset = state2; // state to use on reset (double-click/tap)
cam2.setViewport([width / 2, 0, width / 2, height]);
document.oncontextmenu = function () {
return false;
};
// scene
colorMode(RGB, 1);
boxes = [];
for (let i = 0; i < 5; i++){
for (let j = 0; j < 5; j++) {
boxes.push({
position: createVector(i * 40 - 70, 0, j * 40 - 70),
size: 20,
color: color(random(), random(), random()),
});
}
}
print(fbo1.bounds());
gui = createGui('Double click to close').setPosition(30, 350);
gui.addGlobals('vertical_fov', 'far', 'viewer');
}
function draw() {
fbo1.perspective(vertical_fov*(PI/3)/100, 1, 10, far);
fbo1.background(175, 125, 115);
fbo1.reset();
fbo1.axes({ size: 100, bits: Tree.X | Tree.YNEG });
fbo1.grid();
scene(fbo1);
beginHUD();
image(fbo1, 0, 0);
endHUD();
fbo2.background(130);
fbo2.reset();
fbo2.axes();
fbo2.grid();
scene(fbo2);
fbo2.push();
fbo2.strokeWeight(3);
fbo2.stroke('magenta');
fbo2.fill(color(1, 0, 1, 0.3));
let selectedViewer;
if(viewer === 'arrow'){
selectedViewer = () => {
fbo2.push();
fbo2.stroke('#0803FF');
fbo2.arrow({height: 50});
fbo2.pop();
};
} else {
selectedViewer = () => fbo2.axes({ size: 50, bits: Tree.X | Tree._X | Tree.Y | Tree._Y | Tree.Z | Tree._Z });
}
fbo2.viewFrustum({ fbo: fbo1, bits: Tree.NEAR | Tree.FAR, viewer: selectedViewer });
fbo2.pop();
beginHUD();
image(fbo2, 0, 350);
endHUD();
}
function scene(graphics) {
boxes.forEach(box => {
graphics.push();
graphics.fill(box.color);
graphics.translate(box.position);
graphics.box(box.size);
graphics.pop();
});
}