Vead

Vead, issu des travaux de thèse d'Hugo Loi, EPI Maverick, permet de concevoir des arrangements 2D de petits éléments géométriques afin d'obtenir des textures vectorielles. L'approche cible les artistes techniques qui concevront des textures à l'aide de scripts, basés sur des opérateurs de partition (organisation globale de l'arrangement), de mapping (contrôle de l'organisation locale des éléments) et de fusion (mélange de différents arrangements).
Pour montrer le potentiel applicatif de cette méthode, des textures générées ont été utilisées pour texturer des objets 3D et fabriquer via la découpeuse laser de A4H divers objets usuels.

Génération d'exemples

def CellsRandom():
  density = (50 / 400000)
  props  = IrregularProperties(density)
  part   = RandomPartition(props,CROP_ADD_BOUNDARY)

  def draw_cell(face):
    tile = Nothing()
    for e in IncidentEdges(face):
      line = ToCurve(e)
      tile = Append(tile, line)
    return Scale(tile,0.7)

  txt = MapToFaces(draw_cell,part,DO_NOT_COMPUTE_INCIDENCE)
  square = StartDomain(2000)
  planarMapWithoutIncidence = txt(square)
  Add(planarMapWithoutIncidence)
def Circles(density):
  # Uniform partition with given density
  props  = IrregularProperties(density)
  part   = UniformPartition(props,KEEP_OUTSIDE)
  circle = ImportSVG("data/circle.svg")
   
  # Mapper: place a circle in each face
  def face_to_circle(face):
    src_p = BBoxCenter(circle)
    dst_p = Centroid(face)
    return Scale(MatchPoint(circle,src_p,dst_p),Random(face,0.05,0.10,0))

  return MapToFaces(face_to_circle,part)
def ANGrid():
  theta = pi / 4
  width = 200
  gridH   = StripesProperties(theta,width)
  gridV   = StripesProperties(theta+pi/2.0,width)
  part = GridPartition(gridH,gridV,KEEP_INSIDE)
  pattern   = ImportElt("data/AN_g.svg",10)

  def face_to_pattern(face):
  return MatchFace(pattern,face)

  txt = MapToFaces(face_to_pattern, part)
  area = StartDomain(1000)
  planarMapWithoutIncidence = txt(area)
  Add(planarMapWithoutIncidence)
def ANCoreMedaillon():

  theta = pi / 4
  width = 200
  gridH   = StripesProperties(theta,width)
  gridV   = StripesProperties(theta+pi/2.0,width)
  SetFaceLabels(gridH,"h1","h2")
  SetFaceLabels(gridV,"v1","v2")
  part = GridPartition(gridH,gridV,KEEP_INSIDE)
  pattern   = ImportElt("data/AN.svg",20)
  pattern_core = ImportElt("data/ANCore.svg",20)
    
  def vertex_to_pattern_core(face):
    rot = Random(face,-1,1,0)
    if(HasLabel(face,"h1") and HasLabel(face,"v1")):
      #h1v1
      v = Centroid(face)
      return Rotate(MatchPoint(pattern_core, BBoxCenter(pattern_core),v),rot*pi/6)
    else:
      return Nothing()

  def face_to_pattern(face):   
    src_c = PointLabeled(pattern,"bottom_start")
    dst_c = PointLabeled(pattern,"top_end")  
    if(HasLabel(face,"h1")):
      if(HasLabel(face,"v1")):
        #h1v1
        src_v = Location(IncidentVertices(face)[3])
        #dst_v = Location(IncidentVertices(face)[0])
        v = LocationAt(IncidentEdges(IncidentVertices(face)[0])[1],0.3)
          + LocationAt(IncidentEdges(IncidentVertices(face)[2])[0],0.3)     
      else:
        #h1v2
        src_v = Location(IncidentVertices(face)[1])
        #dst_v = Location(IncidentVertices(face)[2])
        v = LocationAt(IncidentEdges(IncidentVertices(face)[2])[0],0.55)
        + LocationAt(IncidentEdges(IncidentVertices(face)[2])[1],0.45)
    elif(HasLabel(face,"v1")):
      #h2v1
      src_v = Location(IncidentVertices(face)[2])
      #dst_v = Location(IncidentVertices(face)[1])
      v = LocationAt(IncidentEdges(IncidentVertices(face)[3])[0],0.45)
        + LocationAt(IncidentEdges(IncidentVertices(face)[0])[1],0.55)
    else:
      #h2v2
      src_v = Location(IncidentVertices(face)[0])
      #dst_v = Location(IncidentVertices(face)[3])
      v = LocationAt(IncidentEdges(IncidentVertices(face)[3])[0],0.4)
        + LocationAt(IncidentEdges(IncidentVertices(face)[2])[1],0.4)
    dst_v = v*0.5        
    return MatchPoints(pattern,src_c,dst_c,src_v,dst_v)
   
  txt = MapToFaces(face_to_pattern, part, DO_NOT_COMPUTE_INCIDENCE)
  txt_core = MapToFaces(vertex_to_pattern_core, part,DO_NOT_COMPUTE_INCIDENCE)
  area = StartDomain(2000)
  planarMapWithoutIncidence = txt(area)
  planarMapWithoutIncidence_core = txt_core(area)
  Add(planarMapWithoutIncidence)
  Add(planarMapWithoutIncidence_core)

  #txt = MapToFaces(face_to_pattern, part)
  #txt_core = MapToFaces(vertex_to_pattern_core, part)
  #final_txt = Union(txt, txt_core)
  #ExportSVG(final_txt,2000)
def ANStarRot():
 
  props = HexagonalProperties(1 / 22000)
  part = HexagonalPartition(props, KEEP_INSIDE)
  #pattern  = ImportSVG("data/ANStar.svg")
  pattern = ImportElt("data/ANStar.svg",5)

  def face_to_pattern(face):
    return Scale(Rotate(MatchFace(pattern,face),pi/12.0),1.1)
        
  first_txt = MapToFaces(face_to_pattern, part, DO_NOT_COMPUTE_INCIDENCE)
  #ExportSVG(first_txt,1000)
  square = StartDomain(2000)
  planarMap = first_txt(square)
  Add(planarMap)
def BubbleRandom():
 
  density = (50 / 4000000)
  props  = IrregularProperties(density)
  part   = RandomPartition(props,KEEP_INSIDE)
    
  #pattern  = ImportSVG("data/Bubble.svg")
  #to get unique pathes and be able to fill elements in inkscape
  #second argument is sampling, must be set according to pattern size
  pattern = ImportElt("data/Bubble.svg",10)

  def face_to_pattern(face): 
    fsize = min(BBoxWidth(face), BBoxHeight(face))
    size = fsize / BBoxWidth(pattern) 
    return Scale(MatchFace(pattern,face),size*0.9)
 
  #with intersections computation
  #txt = MapToFaces(face_to_pattern, part)
  #ExportSVG(txt,2000)

  #to avoid intersections computation and then get whole elements to fill
  txt = MapToFaces(face_to_pattern, part, DO_NOT_COMPUTE_INCIDENCE)
  #instead of ExportSVG that crops stuff and then return empty because of missing incidences
  #won't draw external square
  square = StartDomain(2000)
  planarMapWithoutIncidence = txt(square)
  Add(planarMapWithoutIncidence)
def SeventiesBig():
  theta = pi/6
  width = 350
  # Grid partition with given width and orientation
  lines1   = StripesProperties(theta,width)
  lines2   = StripesProperties(theta+pi/2.0,width)
  grid_tex = GridPartition(lines1,lines2,KEEP_INSIDE)
  #square   = ImportSVG("data/square.svg") 
  square= ImportElt("data/square.svg",10)
  # Mapper: place a rounded square in each face
  def face_to_square(face):
    i = randint(0,3)
    v = (Centroid(face) - Location(IncidentVertices(face)[i]))*0.5
    return Scale(Translate(MatchFace(square,face),v),0.9)
  # Return the texture genrated via the mapping operator
  txt = MapToFaces(face_to_square,grid_tex, DO_NOT_COMPUTE_INCIDENCE)
  area = StartDomain(2000)
  planarMapWithoutIncidence = txt(area)
  Add(planarMapWithoutIncidence)
def Plush():
  density = 9e-5
  props  = IrregularProperties(density)
  part   = UniformPartition(props,KEEP_INSIDE)
  pattern  = ImportSVG("data/plush.svg")
    
  def face_to_pattern(face):
    rot = Random(face,1,6,0)
    return Scale(Rotate(MatchFace(pattern,face),rot*pi/6),2)
   
  first_txt = MapToFaces(face_to_pattern, part)
  ExportSVG(first_txt,1600)
def Stars():
  props = HexagonalProperties(1 / 22000)
  part = HexagonalPartition(props, KEEP_OUTSIDE)
  pattern  = ImportElt("data/Star.svg",10)
    
  def face_to_pattern(face):
    w = Random(face,1,6,0)
    return Rotate(MatchFace(pattern,face),w*pi/6)
  txt = MapToFaces(face_to_pattern, part,DO_NOT_COMPUTE_INCIDENCE)
  area = StartDomain(1000)
  planarMap = txt(area)
  Add(planarMap)
def curves(theta,width):
  # Stripes partition with given width and orientation
  props   = StripesProperties(theta,width)
  stripes = StripesPartition(props)
  line    = ImportSVG("data/line6.svg")

  # Mapper: replace each edge by a curve 
  def line_to_curve(edge):
    if IsBoundary(edge):
      return Nothing()
    src_c = PointLabeled(line,"start")
    dst_c = PointLabeled(line,"end")
    src_v = Location(SourceVertex(edge))
    dst_v = Location(TargetVertex(edge))
    return MatchPoints(line,src_c,dst_c,src_v,dst_v)

  # Return the texture genrated via the mapping operator
  return MapToEdges(line_to_curve,stripes)
  
def Floor():
  # Grid partition, including face labels
  size   = 2000
  lines1 = StripesProperties(0,200)
  lines2 = StripesProperties(pi/2,200)
  SetFaceLabels(lines1,"h1","h2")
  SetFaceLabels(lines2,"v1","v2")
  grid_tex = GridPartition(lines1,lines2,KEEP_OUTSIDE)

  # Mapper: creates stripes in each face
  def face_to_stripes(face):
    width = BBoxWidth(face)/Random(face,4,6,0)
    theta = 0
    if((HasLabel(face,"h1") and HasLabel(face,"v1")) or
       (HasLabel(face,"h2") and HasLabel(face,"v2"))):
      theta = pi/2
      #return StripesPartition(lines)(face)
      return curves(theta, width)(face)

  # Mapping operator
  tiled_tex = MapToFaces(face_to_stripes,grid_tex)
   
  # Final texture
  ExportSVG(tiled_tex,size)    
def wood_curves(theta,width):
  # Stripes partition with given width and orientation
  props   = StripesProperties(theta,width)
  stripes = StripesPartition(props)
  line    = ImportSVG("data/wood_line.svg")

  # Mapper: replace each edge by a curve 
  def line_to_curve(edge):
    if IsBoundary(edge):
      return Nothing()
    src_c = PointLabeled(line,"start")
    dst_c = PointLabeled(line,"end")
    src_v = Location(SourceVertex(edge))
    dst_v = Location(TargetVertex(edge))
   return MatchPoints(line,src_c,dst_c,src_v,dst_v)

  # Return the texture genrated via the mapping operator
  return MapToEdges(line_to_curve,stripes)

def Wood():
  size   = 4000
  linesV = StripesProperties(pi/2,200)
  linesH = StripesProperties(0,2000)
  part = GridPartition(linesV, linesH, CROP)

  # Mapper: creates stripes in each face
  def stripes_to_face(face):
    width = 10*randint(3,10)
    return wood_curves(pi/2,width)(face)

  # Mapping operator
  tex = MapToFaces(stripes_to_face ,part)  
  # Final texture
  ExportSVG(tex,size)    
def blobs(theta,width):
  # Grid partition with given width and orientation
  lines1   = StripesProperties(theta,width)
  lines2   = StripesProperties(theta+pi/2.0,width)
  grid_tex = GridPartition(lines1,lines2,KEEP_INSIDE)
  square   = ImportSVG("data/blob.svg") 
  # Mapper: place a rounded square in each face
  def face_to_blob(face):
    return Scale(Rotate(MatchFace(square,face),Random(face,0.0,2.0*pi,1)),0.6)
  # Return the texture genrated via the mapping operator
  return MapToFaces(face_to_blob,grid_tex)


def curves_elt(theta,width):
  # Stripes partition with given width and orientation
  props   = StripesProperties(theta,width)
  stripes = StripesPartition(props)
  line    = ImportElt("data/line6.svg",10)

  # Mapper: replace each edge by a curve 
  def line_to_curve(edge):
    if IsBoundary(edge):
      return Nothing()
    src_c = PointLabeled(line,"start")
    dst_c = PointLabeled(line,"end")
    src_v = Location(SourceVertex(edge))
    dst_v = Location(TargetVertex(edge))
    return MatchPoints(line,src_c,dst_c,src_v,dst_v)

  # Return the texture genrated via the mapping operator
  return MapToEdges(line_to_curve,stripes,DO_NOT_COMPUTE_INCIDENCE)


def circles_elt(density):
  # Uniform partition with given density
  props  = IrregularProperties(density)
  part   = UniformPartition(props,KEEP_OUTSIDE)
  circle = ImportElt("data/circle.svg",10)

  # Mapper: place a circle in each face
  def face_to_circle(face):
    src_p = BBoxCenter(circle)
    dst_p = Centroid(face)
    return Scale(MatchPoint(circle,src_p,dst_p),Random(face,0.05,0.10,0))

  return MapToFaces(face_to_circle,part,DO_NOT_COMPUTE_INCIDENCE)
  
def Wallpaper():
    txt_frame = blobs(pi/3,400)
    txt_stripes = curves_elt(pi/6,20)
    txt_circles = circles_elt(9e-5)

    txt_in = Inside(txt_circles, txt_frame, CROP_ADD_BOUNDARY)
    txt_out = Outside(txt_stripes, txt_frame, CROP_ADD_BOUNDARY)
    txt = Union(txt_in, txt_out)
 
    area = StartDomain(4000)
    planarMapWithoutIncidence = txt(area)
    Add(planarMapWithoutIncidence)

Cas d'utilisation

Motifs pour texturation d'objets 3D

Motifs pour gravure/découpe d'Objets

[]

From random bubbles texture to furniture

[]

From random irregular cells texture to trimmed lampshade