Skip to content
Snippets Groups Projects
Commit 49afaedc authored by Your Name's avatar Your Name
Browse files

Project upload

parents
No related branches found
No related tags found
No related merge requests found
Flora.js 0 → 100644
function Leaf(upbringingPoint, length, width){
let endingPoint = upbringingPoint.translate(0, length, 0)
const midPoint = upbringingPoint.translate(0, length / 2, 0)
const tiltAngle = Math.PI / 7;
let hAxisPoints = [-1, 1].map(sign => {
return midPoint.translate(sign * width, 0, 0)
.rotateP(0, sign * tiltAngle, 0, upbringingPoint);
});
this.points = [
upbringingPoint,
endingPoint,
...hAxisPoints,
];
}
Leaf.prototype.webGLVerticeDefinition = function () {
return [
// Primer triangulo de la hoja
...Object.values(this.points[0]),
...Object.values(this.points[2]),
...Object.values(this.points[1]),
// Segundo triangulo de la hoja
...Object.values(this.points[0]),
...Object.values(this.points[3]),
...Object.values(this.points[1]),
]
}
Leaf.prototype.rotate = function (angleX, angleY, angleZ) {
this.points = this.points.map(
p => p.rotateP(angleX, angleY, angleZ, this.points[0])
)
}
function Flower(upbringingPoint, length, width, nPetals){
this.petals = [];
let completeTurn = 2 * Math.PI;
for(let i = 0; i < nPetals; i++){
let petal = new Leaf(upbringingPoint, length, width);
petal.rotate(Math.PI / 2, 0, completeTurn * i / nPetals)
this.petals.push(petal)
}
this.pistil = new Prism(upbringingPoint, length, width * 0.2, 4)
}
Flower.prototype.webGLVerticeDefinition = function () {
let flowerVertices = []
for (const petal of this.petals) {
flowerVertices.push(...petal.webGLVerticeDefinition());
}
flowerVertices.push(...this.pistil.webGLVerticeDefinition())
return flowerVertices;
}
Flower.prototype.rotate = function (angleX, angleY, angleZ){
this.petals.map(
petal => petal.rotate(angleX, angleY, angleZ)
)
this.pistil.rotate(angleX, angleY, angleZ)
}
\ No newline at end of file
/// ParametricSymbol
function ParametricSymbol(symbol, params) {
this.symbol = symbol;
this.params = params;
}
ParametricSymbol.prototype.toString = function(){
return `${this.symbol}` + (this.params.length ? `(${this.params.join(',')})` : "");
}
ParametricSymbol.prototype.calcParams = function(precedentParams, precedentValues) {
let valuedParams = []
for (let param of this.params) {
let functionArgs = precedentParams.join(",");
let argsValues = precedentValues.join(",");
valuedParams.push(
eval(`
(function(${functionArgs}){
return ${param};
})(${argsValues})
`)
);
}
this.params = valuedParams;
}
/// ParametricString
function ParametricString(inputString="") {
const SYMBOL_PARSER = /\S+?(?:\((.*?)\))?/g;
this.symbols = [];
let newSymbol;
while (newSymbol = SYMBOL_PARSER.exec(inputString)){
const PARAMS = newSymbol[1] ? newSymbol[1].split(",") : [];
this.symbols.push(new ParametricSymbol(newSymbol[0][0], PARAMS))
}
}
ParametricString.prototype.calcAllParams = function (precedentParams, precedentValues){
this.symbols.forEach(symbol => symbol.calcParams(precedentParams, precedentValues))
}
ParametricString.prototype.toString = function () {
return this.symbols.map(el => el.toString()).join("")
}
ParametricString.prototype.clone = function () {
return new ParametricString(this.toString())
}
ParametricString.prototype.addSymbol = function(...symbols){
this.symbols.push(...symbols);
}
/// ParametricLSystem
function ParametricLSystem(axiome, productions) {
this.axiome = new ParametricString(axiome);
this.axiome.calcAllParams([], [])
this.productions = productions;
}
ParametricLSystem.prototype.derive = function (numOfDerivations) {
let currentDerivation = this.axiome;
for (let derivations = 0; derivations < numOfDerivations; derivations++) {
let newDerivation = new ParametricString();
for (symbol of currentDerivation.symbols){
const indx = Object.keys(this.productions).findIndex(p => p[0] == symbol.symbol);
if(indx >= 0){
const productionKey = Object.keys(this.productions)[indx]
const precedent = new ParametricString(productionKey);
const consecuent = new ParametricString(this.productions[productionKey]);
const precedentParams = precedent.symbols[0].params;
consecuent.calcAllParams(precedentParams, symbol.params)
newDerivation.addSymbol(...consecuent.symbols);
}
else newDerivation.addSymbol(symbol);
}
currentDerivation = newDerivation;
}
return currentDerivation;
}
Prism.js 0 → 100644
function rep(elem, times){
let arr = [];
for(let i = 0; i < times; i++)
arr.push(elem);
return arr;
}
let m4 = {
multiply: function (a, b) {
var a00 = a[0 * 4 + 0];
var a01 = a[0 * 4 + 1];
var a02 = a[0 * 4 + 2];
var a03 = a[0 * 4 + 3];
var a10 = a[1 * 4 + 0];
var a11 = a[1 * 4 + 1];
var a12 = a[1 * 4 + 2];
var a13 = a[1 * 4 + 3];
var a20 = a[2 * 4 + 0];
var a21 = a[2 * 4 + 1];
var a22 = a[2 * 4 + 2];
var a23 = a[2 * 4 + 3];
var a30 = a[3 * 4 + 0];
var a31 = a[3 * 4 + 1];
var a32 = a[3 * 4 + 2];
var a33 = a[3 * 4 + 3];
var b00 = b[0 * 4 + 0];
var b01 = b[0 * 4 + 1];
var b02 = b[0 * 4 + 2];
var b03 = b[0 * 4 + 3];
var b10 = b[1 * 4 + 0];
var b11 = b[1 * 4 + 1];
var b12 = b[1 * 4 + 2];
var b13 = b[1 * 4 + 3];
var b20 = b[2 * 4 + 0];
var b21 = b[2 * 4 + 1];
var b22 = b[2 * 4 + 2];
var b23 = b[2 * 4 + 3];
var b30 = b[3 * 4 + 0];
var b31 = b[3 * 4 + 1];
var b32 = b[3 * 4 + 2];
var b33 = b[3 * 4 + 3];
return [
b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33,
];
},
translation: function (tx, ty, tz) {
return [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
tx, ty, tz, 1,
];
},
scaling: function (sx, sy, sz) {
return [
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 0,
0, 0, 0, 1,
];
},
xRotation: function (angleInRadians) {
var c = Math.cos(angleInRadians);
var s = Math.sin(angleInRadians);
return [
1, 0, 0, 0,
0, c, s, 0,
0, -s, c, 0,
0, 0, 0, 1,
];
},
yRotation: function (angleInRadians) {
var c = Math.cos(angleInRadians);
var s = Math.sin(angleInRadians);
return [
c, 0, -s, 0,
0, 1, 0, 0,
s, 0, c, 0,
0, 0, 0, 1,
];
},
zRotation: function (angleInRadians) {
var c = Math.cos(angleInRadians);
var s = Math.sin(angleInRadians);
return [
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
},
xRotate: function (m, angleInRadians) {
return m4.multiply(m4.xRotation(angleInRadians), m);
},
yRotate: function (m, angleInRadians) {
return m4.multiply(m4.yRotation(angleInRadians), m);
},
zRotate: function (m, angleInRadians) {
return m4.multiply(m4.zRotation(angleInRadians), m);
},
};
// Point: defined by its 3 coordinates
function Point(x=0, y=0, z=0){
this.x = x;
this.y = y;
this.z = z;
}
Point.prototype.clone = function(){
return new Point(this.x, this.y, this.z);
}
Point.prototype.translate = function(dx, dy, dz){
return new Point(this.x + dx, this.y + dy, this.z + dz)
}
Point.prototype.rotateP = function(angleX, angleY, angleZ, point){
return this.translate(-point.x, -point.y, -point.z)
.rotate(angleX, angleY, angleZ)
.translate(point.x, point.y, point.z);
}
Point.prototype.rotate = function(angleX, angleY, angleZ){
let point = [this.x, this.y, this.z, 1, ...rep(0, 12)]
let p = m4.xRotate(m4.yRotate(m4.zRotate(point, angleZ), angleY), angleX)
return new Point(p[0], p[1], p[2]);
}
function Prism(centerPoint, height, radius, numSides){
const CIRCUNFERENCE_RADIANS = 2*Math.PI;
let firstPoint = centerPoint.translate(0, 0, radius);
let angleIncrement = CIRCUNFERENCE_RADIANS / numSides;
this.prismPoints = [];
this.lateralEdges = numSides;
this.floorPoint = centerPoint.clone();
this.ceilPoint = centerPoint.translate(0, height, 0);
for(let edge = 0; edge < numSides; edge++){
let currentPoint = firstPoint.rotateP(0, edge*angleIncrement, 0, centerPoint);
this.prismPoints.push(currentPoint, currentPoint.translate(0, height, 0));
}
}
Prism.prototype.rotate = function (angleX, angleY, angleZ){
this.prismPoints = this.prismPoints.map(p => p.rotateP(angleX, angleY, angleZ, this.floorPoint));
this.ceilPoint = this.ceilPoint.rotateP(angleX, angleY, angleZ, this.floorPoint)
this.floorPoint = this.floorPoint.rotateP(angleX, angleY, angleZ, this.floorPoint)
}
Prism.prototype.webGLVerticeDefinition = function(){
let vertices = [];
// Caras laterales
for(let i = 0; i < this.lateralEdges; i++){
const numPoints = this.prismPoints.length;
const baseEdgePoint = 2 * i;
const nextEdgeBasePoint = (baseEdgePoint + 2) % numPoints;
vertices.push(
// Primer triangulo
...Object.values(this.prismPoints[baseEdgePoint]),
...Object.values(this.prismPoints[baseEdgePoint + 1]),
...Object.values(this.prismPoints[nextEdgeBasePoint]),
// Segundo triangulo
...Object.values(this.prismPoints[baseEdgePoint + 1]),
...Object.values(this.prismPoints[nextEdgeBasePoint + 1]),
...Object.values(this.prismPoints[nextEdgeBasePoint]),
// Base inferior (triang)
...Object.values(this.prismPoints[baseEdgePoint]),
...Object.values(this.floorPoint),
...Object.values(this.prismPoints[nextEdgeBasePoint]),
// Base superior (triang)
...Object.values(this.prismPoints[baseEdgePoint + 1]),
...Object.values(this.ceilPoint),
...Object.values(this.prismPoints[nextEdgeBasePoint + 1]),
);
}
return vertices;
}
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- MATERIALIZE CSS -->
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">
<!-- ICONOS -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- Compiled and minified CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<!-- Color picker -->
<script src="https://cdn.jsdelivr.net/npm/@jaames/iro/dist/iro.min.js"></script>
<!-- ----------------------------------------------------- -->
<title>Práctica 2 - Víctor López Iglesias</title>
<link rel="stylesheet" href="style.css">
<!-- **************** VERTEX SHADER *******************-->
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec3 aVertexColor;
varying highp vec4 vColor;
uniform mat4 u_matrix_rotation;
uniform mat4 u_matrix_translation;
uniform mat4 u_matrix_scaling;
void main() {
gl_Position = u_matrix_scaling * u_matrix_translation * u_matrix_rotation * vec4(aVertexPosition, 1.0);
gl_PointSize=2.0; //podeis modificarlo
vColor= vec4(aVertexColor,1.0);
}
</script>
<!-- **************** FRAGMENT SHADER *******************-->
<script id="fragment-shader" type="x-shader/x-fragment">
varying highp vec4 vColor;
void main() {
gl_FragColor = vColor;
}
</script>
</head>
<body onload="initWebGL()">
<div id="window">
<div id="leftSide">
<div id="action-bar">
<span>
ROTATE
</span>
<div class="switch">
<label>
<input id="rotate" type="checkbox" class="red lighten-4">
<span class="lever"></span>
</label>
</div>
<span>
TRANSLATE
</span>
<a class="waves-effect waves-gray btn-flat modal-trigger" href="#modal1" id="info-button">
<i class="material-icons large right" style="color: rgb(122, 121, 121);">info</i>
</a>
</div>
<canvas id="canvas" height="850" width="850"></canvas>
</div>
<div id="rightSide">
<h4>Parameter manipulation</h4>
<hr>
<h5>Leaves</h5>
<label class="input-label">
Leaf Probability
</label>
<input id="leafProb" class="graphicParam" type="number" min="0" max="1" step="0.01" width="10px">
<label class="input-label">
Leaf Count
</label>
<input id="leafCount" class="graphicParam" type="number" min="0" step="1" width="10px">
<label class="input-label">
Primary Color
</label>
<a id="leafColor1" class="colorPicker waves-effect waves-light btn modal-trigger" href="#colorPickerModal"></a>
<label class="input-label">
Secondary Color
</label>
<a id="leafColor2" class="colorPicker waves-effect waves-light btn modal-trigger" href="#colorPickerModal"></a>
<h5>Flowers</h5>
<label class="input-label">
Flower Probability
</label>
<input id="flowerProb" class="graphicParam" type="number" min="0" max="1" step="0.01" width="10px">
<label class="input-label">
Primary Color
</label>
<a id="flowerColor1" class="colorPicker waves-effect waves-light btn modal-trigger" href="#colorPickerModal"></a>
<label class="input-label">
Secondary Color
</label>
<a id="flowerColor2" class="colorPicker waves-effect waves-light btn modal-trigger" href="#colorPickerModal"></a>
<h5>Trunk</h5>
<label class="input-label">
START POINT:
</label>
<label class="input-label">
X
</label>
<input id="startPointX" class="graphicParam" type="number" min="-1" max="1" step="0.01" width="10px">
<label class="input-label">
Y
</label>
<input id="startPointY" class="graphicParam" type="number" min="-1" max="1" step="0.01" width="10px">
<label class="input-label">
Z
</label>
<input id="startPointZ" class="graphicParam" type="number" min="-1" max="1" step="0.01" width="10px">
<label class="input-label">
COLOR:
</label>
<label class="input-label">
Primary Color
</label>
<a id="trunkColor1" class="colorPicker waves-effect waves-light btn modal-trigger" href="#colorPickerModal"></a>
<br>
<br>
<label class="input-label">
START ANGLE:
</label>
<label class="input-label">
X
</label>
<input id="startAngleX" class="graphicParam" type="number" min="0" max="360" step="1" width="10px">
<label class="input-label">
Y
</label>
<input id="startAngleY" class="graphicParam" type="number" min="0" max="360" step="1" width="10px">
<label class="input-label">
Z
</label>
<input id="startAngleZ" class="graphicParam" type="number" min="0" max="360" step="1" width="10px">
<label class="input-label">
INITIAL WIDTH:
</label>
<label class="input-label">
Width
</label>
<input id="initialWidth" class="graphicParam" type="number" min="0" max="1" step="0.01">
<h5>Parametric L System</h5>
<br>
<label class="input-label">
Recursion Depth (N)
</label>
<input id="depth" class="graphicParam" type="number" min="0">
<br>
<br>
<label class="input-label">
Axiome
</label>
<input id="axiome" type="text">
<br>
<br>
<label class="input-label">
RULES
</label>
<br>
<br>
<input type="text" class="key"> : <input type="text" class="consecuent"><br>
<input type="text" class="key"> : <input type="text" class="consecuent"><br>
<input type="text" class="key"> : <input type="text" class="consecuent">
<a class="waves-effect waves-light btn" id="addRule"><i class="material-icons large">add</i></a>
</div>
</div>
<div id="modal1" class="modal">
<div class="modal-content">
<h4>Información</h4>
<hr>
<p style="color: red;">
Nota: Este proyecto está desarrollado sobre Ubuntu 18.04 en Google Chrome y un monitor con una resolución de 1920x1080p
</p>
<p>
El sistema de generación de árboles creado es un sistema paramétrico (dado que las producciones y axiomas de la
gramática presentan parámetros) en 3D basado en los sistemas L de Lindenmayer.
</p>
<p>
La tortuga implementada traza prismas en 3D que son el tronco y las ramas (en principio hexágonos por disminuir la carga
computacional aunque se puede modificar), hojas (dibujadas donde se encuentre el símbolo <strong>H</strong>) y flores,
que se dibujan en los bulbos (variables no sustituidas).
</p>
<p>
Los símbolos utilizados para funciones de la tortuga son (<strong>&lt;simbolo&gt;(&lt;parametros&gt; ... )</strong>):
</p>
<ul class="collection">
<li class="collection-item">
<strong>F(l)</strong>: traza un segmento de longitud l (en unidades de las coordenadas normalizadas)
</li>
<li class="collection-item">
<strong>!(w)</strong>: establece como nuevo grosor de los segmentos grosor_actual * w
</li>
<li class="collection-item">
<strong>[</strong>: guarda el estado actual del sistema (ángulo, punto de dibujado actual y grosor de segmento)
</li>
<li class="collection-item">
<strong>]</strong>: recupera estado de la pila de estado
</li>
<li class="collection-item">
<strong>&(alpha)</strong>: rota un ángulo alpha (radianes) en el eje X
</li>
<li class="collection-item">
<strong>/(alpha)</strong>: rota un ángulo alpha (radianes) en el eje Y
</li>
<li class="collection-item">
<strong>+(alpha)</strong>: rota un ángulo alpha (radianes) en el eje Z
</li>
<li class="collection-item">
<strong>H</strong>: dibuja un nodo hoja (leaf count es el número de hojas que pueden aparecer en cada nodo)
</li>
</ul>
<p>
No es necesario mantener el nombre de los parámetros y se pueden definir nuevas variables mediante la interfaz,
los parámetros son evaluados mediante JS así que se puede utilizar dicha notación (PI es una variable de entorno
que he utilizado como abreviatura de Math.PI).
</p>
<p>
Se puede rotar y trasladar la figura mediante el ratón (según el modo del switch) y escalarla mediante la ruleta del
ratón
</p>
</div>
<div class="modal-footer">
<a href="#!" class="modal-close waves-effect waves-green btn-flat">OK</a>
</div>
</div>
<div id="colorPickerModal" class="modal"></div>
<script src="ParametricSystem.js"></script>
<script src="Prism.js"></script>
<script src="eventHandling.js"></script>
<script src="webgl.js"></script>
<script src="Flora.js"></script>
<script src="Turtle.js"></script>
</body>
</html>
function drawParametricLSystem(params) {
let parametricLSystem = new ParametricLSystem(params.axiome, params.productions)
let state = {
drawPoint: new Point(
params.startPointX,
params.startPointY,
params.startPointZ,
),
drawAngle: {
x: params.startAngleX,
y: params.startAngleY,
z: params.startAngleZ,
},
drawWidth: params.initialWidth,
},
stateStack = [],
numEdges = 6,
depth = params.depth,
leafCount = params.leafCount,
leafProb = params.leafProb,
flowerProb = params.flowerProb;
// Reset drawing
resetDrawing();
for (symbol of parametricLSystem.derive(depth).symbols) {
switch (symbol.symbol) {
case "F":
let basePoint = state.drawPoint.clone();
let prismDrawn = new Prism(basePoint, symbol.params[0], state.drawWidth, numEdges);
prismDrawn.rotate(...Object.values(state.drawAngle));
state.drawPoint = prismDrawn.ceilPoint.clone();
let prismVertices = prismDrawn.webGLVerticeDefinition();
vertices.push(...prismVertices);
verticeColors.push(...repArr(Object.values(params.trunkColor1), prismVertices.length / 3));
break;
case "H":
for (let i = 0; i < leafCount; i++) {
if(Math.random() <= leafProb){
let leaf = new Leaf(state.drawPoint.clone(), 0.15, 0.05);
leaf.rotate(...Object.values(state.drawAngle));
leaf.rotate(Math.random() * 2 * Math.PI, Math.random() * 2 * Math.PI, Math.random() * 2 * Math.PI)
vertices.push(...leaf.webGLVerticeDefinition());
verticeColors.push(...repArr(Object.values(params.leafColor1), 3));
verticeColors.push(...repArr(Object.values(params.leafColor2), 3));
}
}
break;
case "!":
state.drawWidth *= symbol.params[0];
break;
case "&":
state.drawAngle.x += symbol.params[0];
break;
case "/":
state.drawAngle.y += symbol.params[0];
break;
case "+":
state.drawAngle.z += symbol.params[0];
break;
case "[":
stateStack.push({
drawAngle: { ...state.drawAngle },
drawPoint: state.drawPoint.clone(),
drawWidth: state.drawWidth,
});
break;
case "]":
state = stateStack.pop();
break;
default:
if(Math.random() <= flowerProb){
let flower = new Flower(state.drawPoint.clone(), 0.05, 0.02, 4);
flower.rotate(...Object.values(state.drawAngle));
let flowerVertices = flower.webGLVerticeDefinition();
let numPistilVertices = flower.pistil.webGLVerticeDefinition().length
vertices.push(...flowerVertices);
verticeColors.push(...repArr(Object.values(params.flowerColor1), (flowerVertices.length - numPistilVertices) / 3));
verticeColors.push(...repArr(Object.values(params.flowerColor2), numPistilVertices / 3));
}
}
}
}
let x, y, angleX0, angleY0, pressed = false;
const delta = 0.005;
let translateMode = false;
let rightSide = document.getElementById("rightSide");
let addRuleButton = document.getElementById("addRule");
addRuleButton.addEventListener('click', e => {
var helper = document.createElement('div');
helper.innerHTML = `
<br><input type="text" class="key"> : <input type="text" class="consecuent">
`;
while (helper.firstChild) {
rightSide.insertBefore(helper.firstChild, addRuleButton);
}
setParametricSystemEventListeners();
});
canvas.onmousedown = e => {
pressed = true;
angleX0 = angleX;
angleY0 = angleY;
x = e.clientX - e.target.offsetLeft
y = e.clientY - e.target.offsetTop
if (translateMode) translate(e);
}
function translate(event) {
translateX = (event.clientX - canvas.offsetLeft) / canvas.width * 2 - 1
translateY = (canvas.offsetTop - event.clientY) / canvas.width * 2 + 0.5
redraw();
}
canvas.onmousemove = e => {
if (pressed) {
// TRANSLATION
if (translateMode) translate(e);
else {
// ROTATION
angleX = angleX0 + (y - (e.clientY - canvas.offsetTop)) * delta
const varAngleY = x - (e.clientX - canvas.offsetLeft)
// Veo cuantos PI/2-giros ha hecho la figura para cambiar la dirección de rotación
let giros90 = Math.abs(angleX) / (Math.PI / 2)
if (1 < (giros90 % 4) && (giros90 % 4) < 3) {
angleY = angleY0 - varAngleY * delta
}
else {
angleY = angleY0 + varAngleY * delta
}
redraw();
}
}
}
document.onmouseup = e => {
pressed = false;
}
document.querySelector('input[type="checkbox"]').addEventListener('change', e => {
translateMode = e.target.checked;
})
canvas.addEventListener("mousewheel", e => {
scaling *= e.deltaY < 0 ? 1.1 : 1 / 1.1;
redraw();
});
document.addEventListener('DOMContentLoaded', function () {
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems, {});
});
graphicParams = {
leafProb: 1,
leafCount: 1,
leafColor1: {
r: 0,
g: 0.8,
b: 0,
},
leafColor2: {
r: 0,
g: 0.7,
b: 0,
},
flowerProb: 1,
flowerColor1: {
r: 0.92,
g: 0.48,
b: 0.78,
},
flowerColor2: {
r: 1,
g: 1,
b: 0,
},
startPointX: 0,
startPointY: -0.7,
startPointZ: 0,
trunkColor1: {
r: 0.71,
g: 0.45,
b: 0.24,
},
startAngleX: 0,
startAngleY: 0,
startAngleZ: 0,
initialWidth: 0.025,
depth: 7,
axiome: "A(0.55,0.67)",
productions: {
"A(l,w)": "!(w)F(l)[+(-PI/4) B(l * 0.75, w)][/(0.8*PI)+(-PI / 3.5) C(l * 0.75, w)]/(0.72 * PI) A(l * 0.6, w)",
"B(l,w)": "!(w)F(l)H[&(-PI/4)C(l * 0.75, w)]/(0.32*PI)C(l * 0.6, w)",
"C(l,w)": "!(w)F(l)H[&(PI/4)B(l * 0.75, w)]/(0.32*PI)B(l * 0.6, w)",
}
}
// Graphic params UI
let graphicParamsUI = Array.from(document.getElementsByClassName('graphicParam'));
graphicParamsUI.forEach(elem => {
elem.value = graphicParams[elem.id]
elem.addEventListener("input", e => {
graphicParams[elem.id] = Number(elem.value);
drawParametricLSystem(graphicParams);
redraw();
})
})
// Color UI Init
let colorPickers = Array.from(document.getElementsByClassName('colorPicker'));
for (colorPicker of colorPickers) {
colorizeElementBackground(colorPicker, graphicParams[colorPicker.id])
}
// Color selection
colorPickers.forEach(
el => el.addEventListener("click", e => {
document.getElementById('colorPickerModal').innerHTML = '';
let colorizedElement = e.target.id;
let currentColor = graphicParams[colorizedElement];
colPicker = new iro.ColorPicker('#colorPickerModal',
{
width: 320,
borderWidth: 2,
borderColor: "#000",
color: `rgb(${currentColor.r * 255},${currentColor.g * 255},${currentColor.b * 255})`,
}
);
colPicker.on(["color:change"], function () {
let selectedColor = colPicker.color.rgb;
Object.keys(selectedColor).map(k => graphicParams[colorizedElement][k] = selectedColor[k] / 255)
colorizeElementBackground(el, graphicParams[colorizedElement])
drawParametricLSystem(graphicParams);
redraw();
})
})
)
function colorizeElementBackground(element, color) {
element.style.background = `rgb(${color.r * 255}, ${color.g * 255}, ${color.b * 255})`
}
// Parametric System Engine UI
let axiome = document.getElementById('axiome');
axiome.value = graphicParams[axiome.id]
axiome.addEventListener("input", e => {
graphicParams[e.target.id] = e.target.value;
drawParametricLSystem(graphicParams);
redraw();
})
function setParametricSystemEventListeners(){
let productionAntecedents = Array.from(document.querySelectorAll('.key'));
let productionConsecuents = Array.from(document.querySelectorAll('.consecuent'));
productionAntecedents.forEach((elem, i) => {
elem.value = Object.keys(graphicParams.productions)[i];
productionConsecuents[i].value = graphicParams.productions[elem.value];
})
let productionAntecedentsAndConsecuents = productionAntecedents.concat(productionConsecuents);
productionAntecedentsAndConsecuents.forEach(elem => {
elem.addEventListener('input', e => {
graphicParams.productions = {}
for (let i = 0; i < productionAntecedents.length; i++)
graphicParams.productions[productionAntecedents[i].value] = productionConsecuents[i].value;
drawParametricLSystem(graphicParams);
redraw();
})
});
}
setParametricSystemEventListeners();
style.css 0 → 100644
*{
font-family: 'Montserrat';
}
html, body {
height: 100%;
background-color: white;
margin: 0;
position: relative;
}
canvas {
background-color: white;
cursor: move;
}
strong{
font-weight: bold;
}
#window{
height: 100%;
display: flex;
flex-direction: row;
align-content: center;
}
#leftSide{
height: 100%;
display: flex;
flex-direction: column;
-webkit-user-drag: auto;
}
#action-bar{
background: rgb(250, 250, 250);
flex: 1;
padding: 5px 0px;
padding-left: 10px;
display: flex;
align-items: center;
position: relative;
}
#action-bar *{
margin: 0px 5px;
padding: 0px;
}
#action-bar > span{
border: 1px solid black;
padding: 3px;
}
#info-button{
border-radius: 50%;
width: 40px;
height: 40px;
display: flex;
align-items: center;
position: absolute;
right: 35px;
}
#info-button i {
font-size: 32px;
justify-self: center;
}
#rightSide{
height: 100%;
display: block;
flex: 1;
background: rgb(97, 105, 139);
color: rgb(240, 240, 252);
padding: 20px;
overflow-y: scroll;
}
#rightSide hr{
margin-bottom: 40px;
}
#rightSide h4{
display: flex;
justify-content: center;
}
#rightSide input{
background: rgb(236, 233, 250);
outline: none;
border: none;
font-family: 'Montserrat';
border-radius: 5px;
height: 40px !important;
}
.input-label{
color: rgb(236, 233, 250);
font-size: 16px;
margin: 0px 10px;
}
.input-label.active{color: rgb(236, 233, 250) !important;}
input[type="number"]{
width: 50px !important;
margin-right: 20px !important;
text-align: center;
}
#initialWidth{
width: 60px !important;
}
input[type="text"].key{
width: 70px !important;
}
input[type="text"]{
width: 700px !important;
padding-left: 10px !important;
}
#addRule {
margin-left: 10px;
}
#colorPickerModal {
background: none;
box-shadow: none;
width: fit-content !important;
}
\ No newline at end of file
webgl.js 0 → 100644
let gl = null,
canvas = document.getElementById("canvas"),
glProgram = null,
fragmentShader = null,
vertexShader = null;
let positionLocation = null,
colorLocation = null;
let verticeBuffer = null,
vertices = [],
verticeColors = [],
colorBuffer = null;
let angleX = 0,
angleY = 0,
translateX = 0,
translateY = 0,
scaling = 1;
let myParametricSystem = null;
function repArr(arr, times) {
let arr2 = [];
for (let i = 0; i < times; i++) arr2 = [...arr2, ...arr];
return arr2;
}
/********************* 1. INIT WEBGL **************************************/
function initWebGL() {
// gl
gl = canvas.getContext("webgl");
PI = Math.PI
drawParametricLSystem(graphicParams);
if (gl) {
setupWebGL();
initShaders();
setupBuffers();
drawScene();
}
else {
alert("El navegador no soporta WEBGL.");
}
}
/********************* 2.setupWEBGL **************************************/
function setupWebGL() {
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//Pone el color de fondo a blanco ---para 2d no funciona
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
//Crea un viewport del tamaño del canvas
gl.viewport(0, 0, canvas.width, canvas.height);
}
function initShaders() {
var fs_source = document.getElementById('fragment-shader').innerHTML;
var vs_source = document.getElementById('vertex-shader').innerHTML;
vertexShader = makeShader(vs_source, gl.VERTEX_SHADER);
fragmentShader = makeShader(fs_source, gl.FRAGMENT_SHADER);
glProgram = gl.createProgram();
gl.attachShader(glProgram, vertexShader);
gl.attachShader(glProgram, fragmentShader);
gl.linkProgram(glProgram);
if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
alert("No se puede inicializar el Programa .");
}
gl.useProgram(glProgram);
}
function makeShader(src, type) {
var shader = gl.createShader(type);
gl.shaderSource(shader, src);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert("Error de compilación del shader: " + gl.getShaderInfoLog(shader));
}
return shader;
}
function setupBuffers() {
verticeBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, verticeBuffer);//ARRAY_BUFFER son datos vertice
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
/**
** Colores y Buffer de colores
**/
//BUFFER de color
colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticeColors), gl.STATIC_DRAW);
}
/********************* 5. DRAW SCENE *******************/
function drawScene() {
/* ATRIBUTO DE POSICION DE VERTICES*/
positionLocation = gl.getAttribLocation(glProgram, "aVertexPosition");
gl.enableVertexAttribArray(positionLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, verticeBuffer);//OJO! se lo recordamos
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
/* ATRIBUTO DE COLOR DE VERTICES*/
colorLocation = gl.getAttribLocation(glProgram, "aVertexColor");
gl.enableVertexAttribArray(colorLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); //OJO! se lo recordamos
gl.vertexAttribPointer(colorLocation, 3, gl.FLOAT, false, 0, 0);
var rotationMatrix = m4.multiply(m4.xRotation(angleX), m4.yRotation(angleY));
var translationMatrix = m4.translation(translateX, translateY, 0);
var scalingMatrix = m4.scaling(scaling, scaling, scaling);
var matrixLocation = gl.getUniformLocation(glProgram, "u_matrix_translation");
gl.uniformMatrix4fv(matrixLocation, false, translationMatrix);
var matrixLocation = gl.getUniformLocation(glProgram, "u_matrix_rotation");
gl.uniformMatrix4fv(matrixLocation, false, rotationMatrix);
var matrixLocation = gl.getUniformLocation(glProgram, "u_matrix_scaling");
gl.uniformMatrix4fv(matrixLocation, false, scalingMatrix);
//Dibuja el tipo de primitiva, desde qué elemento comienza y cuantos dibuja
gl.drawArrays(gl.TRIANGLES, 0, vertices.length / 3);
}
function redraw(){
setupBuffers();
drawScene();
}
function resetDrawing(){
vertices = [];
verticeColors = [];
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment