Parte 2 #
- Colisiones y Creacion: Tomando lo creado en los ejercicios anteriores se crea un laberinto sencillo por el cual la esfera pueda desplazarse, se trata de simular fisicas como fuerzas Newtonianas para dar realismo a la aplicacion.
¿Como interactuar con el plano? Para cambiar la inclinacion debe deslizar el mouse presionando el boton de click derecho sobre el Canvas, la esfera puede salirse del plano y del area visible por lo cual puede usar el slider para ajustar el zoom o el boton central del mouse.
CODIGO: Aceleracion
function Ball(P){
this.sphereMoveVector = createVector(0,0,0);
this.acceleration = createVector(0,0,0)
this.sphereRadius = 7;
this.spherePosition = createVector(92.5-38*4.5,38*-1,this.sphereRadius);
this.minVertex = createVector(-P.planeSize.x/2,-P.planeSize.y/2,0);
this.maxVertex = createVector(P.planeSize.x/2,P.planeSize.y/2,0);
this.draw = function(fbo){
fbo.push();
fbo.fill("rgb(0, 0, 0)");
fbo1.noStroke();
fbo.translate(this.spherePosition);
fbo.sphere(this.sphereRadius)
fbo.pop()
}
this.move = function(P, acceleration, factorAcc, isAcelerate){
if(P.planeRotateV.x != 0 || P.planeRotateV.y != 0){
if(isAcelerate){
this.sphereMoveVector.x = (acceleration.x*factorAcc)*isAcelerate;
this.sphereMoveVector.y = (acceleration.y*factorAcc)*isAcelerate;
this.spherePosition.x = (this.sphereMoveVector.x*factorAcc) + this.spherePosition.x
this.spherePosition.y = (this.sphereMoveVector.y*factorAcc) + this.spherePosition.y;
}
else{
this.sphereMoveVector.x = (acceleration.x*factorAcc) + this.sphereMoveVector.x;
this.sphereMoveVector.y = (acceleration.y*factorAcc) + this.sphereMoveVector.y;
this.spherePosition.x = (this.sphereMoveVector.x*factorAcc) + this.spherePosition.x
this.spherePosition.y = (this.sphereMoveVector.y*factorAcc) + this.spherePosition.y;
}
}else if(P.planeRotateV.x == 0 && P.planeRotateV.y == 0){
this.sphereMoveVector = createVector(0,0,0);
this.acceleration = createVector(0,0,0);
}
// if(P.planeRotateV.x != 0 || P.planeRotateV.y != 0){
// B.sphereMoveVector.x = (B.acceleration.x*0.1) + B.sphereMoveVector.x;
// B.sphereMoveVector.y = (B.acceleration.y*0.1) + B.sphereMoveVector.y;
// B.spherePosition.x = (B.sphereMoveVector.x*0.1) + B.spherePosition.x
// B.spherePosition.y = (B.sphereMoveVector.y*0.1) + B.spherePosition.y;
// }else if(P.planeRotateV.x == 0 && P.planeRotateV.y == 0){
// B.sphereMoveVector = createVector(0,0,0);
// B.acceleration = createVector(0,0,0);
// }
}
}
'use strict';
// See:
// https://github.com/processing/p5.js/blob/main/contributor_docs/creating_libraries.md
// https://github.com/processing/p5.js/blob/main/src/core/README.md
// https://github.com/processing/p5.js/blob/main/contributor_docs/webgl_mode_architecture.md
/** @namespace */
var Tree = (function (ext) {
const INFO =
{
LIBRARY: 'p5.treegl',
VERSION: '0.3.0',
HOMEPAGE: 'https://github.com/VisualComputing/p5.treegl'
};
Object.freeze(INFO);
const NONE = 0;
// Axes consts
const X = 1 << 0;
const Y = 1 << 1;
const Z = 1 << 2;
const _X = 1 << 3;
const _Y = 1 << 4;
const _Z = 1 << 5;
const LABELS = 1 << 6;
// grid style
const SOLID = 0;
const DOTS = 1
// bullseye and picking shape
const SQUARE = 0;
const CIRCLE = 1;
// only picking shape
const PROJECTION = 2;
// Frustum consts
const NEAR = 1 << 0;
const FAR = 1 << 1;
const LEFT = 1 << 2;
const RIGHT = 1 << 3;
const BOTTOM = 1 << 4;
const TOP = 1 << 5;
const BODY = 1 << 6;
// visibility
const INVISIBLE = 0;
const VISIBLE = 1;
const SEMIVISIBLE = 2;
// spaces
const WORLD = 'WORLD';
const EYE = 'EYE';
const NDC = 'NDC';
const SCREEN = 'SCREEN';
const MODEL = 'MODEL';
// points
const ORIGIN = [0, 0, 0];
// vectors
const i = [1, 0, 0];
const j = [0, 1, 0];
const k = [0, 0, 1];
const _i = [-1, 0, 0];
const _j = [0, -1, 0];
const _k = [0, 0, -1];
// shaders
// precision
const lowp = 0;
const mediump = 1;
const highp = 2;
// in
const pmvMatrix = 1 << 0;
const pMatrix = 1 << 1;
const mvMatrix = 1 << 2;
const nMatrix = 1 << 3;
// out
const color4 = 1 << 0;
const texcoords2 = 1 << 1;
const normal3 = 1 << 2;
const position2 = 1 << 3;
const position3 = 1 << 4;
ext ??= {};
ext.INFO = INFO;
ext.NONE = NONE;
ext.X = X;
ext.Y = Y;
ext.Z = Z;
ext._X = _X;
ext._Y = _Y;
ext._Z = _Z;
ext.LABELS = LABELS;
ext.SOLID = SOLID;
ext.DOTS = DOTS;
ext.SQUARE = SQUARE;
ext.CIRCLE = CIRCLE;
ext.PROJECTION = PROJECTION;
ext.NEAR = NEAR;
ext.FAR = FAR;
ext.LEFT = LEFT;
ext.RIGHT = RIGHT;
ext.BOTTOM = BOTTOM;
ext.TOP = TOP;
ext.BODY = BODY;
ext.INVISIBLE = INVISIBLE;
ext.VISIBLE = VISIBLE;
ext.SEMIVISIBLE = SEMIVISIBLE;
ext.WORLD = WORLD;
ext.EYE = EYE;
ext.NDC = NDC;
ext.SCREEN = SCREEN;
ext.MODEL = MODEL;
ext.ORIGIN = ORIGIN;
ext.i = i;
ext.j = j;
ext.k = k;
ext._i = _i;
ext._j = _j;
ext._k = _k;
ext.lowp = lowp;
ext.mediump = mediump;
ext.highp = highp;
ext.pmvMatrix = pmvMatrix;
ext.pMatrix = pMatrix;
ext.mvMatrix = mvMatrix;
ext.nMatrix = nMatrix;
ext.color4 = color4;
ext.texcoords2 = texcoords2;
ext.normal3 = normal3;
ext.position2 = position2;
ext.position3 = position3;
return ext;
})(Tree);
(function () {
console.log(Tree.INFO);
// 1. Matrix stuff
p5.Matrix.prototype.mult3 = function (vector) {
if (this.mat3 === undefined) {
console.error('mult3 only works with mat3');
return;
}
return new p5.Vector(this.mat3[0] * vector.x + this.mat3[3] * vector.y + this.mat3[6] * vector.z,
this.mat3[1] * vector.x + this.mat3[4] * vector.y + this.mat3[7] * vector.z,
this.mat3[2] * vector.x + this.mat3[5] * vector.y + this.mat3[8] * vector.z);
};
p5.Matrix.prototype.mult4 = function (vector) {
return new p5.Vector(...this._mult4([vector.x, vector.y, vector.z, 1]));
};
p5.Matrix.prototype._mult4 = function (vec4) {
if (this.mat4 === undefined) {
console.error('_mult4 only works with mat4');
return;
}
return [this.mat4[0] * vec4[0] + this.mat4[4] * vec4[1] + this.mat4[8] * vec4[2] + this.mat4[12] * vec4[3],
this.mat4[1] * vec4[0] + this.mat4[5] * vec4[1] + this.mat4[9] * vec4[2] + this.mat4[13] * vec4[3],
this.mat4[2] * vec4[0] + this.mat4[6] * vec4[1] + this.mat4[10] * vec4[2] + this.mat4[14] * vec4[3],
this.mat4[3] * vec4[0] + this.mat4[7] * vec4[1] + this.mat4[11] * vec4[2] + this.mat4[15] * vec4[3]];
};
p5.prototype.tMatrix = function (matrix) {
return matrix.copy().transpose(matrix);
}
p5.prototype.invMatrix = function (matrix) {
return matrix.copy().invert(matrix);
}
p5.prototype.axbMatrix = function (a, b) {
return a.copy().apply(b);
}
p5.prototype.iMatrix = function () {
return new p5.Matrix();
}
p5.prototype.lMatrix = function () {
return this._renderer.lMatrix(...arguments);
}
// defaults: from: iMatrix, to: eMatrix
p5.RendererGL.prototype.lMatrix = function (
{
from = new p5.Matrix(),
to = this.eMatrix()
} = {}) {
return to.copy().invert(to).apply(from);
}
p5.prototype.dMatrix = function () {
return this._renderer.dMatrix(...arguments);
}
// defaults: from: iMatrix, to: eMatrix
p5.RendererGL.prototype.dMatrix = function (
{
from = new p5.Matrix(),
to = this.eMatrix(),
matrix = from.copy().invert(from).apply(to)
} = {}) {
// Note that this transposes mat4 into mat3
return new p5.Matrix('mat3', [matrix.mat4[0], matrix.mat4[4], matrix.mat4[8],
matrix.mat4[1], matrix.mat4[5], matrix.mat4[9],
matrix.mat4[2], matrix.mat4[6], matrix.mat4[10]]);
}
p5.prototype.pMatrix = function () {
return this._renderer.pMatrix(...arguments);
}
p5.RendererGL.prototype.pMatrix = function () {
return this.uPMatrix.copy();
}
p5.prototype.mvMatrix = function () {
return this._renderer.mvMatrix(...arguments);
}
// defaults when mMatrix is defined: vMatrix: this.vMatrix, mMatrix:
// otherwise it returns a copy of the current mvMatrix
p5.RendererGL.prototype.mvMatrix = function (
{
vMatrix,
mMatrix
} = {}) {
return mMatrix ? (vMatrix ?? this.vMatrix()).copy().apply(mMatrix) : this.uMVMatrix.copy();
}
p5.prototype.mMatrix = function () {
return this._renderer.mMatrix(...arguments);
}
// defaults: eMatrix: this.eMatrix, mvMatrix: this.mvMatrix
p5.RendererGL.prototype.mMatrix = function (
{
eMatrix = this.eMatrix(),
mvMatrix = this.mvMatrix()
} = {}) {
return eMatrix.copy().apply(mvMatrix);
}
p5.prototype.nMatrix = function () {
return this._renderer.nMatrix(...arguments);
}
p5.RendererGL.prototype.nMatrix = function ({
vMatrix,
mMatrix,
mvMatrix = this.mvMatrix({ mMatrix: mMatrix, vMatrix: vMatrix })
} = {}) {
return new p5.Matrix('mat3').inverseTranspose(mvMatrix);
}
// TODO check where to replace vMatrix for:
// this._curCamera.cameraMatrix
p5.prototype.vMatrix = function () {
return this._renderer.vMatrix(...arguments);
}
p5.RendererGL.prototype.vMatrix = function () {
return this._curCamera.vMatrix();
}
p5.Camera.prototype.vMatrix = function () {
return this.cameraMatrix.copy();
}
p5.prototype.eMatrix = function () {
return this._renderer.eMatrix(...arguments);
}
p5.RendererGL.prototype.eMatrix = function () {
return this._curCamera.eMatrix();
}
p5.Camera.prototype.eMatrix = function () {
return this.cameraMatrix.copy().invert(this.cameraMatrix);
}
p5.prototype.pmvMatrix = function () {
return this._renderer.pmvMatrix(...arguments);
}
p5.RendererGL.prototype.pmvMatrix = function (
{
pMatrix = this.uPMatrix,
vMatrix,
mMatrix,
mvMatrix = this.mvMatrix({ mMatrix: mMatrix, vMatrix: vMatrix })
} = {}) {
return pMatrix.copy().apply(mvMatrix);
}
p5.prototype.pvMatrix = function () {
return this._renderer.pvMatrix(...arguments);
}
// defaults: pMatrix: this.pMatrix, vMatrix: this.vMatrix
p5.RendererGL.prototype.pvMatrix = function (
{
pMatrix = this.uPMatrix,
vMatrix = this._curCamera.cameraMatrix
} = {}) {
return pMatrix.copy().apply(vMatrix);
}
p5.prototype.pvInvMatrix = function () {
return this._renderer.pvInvMatrix(...arguments);
}
p5.RendererGL.prototype.pvInvMatrix = function (
{
pMatrix,
vMatrix,
pvMatrix
} = {}) {
let matrix = pvMatrix ? pvMatrix.copy() : this.pvMatrix({ pMatrix: pMatrix, vMatrix: vMatrix });
return matrix.invert(matrix);
}
p5.prototype._isOrtho = function () {
return this._renderer._isOrtho(...arguments);
}
p5.RendererGL.prototype._isOrtho = function () {
return this.uPMatrix._isOrtho();
}
p5.Matrix.prototype._isOrtho = function () {
return this.mat4[15] != 0;
}
p5.prototype.nPlane = function () {
return this._renderer.nPlane(...arguments);
}
p5.RendererGL.prototype.nPlane = function () {
return this.uPMatrix.nPlane();
}
p5.Matrix.prototype.nPlane = function () {
return this.mat4[15] == 0 ? this.mat4[14] / (this.mat4[10] - 1) :
(1 + this.mat4[14]) / this.mat4[10];
}
p5.prototype.fPlane = function () {
return this._renderer.fPlane(...arguments);
}
p5.RendererGL.prototype.fPlane = function () {
return this.uPMatrix.fPlane();
}
p5.Matrix.prototype.fPlane = function () {
return this.mat4[15] == 0 ? this.mat4[14] / (1 + this.mat4[10]) :
(this.mat4[14] - 1) / this.mat4[10];
}
p5.prototype.lPlane = function () {
return this._renderer.lPlane(...arguments);
}
p5.RendererGL.prototype.lPlane = function () {
return this.uPMatrix.lPlane();
}
p5.Matrix.prototype.lPlane = function () {
return this.mat4[15] == 1 ? -(1 + this.mat4[12]) / this.mat4[0] :
this.nPlane() * (this.mat4[8] - 1) / this.mat4[0];
}
p5.prototype.rPlane = function () {
return this._renderer.rPlane(...arguments);
}
p5.RendererGL.prototype.rPlane = function () {
return this.uPMatrix.rPlane();
}
p5.Matrix.prototype.rPlane = function () {
return this.mat4[15] == 1 ? (1 - this.mat4[12]) / this.mat4[0] :
this.nPlane() * (1 + this.mat4[8]) / this.mat4[0];
}
p5.prototype.tPlane = function () {
return this._renderer.tPlane(...arguments);
}
p5.RendererGL.prototype.tPlane = function () {
return this.uPMatrix.tPlane();
}
p5.Matrix.prototype.tPlane = function () {
// note that inverted values are returned if the projection
// matrix was set with @function frustum.
return this.mat4[15] == 1 ? (this.mat4[13] - 1) / this.mat4[5] :
this.nPlane() * (this.mat4[9] - 1) / this.mat4[5];
}
p5.prototype.bPlane = function () {
return this._renderer.bPlane(...arguments);
}
p5.RendererGL.prototype.bPlane = function () {
return this.uPMatrix.bPlane();
}
p5.Matrix.prototype.bPlane = function () {
// note that inverted values are returned if the projection
// matrix was set with @function frustum.
return this.mat4[15] == 1 ? (1 + this.mat4[13]) / this.mat4[5] :
this.nPlane() * (1 + this.mat4[9]) / this.mat4[5];
}
p5.prototype.fov = function () {
return this._renderer.fov(...arguments);
}
p5.RendererGL.prototype.fov = function () {
return this.uPMatrix.fov();
}
p5.Matrix.prototype.fov = function () {
if (this.mat4[15] != 0) {
console.error('fov only works for a perspective projection');
return;
}
return Math.abs(2 * Math.atan(1 / this.mat4[5]));
}
p5.prototype.hfov = function () {
return this._renderer.hfov(...arguments);
}
p5.RendererGL.prototype.hfov = function () {
return this.uPMatrix.hfov();
}
p5.Matrix.prototype.hfov = function () {
if (this.mat4[15] != 0) {
console.error('hfov only works for a perspective projection');
return;
}
return Math.abs(2 * Math.atan(1 / this.mat4[0]));
}
// 2. Space transformations
p5.prototype.beginHUD = function () {
if (this._renderer instanceof p5.RendererGL) {
this._renderer.beginHUD(...arguments);
}
}
p5.RendererGL.prototype.beginHUD = function () {
this.mv = this.mvMatrix();
this.p = this.pMatrix();
this._rendererState = this.push();
let gl = this.drawingContext;
gl.flush();
gl.disable(gl.DEPTH_TEST);
this.resetMatrix();
let z = Number.MAX_VALUE;
this._curCamera.ortho(0, this.width, -this.height, 0, -z, z);
}
p5.prototype.endHUD = function () {
if (this._renderer instanceof p5.RendererGL) {
this._renderer.endHUD(...arguments);
}
}
p5.RendererGL.prototype.endHUD = function () {
let gl = this.drawingContext;
gl.flush();
gl.enable(gl.DEPTH_TEST);
this.pop(this._rendererState);
this.uPMatrix.set(this.p);
this.uMVMatrix.set(this.mv);
}
// 2.1 Points
// NDC stuff needs testing
p5.prototype._map = function () {
return this._renderer._map(...arguments);
}
p5.RendererGL.prototype._map = function (n, start1, stop1, start2, stop2) {
return (n - start1) / (stop1 - start1) * (stop2 - start2) + start2;
}
p5.prototype.treeLocation = function () {
return this._renderer.treeLocation(...arguments);
}
/**
* Converts locations (i.e., points) from one space into another.
* @param {p5.Vector} vector location to be converted.
* @param {p5.Matrix|String} from source space: either a global
* transform matrix or Tree.WORLD, Tree.EYE,
* Tree.SCREEN, Tree.NDC or Tree.MODEL.
* @param {p5.Matrix|String} to target space: either a global
* transform matrix or Tree.WORLD, Tree.EYE,
* Tree.SCREEN, Tree.NDC or Tree.MODEL.
* @param {p5.Matrix} pMatrix projection matrix.
* @param {p5.Matrix} vMatrix view matrix.
* @param {p5.Matrix} pvMatrix projection times view matrix.
* @param {p5.Matrix} pvInvMatrix (projection times view matrix)^-1.
*/
p5.RendererGL.prototype.treeLocation = function () {
return arguments.length === 1 & arguments[0] instanceof Object ? this._treeLocation(Tree.ORIGIN, arguments[0]) :
this._treeLocation(...arguments);
}
p5.prototype._treeLocation = function () {
return this._renderer._treeLocation(...arguments);
}
p5.RendererGL.prototype._treeLocation = function (vector = Tree.ORIGIN,
{
from = Tree.EYE,
to = Tree.WORLD,
pMatrix,
vMatrix,
eMatrix,
pvMatrix,
pvInvMatrix
} = {}) {
if (Array.isArray(vector)) {
vector = new p5.Vector(vector[0] ?? 0, vector[1] ?? 0, vector[2] ?? 0);
}
if (from == Tree.MODEL) {
from = this.mMatrix({ eMatrix: eMatrix });
}
if (to == Tree.MODEL) {
to = this.mMatrix({ eMatrix: eMatrix });
}
if ((from == Tree.WORLD) && (to == Tree.SCREEN)) {
return this._screenLocation({ vector: vector, pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix });
}
if ((from == Tree.SCREEN) && (to == Tree.WORLD)) {
return this._location({ vector: vector, pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix, pvInvMatrix: pvInvMatrix });
}
if (from == Tree.SCREEN && to == Tree.NDC) {
return this._screenToNDCLocation(vector);
}
if (from == Tree.NDC && to == Tree.SCREEN) {
return this._ndcToScreenLocation(vector);
}
if (from == Tree.WORLD && to == Tree.NDC) {
return this._screenToNDCLocation(this._screenLocation({ vector: vector, pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix }));
}
if (from == Tree.NDC && to == Tree.WORLD) {
return this._location({ vector: this._ndcToScreenLocation(vector), pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix, pvInvMatrix: pvInvMatrix });
}
if (from == Tree.NDC && (to instanceof p5.Matrix || to == Tree.EYE)) {
return (to == Tree.EYE ? (vMatrix ?? this.vMatrix()) : to.copy().invert(to)).mult4(this._location({ vector: this._ndcToScreenLocation(vector), pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix, pvInvMatrix: pvInvMatrix }));
}
if ((from instanceof p5.Matrix || from == Tree.EYE) && to == Tree.NDC) {
return this._screenToNDCLocation(this._screenLocation({ vector: (from == Tree.EYE ? (eMatrix ?? this.eMatrix()) : from).mult4(vector), pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix }));
}
if (from == Tree.WORLD && (to instanceof p5.Matrix || to == Tree.EYE)) {
return (to == Tree.EYE ? (vMatrix ?? this.vMatrix()) : to.copy().invert(to)).mult4(vector);
}
if ((from instanceof p5.Matrix || from == Tree.EYE) && to == Tree.WORLD) {
return (from == Tree.EYE ? (eMatrix ?? this.eMatrix()) : from).mult4(vector);
}
if (from instanceof p5.Matrix && to instanceof p5.Matrix) {
return this.lMatrix({ from: from, to: to }).mult4(vector);
}
if (from == Tree.SCREEN && (to instanceof p5.Matrix || to == Tree.EYE)) {
return (to == Tree.EYE ? (vMatrix ?? this.vMatrix()) : to.copy().invert(to)).mult4(this._location({ vector: vector, pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix, pvInvMatrix: pvInvMatrix }));
}
if ((from instanceof p5.Matrix || from == Tree.EYE) && to == Tree.SCREEN) {
return this._screenLocation({ vector: (from == Tree.EYE ? (eMatrix ?? this.eMatrix()) : from).mult4(vector), pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix });
}
console.error('couldn\'t parse your treeLocation query!');
return vector;
}
p5.RendererGL.prototype._ndcToScreenLocation = function (vector) {
return new p5.Vector(this._map(vector.x, -1, 1, 0, this.width),
this._map(vector.y, -1, 1, 0, this.height),
this._map(vector.z, -1, 1, 0, 1));
}
p5.RendererGL.prototype._screenToNDCLocation = function (vector) {
return new p5.Vector(this._map(vector.x, 0, this.width, -1, 1),
this._map(vector.y, 0, this.height, -1, 1),
this._map(vector.z, 0, 1, -1, 1));
}
p5.RendererGL.prototype._screenLocation = function (
{
vector = new p5.Vector(0, 0, 0.5),
pMatrix,
vMatrix,
pvMatrix = this.pvMatrix({ pMatrix: pMatrix, vMatrix: vMatrix })
} = {}) {
let target = pvMatrix._mult4([vector.x, vector.y, vector.z, 1]);
if (target[3] == 0) {
console.error('screenLocation broken. Check your pvMatrix!');
return;
}
let viewport = [0, this.height, this.width, -this.height];
// ndc, but y is inverted
target[0] /= target[3];
target[1] /= target[3];
target[2] /= target[3];
// Map x, y and z to range 0-1
target[0] = target[0] * 0.5 + 0.5;
target[1] = target[1] * 0.5 + 0.5;
target[2] = target[2] * 0.5 + 0.5;
// Map x,y to viewport
target[0] = target[0] * viewport[2] + viewport[0];
target[1] = target[1] * viewport[3] + viewport[1];
return new p5.Vector(target[0], target[1], target[2]);
}
p5.RendererGL.prototype._location = function (
{
vector = new p5.Vector(this.width / 2, this.height / 2, 0.5),
pMatrix,
vMatrix,
pvMatrix,
pvInvMatrix = this.pvInvMatrix({ pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix })
} = {}) {
let viewport = [0, this.height, this.width, -this.height];
let source = [vector.x, vector.y, vector.z, 1];
// Map x and y from window coordinates
source[0] = (source[0] - viewport[0]) / viewport[2];
source[1] = (source[1] - viewport[1]) / viewport[3];
// Map to range -1 to 1
source[0] = source[0] * 2 - 1;
source[1] = source[1] * 2 - 1;
source[2] = source[2] * 2 - 1;
let target = pvInvMatrix._mult4(source);
if (target[3] == 0) {
console.error('location broken. Check your pvInvMatrix!');
return;
}
target[0] /= target[3];
target[1] /= target[3];
target[2] /= target[3];
return new p5.Vector(target[0], target[1], target[2]);
}
// 2.2. Vectors
// NDC stuff needs testing
p5.prototype.treeDisplacement = function () {
return this._renderer.treeDisplacement(...arguments);
}
/**
* Converts displacements (i.e., vectors) from one space into another.
* @param {p5.Vector} vector location to be converted.
* @param {p5.Matrix|String} from source space: either a global
* transform matrix or Tree.WORLD, Tree.EYE,
* Tree.SCREEN, Tree.NDC or Tree.MODEL.
* @param {p5.Matrix|String} to target space: either a global
* transform matrix or Tree.WORLD, Tree.EYE,
* Tree.SCREEN, Tree.NDC or Tree.MODEL.
* @param {p5.Matrix} pMatrix projection matrix.
* @param {p5.Matrix} vMatrix view matrix.
* @param {p5.Matrix} pvMatrix projection times view matrix.
* @param {p5.Matrix} pvInvMatrix (projection times view matrix)^-1.
*/
p5.RendererGL.prototype.treeDisplacement = function () {
return arguments.length === 1 & arguments[0] instanceof Object ? this._treeDisplacement(Tree._k, arguments[0]) :
this._treeDisplacement(...arguments);
}
p5.prototype._treeDisplacement = function () {
return this._renderer._treeDisplacement(...arguments);
}
p5.RendererGL.prototype._treeDisplacement = function (vector = Tree._k,
{
from = Tree.EYE,
to = Tree.WORLD,
vMatrix,
eMatrix,
pMatrix
} = {}) {
if (Array.isArray(vector)) {
vector = new p5.Vector(vector[0] ?? 0, vector[1] ?? 0, vector[2] ?? 0);
}
if (from == Tree.MODEL) {
from = this.mMatrix({ eMatrix: eMatrix });
}
if (to == Tree.MODEL) {
to = this.mMatrix({ eMatrix: eMatrix });
}
if ((from == Tree.WORLD) && (to == Tree.SCREEN)) {
return this._worldToScreenDisplacement(vector, pMatrix);
}
if ((from == Tree.SCREEN) && (to == Tree.WORLD)) {
return this._screenToWorldDisplacement(vector, pMatrix);
}
if (from == Tree.SCREEN && to == Tree.NDC) {
return this._screenToNDCDisplacement(vector);
}
if (from == Tree.NDC && to == Tree.SCREEN) {
return this._ndcToScreenDisplacement(vector);
}
if (from == Tree.WORLD && to == Tree.NDC) {
return this._screenToNDCDisplacement(this._worldToScreenDisplacement(vector, pMatrix));
}
if (from == Tree.NDC && to == Tree.WORLD) {
return this._screenToWorldDisplacement(this._ndcToScreenDisplacement(vector), pMatrix);
}
if (from == Tree.NDC && to == Tree.EYE) {
return this.dMatrix({ matrix: eMatrix ?? this.eMatrix() }).mult3(this._screenToWorldDisplacement(this._ndcToScreenDisplacement(vector), pMatrix));
}
if (from == Tree.EYE && to == Tree.NDC) {
return this._screenToNDCDisplacement(this._worldToScreenDisplacement(this.dMatrix({ matrix: vMatrix ?? this.vMatrix() }).mult3(vector), pMatrix));
}
if (from == Tree.SCREEN && to instanceof p5.Matrix) {
return this.dMatrix({ matrix: to }).mult3(this._screenToWorldDisplacement(vector, pMatrix));
}
if (from instanceof p5.Matrix && to == Tree.SCREEN) {
return this._worldToScreenDisplacement(this.dMatrix({ matrix: from.copy().invert(from) }).mult3(vector), pMatrix);
}
if (from instanceof p5.Matrix && to instanceof p5.Matrix) {
return this.dMatrix({ from: from, to: to }).mult3(vector);
}
// all cases below kept for efficiency but they all may
// be simply expressed in terms of the previous case, by:
// Tree.EYE -> eMatrix()
// Tree.WORLD -> iMatrix()
if (from == Tree.EYE && to == Tree.WORLD) {
return this.dMatrix({ matrix: vMatrix ?? this.vMatrix() }).mult3(vector);
}
if (from == Tree.WORLD && to == Tree.EYE) {
return this.dMatrix({ matrix: eMatrix ?? this.eMatrix() }).mult3(vector);
}
if (from == Tree.EYE && to == Tree.SCREEN) {
return this._worldToScreenDisplacement(this.dMatrix({ matrix: vMatrix ?? this.vMatrix() }).mult3(vector), pMatrix);
}
if (from == Tree.SCREEN && to == Tree.EYE) {
return this.dMatrix({ matrix: eMatrix ?? this.eMatrix() }).mult3(this._screenToWorldDisplacement(vector, pMatrix));
}
if (from == Tree.EYE && to instanceof p5.Matrix) {
return this.dMatrix({ matrix: (vMatrix ?? this.vMatrix()).apply(to) }).mult3(vector);
}
if (from instanceof p5.Matrix && to == Tree.EYE) {
return this.dMatrix({ matrix: from.copy().invert(from).apply(eMatrix ?? this.eMatrix()) }).mult3(vector);
}
if (from == Tree.WORLD && to instanceof p5.Matrix) {
return this.dMatrix({ matrix: to }).mult3(vector);
}
if (from instanceof p5.Matrix && to == Tree.WORLD) {
return this.dMatrix({ matrix: from.copy().invert(from) }).mult3(vector);
}
console.error('couldn\'t parse your treeDisplacement query!');
return vector;
}
p5.RendererGL.prototype._worldToScreenDisplacement = function (vector, pMatrix = this.uPMatrix) {
let eyeVector = this._treeDisplacement(vector, { from: Tree.WORLD, to: Tree.EYE });
let dx = eyeVector.x;
let dy = eyeVector.y;
let perspective = pMatrix.mat4[15] == 0;
if (perspective) {
let position = new p5.Vector();
let k = Math.abs(this._treeLocation(position, { from: Tree.WORLD, to: Tree.EYE }).z * Math.tan(this.fov(pMatrix) / 2));
dx /= 2 * k / this.height;
dy /= 2 * k / this.height;
}
let dz = eyeVector.z;
// sign is inverted
dz /= (pMatrix.nPlane() - pMatrix.fPlane()) / (perspective ? Math.tan(this.fov(pMatrix) / 2) : Math.abs(pMatrix.rPlane() - pMatrix.lPlane()) / this.width);
return new p5.Vector(dx, dy, dz);
}
p5.RendererGL.prototype._screenToWorldDisplacement = function (vector, pMatrix = this.uPMatrix) {
let dx = vector.x;
let dy = vector.y;
// Scale to fit the screen relative vector displacement
let perspective = pMatrix.mat4[15] == 0;
if (perspective) {
let position = new p5.Vector();
let k = Math.abs(this._treeLocation(position, { from: Tree.WORLD, to: Tree.EYE }).z * Math.tan(this.fov(pMatrix) / 2));
dx *= 2 * k / this.height;
dy *= 2 * k / this.height;
}
let dz = vector.z;
dz *= (pMatrix.nPlane() - pMatrix.fPlane()) / (perspective ? Math.tan(this.fov(pMatrix) / 2) : Math.abs(pMatrix.rPlane() - pMatrix.lPlane()) / this.width);
let eyeVector = new p5.Vector(dx, dy, dz);
return this._treeDisplacement(eyeVector, { from: Tree.EYE, to: Tree.WORLD });
}
p5.RendererGL.prototype._ndcToScreenDisplacement = function (vector) {
return new p5.Vector(this.width * vector.x / 2, this.height * vector.y / 2, vector.z / 2);
}
p5.RendererGL.prototype._screenToNDCDisplacement = function (vector) {
return new p5.Vector(2 * vector.x / this.width, 2 * vector.y / this.height, 2 * vector.z);
}
// 3. Shader utilities
p5.prototype.readShader = function (fragFilename, {
precision,
matrices,
varyings
} = {}) {
let shader = new p5.Shader();
this._coupledWith = fragFilename.substring(fragFilename.lastIndexOf('/') + 1);
shader._vertSrc = this.parseVertexShader({ precision: precision, matrices: matrices, varyings: varyings, _specs: false });
this._coupledWith = undefined;
this.loadStrings(
fragFilename,
result => {
shader._fragSrc = result.join('\n')
}
);
return shader;
}
p5.prototype.makeShader = function (fragSrc, {
precision,
matrices,
varyings
} = {}) {
let shader = new p5.Shader();
this._coupledWith = 'the fragment shader provided as param in makeShader()';
shader._vertSrc = this.parseVertexShader({ precision: precision, matrices: matrices, varyings: varyings, _specs: false });
this._coupledWith = undefined;
shader._fragSrc = fragSrc;
return shader;
}
p5.prototype.parseVertexShader = function ({
precision = Tree.mediump,
matrices = Tree.pmvMatrix,
varyings = Tree.color4 | Tree.texcoords2,
_specs = true
} = {}) {
let floatPrecision = `precision ${precision === Tree.highp ? 'highp' : `${precision === Tree.mediump ? 'mediump' : 'lowp'}`} float;`
let color4 = ~(varyings | ~Tree.color4) === 0;
let texcoords2 = ~(varyings | ~Tree.texcoords2) === 0;
let normal3 = ~(varyings | ~Tree.normal3) === 0;
let position2 = ~(varyings | ~Tree.position2) === 0;
let position3 = ~(varyings | ~Tree.position3) === 0;
let pmv = ~(matrices | ~Tree.pmvMatrix) === 0;
let p = ~(matrices | ~Tree.pMatrix) === 0;
let mv = ~(matrices | ~Tree.mvMatrix) === 0;
let n = (~(matrices | ~Tree.nMatrix) === 0) || normal3;
const target = `gl_Position =${pmv ? ' uModelViewProjectionMatrix * ' : `${p && mv ? ' uProjectionMatrix * uModelViewMatrix *' : ''} `}vec4(aPosition, 1.0)`;
let vertexShader = `
${floatPrecision}
attribute vec3 aPosition;
${color4 ? 'attribute vec4 aVertexColor;' : ''}
${texcoords2 ? 'attribute vec2 aTexCoord;' : ''}
${normal3 ? 'attribute vec3 aNormal;' : ''}
${pmv ? 'uniform mat4 uModelViewProjectionMatrix;' : ''}
${p ? 'uniform mat4 uProjectionMatrix;' : ''}
${mv ? 'uniform mat4 uModelViewMatrix;' : ''}
${n ? 'uniform mat3 uNormalMatrix;' : ''}
${color4 ? 'varying vec4 color4;' : ''}
${texcoords2 ? 'varying vec2 texcoords2;' : ''}
${normal3 ? 'varying vec3 normal3;' : ''}
${position2 ? 'varying vec2 position2;' : ''}
${position3 ? 'varying vec3 position3;' : ''}
void main() {
${color4 ? 'color4 = aVertexColor;' : ''}
${texcoords2 ? 'texcoords2 = aTexCoord;' : ''}
${normal3 ? 'normal3 = normalize(uNormalMatrix * aNormal);' : ''}
${position2 ? 'position2 = vec4(aPosition, 1.0).xy;' : ''}
${position3 ? 'position3 = vec4(aPosition, 1.0).xyz;' : ''}
${target};
}
`;
let advice = `
/*
${this._coupledWith ? 'Vertex shader code to be coupled with ' + this._coupledWith : ''}
Generated with treegl version ${Tree.INFO.VERSION}
${_specs ? `
Feel free to copy, paste, edit and save it.
Refer to createShader (https://p5js.org/reference/#/p5/createShader),
loadShader (https://p5js.org/reference/#/p5/loadShader), readShader
and makeShader (https://github.com/VisualComputing/p5.treegl#handling),
for details.` : ''}
*/
`;
let result = advice + vertexShader;
result = result.split(/\r?\n/)
.filter(line => line.trim() !== '')
.join("\n");
console.log(result);
return result;
}
p5.prototype.emitMousePosition = function (shader, uniform = 'u_mouse') {
shader.setUniform(uniform, [this.mouseX * pixelDensity(), (this.height - this.mouseY) * pixelDensity()]);
}
p5.prototype.emitPointerPosition = function () {
this._renderer.emitPointerPosition(...arguments);
}
p5.RendererGL.prototype.emitPointerPosition = function (shader, pointerX, pointerY, uniform = 'u_pointer') {
shader.setUniform(uniform, [pointerX * pixelDensity(), (this.height - pointerY) * pixelDensity()]);
}
p5.prototype.emitResolution = function () {
this._renderer.emitResolution(...arguments);
}
p5.RendererGL.prototype.emitResolution = function (shader, uniform = 'u_resolution') {
shader.setUniform(uniform, [this.width * pixelDensity(), this.height * pixelDensity()]);
}
p5.prototype.emitTexOffset = function (shader, image, uniform = 'u_texoffset') {
shader.setUniform(uniform, [1 / image.width, 1 / image.height]);
}
// 4. Utility functions
p5.prototype.pixelRatio = function () {
return this._renderer.pixelRatio(...arguments);
}
/**
* Returns the world to pixel ratio units at given world location.
* A line of n * pixelRatio(location) world units will be projected
* with a length of n pixels on screen.
* @param {p5.Vector | Array} location world location reference
*/
p5.RendererGL.prototype.pixelRatio = function (location) {
return this._isOrtho() ? Math.abs(this.tPlane() - this.bPlane()) / this.height :
2 * Math.abs((this._treeLocation(location, { from: Tree.WORLD, to: Tree.EYE, vMatrix: this._curCamera.cameraMatrix })).z) * Math.tan(this.fov() / 2) / this.height;
}
p5.prototype.visibility = function () {
return this._renderer.visibility(...arguments);
}
/**
* Returns object visibility (i.e, lies within the eye bounds)
* either Tree.VISIBLE, Tree.INVISIBLE, or Tree.SEMIVISIBLE.
* Object may be either a point, a sphere or an axis-aligned box.
* @param {p5.Vector | Array} corner1 box corner1, use it with corner2.
* @param {p5.Vector | Array} corner2 box corner2, use it with corner1.
* @param {p5.Vector | Array} center sphere (or point) center.
* @param {Number} radius sphere radius.
* @param {Array} bounds frustum equations 6x4 matrix.
*/
p5.RendererGL.prototype.visibility = function ({
corner1,
corner2,
center,
radius,
bounds = this.bounds()
} = {}) {
return center ? radius ? this._ballVisibility(center, radius, bounds) : this._pointVisibility(center, bounds)
: corner1 && corner2 ? this._boxVisibility(corner1, corner2, bounds) : console.error('couldn\'t parse your visibility query!');
}
p5.RendererGL.prototype._pointVisibility = function (point, bounds = this.bounds()) {
for (const key in bounds) {
let d = this.distanceToBound(point, key, bounds);
if (d > 0) {
return Tree.INVISIBLE;
}
if (d === 0) {
return Tree.SEMIVISIBLE;
}
}
return Tree.VISIBLE;
}
p5.RendererGL.prototype._ballVisibility = function (center, radius, bounds = this.bounds()) {
let allInForAllPlanes = true;
for (const key in bounds) {
let d = this.distanceToBound(center, key, bounds);
if (d > radius) {
return Tree.INVISIBLE;
}
if ((d > 0) || (-d < radius)) {
allInForAllPlanes = false;
}
}
if (allInForAllPlanes) {
return Tree.VISIBLE;
}
return Tree.SEMIVISIBLE;
}
p5.RendererGL.prototype._boxVisibility = function (corner1, corner2, bounds = this.bounds()) {
if (Array.isArray(corner1)) {
corner1 = new p5.Vector(corner1[0] ?? 0, corner1[1] ?? 0, corner1[2] ?? 0);
}
if (Array.isArray(corner2)) {
corner2 = new p5.Vector(corner2[0] ?? 0, corner2[1] ?? 0, corner2[2] ?? 0);
}
let allInForAllPlanes = true;
for (const key in bounds) {
let allOut = true;
for (let c = 0; c < 8; ++c) {
let pos = new p5.Vector(((c & 4) != 0) ? corner1.x : corner2.x, ((c & 2) != 0) ? corner1.y : corner2.y,
((c & 1) != 0) ? corner1.z : corner2.z);
if (this.distanceToBound(pos, key, bounds) > 0) {
allInForAllPlanes = false;
}
else {
allOut = false;
}
}
// The eight points are on the outside side of this plane
if (allOut) {
return Tree.INVISIBLE;
}
}
if (allInForAllPlanes) {
return Tree.VISIBLE;
}
// Too conservative, but tangent cases are too expensive to detect
return Tree.SEMIVISIBLE;
}
p5.prototype.bounds = function () {
return this._renderer.bounds(...arguments);
}
/**
* Returns the 6 plane equations of the eye frustum bounds defined
* in the world coordinate system encoded as an object literal
* having 'Tree.LEFT' (left plane), 'Tree.RIGHT' (right plane),
* 'Tree.NEAR' (near plane), 'Tree.FAR' (far plane) 'Tree.TOP'
* (top plane) and 'Tree.BOTTOM' (bottom plane) keys.
* Each key holds a plane equation of the form:
* a*x + b*y + c*z + d = 0, where a, b, c and d are the 4
* keys of each object literal.
*/
p5.RendererGL.prototype.bounds = function () {
let normals = Array(6);
let distances = Array(6);
// Computed once and for all
// TODO experimental: no need to normalize
let pos = this._treeLocation([0, 0, 0], { from: Tree.EYE, to: Tree.WORLD });
let viewDir = this._treeDisplacement([0, 0, -1], { from: Tree.EYE, to: Tree.WORLD });
// same as: let viewDir = this.treeDisplacement();
let up = this._treeDisplacement([0, 1, 0], { from: Tree.EYE, to: Tree.WORLD });
let right = this._treeDisplacement([1, 0, 0], { from: Tree.EYE, to: Tree.WORLD });
let posViewDir = p5.Vector.dot(pos, viewDir);
if (this._isOrtho()) {
normals[0] = p5.Vector.mult(right, -1);
normals[1] = right;
normals[4] = up;
normals[5] = p5.Vector.mult(up, -1);
let wh0 = Math.abs(this.rPlane() - this.lPlane()) / 2;
let wh1 = Math.abs(this.tPlane() - this.bPlane()) / 2;
distances[0] = p5.Vector.dot(p5.Vector.sub(pos, p5.Vector.mult(right, wh0)), normals[0]);
distances[1] = p5.Vector.dot(p5.Vector.add(pos, p5.Vector.mult(right, wh0)), normals[1]);
distances[4] = p5.Vector.dot(p5.Vector.add(pos, p5.Vector.mult(up, wh1)), normals[4]);
distances[5] = p5.Vector.dot(p5.Vector.sub(pos, p5.Vector.mult(up, wh1)), normals[5]);
}
else {
let hhfov = this.hfov() / 2;
let chhfov = Math.cos(hhfov);
let shhfov = Math.sin(hhfov);
normals[0] = p5.Vector.mult(viewDir, -shhfov);
normals[1] = p5.Vector.add(normals[0], p5.Vector.mult(right, chhfov));
normals[0] = p5.Vector.add(normals[0], p5.Vector.mult(right, -chhfov));
normals[2] = p5.Vector.mult(viewDir, -1);
normals[3] = viewDir;
let hfov = this.fov() / 2;
let chfov = Math.cos(hfov);
let shfov = Math.sin(hfov);
normals[4] = p5.Vector.mult(viewDir, -shfov);
normals[5] = p5.Vector.add(normals[4], p5.Vector.mult(up, -chfov));
normals[4] = p5.Vector.add(normals[4], p5.Vector.mult(up, chfov));
for (let i = 0; i < 2; ++i) {
distances[i] = p5.Vector.dot(pos, normals[i]);
}
for (let j = 4; j < 6; ++j) {
distances[j] = p5.Vector.dot(pos, normals[j]);
}
// Natural equations are:
// dist[0,1,4,5] = pos * normal[0,1,4,5];
// dist[2] = (pos + zNear() * viewDir) * normal[2];
// dist[3] = (pos + zFar() * viewDir) * normal[3];
// 2 times less computations using expanded/merged equations. Dir vectors
// are normalized.
let posRightCosHH = chhfov * p5.Vector.dot(pos, right);
distances[0] = -shhfov * posViewDir;
distances[1] = distances[0] + posRightCosHH;
distances[0] = distances[0] - posRightCosHH;
let posUpCosH = chfov * p5.Vector.dot(pos, up);
distances[4] = -shfov * posViewDir;
distances[5] = distances[4] - posUpCosH;
distances[4] = distances[4] + posUpCosH;
}
// Front and far planes are identical for both camera types.
normals[2] = p5.Vector.mult(viewDir, -1);
normals[3] = viewDir;
distances[2] = -posViewDir - this.nPlane();
distances[3] = posViewDir + this.fPlane();
let bounds = {};
bounds[Tree.LEFT] = { a: normals[0].x, b: normals[0].y, c: normals[0].z, d: distances[0] };
bounds[Tree.RIGHT] = { a: normals[1].x, b: normals[1].y, c: normals[1].z, d: distances[1] };
bounds[Tree.NEAR] = { a: normals[2].x, b: normals[2].y, c: normals[2].z, d: distances[2] };
bounds[Tree.FAR] = { a: normals[3].x, b: normals[3].y, c: normals[3].z, d: distances[3] };
bounds[Tree.TOP] = { a: normals[4].x, b: normals[4].y, c: normals[4].z, d: distances[4] };
bounds[Tree.BOTTOM] = { a: normals[5].x, b: normals[5].y, c: normals[5].z, d: distances[5] };
return bounds;
}
p5.prototype.distanceToBound = function () {
return this._renderer.distanceToBound(...arguments);
}
/**
* Returns the signed distance between location and the frustum plane defined
* by bounds and key which may be either Tree.LEFT, Tree.RIGHT, Tree.BOTTOM,
* Tree.TOP, Tree.NEAR or Tree.FAR. The distance is negative if the point lies
* in the planes's bounding halfspace, and positive otherwise.
*/
p5.RendererGL.prototype.distanceToBound = function (location, key, bounds = this.bounds()) {
if (Array.isArray(location)) {
location = new p5.Vector(location[0] ?? 0, location[1] ?? 0, location[2] ?? 0);
}
return p5.Vector.dot(location, new p5.Vector(bounds[key].a, bounds[key].b, bounds[key].c)) - bounds[key].d;
}
p5.prototype.mousePicking = function ({
mMatrix = this.mMatrix(),
x,
y,
size = 50,
shape = Tree.CIRCLE,
eMatrix,
pMatrix,
vMatrix,
pvMatrix
} = {}) {
return this.pointerPicking(this.mouseX, this.mouseY, { mMatrix: mMatrix, x: x, y: y, size: size, shape: shape, eMatrix: eMatrix, pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix });
}
p5.prototype.pointerPicking = function () {
return this._renderer.pointerPicking(...arguments);
}
/**
* Returns true if pointer is close enough to pointerX, pointerY screen location.
* @param {p5.Matrix} mMatrix model space matrix origin to compute (x, y) from.
* @param {Number} x screen x coordinate. Default is width / 2.
* @param {Number} y screen y coordinate. Default is height / 2.
* @param {Number} size bullseye diameter. Default is 50.
* @param {Number} shape either Tree.CIRCLE, Tree.SQUARE or Tree.PROJECTION. Default is Tree.CIRCLE.
*/
p5.RendererGL.prototype.pointerPicking = function (pointerX, pointerY, {
mMatrix = this.mMatrix(),
x,
y,
size = 50,
shape = Tree.CIRCLE,
eMatrix,
pMatrix,
vMatrix,
pvMatrix
} = {}) {
if (!(x && y)) {
let screenLocation = this.treeLocation({ from: mMatrix, to: Tree.SCREEN, pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix });
x = screenLocation.x;
y = screenLocation.y;
size = size / this.pixelRatio(this.treeLocation({ from: mMatrix, to: Tree.WORLD, eMatrix: eMatrix }));
}
// TODO implement webgl picking here using a switch statement: Tree.CIRCLE, Tree.SQUARE, Tree.PROJECTION
let radius = size / 2;
return shape === Tree.CIRCLE ?
Math.sqrt(Math.pow((x - pointerX), 2.0) + Math.pow((y - pointerY), 2.0)) < radius :
((Math.abs(pointerX - x) < radius) && (Math.abs(pointerY - y) < radius));
}
// 5. Drawing stuff
p5.prototype.axes = function () {
this._renderer.axes(...arguments);
};
/**
* Draws axes.
* @param {Number} size size in world units.
* @param {Number} bits bitwise mask that may be composed of Tree.X, Tree._X,
* Tree.Y, Tree._Y, Tree.Z, Tree._Z and Tree.LABELS bits.
*/
p5.RendererGL.prototype.axes = function ({ size = 100, bits = Tree.LABELS | Tree.X | Tree.Y | Tree.Z } = {}) {
this._rendererState = this.push();
if (~(bits | ~Tree.LABELS) === 0) {
const charWidth = size / 40.0;
const charHeight = size / 30.0;
const charShift = 1.04 * size;
// The X
this.stroke(200, 0, 0);
this.line(charShift, charWidth, -charHeight, charShift, -charWidth, charHeight);
this.line(charShift, -charWidth, -charHeight, charShift, charWidth, charHeight);
// The Y
this.stroke(0, 200, 0);
this.line(charWidth, charShift, charHeight, 0.0, charShift, 0.0);
this.line(0.0, charShift, 0.0, -charWidth, charShift, charHeight);
this.line(-charWidth, charShift, charHeight, 0.0, charShift, 0.0);
this.line(0.0, charShift, 0.0, 0.0, charShift, -charHeight);
// The Z
this.stroke(0, 100, 200);
this.line(-charWidth, -charHeight, charShift, charWidth, -charHeight, charShift);
this.line(charWidth, -charHeight, charShift, -charWidth, charHeight, charShift);
this.line(-charWidth, charHeight, charShift, charWidth, charHeight, charShift);
}
// X Axis
this.stroke(200, 0, 0);
if (~(bits | ~Tree.X) === 0) {
this.line(0, 0, 0, size, 0, 0);
}
if (~(bits | ~Tree._X) === 0) {
this.line(0, 0, 0, -size, 0, 0);
}
// Y Axis
this.stroke(0, 200, 0);
if (~(bits | ~Tree.Y) === 0) {
this.line(0, 0, 0, 0, size, 0);
}
if (~(bits | ~Tree._Y) === 0) {
this.line(0, 0, 0, 0, -size, 0);
}
// Z Axis
this.stroke(0, 100, 200);
if (~(bits | ~Tree.Z) === 0) {
this.line(0, 0, 0, 0, 0, size);
}
if (~(bits | ~Tree._Z) === 0) {
this.line(0, 0, 0, 0, 0, -size);
}
this.pop(this._rendererState);
};
p5.prototype.grid = function () {
this._renderer.grid(...arguments);
};
/**
* Draws grid
* @param {Number} size grid size in world units. Default is 100.
* @param {Number} subdivisions number of grid subdivisions. Default is 10.
* @param {Number} style either Tree.DOTS or Tree.SOLID. Default is Tree.DOTS.
*/
p5.RendererGL.prototype.grid = function ({ size = 100, subdivisions = 10, style = Tree.DOTS } = {}) {
this._rendererState = this.push();
if (style === Tree.DOTS) {
let weight = this.curStrokeWeight;
// other useful as well: this.curStrokeColor this.curFillColor
let posi = 0;
let posj = 0;
this.strokeWeight(weight * 2);
this.beginShape(0x0000);
for (let i = 0; i <= subdivisions; ++i) {
posi = size * (2.0 * i / subdivisions - 1.0);
for (let j = 0; j <= subdivisions; ++j) {
posj = size * (2.0 * j / subdivisions - 1.0);
this.vertex(posi, posj, 0);
}
}
this.endShape();
const internalSub = 5;
const subSubdivisions = subdivisions * internalSub;
this.strokeWeight(weight);
this.beginShape(0x0000);
for (let i = 0; i <= subSubdivisions; ++i) {
posi = size * (2.0 * i / subSubdivisions - 1.0);
for (let j = 0; j <= subSubdivisions; ++j) {
posj = size * (2.0 * j / subSubdivisions - 1.0);
if (((i % internalSub) != 0) || ((j % internalSub) != 0))
this.vertex(posi, posj, 0);
}
}
this.endShape();
}
else {
for (let i = 0; i <= subdivisions; ++i) {
const pos = size * (2.0 * i / subdivisions - 1.0);
this.line(pos, -size, 0, pos, +size, 0);
this.line(-size, pos, 0, size, pos, 0);
}
}
this.pop(this._rendererState);
};
p5.prototype.cross = function () {
this._renderer.cross(...arguments);
};
/**
* Draws a cross on the screen.
* @param {p5.Matrix} mMatrix model space matrix origin to compute (x, y) from.
* @param {Number} x screen x coordinate. Default is width / 2.
* @param {Number} y screen y coordinate. Default is height / 2.
* @param {Number} size cross size. Default is 50.
*/
p5.RendererGL.prototype.cross = function ({
mMatrix = this.mMatrix(),
x,
y,
size = 50,
eMatrix,
pMatrix,
vMatrix,
pvMatrix
} = {}) {
if (!(x && y)) {
let screenLocation = this.treeLocation({ from: mMatrix, to: Tree.SCREEN, pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix });
x = screenLocation.x;
y = screenLocation.y;
size = size / this.pixelRatio(this.treeLocation({ from: mMatrix, to: Tree.WORLD, eMatrix: eMatrix }));
}
const half_size = size / 2.0;
this._rendererState = this.push();
this.beginHUD();
this.line(x - half_size, y, x + half_size, y);
this.line(x, y - half_size, x, y + half_size);
this.endHUD();
this.pop(this._rendererState);
};
p5.prototype.bullsEye = function () {
this._renderer.bullsEye(...arguments);
};
/**
* Draws a bulls-eye on the screen.
* @param {p5.Matrix} mMatrix model space matrix origin to compute (x, y) from.
* @param {Number} x screen x coordinate. Default is width / 2.
* @param {Number} y screen y coordinate. Default is height / 2.
* @param {Number} size bullseye diameter. Default is 50.
* @param {Number} shape either Tree.CIRCLE or Tree.SQUARE. Default is Tree.CIRCLE.
*/
p5.RendererGL.prototype.bullsEye = function ({
mMatrix = this.mMatrix(),
x,
y,
size = 50,
shape = Tree.CIRCLE,
eMatrix,
pMatrix,
vMatrix,
pvMatrix
} = {}) {
if (!(x && y)) {
let screenLocation = this.treeLocation({ from: mMatrix, to: Tree.SCREEN, pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix });
x = screenLocation.x;
y = screenLocation.y;
size = size / this.pixelRatio(this.treeLocation({ from: mMatrix, to: Tree.WORLD, eMatrix: eMatrix }));
}
this._rendererState = this.push();
if (shape === Tree.CIRCLE) {
this.beginHUD();
this._circle({ x, y, radius: size / 2 })
this.endHUD();
}
else {
const half_length = size / 2.0;
this.beginHUD();
this.line((x - half_length), (y - half_length) + (0.6 * half_length), (x - half_length), (y - half_length));
this.line((x - half_length), (y - half_length), (x - half_length) + (0.6 * half_length), (y - half_length));
this.line((x + half_length) - (0.6 * half_length), (y - half_length), (x + half_length), (y - half_length));
this.line((x + half_length), (y - half_length), (x + half_length), ((y - half_length) + (0.6 * half_length)));
this.line((x + half_length), ((y + half_length) - (0.6 * half_length)), (x + half_length), (y + half_length));
this.line((x + half_length), (y + half_length), ((x + half_length) - (0.6 * half_length)), (y + half_length));
this.line((x - half_length) + (0.6 * half_length), (y + half_length), (x - half_length), (y + half_length));
this.line((x - half_length), (y + half_length), (x - half_length), ((y + half_length) - (0.6 * half_length)));
this.endHUD();
}
this.cross({ x: x, y: y, size: 0.6 * size });
this.pop(this._rendererState);
};
p5.prototype._circle = function () {
this._renderer._circle(...arguments);
};
p5.RendererGL.prototype._circle = function ({ filled = false, x = this.width / 2, y = this.height / 2, radius = 100, detail = 50 } = {}) {
this._rendererState = this.push();
if (filled) {
this.beginShape(0x0005);
for (let t = 0; t <= detail; t++) {
const x = Math.cos(t * (2 * Math.PI) / detail);
const y = Math.sin(t * (2 * Math.PI) / detail);
this.vertex(0, 0, 0, 0.5, 0.5)
this.vertex(radius * x, radius * y, 0, (x * 0.5) + 0.5, (y * 0.5) + 0.5);
}
this.endShape();
}
else {
this.translate(x, y);
const angle = (2 * Math.PI) / detail;
let lastPosition = { x: radius, y: 0 };
for (let i = 1; i <= detail; i++) {
let position = { x: Math.cos(i * angle) * radius, y: Math.sin(i * angle) * radius };
this.line(lastPosition.x, lastPosition.y, position.x, position.y);
lastPosition = position;
}
}
this.pop(this._rendererState);
};
p5.prototype.viewFrustum = function () {
this._renderer.viewFrustum(...arguments);
};
/**
* Display fbo view frustum.
* @param {p5.RendererGL | p5.Graphics} fbo renderer which viewing frustum is to be displayed.
* @param {Number} bits bitwise view-frustum mask that may be composed of Tree.NEAR, Tree.FAR and Tree.BODY bits.
* @param {Function} viewer callback fbo visual representation.
*/
p5.RendererGL.prototype.viewFrustum = function ({
fbo = _renderer,
bits = Tree.NEAR | Tree.FAR,
viewer = () => this.axes({ size: 50, bits: Tree.X | Tree._X | Tree.Y | Tree._Y | Tree.Z | Tree._Z })
} = {}) {
if (this === fbo) {
console.error('displaying viewFrustum requires an fbo different than this');
return;
}
this._rendererState = this.push();
this.resetMatrix();
this.applyMatrix(...this.vMatrix().mat4);
this.applyMatrix(...fbo.eMatrix().mat4);
fbo._isOrtho() ? this._viewOrtho(fbo, bits, viewer) : this._viewPerspective(fbo, bits, viewer);
this.pop(this._rendererState);
};
p5.RendererGL.prototype._viewOrtho = function (fbo, bits, viewer) {
if (viewer !== Tree.NONE) {
viewer();
}
let l = fbo.lPlane();
let r = fbo.rPlane();
let b = fbo.bPlane();
let t = fbo.tPlane();
let n = fbo.nPlane();
let f = fbo.fPlane();
if (~(bits | ~Tree.FAR) === 0) {
this.beginShape();
this.vertex(r, t, -f, 0, 0);
this.vertex(l, t, -f, 1, 0);
this.vertex(l, b, -f, 1, 1);
this.vertex(r, b, -f, 0, 1);
this.endShape();
}
else {
this.line(r, t, -f, l, t, -f);
this.line(l, t, -f, l, b, -f);
this.line(l, b, -f, r, b, -f);
this.line(r, b, -f, r, t, -f);
}
if (~(bits | ~Tree.BODY) === 0) {
this.beginShape();
this.vertex(l, t, -f);
this.vertex(l, t, -n);
this.vertex(r, t, -n);
this.vertex(r, t, -f);
this.endShape();
this.beginShape();
this.vertex(r, t, -f);
this.vertex(r, t, -n);
this.vertex(r, b, -n);
this.vertex(r, b, -f);
this.endShape();
this.beginShape();
this.vertex(r, b, -f);
this.vertex(r, b, -n);
this.vertex(l, b, -n);
this.vertex(l, b, -f);
this.endShape();
this.beginShape();
this.vertex(l, t, -n);
this.vertex(l, t, -f);
this.vertex(l, b, -f);
this.vertex(l, b, -n);
this.endShape();
}
else {
this.line(r, t, -n, r, t, -f);
this.line(l, t, -n, l, t, -f);
this.line(l, b, -n, l, b, -f);
this.line(r, b, -n, r, b, -f);
}
// TODO implement near plane texture
if (~(bits | ~Tree.NEAR) === 0) {
this.beginShape();
this.vertex(r, t, -n, 0, 0);
this.vertex(l, t, -n, 1, 0);
this.vertex(l, b, -n, 1, 1);
this.vertex(r, b, -n, 0, 1);
this.endShape();
}
else {
this.line(r, t, -n, l, t, -n);
this.line(l, t, -n, l, b, -n);
this.line(l, b, -n, r, b, -n);
this.line(r, b, -n, r, t, -n);
}
};
p5.RendererGL.prototype._viewPerspective = function (fbo, bits, viewer) {
if (viewer !== Tree.NONE) {
viewer();
}
let magnitude = Math.tan(fbo.fov() / 2);
let aspectRatio = fbo.width / fbo.height;
const points = [
{ x: 0, y: 0, z: 0 },
{ x: 0, y: 0, z: 0 },
];
points[0].z = fbo.nPlane();
points[1].z = fbo.fPlane();
points[0].y = points[0].z * magnitude;
points[0].x = points[0].y * aspectRatio;
const ratio = points[1].z / points[0].z;
points[1].y = ratio * points[0].y;
points[1].x = ratio * points[0].x;
if (~(bits | ~Tree.FAR) === 0) {
this.beginShape();
this.vertex(-points[1].x, points[1].y, -points[1].z, 0, 0);
this.vertex(points[1].x, points[1].y, -points[1].z, 1, 0);
this.vertex(points[1].x, -points[1].y, -points[1].z, 0, 1);
this.vertex(-points[1].x, -points[1].y, -points[1].z, 1, 1);
this.endShape();
}
else {
this.line(-points[1].x, points[1].y, -points[1].z, points[1].x, points[1].y, -points[1].z);
this.line(points[1].x, points[1].y, -points[1].z, points[1].x, -points[1].y, -points[1].z);
this.line(points[1].x, -points[1].y, -points[1].z, -points[1].x, -points[1].y, -points[1].z);
this.line(-points[1].x, -points[1].y, -points[1].z, -points[1].x, points[1].y, -points[1].z);
}
if (~(bits | ~Tree.BODY) === 0) {
this.beginShape();
this.vertex(-points[1].x, points[1].y, -points[1].z);
this.vertex(-points[0].x, points[0].y, -points[0].z);
this.vertex(points[0].x, points[0].y, -points[0].z);
this.vertex(points[1].x, points[1].y, -points[1].z);
this.endShape();
this.beginShape();
this.vertex(points[1].x, points[1].y, -points[1].z);
this.vertex(points[0].x, points[0].y, -points[0].z);
this.vertex(points[0].x, -points[0].y, -points[0].z);
this.vertex(points[1].x, -points[1].y, -points[1].z);
this.endShape();
this.beginShape();
this.vertex(points[1].x, -points[1].y, -points[1].z);
this.vertex(points[0].x, -points[0].y, -points[0].z);
this.vertex(-points[0].x, -points[0].y, -points[0].z);
this.vertex(-points[1].x, -points[1].y, -points[1].z);
this.endShape();
this.beginShape();
this.vertex(-points[0].x, points[0].y, -points[0].z);
this.vertex(-points[1].x, points[1].y, -points[1].z);
this.vertex(-points[1].x, -points[1].y, -points[1].z);
this.vertex(-points[0].x, -points[0].y, -points[0].z);
this.endShape();
this.line(0, 0, 0, points[0].x, points[0].y, -points[0].z);
this.line(0, 0, 0, -points[0].x, points[0].y, -points[0].z);
this.line(0, 0, 0, -points[0].x, -points[0].y, -points[0].z);
this.line(0, 0, 0, points[0].x, -points[0].y, -points[0].z);
}
else {
this.line(0, 0, 0, points[1].x, points[1].y, -points[1].z);
this.line(0, 0, 0, -points[1].x, points[1].y, -points[1].z);
this.line(0, 0, 0, -points[1].x, -points[1].y, -points[1].z);
this.line(0, 0, 0, points[1].x, -points[1].y, -points[1].z);
}
// TODO implement near plane texture
// Something along the lines
// this.textureMode(NORMAL);
// this.tint(255, 126); // Apply transparency without changing color
// this.texture(fbo);
// doesn't work since this.texture is not found
if (~(bits | ~Tree.NEAR) === 0) {
this.beginShape();
this.vertex(-points[0].x, points[0].y, -points[0].z, 0, 0);
this.vertex(points[0].x, points[0].y, -points[0].z, 1, 0);
this.vertex(points[0].x, -points[0].y, -points[0].z, 0, 1);
this.vertex(-points[0].x, -points[0].y, -points[0].z, 1, 1);
this.endShape();
}
else {
this.line(-points[0].x, points[0].y, -points[0].z, points[0].x, points[0].y, -points[0].z);
this.line(points[0].x, points[0].y, -points[0].z, points[0].x, -points[0].y, -points[0].z);
this.line(points[0].x, -points[0].y, -points[0].z, -points[0].x, -points[0].y, -points[0].z);
this.line(-points[0].x, -points[0].y, -points[0].z, -points[0].x, points[0].y, -points[0].z);
}
};
})();
function Plane(){
this.planeMaxMagR = 25;
this.planeColor = "rgb(255, 247, 233)";
this.planeMagnitudeR = 0;
this.planeRotateV = createVector(1,0,0);
this.planeSize = createVector(200,200,0); //ancho y alto
this.planePosition = createVector(0,0,0);
this.draw = function(fbo){
fbo.fill(this.planeColor);
fbo.translate(this.planePosition);
fbo.plane(this.planeSize.x,this.planeSize.y)
};
}
class Wall {
constructor(originX,originY,originZ,width,height,depth, fillColor){
this.fillColor = fillColor
this.origin = createVector(originX,originY,originZ)
this.width = width
this.height = height
this.depth = depth
this.wallMax = createVector(originX+ width/2, originY+ height/2, originZ+ depth/2)
this.wallMin = createVector(originX-width/2, originY-height/2, originZ - depth/2)
}
draw(fbo){
fbo.push()
//fbo.line(this.wallMin.x,this.wallMin.y,this.wallMin.z,this.wallMax.x,this.wallMax.y,this.wallMax.z)
fbo.fill(this.fillColor)
fbo.translate(this.origin.x,this.origin.y,this.origin.z)
fbo.box(this.width, this.height,this.depth)
fbo.pop()
};
closestPointSphere(B) {
// get box closest point to sphere center by clamping
const x = Math.max(this.wallMin.x, Math.min(B.spherePosition.x, this.wallMax.x));
const y = Math.max(this.wallMin.y, Math.min(B.spherePosition.y, this.wallMax.y));
const z = Math.max(this.wallMin.z, Math.min(B.spherePosition.z, this.wallMax.z));
// this is the same as isPointInsidespherePosition
return createVector(x,y,z);
}
isPointInside(point) {
return (
point.x >= this.wallMin.x &&
point.x <= this.wallMax.x &&
point.y >= this.wallMin.y &&
point.y <= this.wallMax.y &&
point.z >= this.wallMin.z &&
point.z <= this.wallMax.z
);
}
collisionWithSphere(B){
let cPoint = this.closestPointSphere(B)
const distance = Math.sqrt(
(cPoint.x - B.spherePosition.x) * (cPoint.x - B.spherePosition.x) +
(cPoint.y - B.spherePosition.y) * (cPoint.y - B.spherePosition.y) +
(cPoint.z - B.spherePosition.z) * (cPoint.z - B.spherePosition.z)
);
let sine = sqrt(1-sq(B.acceleration.z));
let cPointBouncing = undefined
if(distance<B.sphereRadius){
let cPointM = getVectorModule(cPoint)
let cPointDir = createVector(cPoint.x/cPointM,cPoint.y/cPointM,cPoint.z/cPointM)
cPointBouncing = createVector(sine*cPointDir.x,-sine*cPointDir.y,cPointDir.z)
//ajustar
let testVec = createVector(cPointBouncing.x +cPoint.x,cPointBouncing.y +cPoint.y, cPointBouncing.z +cPoint.z)
if(this.isPointInside(testVec)){
cPointBouncing = createVector(-sine*cPointDir.x,sine*cPointDir.y,cPointDir.z)
}
}
return cPointBouncing
}
}
let fbo1, cam1, fovy
let P,B
let mouseInitialV,mouseCurrentV
let box
let boxMax
let boxMin
let vectorCollision
let wallsData
let Walls
let startData
let finishData
let startBox
let finishBox
let startTime
let endTime
let textTime
let isGameStarted
let isGameEnd
function setup() {
createCanvas(200, 200);
initState()
var resetBtn = createButton("Reinicio")
resetBtn.position(0, 10);
resetBtn.mousePressed(initState)
}
function draw() {
if(!isGameEnd){
fbo1.background(120, 125, 115);
fbo1.reset();
fbo1.perspective(PI/2.5);
fbo1.rotate((PI/180)*P.planeMagnitudeR, P.planeRotateV);
fbo1.strokeWeight(0.5)
P.draw(fbo1);
B.draw(fbo1);
//Inicio y final:
startBox.draw(fbo1)
finishBox.draw(fbo1)
if(finishBox.collisionWithSphere(B) && isGameStarted){
isGameEnd = true
textTime.style("background-color","green", "color", "white")
textTime.style("color", "white")
}
if(!startBox.collisionWithSphere(B) && !isGameStarted){
isGameStarted = true
startTime = second()
}
if(isGameStarted){
endTime = second() - startTime
textTime.html("Tiempo: "+ endTime + "s")
}
drawListObjects(Walls, fbo1)
// movimiento de la esfera
vectorCollision = createVector(B.acceleration.x*B.sphereRadius+B.spherePosition.x, B.acceleration.y*B.sphereRadius+B.spherePosition.y,0)
// fbo1.push()
// fbo1.translate(vectorCollision.x,vectorCollision.y,vectorCollision.z)
// fbo1.fill("red")
// fbo1.sphere(5)
// fbo1.pop()
//console.log(vectorCollision.x);
//Colisión con la pared
let collisionV = collisionWalls(Walls, B)
if(collisionV){
console.log("Colisiones", collisionWalls(Walls,B), B.acceleration)
currentAccMod = getVectorModule(B.acceleration)
//collisionV = createVector(B.acceleration.x, B.acceleration.y, B.acceleration.z)
console.log(getVectorModule(B.acceleration), getVectorModule(collisionV));
B.move(P,collisionV, 0.6,true)
}
else{
console.log("Normal", B.acceleration)
B.move(P, B.acceleration, 0.1, false)
// if(P.planeRotateV.x != 0 || P.planeRotateV.y != 0){
// B.sphereMoveVector.x = (B.acceleration.x*0.1) + B.sphereMoveVector.x;
// B.sphereMoveVector.y = (B.acceleration.y*0.1) + B.sphereMoveVector.y;
// B.spherePosition.x = (B.sphereMoveVector.x*0.1) + B.spherePosition.x
// B.spherePosition.y = (B.sphereMoveVector.y*0.1) + B.spherePosition.y;
// }else if(P.planeRotateV.x == 0 && P.planeRotateV.y == 0){
// B.sphereMoveVector = createVector(0,0,0);
// B.acceleration = createVector(0,0,0);
// }
}
//Colisión
if(B.spherePosition.x >= B.minVertex.x &&
B.spherePosition.y >= B.minVertex.y &&
B.spherePosition.z-10 >= B.minVertex.z &&
B.spherePosition.x <= B.maxVertex.x &&
B.spherePosition.y <= B.maxVertex.y &&
B.spherePosition.z-10 <= B.maxVertex.z){
P.planeColor = "white"
}
else{
P.planeColor = "rgba(255, 247, 233,1)"
}
beginHUD();
image(fbo1, 0, 0);
endHUD();
}
}
function getVectorModule(vector){
return Math.sqrt(vector.x**2 +vector.y**2 +vector.z**2);
}
function mousePressed() {
mouseInitialV = createVector(mouseX, mouseY, 0);
}
function mouseDragged(){
mouseCurrentV = createVector(mouseX, mouseY, 0);
let vectorSubstra = createVector(mouseInitialV.x - mouseCurrentV.x,
mouseInitialV.y - mouseCurrentV.y,
mouseInitialV.z - mouseCurrentV.z);
let mod = getVectorModule(vectorSubstra);
let vectorDir = createVector(vectorSubstra.x/mod,
vectorSubstra.y/mod,
vectorSubstra.z/mod );
let sine = sqrt(1-sq(vectorDir.z));
B.acceleration = createVector(-sine*vectorDir.x, -sine*vectorDir.y, sine*vectorDir.z);
let aux = vectorDir.x;
vectorDir.x = vectorDir.y;
vectorDir.y = -aux;
if (mod < P.planeMaxMagR){
P.planeMagnitudeR = mod
}
P.planeRotateV = vectorDir;
P.planeRotateV.z = 0;
}
function closestPoint(spherePosition, boxMin, boxMax) {
// get box closest point to sphere center by clamping
const x = Math.max(boxMin.x, Math.min(spherePosition.x, boxMax.x));
const y = Math.max(boxMin.y, Math.min(spherePosition.y, boxMax.y));
const z = Math.max(boxMin.z, Math.min(spherePosition.z, boxMax.z));
// this is the same as isPointInsidespherePosition
return createVector(x,y,z);
}
function dataToWalls(wallsData){
let walls = wallsData.map(({x,y,z,width,height,depth, fillColor}) =>{
return new Wall(x,y,z,width,height,depth,fillColor)
})
return walls
}
function drawListObjects(list, fbo){
list.forEach(object =>{
object.draw(fbo)
})
}
function collisionWalls(walls, B) {
for(let i=0;i<walls.length; i++){
let cNewVector = walls[i].collisionWithSphere(B)
if (cNewVector){
return cNewVector
}
}
}
function initState(){
startTime = 0
endTime = 0
isGameStarted = false
isGameEnd = false
textTime = createP('this is some text');
textTime.html("Tiempo: ")
textTime.position(0, 350);
textTime.style("background-color","white")
startData = {width: "38", height: "38", depth: "2", x: 92.5-38*4.5,y: 38*-1,z: 0, fillColor:"rgb(255, 115, 29)"}
finishData = {width: "38", height: "38", depth: "2", x: 92.5-38/2+2.5,y: 38*-2,z: 0, fillColor:"rgb(255, 115, 29)"}
startBox = new Wall(startData.x, startData.y, startData.z, startData.width,startData.height, startData.depth,startData.fillColor)
finishBox = new Wall(finishData.x, finishData.y, finishData.z, finishData.width,finishData.height, finishData.depth,finishData.fillColor)
createCanvas(400, 400);
wallsData = [{width: "200", height: "10", depth: "20", x: 0,y: -100,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
{width: "10", height: "200", depth: "20", x: 100,y: 0,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
{width: "10", height: "200", depth: "20", x: -100,y: 0,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
//Fila 1
{width: 38, height: "5", depth: "20", x: 38*-2,y: 92.5-38*4,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
{width: 38, height: "5", depth: "20", x: 38*1,y: 92.5-38*4,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
//Fila 2
{width: "38", height: "5", depth: "20", x: 38*-1,y: 92.5-38*3,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
//Fila3
{width: "38", height: "5", depth: "20", x: 38*-2,y: 92.5-38*2,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
{width: "38", height: "5", depth: "20", x: 0,y: 92.5-38*2,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
{width: "38", height: "5", depth: "20", x: 38*2,y: 92.5-38*2,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
//Fila 4
{width: "38", height: "5", depth: "20", x: 38*-1,y: 92.5-38,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
{width: "38", height: "5", depth: "20", x: 0,y: 92.5-38,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
//Columna 1
{width: "5", height: "38", depth: "20", x: 92.5-38*4,y: 38*-1,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
//Columna 2
{width: "5", height: "38", depth: "20", x: 92.5-38*3,y: 38*-1,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
{width: "5", height: "38", depth: "20", x: 92.5-38*3,y: 0,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
//Columna 3
{width: "5", height: "38", depth: "20", x: 92.5-38*2,y: 0,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
{width: "5", height: "38", depth: "20", x: 92.5-38*2,y: 38*1,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
//Columna 4
{width: "5", height: "38", depth: "20", x: 92.5-38*1,y: 38*-2,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
{width: "5", height: "38", depth: "20", x: 92.5-38*1,y: 0,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
{width: "5", height: "38", depth: "20", x: 92.5-38*1,y: 38,z: 10, fillColor:"rgba(95, 157, 247,0.5)"},
{width: "200", height: "10", depth: "20", x:0, y:100, z:0, fillColor:"rgba(95, 157, 247,0.5)"},
]
Walls = dataToWalls(wallsData)
box = {width: "100", height: "10", depth: "20", origin: createVector(0,50,10)}
boxMax = createVector(box.origin.x+ box.width/2, box.origin.y+ box.height/2, box.origin.z+ box.depth/2)
boxMin = createVector(box.origin.x- box.width/2, box.origin.y- box.height/2, box.origin.z- box.depth/2)
console.log("origin ", box.origin, "max: ", boxMin,"min: ", boxMax);
fbo1 = createGraphics(width, height, WEBGL);
// FBO camera
cam1 = new Dw.EasyCam(fbo1._renderer, { distance: 200 });
let state1 = cam1.getState();
cam1.state_reset = state1; // state to use on reset (double-click/tap)
cam1.setViewport([0, 0, width / 2, height]);
document.oncontextmenu = function () { return false; }
// scene interactions
P = new Plane();
B = new Ball(P);
}
Conclusiones #
- P5.treegl Permitio que la realizacion del ejercicio fuera un poco mas simple de lo que se hubiese logrado a fuerza bruta, sin embargo p5.js presenta muchas desventajas al momento de simular fisicas en los objetos ya que para crearlos son pocos los parametros que existen por lo cual no se recomienda para personas no experimentadas.
- El Funcionamiento de tipo vectorial que existe en P5 permite una aproximacion matematica para la manipulacion del espacio y los objetos creados en el.
Referencias #
- [1] “Reference | p5.js,” p5js.org. https://p5js.org/es/reference/ (accessed Oct. 18, 2022).
- [2] “p5.treegl,” GitHub, Sep. 12, 2022. https://github.com/VisualComputing/p5.treegl (accessed Oct. 18, 2022).
- [3] “Laberinto,” Wikipedia, Aug. 24, 2022. https://es.wikipedia.org/wiki/Laberinto (accessed Oct. 18, 2022).