Compare commits
3 Commits
a68ba2d63c
...
5d926f3e8c
Author | SHA1 | Date |
---|---|---|
sejo | 5d926f3e8c | |
sejo | 1d48181839 | |
sejo | 0e5b209738 |
After Width: | Height: | Size: 160 KiB |
After Width: | Height: | Size: 185 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 166 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 135 KiB |
After Width: | Height: | Size: 135 KiB |
After Width: | Height: | Size: 311 KiB |
|
@ -98,6 +98,7 @@ title: "🍃 jardínBit"
|
||||||
### Apariencia
|
### Apariencia
|
||||||
|
|
||||||
* [[P3D: Iluminación]](/notasP3D/iluminacion.html)
|
* [[P3D: Iluminación]](/notasP3D/iluminacion.html)
|
||||||
|
* [[P3D: Texturas en Mallas]](/notasP3D/texturas.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -39,14 +39,13 @@ void cono(float r, float h, int N){
|
||||||
// N: número de divisiones en la base
|
// N: número de divisiones en la base
|
||||||
|
|
||||||
// variables auxiliares:
|
// variables auxiliares:
|
||||||
float x,y,angulo;
|
float x,y;
|
||||||
|
|
||||||
beginShape(TRIANGLE_FAN);
|
beginShape(TRIANGLE_FAN);
|
||||||
vertex(0,0,h); // vértice de la punta
|
vertex(0,0,h); // vértice de la punta
|
||||||
|
|
||||||
// ciclo para los vértices de la base
|
// ciclo para los vértices de la base
|
||||||
for(int i=0;i<=N;i=i+1){
|
for(float angulo=0; angulo<=TWO_PI; angulo=angulo+TWO_PI/N){
|
||||||
angulo = i*TWO_PI/N;
|
|
||||||
x = r*cos(angulo);
|
x = r*cos(angulo);
|
||||||
y = r*sin(angulo);
|
y = r*sin(angulo);
|
||||||
vertex(x,y,0);
|
vertex(x,y,0);
|
||||||
|
@ -55,6 +54,8 @@ void cono(float r, float h, int N){
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Cono con base aleatoria
|
## Cono con base aleatoria
|
||||||
|
|
||||||
![](/img/conos-aleatorios.png)
|
![](/img/conos-aleatorios.png)
|
||||||
|
@ -147,11 +148,10 @@ void cilindro(float r, float h, int N){
|
||||||
// N: número de divisiones en la base
|
// N: número de divisiones en la base
|
||||||
|
|
||||||
// variables auxiliares
|
// variables auxiliares
|
||||||
float x,y,angulo;
|
float x,y;
|
||||||
|
|
||||||
beginShape(QUAD_STRIP);
|
beginShape(QUAD_STRIP);
|
||||||
for(int i=0; i<=N; i=i+1){
|
for(float angulo=0; angulo<=TWO_PI; angulo=angulo+TWO_PI/N){
|
||||||
angulo = i*TWO_PI/N;
|
|
||||||
x = r*cos(angulo);
|
x = r*cos(angulo);
|
||||||
y = r*sin(angulo);
|
y = r*sin(angulo);
|
||||||
// vértice en la base
|
// vértice en la base
|
||||||
|
@ -163,6 +163,35 @@ void cilindro(float r, float h, int N){
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Variación: Cilindro con rango de ángulo
|
||||||
|
|
||||||
|
Esta función permite determinar el ángulo de inicio y fin del cilindro. Nota que los ángulos se especifican en radianes.
|
||||||
|
|
||||||
|
```java
|
||||||
|
void cilindro(float r, float h, int N, float anguloInicial, float anguloFinal){
|
||||||
|
// dibuja un cilindro tradicional, en un rango específico de ángulo
|
||||||
|
// r: radio de la base
|
||||||
|
// h: altura
|
||||||
|
// N: número de divisiones en la base
|
||||||
|
// anguloInicial: a partir de qué ángulo empieza el cilindro (en radianes)
|
||||||
|
// anguloFinal: en qué ángulo termina el cilindro (en radianes)
|
||||||
|
|
||||||
|
// variables auxiliares
|
||||||
|
float x,y;
|
||||||
|
|
||||||
|
beginShape(QUAD_STRIP);
|
||||||
|
for(float angulo=anguloInicial; angulo<=anguloFinal; angulo += (anguloFinal-anguloInicial)/N){
|
||||||
|
x = r*cos(angulo);
|
||||||
|
y = r*sin(angulo);
|
||||||
|
// vértice en la base
|
||||||
|
vertex(x,y,0);
|
||||||
|
// vértice en la tapa
|
||||||
|
vertex(x,y,h);
|
||||||
|
}
|
||||||
|
endShape();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Cilindro con base/tapa aleatoria
|
## Cilindro con base/tapa aleatoria
|
||||||
|
|
||||||
![](/img/cilindros-aleatorios.png)
|
![](/img/cilindros-aleatorios.png)
|
||||||
|
@ -311,6 +340,39 @@ void cilindroCono(float r1, float r2, float h, int N){
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Variación: rango de ángulos
|
||||||
|
|
||||||
|
Esta versión de la función permite especificar el ángulo inicial y final de la figura. Nota que los ángulos son en radianes:
|
||||||
|
|
||||||
|
```java
|
||||||
|
void cilindroCono(float r1, float r2, float h, int N, float anguloInicial, float anguloFinal) {
|
||||||
|
// dibuja un cilindro con base y tapa de diferente radio
|
||||||
|
// r1: radio de la base
|
||||||
|
// r2: radio de la tapa
|
||||||
|
// h: altura
|
||||||
|
// N: número de divisiones en la base/tapa
|
||||||
|
// anguloInicial: a partir de qué ángulo empieza el cilindro (en radianes)
|
||||||
|
// anguloFinal: en qué ángulo termina el cilindro (en radianes)
|
||||||
|
|
||||||
|
// variables auxiliares
|
||||||
|
float x, y;
|
||||||
|
|
||||||
|
beginShape(QUAD_STRIP);
|
||||||
|
for (float angulo=anguloInicial; angulo<=anguloFinal; angulo += (anguloFinal-anguloInicial)/N) {
|
||||||
|
x = r1*cos(angulo);
|
||||||
|
y = r1*sin(angulo);
|
||||||
|
// vértice en la base
|
||||||
|
vertex(x, y, 0);
|
||||||
|
|
||||||
|
x = r2*cos(angulo);
|
||||||
|
y = r2*sin(angulo);
|
||||||
|
// vértice en la tapa
|
||||||
|
vertex(x, y, h);
|
||||||
|
}
|
||||||
|
endShape();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Cono-cilindro 2
|
## Cono-cilindro 2
|
||||||
|
|
||||||
![](/img/cilindrocono-complejo.png)
|
![](/img/cilindrocono-complejo.png)
|
||||||
|
|
|
@ -233,3 +233,7 @@ Si no, no hay problema, y podemos definir todas las caras como triángulos (`TRI
|
||||||
## Codificación
|
## Codificación
|
||||||
|
|
||||||
Ya que tenemos todos nuestros elementos - vértices nombrados/numerados y con posición, y caras definidas - podemos pasar a escribirlos en Processing. Como referencia, tenemos la Pirámide de arriba.
|
Ya que tenemos todos nuestros elementos - vértices nombrados/numerados y con posición, y caras definidas - podemos pasar a escribirlos en Processing. Como referencia, tenemos la Pirámide de arriba.
|
||||||
|
|
||||||
|
# Apariencia: Texturas
|
||||||
|
|
||||||
|
[[P3D: Texturas en Mallas]](/notasP3D/texturas.html)
|
||||||
|
|
|
@ -0,0 +1,245 @@
|
||||||
|
---
|
||||||
|
title: "P3D: Texturas en Mallas"
|
||||||
|
---
|
||||||
|
|
||||||
|
En el mundo 3D podemos utilizar imágenes de mapa de bits como *texturas* de nuestras mallas.
|
||||||
|
|
||||||
|
[[P3D: Mallas]](/notasP3D/mallas.html)
|
||||||
|
|
||||||
|
Hay múltiples formas de asignar una imagen como textura de una malla. El sistema de coordenadas UV nos permitirá determinar con precisión qué puntos de nuestra textura corresponden a qué vértices de nuestra malla.
|
||||||
|
|
||||||
|
# Coordenadas UV
|
||||||
|
|
||||||
|
Se les llaman coordenadas UV a las que nos permiten ubicar puntos en una *textura*. El eje U es el horizontal y comienza en 0 en el borde izquierdo, y el eje V es el eje vertical que comienza en 0 en el borde superior.
|
||||||
|
|
||||||
|
![](/img/coordenadas-uv.png)
|
||||||
|
|
||||||
|
## Modos: `IMAGE` o `NORMAL`
|
||||||
|
|
||||||
|
El valor máximo de cada coordenada UV va a depender del modo que escojamos.
|
||||||
|
|
||||||
|
La función para asignarlo es `textureMode( )`, que puede tener alguno de los siguientes dos argumentos:
|
||||||
|
|
||||||
|
* `IMAGE`: Las coordenadas UV corresponden a las coordenadas de los pixeles de la imagen original.
|
||||||
|
* `NORMAL`: Las coordenadas UV se *normalizan*: la U va de 0 (borde izquierdo) a 1 (borde derecho), y la V de 0 (borde superior) a 1 (borde inferior)
|
||||||
|
|
||||||
|
![](/img/textura-ladrillos-image-y-normal.png)
|
||||||
|
|
||||||
|
Es recomendable trabajar con el modo `NORMAL` pues nos permite pensar en términos de porcentajes, sin importar las dimensiones de la imagen original:
|
||||||
|
|
||||||
|
```java
|
||||||
|
// normaliza las coordenadas UV de las texturas
|
||||||
|
textureMode( NORMAL );
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wrapping: `CLAMP` o `REPEAT`
|
||||||
|
|
||||||
|
Con el modo de *wrapping* indicamos qué queremos que suceda al utilizar coordenadas UV que excedan los límites de la textura.
|
||||||
|
|
||||||
|
La función para asignarlo es `textureWrap( )`, que puede tener alguno de los siguientes dos argumentos:
|
||||||
|
|
||||||
|
* `CLAMP`: La textura original solo existe dentro de sus límites, y fuera de ellos se asigna el color más cercano a los bordes
|
||||||
|
* `REPEAT`: La textura se repite tanto en el eje U como en V.
|
||||||
|
|
||||||
|
![](/img/textura-ladrillos-clamp-y-repeat.png)
|
||||||
|
|
||||||
|
En general puede convenir utilizar la modalidad de `REPEAT`:
|
||||||
|
|
||||||
|
```java
|
||||||
|
// repite las texturas en sus ejes U y V
|
||||||
|
textureWrap( REPEAT );
|
||||||
|
```
|
||||||
|
|
||||||
|
## Mapeo de coordenadas
|
||||||
|
|
||||||
|
Para utilizar una textura en una malla, necesitamos:
|
||||||
|
|
||||||
|
* Indicar una textura de tipo `PImage` o `PGraphics` con la función `texture( )`
|
||||||
|
* Asignar a cada vértice, no solo sus coordenadas x,y,z, sino también las coordenadas u,v que le corresponderían de la textura.
|
||||||
|
|
||||||
|
A continuación algunos ejemplos donde se ve en acción.
|
||||||
|
|
||||||
|
La textura utilizada es la siguiente imagen:
|
||||||
|
|
||||||
|
![](/img/ladrillos.jpg)
|
||||||
|
|
||||||
|
# Ejemplos
|
||||||
|
|
||||||
|
## Plano con textura de imagen
|
||||||
|
|
||||||
|
En este ejemplo se carga una imagen y se utiliza como textura de un plano en XY.
|
||||||
|
|
||||||
|
![](/img/textura-ladrillos-perspectiva.png)
|
||||||
|
|
||||||
|
Observa la correspondencia entre las coordenadas `x,y,z, u,v` de los cuatro vértices.
|
||||||
|
|
||||||
|
Experimenta cambiando las coordenadas de los vértices para observar qué pasa con la malla y su textura.
|
||||||
|
|
||||||
|
```java
|
||||||
|
import peasy.PeasyCam;
|
||||||
|
PeasyCam cam;
|
||||||
|
|
||||||
|
// declara variable para textura
|
||||||
|
PImage textura;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
size(800, 600, P3D);
|
||||||
|
cam = new PeasyCam(this, 40);
|
||||||
|
perspective(PI/3, 1.0*width/height, 1, 100);
|
||||||
|
|
||||||
|
// carga imagen en la variable
|
||||||
|
textura = loadImage("ladrillos.jpg");
|
||||||
|
|
||||||
|
// configura modos de textura
|
||||||
|
textureMode( NORMAL ); // coords normalizadas
|
||||||
|
textureWrap( REPEAT ); // repite textura
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
background(255);
|
||||||
|
lights();
|
||||||
|
|
||||||
|
beginShape(QUADS);
|
||||||
|
texture( textura ); //asigna textura a malla
|
||||||
|
// coordenadas x,y,z, u,v:
|
||||||
|
vertex( 0, 0, 0, 0, 0); // superior izquierda
|
||||||
|
vertex( 5, 0, 0, 1, 0); // superior derecha
|
||||||
|
vertex( 5, 5, 0, 1, 1); // inferior derecha
|
||||||
|
vertex( 0, 5, 0, 0, 1); // inferior izquierda
|
||||||
|
endShape();
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Importante: la imagen debe estar en el mismo directorio que el sketch.
|
||||||
|
|
||||||
|
Aquí más notas sobre cargar imágenes:
|
||||||
|
|
||||||
|
[[Imágenes: Abrir, mostrar, leer]](/notas/imagenes-read.html)
|
||||||
|
|
||||||
|
## Plano con textura generada (`PGraphics`)
|
||||||
|
|
||||||
|
Este ejemplo es similar al anterior, pero con una imagen generada algorítmicamente dentro de un canvas virtual o "capa" de tipo `PGraphics`.
|
||||||
|
|
||||||
|
![](/img/textura-circulos.png)
|
||||||
|
|
||||||
|
Nota cómo las funciones de dibujo que ya conoces se utilizan para dibujar *dentro* de la capa.
|
||||||
|
|
||||||
|
```java
|
||||||
|
import peasy.PeasyCam;
|
||||||
|
PeasyCam cam;
|
||||||
|
|
||||||
|
// declara variable para capa
|
||||||
|
PGraphics capa;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
size(800, 600, P3D);
|
||||||
|
cam = new PeasyCam(this, 40);
|
||||||
|
perspective(PI/3, 1.0*width/height, 1, 100);
|
||||||
|
|
||||||
|
capa = createGraphics( 400, 400 );
|
||||||
|
|
||||||
|
// configura modos de textura
|
||||||
|
textureMode( NORMAL ); // coords normalizadas
|
||||||
|
textureWrap( REPEAT ); // repite textura
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
background(255);
|
||||||
|
lights();
|
||||||
|
|
||||||
|
// dibuja en la capa dos círculos que crecen
|
||||||
|
capa.beginDraw();
|
||||||
|
capa.background( 0 ); // fondo negro
|
||||||
|
capa.stroke( 255 );
|
||||||
|
capa.noFill();
|
||||||
|
capa.strokeWeight(10);
|
||||||
|
capa.circle( 200, 200, frameCount%400);
|
||||||
|
capa.circle( 200, 200, (frameCount+200)%400);
|
||||||
|
capa.endDraw();
|
||||||
|
|
||||||
|
beginShape(QUADS);
|
||||||
|
texture( capa ); //asigna textura a malla
|
||||||
|
// coordenadas x,y,z, u,v:
|
||||||
|
vertex( 0, 0, 0, 0, 0); // superior izquierda
|
||||||
|
vertex( 5, 0, 0, 1, 0); // superior derecha
|
||||||
|
vertex( 5, 5, 0, 1, 1); // inferior derecha
|
||||||
|
vertex( 0, 5, 0, 0, 1); // inferior izquierda
|
||||||
|
endShape();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Notas sobre capas:
|
||||||
|
|
||||||
|
[[Imágenes: Capas y máscaras]](/notas/imagenes-capas.html)
|
||||||
|
|
||||||
|
La técnica de animación utilizada en el ejemplo se aborda en estas notas:
|
||||||
|
|
||||||
|
[[Animación en función del tiempo (*frameCount*)]](/notas/animacion-frameCount.html)
|
||||||
|
|
||||||
|
## Cilindro con textura de imagen
|
||||||
|
|
||||||
|
Este ejemplo parte de un cilindro tradicional, asignando a cada cara cuadrangular una fracción proporcional de la textura en U.
|
||||||
|
|
||||||
|
![](/img/textura-cilindro.png)
|
||||||
|
|
||||||
|
Mira qué pasa si cambias el factor que multiplica a la cantidad correspondiente a la coordenada U.
|
||||||
|
|
||||||
|
```java
|
||||||
|
import peasy.PeasyCam;
|
||||||
|
PeasyCam cam;
|
||||||
|
|
||||||
|
// declara variable para textura
|
||||||
|
PImage textura;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
size(800, 600, P3D);
|
||||||
|
cam = new PeasyCam(this, 40);
|
||||||
|
perspective(PI/3, 1.0*width/height, 1, 100);
|
||||||
|
|
||||||
|
// carga imagen en la variable
|
||||||
|
textura = loadImage("ladrillos.jpg");
|
||||||
|
|
||||||
|
// configura modos de textura
|
||||||
|
textureMode( NORMAL ); // coords normalizadas
|
||||||
|
textureWrap( REPEAT ); // repite textura
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
background(255);
|
||||||
|
lights();
|
||||||
|
|
||||||
|
noStroke();
|
||||||
|
rotateX( PI/2 );
|
||||||
|
cilindro(5, 10, 20);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void cilindro(float r, float h, int N){
|
||||||
|
// dibuja un cilindro tradicional
|
||||||
|
// r: radio de la base
|
||||||
|
// h: altura
|
||||||
|
// N: número de divisiones en la base
|
||||||
|
|
||||||
|
// variables auxiliares
|
||||||
|
float x,y,angulo;
|
||||||
|
|
||||||
|
beginShape(QUAD_STRIP);
|
||||||
|
texture( textura ); // asigna textura
|
||||||
|
for(int i=0; i<=N; i=i+1){
|
||||||
|
angulo = i*TWO_PI/N;
|
||||||
|
x = r*cos(angulo);
|
||||||
|
y = r*sin(angulo);
|
||||||
|
// vértice en la base
|
||||||
|
vertex(x,y,0, 1.0*i, 1); // uv: 1.0*i, 1
|
||||||
|
// vértice en la tapa
|
||||||
|
vertex(x,y,h, 1.0*i, 0); // uv: 1.0*i, 0
|
||||||
|
}
|
||||||
|
endShape();
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
[[P3D: Sólidos cilíndricos y cónicos]](/notasP3D/cilindricos-y-conicos.html)
|