Disegna la teiera dello Utah


20

La teiera Utah , originariamente creata da Martin Newell, è un comodo oggetto per testare programmi di grafica 3D.

Il compito è quello di creare un'immagine wireframe della teiera nella proiezione prospettica. Per incoraggiare l'idea di un'applicazione con codice sorgente , la visualizzazione e il controllo della telecamera possono essere isolati ed esclusi dal conteggio. In questo modo è possibile modificare i parametri e il file di input e riutilizzare il codice per generare immagini diverse, ma non è necessario creare un'utilità completa che accetta argomenti della riga di comando complicati o simili. Si cerca un equilibrio "hacker".

teiera wireframe

rif. StackOverflow: come funzionano le patch di Bezier nella teiera dello Utah?

Quindi ci sono tre sottoattività qui:

  • leggere i dati della teiera nel suo formato originale .
  • suddividere i dati della patch usando la divisione deCasteljau o un altro metodo. Altri metodi stanno usando le matrici di base di Bezier e valutando i polinomi (riferimenti standard, come Foley e van Dam, Newmann e Sproull) o metodi di base di Bernstein (che sono ancora al di là di me).
  • proiettare i punti in 2D (se il linguaggio non supporta il 3D in modo nativo) e disegnare il contorno di ogni piccola patch vista da un punto dell'occhio la cui vista è centrata su un punto LookAt e il cui asse verticale è allineato con l'asse verticale della teiera (cioè disegnarlo "in posizione verticale" da un bel punto di vista).

Supponendo che la lettura di dati di testo orientati alla linea da un file sia un piccolo problema, questa sfida riguarda davvero la pratica con i dati di patch di Bezier bi-cubici.

Poiché il semplice test normale per l'abbattimento del backface non è sufficiente (le patch non sono tutte orientate verso l'esterno), non è necessaria la rimozione di linee nascoste o superfici. Come un wireframe, dovrebbe apparire bene con la parte posteriore visibile. L'aspetto può essere migliorato regolando la larghezza della linea in base alla distanza dall'occhio, ma ciò non è strettamente necessario (i miei programmi non lo fanno).

Questo è sia che . Le risposte in competizione nel golf dovrebbero includere un conteggio normale. Ma le presentazioni in lingue insolite sono molto incoraggiate, anche se non sono particolarmente brevi.

Per gli appassionati di complessità di Kolmogorov, esiste un set di dati più conciso in cui è possibile ricostruire l'intero set aggiungendo rotazioni e mirroring delle patch. E in A Trip Down the Graphics Pipeline di Jim Blinn , c'è un metodo di generazione ancora più conciso usando il fatto che le singole patch hanno simmetrie rotazionali o di altro tipo. L'intero corpo (o coperchio) può essere descritto da una singola curva di Bezier che viene ruotata attorno all'asse y. Il beccuccio e le maniglie possono essere descritti dalle due curve del loro profilo, quindi selezionando i punti di controllo intermedi per approssimare un'estrusione circolare.


Devo includere il conteggio della matrice di punti nel mio conteggio?
TheDoctor

Preferirei vederlo provenire da un file, ... ma no, non c'è bisogno di contare i dati della patch comunque.
Luser droog

Suggerirei di non consentire i builtin come glutSolidTeapoteglutWireTeapot !
Anders Kaseorg,

@AndersKaseorg Penso di averlo coperto richiedendo di leggere i dati originali. ... Detto questo, sono stato rilassato nel far rispettare questa regola. Una risposta più strettamente valida prenderebbe facilmente il segno di spunta, anche se è più lunga.
Luser droog,

@luserdroog Immagina una soluzione che legge i dati originali, li ignora e chiama glutWireTeapot.
Anders Kaseorg,

Risposte:


9

Processing (java), 314 (237 senza controllo videocamera)

Non comprese le definizioni di array:

void setup(){size(640,480,P3D);}void draw(){background(0);noFill();stroke(255);translate(width/2,height/2,70);scale(30);rotateX(map(mouseX,0,width,0,TWO_PI));rotateY(map(mouseY,0,height,0,TWO_PI));for(int[] p:patches){beginShape();for(int pt:p){vertex(data[pt-1][0],data[pt-1][1],data[pt-1][2]);}endShape(CLOSE);}}

Definizioni dell'array di dati:

float [][] data = {{1.4,0.0,2.4},
{1.4,-0.784,2.4},
{0.784,-1.4,2.4},
{0.0,-1.4,2.4},
{1.3375,0.0,2.53125},
{1.3375,-0.749,2.53125},
{0.749,-1.3375,2.53125},
{0.0,-1.3375,2.53125},
{1.4375,0.0,2.53125},
{1.4375,-0.805,2.53125},
{0.805,-1.4375,2.53125},
{0.0,-1.4375,2.53125},
{1.5,0.0,2.4},
{1.5,-0.84,2.4},
{0.84,-1.5,2.4},
{0.0,-1.5,2.4},
{-0.784,-1.4,2.4},
{-1.4,-0.784,2.4},
{-1.4,0.0,2.4},
{-0.749,-1.3375,2.53125},
{-1.3375,-0.749,2.53125},
{-1.3375,0.0,2.53125},
{-0.805,-1.4375,2.53125},
{-1.4375,-0.805,2.53125},
{-1.4375,0.0,2.53125},
{-0.84,-1.5,2.4},
{-1.5,-0.84,2.4},
{-1.5,0.0,2.4},
{-1.4,0.784,2.4},
{-0.784,1.4,2.4},
{0.0,1.4,2.4},
{-1.3375,0.749,2.53125},
{-0.749,1.3375,2.53125},
{0.0,1.3375,2.53125},
{-1.4375,0.805,2.53125},
{-0.805,1.4375,2.53125},
{0.0,1.4375,2.53125},
{-1.5,0.84,2.4},
{-0.84,1.5,2.4},
{0.0,1.5,2.4},
{0.784,1.4,2.4},
{1.4,0.784,2.4},
{0.749,1.3375,2.53125},
{1.3375,0.749,2.53125},
{0.805,1.4375,2.53125},
{1.4375,0.805,2.53125},
{0.84,1.5,2.4},
{1.5,0.84,2.4},
{1.75,0.0,1.875},
{1.75,-0.98,1.875},
{0.98,-1.75,1.875},
{0.0,-1.75,1.875},
{2.0,0.0,1.35},
{2.0,-1.12,1.35},
{1.12,-2.0,1.35},
{0.0,-2.0,1.35},
{2.0,0.0,0.9},
{2.0,-1.12,0.9},
{1.12,-2.0,0.9},
{0.0,-2.0,0.9},
{-0.98,-1.75,1.875},
{-1.75,-0.98,1.875},
{-1.75,0.0,1.875},
{-1.12,-2.0,1.35},
{-2.0,-1.12,1.35},
{-2.0,0.0,1.35},
{-1.12,-2.0,0.9},
{-2.0,-1.12,0.9},
{-2.0,0.0,0.9},
{-1.75,0.98,1.875},
{-0.98,1.75,1.875},
{0.0,1.75,1.875},
{-2.0,1.12,1.35},
{-1.12,2.0,1.35},
{0.0,2.0,1.35},
{-2.0,1.12,0.9},
{-1.12,2.0,0.9},
{0.0,2.0,0.9},
{0.98,1.75,1.875},
{1.75,0.98,1.875},
{1.12,2.0,1.35},
{2.0,1.12,1.35},
{1.12,2.0,0.9},
{2.0,1.12,0.9},
{2.0,0.0,0.45},
{2.0,-1.12,0.45},
{1.12,-2.0,0.45},
{0.0,-2.0,0.45},
{1.5,0.0,0.225},
{1.5,-0.84,0.225},
{0.84,-1.5,0.225},
{0.0,-1.5,0.225},
{1.5,0.0,0.15},
{1.5,-0.84,0.15},
{0.84,-1.5,0.15},
{0.0,-1.5,0.15},
{-1.12,-2.0,0.45},
{-2.0,-1.12,0.45},
{-2.0,0.0,0.45},
{-0.84,-1.5,0.225},
{-1.5,-0.84,0.225},
{-1.5,0.0,0.225},
{-0.84,-1.5,0.15},
{-1.5,-0.84,0.15},
{-1.5,0.0,0.15},
{-2.0,1.12,0.45},
{-1.12,2.0,0.45},
{0.0,2.0,0.45},
{-1.5,0.84,0.225},
{-0.84,1.5,0.225},
{0.0,1.5,0.225},
{-1.5,0.84,0.15},
{-0.84,1.5,0.15},
{0.0,1.5,0.15},
{1.12,2.0,0.45},
{2.0,1.12,0.45},
{0.84,1.5,0.225},
{1.5,0.84,0.225},
{0.84,1.5,0.15},
{1.5,0.84,0.15},
{-1.6,0.0,2.025},
{-1.6,-0.3,2.025},
{-1.5,-0.3,2.25},
{-1.5,0.0,2.25},
{-2.3,0.0,2.025},
{-2.3,-0.3,2.025},
{-2.5,-0.3,2.25},
{-2.5,0.0,2.25},
{-2.7,0.0,2.025},
{-2.7,-0.3,2.025},
{-3.0,-0.3,2.25},
{-3.0,0.0,2.25},
{-2.7,0.0,1.8},
{-2.7,-0.3,1.8},
{-3.0,-0.3,1.8},
{-3.0,0.0,1.8},
{-1.5,0.3,2.25},
{-1.6,0.3,2.025},
{-2.5,0.3,2.25},
{-2.3,0.3,2.025},
{-3.0,0.3,2.25},
{-2.7,0.3,2.025},
{-3.0,0.3,1.8},
{-2.7,0.3,1.8},
{-2.7,0.0,1.575},
{-2.7,-0.3,1.575},
{-3.0,-0.3,1.35},
{-3.0,0.0,1.35},
{-2.5,0.0,1.125},
{-2.5,-0.3,1.125},
{-2.65,-0.3,0.9375},
{-2.65,0.0,0.9375},
{-2.0,-0.3,0.9},
{-1.9,-0.3,0.6},
{-1.9,0.0,0.6},
{-3.0,0.3,1.35},
{-2.7,0.3,1.575},
{-2.65,0.3,0.9375},
{-2.5,0.3,1.125},
{-1.9,0.3,0.6},
{-2.0,0.3,0.9},
{1.7,0.0,1.425},
{1.7,-0.66,1.425},
{1.7,-0.66,0.6},
{1.7,0.0,0.6},
{2.6,0.0,1.425},
{2.6,-0.66,1.425},
{3.1,-0.66,0.825},
{3.1,0.0,0.825},
{2.3,0.0,2.1},
{2.3,-0.25,2.1},
{2.4,-0.25,2.025},
{2.4,0.0,2.025},
{2.7,0.0,2.4},
{2.7,-0.25,2.4},
{3.3,-0.25,2.4},
{3.3,0.0,2.4},
{1.7,0.66,0.6},
{1.7,0.66,1.425},
{3.1,0.66,0.825},
{2.6,0.66,1.425},
{2.4,0.25,2.025},
{2.3,0.25,2.1},
{3.3,0.25,2.4},
{2.7,0.25,2.4},
{2.8,0.0,2.475},
{2.8,-0.25,2.475},
{3.525,-0.25,2.49375},
{3.525,0.0,2.49375},
{2.9,0.0,2.475},
{2.9,-0.15,2.475},
{3.45,-0.15,2.5125},
{3.45,0.0,2.5125},
{2.8,0.0,2.4},
{2.8,-0.15,2.4},
{3.2,-0.15,2.4},
{3.2,0.0,2.4},
{3.525,0.25,2.49375},
{2.8,0.25,2.475},
{3.45,0.15,2.5125},
{2.9,0.15,2.475},
{3.2,0.15,2.4},
{2.8,0.15,2.4},
{0.0,0.0,3.15},
{0.0,-0.002,3.15},
{0.002,0.0,3.15},
{0.8,0.0,3.15},
{0.8,-0.45,3.15},
{0.45,-0.8,3.15},
{0.0,-0.8,3.15},
{0.0,0.0,2.85},
{0.2,0.0,2.7},
{0.2,-0.112,2.7},
{0.112,-0.2,2.7},
{0.0,-0.2,2.7},
{-0.002,0.0,3.15},
{-0.45,-0.8,3.15},
{-0.8,-0.45,3.15},
{-0.8,0.0,3.15},
{-0.112,-0.2,2.7},
{-0.2,-0.112,2.7},
{-0.2,0.0,2.7},
{0.0,0.002,3.15},
{-0.8,0.45,3.15},
{-0.45,0.8,3.15},
{0.0,0.8,3.15},
{-0.2,0.112,2.7},
{-0.112,0.2,2.7},
{0.0,0.2,2.7},
{0.45,0.8,3.15},
{0.8,0.45,3.15},
{0.112,0.2,2.7},
{0.2,0.112,2.7},
{0.4,0.0,2.55},
{0.4,-0.224,2.55},
{0.224,-0.4,2.55},
{0.0,-0.4,2.55},
{1.3,0.0,2.55},
{1.3,-0.728,2.55},
{0.728,-1.3,2.55},
{0.0,-1.3,2.55},
{1.3,0.0,2.4},
{1.3,-0.728,2.4},
{0.728,-1.3,2.4},
{0.0,-1.3,2.4},
{-0.224,-0.4,2.55},
{-0.4,-0.224,2.55},
{-0.4,0.0,2.55},
{-0.728,-1.3,2.55},
{-1.3,-0.728,2.55},
{-1.3,0.0,2.55},
{-0.728,-1.3,2.4},
{-1.3,-0.728,2.4},
{-1.3,0.0,2.4},
{-0.4,0.224,2.55},
{-0.224,0.4,2.55},
{0.0,0.4,2.55},
{-1.3,0.728,2.55},
{-0.728,1.3,2.55},
{0.0,1.3,2.55},
{-1.3,0.728,2.4},
{-0.728,1.3,2.4},
{0.0,1.3,2.4},
{0.224,0.4,2.55},
{0.4,0.224,2.55},
{0.728,1.3,2.55},
{1.3,0.728,2.55},
{0.728,1.3,2.4},
{1.3,0.728,2.4},
{0.0,0.0,0.0},
{1.5,0.0,0.15},
{1.5,0.84,0.15},
{0.84,1.5,0.15},
{0.0,1.5,0.15},
{1.5,0.0,0.075},
{1.5,0.84,0.075},
{0.84,1.5,0.075},
{0.0,1.5,0.075},
{1.425,0.0,0.0},
{1.425,0.798,0.0},
{0.798,1.425,0.0},
{0.0,1.425,0.0},
{-0.84,1.5,0.15},
{-1.5,0.84,0.15},
{-1.5,0.0,0.15},
{-0.84,1.5,0.075},
{-1.5,0.84,0.075},
{-1.5,0.0,0.075},
{-0.798,1.425,0.0},
{-1.425,0.798,0.0},
{-1.425,0.0,0.0},
{-1.5,-0.84,0.15},
{-0.84,-1.5,0.15},
{0.0,-1.5,0.15},
{-1.5,-0.84,0.075},
{-0.84,-1.5,0.075},
{0.0,-1.5,0.075},
{-1.425,-0.798,0.0},
{-0.798,-1.425,0.0},
{0.0,-1.425,0.0},
{0.84,-1.5,0.15},
{1.5,-0.84,0.15},
{0.84,-1.5,0.075},
{1.5,-0.84,0.075},
{0.798,-1.425,0.0},
{1.425,-0.798,0.0}
};

int [][] patches = {
    {32},
{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
{4,17,18,19,8,20,21,22,12,23,24,25,16,26,27,28},
{19,29,30,31,22,32,33,34,25,35,36,37,28,38,39,40},
{31,41,42,1,34,43,44,5,37,45,46,9,40,47,48,13},
{13,14,15,16,49,50,51,52,53,54,55,56,57,58,59,60},
{16,26,27,28,52,61,62,63,56,64,65,66,60,67,68,69},
{28,38,39,40,63,70,71,72,66,73,74,75,69,76,77,78},
{40,47,48,13,72,79,80,49,75,81,82,53,78,83,84,57},
{57,58,59,60,85,86,87,88,89,90,91,92,93,94,95,96},
{60,67,68,69,88,97,98,99,92,100,101,102,96,103,104,105},
{69,76,77,78,99,106,107,108,102,109,110,111,105,112,113,114},
{78,83,84,57,108,115,116,85,111,117,118,89,114,119,120,93},
{121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136},
{124,137,138,121,128,139,140,125,132,141,142,129,136,143,144,133},
{133,134,135,136,145,146,147,148,149,150,151,152,69,153,154,155},
{136,143,144,133,148,156,157,145,152,158,159,149,155,160,161,69},
{162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177},
{165,178,179,162,169,180,181,166,173,182,183,170,177,184,185,174},
{174,175,176,177,186,187,188,189,190,191,192,193,194,195,196,197},
{177,184,185,174,189,198,199,186,193,200,201,190,197,202,203,194},
{204,204,204,204,207,208,209,210,211,211,211,211,212,213,214,215},
{204,204,204,204,210,217,218,219,211,211,211,211,215,220,221,222},
{204,204,204,204,219,224,225,226,211,211,211,211,222,227,228,229},
{204,204,204,204,226,230,231,207,211,211,211,211,229,232,233,212},
{212,213,214,215,234,235,236,237,238,239,240,241,242,243,244,245},
{215,220,221,222,237,246,247,248,241,249,250,251,245,252,253,254},
{222,227,228,229,248,255,256,257,251,258,259,260,254,261,262,263},
{229,232,233,212,257,264,265,234,260,266,267,238,263,268,269,242},
{270,270,270,270,279,280,281,282,275,276,277,278,271,272,273,274},
{270,270,270,270,282,289,290,291,278,286,287,288,274,283,284,285},
{270,270,270,270,291,298,299,300,288,295,296,297,285,292,293,294},
{270,270,270,270,300,305,306,279,297,303,304,275,294,301,302,271},
{306}
};

Versione più leggibile:

void setup() {
  size(640,480,P3D);
}

void draw() {
  background(0);
  noFill();
  stroke(255);
  translate(width/2,height/2,70);
  scale(30);
  rotateX(map(mouseX,0,width,0,TWO_PI));
  rotateY(map(mouseY,0,height,0,TWO_PI));
  for (int[] p:patches) {
    beginShape();
    for (int pt:p) {
      vertex(data[pt-1][0],data[pt-1][2],data[pt-1][2]);
    }
    endShape(CLOSE); 
  }
}

E alcune foto:

prodotto finito

Un'altra versione con alcuni effetti interessanti:

void setup(){size(640,480,P3D);}
void draw(){
  background(0);noFill();stroke(255);
  translate(width/2,height/2,70);scale(30);
  rotateX(map(mouseX,0,width,0,TWO_PI));rotateY(map(mouseY,0,height,0,TWO_PI));
  for(int[] p:patches){
    //beginShape(QUADS);
    for(int pt:p){
      for(int pu:p){
        //vertex(data[pu-1][0],data[pu-1][4],data[pu-1][2]);
        line(data[pt-1][0],data[pt-1][5],data[pt-1][2],data[pu-1][0],data[pu-1][6],data[pu-1][2]);
    }}
    //endShape(CLOSE);
  }
}

versione 2


Dovrei dividere i cerotti almeno una volta, credo, affinché il beccuccio prenda forma.
Luser droog

Sì, la seconda foto è migliore. Pero 'non stai davvero facendo una suddivisione. I bordi di ogni patch sono curve di Bezier ... Anche così, +1 Sembra una teiera!
Luser droog

stroke(-1)è un byte più breve distroke(255)
Kritixi Lithos il

11

poscritto

Non completamente giocato a golf, ma questo dimostra un approccio diverso rispetto alla suddivisione deCasteljau: la valutazione del polinomio di base. Usi mat.ps .

(mat.ps)run[    % load matrix library, begin dictionary construction

/N 17
/C [ 0 7 4 ]   % Cam
/E [ 0 0 40 ] % Eye
/R 0 roty 120 rotx 90 rotz   % Rot: pan tilt twist
          matmul   matmul

/f(teapot)(r)file
/t{token pop exch pop}      % parse a number or other ps token
/s{(,){search not{t exit}if t 3 1 roll}loop}  % parse a comma-separated list
/r{token pop{[f 99 string readline pop s]}repeat}>>begin   % parse a count-prefixed paragraph of csv numbers
[/P[f r]/V[f r]/v{1 sub V exch get}        % Patches and Vertices and vert lookup shortcut
/B[[-1 3 -3 1][3 -6 3 0][-3 3 0 0][1 0 0 0]]              % Bezier basis matrix
/A{dup dup mul exch 2 copy mul 3 1 roll 1 4 array astore} % x->[x^3 x^2 x 1]
/M{[1 index 0 4 getinterval 2 index 4 4 getinterval       % flattened matrix->rowXcolumn matrix
3 index 8 4 getinterval 4 index 12 4 getinterval]exch pop}
/J{ C{sub}vop R matmul 0 get                              % perspective proJection  [x y z]->[X Y]
    aload pop E aload pop
    4 3 roll div exch neg
    4 3 roll add 1 index mul 4 1 roll
    3 1 roll sub mul}
>>begin

300 400 translate
1 14 dup dup scale div currentlinewidth mul setlinewidth  % global scale
/newline { /line {moveto /line {lineto} store} store } def
newline
P{
    8 dict begin
        [exch{v J 2 array astore}forall]/p exch def   % load patch vertices and project to 2D
        /X[p{0 get}forall] M B exch matmul B matmul def  % multiply control points by Bezier basis
        /Y[p{1 get}forall] M B exch matmul B matmul def

        0 1 N div 1 1 index .2 mul add{A/U exch def   % interpolate the polynomial over (u,v)/(N)
            /UX U X matmul def
            /UY U Y matmul def
            0 1 N div 1 1 index .2 mul add{A/V exch 1 array astore transpose def
                /UXV UX V matmul def
                /UYV UY V matmul def
                UXV 0 get 0 get
                UYV 0 get 0 get line
            }for
            newline
        }for

        0 1 N div 1 1 index .2 mul add{A/V exch def   % interpolate the polynomial over (u,v)/(N)
            /V [V] transpose def
            /XV X V matmul def
            /YV Y V matmul def
            0 1 N div 1 1 index .2 mul add{A/U exch 1 array astore transpose def
                /UXV U XV matmul def
                /UYV U YV matmul def
                UXV 0 get 0 get
                UYV 0 get 0 get line
            }for
            newline
        }for

    end

    %exit
}forall
stroke

Teiera a base di Bezier

1112

L'eliminazione delle linee verticali e l'attualizzazione dei parametri produce questa versione di 1112 caratteri. Usi mat.ps .

(mat.ps)run[    % 12

/N 17
/C [ 0 7 4 ]   % Cam 
/E [ 0 0 40 ] % Eye 
/R 0 roty 120 rotx 90 rotz   % Rot: pan tilt twist
          matmul   matmul

/f(teapot)(r)file/t{token pop exch pop}/s{(,){search not{t exit}if t   % 1100
3 1 roll}loop}/r{token pop{[f 99 string readline pop 
s]}repeat}>>begin[/P[f r]/V[f r]/v{1 sub 
V exch get}/B[[-1 3 -3 1][3 -6 3 0][-3 3 0 0][1 0 0 0]]/A{dup dup mul exch
2 copy mul 3 1 roll 1 4 array astore}/M{[1 index 0 4 getinterval 2 index 4 4 getinterval    
3 index 8 4 getinterval 4 index 12 4 getinterval]exch pop}/J{C{sub}vop R matmul 0 get    
aload pop E aload pop 4 3 roll div exch neg 4 3 roll add 1 index mul 4 1 roll
3 1 roll sub mul}>>begin 300 400 translate
1 14 dup dup scale div currentlinewidth mul setlinewidth  
/newline{/line{moveto/line{lineto}store}store}def newline
P{8 dict begin[exch{v J 2 array astore}forall]/p
exch def/X[p{0 get}forall] M B exch matmul B matmul
def/Y[p{1 get}forall] M B exch matmul B matmul def 
0 1 N div 1 1 index .2 mul add{A/U exch def/UX U X matmul def/UY U Y matmul def 
0 1 N div 1 1 index .2 mul add{A/V exch 1 array astore transpose
def/UXV UX V matmul def/UYV UY V matmul def UXV 0 get 0 get UYV 0 get 0 get line}for
newline}for end}forall stroke

Anelli a base di Bezier

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.