jardínBit

P3D: Texturas en Mallas

En el mundo 3D podemos utilizar imágenes de mapa de bits como texturas de nuestras mallas.

[P3D: Mallas]

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.

1 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.

1.1 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:

Es recomendable trabajar con el modo NORMAL pues nos permite pensar en términos de porcentajes, sin importar las dimensiones de la imagen original:

// normaliza las coordenadas UV de las texturas
textureMode( NORMAL ); 

1.2 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:

En general puede convenir utilizar la modalidad de REPEAT:

// repite las texturas en sus ejes U y V
textureWrap( REPEAT ); 

1.3 Mapeo de coordenadas

Para utilizar una textura en una malla, necesitamos:

A continuación algunos ejemplos donde se ve en acción.

La textura utilizada es la siguiente imagen:

2 Ejemplos

2.1 Plano con textura de imagen

En este ejemplo se carga una imagen y se utiliza como textura de un plano en XY.

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.

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]

2.2 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.

Nota cómo las funciones de dibujo que ya conoces se utilizan para dibujar dentro de la capa.

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]

La técnica de animación utilizada en el ejemplo se aborda en estas notas:

[Animación en función del tiempo (frameCount)]

2.3 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.

Mira qué pasa si cambias el factor que multiplica a la cantidad correspondiente a la coordenada U.

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]