Texturing

Texturing #

La texturizacion es el proceso por el cual una imagen o mapa de bits es mapeado sobre un objeto 3D o una superficie, esto se logra trabajando con los sistemas coorddenados de las figuras y de la textura, la cual mediante el shader y la GPU son procesados haciendo uso de GLSL y algunos paradigmas de programacion, como programacion en paralelo.

1. Visualizacion UV #

La visualizacion UV nos permite mostrar una textura sobre un espacio particular.

Ejercicio 1:
Redefinir las coordenas de la figura texturizada para invertir la orientacion vertical de la imagen.
Solucion Ejercicio 1:
Redefinir las coordenadas [u] y [v] de los vertex definidos en uv.js para que cada punto del clip space mapeara a su inverso en el texture space.
CODIGO: uv_inverse.js
let uvShader;

function preload() {
  uvShader = readShader('/visual_computing/sketches/shaders/uv.frag', { matrices: Tree.NONE, varyings: Tree.texcoords2 });
}

function setup() {
  createCanvas(300, 300, WEBGL);
  noStroke();
  shader(uvShader);
  textureMode(NORMAL);
}

function draw() {
  background(0);
  beginShape();
  vertex(-1, -1, 0, 0, 1);
  vertex( 1, -1, 0, 1, 1);
  vertex( 1,  1, 0, 1, 0);
  vertex(-1,  1, 0, 0, 0);
  endShape();
}
CODIGO: uv.frag
precision mediump float;
varying vec2 texcoords2;

void main() {
  gl_FragColor = vec4(texcoords2.xy, 0.0, 1.0);
}

2. 3D #

La visualizacion 3D de espaciosUV nos permite mostrar una textura sobre un objeto particular en un espacio que permite la interaccion 3D, sin embargo esto no altera en demasia .

Ejercicio 2.1:
Incluir el canal azul en la visualizacion UV, ya sea Azul + Verde ó Azul + Rojo.
Solucion Ejercicio 2.1:
Modificar el shader para que evalue 2 variables y reajuste el color dependiendo de una de las opciones seleccionadas, modificando uno de los canales dependiendo de la opcion.
CODIGO: uvplus.js
let easycam;
let uvShader;
let c1, c2;

let rtb = false, gtb = false;

function preload() {
  uvShader = readShader('/visual_computing/sketches/shaders/uvplus.frag',{ matrices: Tree.pmvMatrix, varyings: Tree.texcoords2 });
}

function setup() {
  createCanvas(300, 300, WEBGL);
  textureMode(NORMAL);
  c1 = createCheckbox('Red To Blue', false);
  c2 = createCheckbox('Green To Blue', false);
  c1.position(10, 310);
  c2.position(150, 310);
  shader(uvShader);
}

function draw() {
  background(200);
  orbitControl();
  axes();
  push();
  noStroke();
  quad(-width / 2, -height / 2, width / 2, -height / 2,
        width / 2, height / 2, -width / 2, height / 2);
  pop();
  
  if(c1.checked()){
    uvShader.setUniform('rtb',true)
     uvShader.setUniform('gtb',false)
  }else if(c2.checked()){
    uvShader.setUniform('rtb',false)
    uvShader.setUniform('gtb',true)
  }else{
    uvShader.setUniform('rtb',false)
    uvShader.setUniform('gtb',false)
  }
}

function mouseWheel(event) {
  return false;
}
CODIGO: uvplus.frag
precision mediump float;

uniform bool rtb;
uniform bool gtb;
varying vec2 texcoords2;

void main() {
  if(rtb==true){
     gl_FragColor = vec4(0.0 ,texcoords2.y,texcoords2.x, 1.0);
  }else if(gtb==true){
    gl_FragColor = vec4(texcoords2.x , 0.0, texcoords2.y, 1.0);
  }else{
    gl_FragColor = vec4(texcoords2.xy, 0.0, 1.0);
  }
}

Ejercicio 2.2:
Utilizar figuras diferentes a Quad como filtros de pantalla.
Solucion Ejercicio 2.2:
Modificar las figuras mediante la definicion de metodos y figuras de P5, añadir el control de opacidad y el cambio de canales [RGB].
CODIGO: screen.js
let easycam;
let uvShader;
let opacity;

let c1, c2;

let rtb = false, gtb = false;

function preload() {
  uvShader = readShader('/visual_computing/sketches/shaders/screen.frag',{ matrices: Tree.pmvMatrix, varyings: Tree.texcoords2 });
}

function setup() {
  createCanvas(450, 450, WEBGL);
  
  // easycam stuff
  let state = {
    distance: 250,           
    center: [0, 0, 0],       
    rotation: [0, 0, 0, 1],  
  };
  easycam = createEasyCam();
  easycam.state_reset = state;   
  easycam.setState(state, 2000); 
  textureMode(NORMAL);
  opacity = createSlider(0, 1, 0.5, 0.01);
  opacity.position(10, 25);
  opacity.style('width', '280px');
  
  c1 = createCheckbox('R To B', false);
  c2 = createCheckbox('G To B', false);
  c1.position(100, 10);
  c2.position(200, 10);
  
  sel = createSelect();
  sel.position(10, 10);
  sel.option('Quad');
  sel.option('Triangle');
  sel.option('Circle');
  sel.selected('Quad');
  
}

function draw() {
  background(200);
  
  resetShader();
  
  axes();
  grid();
  translate(0, -70);
  rotateY(0.5);
  fill(color(255, 0, 255, 125));
  box(30, 50);
  translate(70, 70);
  fill(color(0, 255, 255, 125));
  sphere(30, 50);
  
  shader(uvShader);
 
  uvShader.setUniform('opacity', opacity.value());
  
  beginHUD();
  
    noStroke();

    if(sel.value() == "Quad"){
      quad(0, 0, width, 0, width, height, 0, height);
    }else if(sel.value() == "Triangle"){
      triangle(0,0,width,0,width/2,height)
    }else if (sel.value() == "Circle"){
      circle(width/2,height/2,width)
    }
  
    if(c1.checked()){
      uvShader.setUniform('rtb',true)
       uvShader.setUniform('gtb',false)
    }else if(c2.checked()){
      uvShader.setUniform('rtb',false)
      uvShader.setUniform('gtb',true)
    }else{
      uvShader.setUniform('rtb',false)
      uvShader.setUniform('gtb',false)
    }

  endHUD();
}

function mouseWheel(event) {
  //comment to enable page scrolling
  return false;
}
CODIGO: screen.frag
precision mediump float;

uniform bool rtb;
uniform bool gtb;
uniform float opacity;
varying vec2 texcoords2;

void main() {
  if(rtb==true){
     gl_FragColor = vec4(0.0 ,texcoords2.y,texcoords2.x, opacity);
  }else if(gtb==true){
    gl_FragColor = vec4(texcoords2.x , 0.0, texcoords2.y, opacity);
  }else{
    gl_FragColor = vec4(texcoords2.xy, 0.0, opacity);
  }
}

3. Muestreo de Texturas #

Los efectos que puedan aplicarse a una imagen requieren utilizar coordenaddas dadas, las coordenadas texcoords2 y los texels permiten realizar operaciones pixel a pixel haciendo uso de la GPU .

Ejercicio 3.1 y 3.2:

  • Implementar heraamientas de iluminacion i color tales como HSV valor V, HSL luminancia L, Promedio de componentes.
  • Implementar el tintado de texturas mezclando el colo y los datos interpolados de los texeles.
Solucion Ejercicio 3.1 y 3.2:
Para modificar la imagen se opera matematicamente los valores que se obtienen en los texels [Canales RGBA] , o se modifican de plano para que el shader los procese nuevamente.
CODIGO: tools.js
let lumaShader;
let img;
let grey_scale;
let average;
let HSVV;
let Tint;
let ColorT;

function preload() {
  lumaShader = readShader('/visual_computing/sketches/shaders/colors.frag',{ varyings: Tree.texcoords2});
  img = loadImage('/visual_computing/imgs/car.jpg');
}

function drawControls(enabled){
  if(enabled){
    colorT = createColorPicker(color(255,255,255));
    colorT.position(125, 10);
  }
}

function setup() {
  createCanvas(700, 500, WEBGL);
  noStroke();
  textureMode(NORMAL);
  
  sel = createSelect();
  sel.position(10, 10);
  sel.option('None');
  sel.option('Luma');
  sel.option('Average');
  sel.option('HSV Value V');
  sel.option('HSL Value L');
  sel.option('Tint');
  
  sel.selected('None');
  
  drawControls(true);
  
  
  
}

function draw() {
  background(0);
  
  if(sel.value()=="None"){
    shader(lumaShader);
    lumaShader.setUniform('texture', img);
    lumaShader.setUniform('HSVV',false);
    lumaShader.setUniform('HSLL',false);
    lumaShader.setUniform('grey_scale',false);
    lumaShader.setUniform('average',false);
    
  }else if(sel.value()=="Luma"){
    shader(lumaShader);
    lumaShader.setUniform('grey_scale',true);
    lumaShader.setUniform('average',false);
    lumaShader.setUniform('HSVV',false);
    lumaShader.setUniform('HSLL',false);
    lumaShader.setUniform('texture', img);
    
  }else if(sel.value()=="Average"){
    shader(lumaShader);
    lumaShader.setUniform('average',true);
    lumaShader.setUniform('grey_scale',false);
    lumaShader.setUniform('HSVV',false);
    lumaShader.setUniform('HSLL',false);
    lumaShader.setUniform('texture', img);
    
  }else if(sel.value() =="HSV Value V"){
    shader(lumaShader);
    lumaShader.setUniform('HSVV',true);
    lumaShader.setUniform('HSLL',false);
    lumaShader.setUniform('average',false);
    lumaShader.setUniform('grey_scale',false);
    lumaShader.setUniform('texture', img);
    
  }else if(sel.value() =="HSL Value L"){
    shader(lumaShader);
    lumaShader.setUniform('HSLL',true);
    lumaShader.setUniform('HSVV',false);
    lumaShader.setUniform('average',false);
    lumaShader.setUniform('grey_scale',false);
    lumaShader.setUniform('texture', img);
    
  }else if(sel.value() =="Tint"){
    shader(lumaShader);
    lumaShader.setUniform('Tint',true);
    lumaShader.setUniform('HSLL',false);
    lumaShader.setUniform('HSVV',false);
    lumaShader.setUniform('average',false);
    lumaShader.setUniform('grey_scale',false);
    lumaShader.setUniform('texture', img);
    
    let RC = colorT.color();
    lumaShader.setUniform('colorT',[red(RC),green(RC),blue(RC),1.0]);
    
  }
  
  quad(-width / 2, -height / 2, width / 2, -height / 2, width / 2, height / 2, -width / 2, height / 2);
}
CODIGO: colors.frag
precision mediump float;

uniform bool grey_scale;
uniform bool average;
uniform bool HSVV;
uniform bool HSLL;
uniform bool Tint;

uniform vec4 colorT;

uniform sampler2D texture;

varying vec2 texcoords2;

float luma(vec3 texel) {
  return 0.299 * texel.r + 0.587 * texel.g + 0.114 * texel.b;
}

float favg(vec3 texel){
  return (texel.r + texel.g + texel.b ) / 3.0;
}

float HSV (vec3 texel){
  return max(max(texel.r,texel.g),texel.b); ;
}

float HSL (vec3 texel){
  float CMax = max(max(texel.r,texel.g),texel.b);
  float CMin = min(min(texel.r,texel.g),texel.b);
  return (CMax + CMin) / 2.0 ;
}

float Ftint(float channel, float color){
  float N = channel * (color / 255.0);
  return N;
}


void main() {
  
  vec4 texel = texture2D(texture, texcoords2);
  
  if(grey_scale == true){
    gl_FragColor = vec4((vec3(luma(texel.rgb))), 1.0); 
  }else if(average == true){
    gl_FragColor = vec4((vec3(favg(texel.rgb))), 1.0); 
  }else if(HSVV== true){
    gl_FragColor = vec4((vec3(HSV(texel.rgb))), 1.0);
  }else if(HSLL== true){
    gl_FragColor = vec4((vec3(HSL(texel.rgb))), 1.0);
  }else if(Tint == true){
    gl_FragColor = vec4(Ftint(texel.r,colorT.x),Ftint(texel.g,colorT.y),Ftint(texel.b,colorT.z),1.0);
  }else{
    gl_FragColor = texel;  
  }
  
}

Referencias: