Disegnare 3D "from scratch"

18 views
Skip to first unread message

antonio.ma...@gmail.com

unread,
Jul 17, 2021, 8:18:10 AM7/17/21
to
disegnare 3D "from scratch"
---

tutto quello che serve e'

1) un computerino (anche un Pentium III usato da 50 Euro)
2) una distribuzione linux qualsiasi (Slackware va benissimo)
3) competenze base di Bash/Linux (terminale)
4) competenze base di C/Linux (K&R fino ai puntatori)
5) competenze base di matematica (scuole medie)
6) competenze base di geometria cartesiana 3D (piani e rette)

questo e' un software che disegna un tetraedro regolare su una bitmap 500x500

////////////////////////////////////////

$ cat tetraedro.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define SCREENWIDTH 500
#define SCREENHEIGHT 500

double POVX = SCREENWIDTH / 8 * 3;
double POVY = SCREENHEIGHT / 8;
double POVZ = -SCREENHEIGHT;

int screen[SCREENHEIGHT][SCREENWIDTH];

////////////////////////////////////////

void pset(double x, double y, int colour) {
int ix, iy;
ix = (int)round(x);
iy = (int)round(y);
if(ix < 0 || ix >= SCREENWIDTH || iy < 0 || iy >= SCREENHEIGHT) return;
screen[iy][ix] = colour;
}

void line(double x1, double y1, double x2, double y2, int colour) {
double j, k, l;
double mx, my;

l = sqrt(pow(x2-x1,2) + pow(y2-y1,2));

for(j=0,k=l; k>0; ++j,--k) {
mx = (x1*j + x2*k) / l;
my = (y1*j + y2*k) / l;
pset(mx, my, colour);
}
pset(x1, y1, colour);
}

void circle(double cx, double cy, double px, double py, int colour) {
double r, l;
double a, b;

r = sqrt(pow(cx-px,2) + pow(cy-py,2));

for(a = -50; a < 50; ++a) {
for(b = -50; b < 50; ++b) {
l = sqrt(pow(a,2) + pow(b,2));
pset(cx + a*r/l, cy + b*r/l, colour);
}
}
}

////////////////////////////////////////

void from3dto2d(double x3, double y3, double z3, double *x2, double *y2) {
*x2 = x3 - z3*(x3 - POVX) / (z3 - POVZ);
*y2 = y3 - z3*(y3 - POVY) / (z3 - POVZ);
}

void pset3d(double x, double y, double z, int colour) {
from3dto2d(x, y, z, &x, &y);
pset(x, y, colour);
}

void line3d(double x1, double y1, double z1,
double x2, double y2, double z2, int colour) {
from3dto2d(x1, y1, z1, &x1, &y1);
from3dto2d(x2, y2, z2, &x2, &y2);
line(x1, y1, x2, y2, colour);
}

void circle3d(double cx, double cy, double cz,
double px1, double py1, double pz1,
double px2, double py2, double pz2, int colour) {
double r, l;
double a1, b1, c1, a2, b2, c2, a3, b3, c3;

r = sqrt(pow(cx-px1,2) + pow(cy-py1,2) + pow(cz-pz1,2));

a1 = cy*(pz1 - pz2) + py1*(pz2 - cz) + py2*(cz - pz1);
b1 = cz*(px1 - px2) + pz1*(px2 - cx) + pz2*(cx - px1);
c1 = cx*(py1 - py2) + px1*(py2 - cy) + px2*(cy - py1);

for(a2 = -50; a2 < 50; ++a2) {
for(b2 = -50; b2 < 50; ++b2) {
for(c2 = -50; c2 < 50; ++c2) {
a3 = b1*c2 - c1*b2;
b3 = c1*a2 - a1*c2;
c3 = a1*b2 - b1*a2;
l = sqrt(pow(a3,2) + pow(b3,2) + pow(c3,2));
pset3d(cx+a3*r/l, cy+b3*r/l, cz+c3*r/l, colour);
}
}
}
}

////////////////////////////////////////

void ppm(void) {
int x, y, colour;
char red, green, blue;

printf("P6\n");
printf("%d %d 255\n", SCREENWIDTH, SCREENHEIGHT);

for(y = 0; y < SCREENHEIGHT; ++y) {
for(x = 0; x < SCREENWIDTH; ++x) {
colour = screen[y][x];
red = colour >> 16;
green = colour >> 8;
blue = colour;
printf("%c%c%c", red, green, blue);
}
}
}

////////////////////////////////////////

int main(int argc, char **argv) {
double a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;
double ax,ay,az,bx,by,bz,cx,cy,cz,dx,dy,dz,ex,ey,ez,fx,fy,fz,gx,gy,gz,hx,hy,hz,ix,iy,iz,jx,jy,jz,kx,ky,kz,lx,ly,lz,mx,my,mz,nx,ny,nz,ox,oy,oz,px,py,pz,qx,qy,qz,rx,ry,rz,sx,sy,sz,tx,ty,tz,ux,uy,uz,vx,vy,vz,wx,wy,wz,xx,xy,xz,yx,yy,yz,zx,zy,zz;

if(argc != 2) {
printf("Usage: %s radians\n", argv[0]);
printf("Example: %s 0\n");
return 1;
}

a = atof(argv[1]);

ox = SCREENWIDTH/2; oy = SCREENHEIGHT/2; oz = 0;
r = SCREENHEIGHT/4;
ax = ox + cos(a)*r; ay = oy; az = oz + sin(a)*r;
a += 2*M_PI/3;
bx = ox + cos(a)*r; by = oy; bz = oz + sin(a)*r;
a += 2*M_PI/3;
cx = ox + cos(a)*r; cy = oy; cz = oz + sin(a)*r;
dx = ox; dy = oy - r*sqrt(2); dz = oz;

circle3d(ox,oy,oz,ax,ay,az,bx,by,bz,0x000000FF);
line3d(ax,ay,az,bx,by,bz,0x0000FF00);
line3d(bx,by,bz,cx,cy,cz,0x0000FF00);
line3d(cx,cy,cz,ax,ay,az,0x0000FF00);
line3d(dx,dy,dz,ax,ay,az,0x0000FF00);
line3d(dx,dy,dz,bx,by,bz,0x0000FF00);
line3d(dx,dy,dz,cx,cy,cz,0x0000FF00);
line3d(dx,dy,dz,ox,oy,oz,0x00FF00FF);

ppm();

return 0;
}

////////////////////////////////////////

dopo averlo compilato...

$ gcc tetraedro.c -lm -o tetraedro

basta eseguirlo, passando come parametro l'angolo di rotazione (in radianti), e ridirigendo l'output a proprio piacere (su un file .ppm)...

$ ./tetraedro 0 > tetraedro.ppm

volendo si puo' convertire l'immagine in un altro formato piu' classico (gif)...

$ convert tetraedro.ppm tetraedro.gif

ed e' possibile, con poche righe in bash, costruirsi un'animazione gif...

$ a120=`echo "120/45*a(1)" | bc -l`

$ i=0; for k in `seq 0 0.05 $a120`; do ((++i)); ./tetraedro $k > frame_`printf "%03d" "$i"`.ppm; echo $i; done

$ for f in frame*ppm; do echo $f; convert $f ${f%ppm}gif; done

$ convert -delay 0 -loop 0 -size 500x500 frame*gif rotaedro.gif

e questo e' il risultato (rotaedro.gif)...

https://ibb.co/FJv6yQL

aggiungendo poi un po' di funzionalita' (lettere, sfumatura su z, gestione dei piani, ecc.), si arriva con non troppo lavoro ulteriore, a questo...

https://ibb.co/JR4GTzH

---

se il tempo che dedichi alla sera a vagabondare tra i locali alla ricerca di qualche sfigata che non e' riuscita a rimediare niente di meglio che te... piuttosto lo dedichi ad imparare un po' di C... vai pure in pari!

antonio.ma...@gmail.com

unread,
Jul 17, 2021, 9:38:16 AM7/17/21
to
> se il tempo che dedichi alla sera a vagabondare tra i locali alla ricerca di qualche sfigata che non e' riuscita a rimediare niente di meglio che te... piuttosto lo dedichi ad imparare un po' di C... vai pure in pari!


... o invece di leggersi libri da 500 pagine tipo
"INTRODUZIONE all'ECONOMETRIA" ...

fract

unread,
Jul 17, 2021, 10:39:25 AM7/17/21
to
Il Sat, 17 Jul 2021 05:18:09 -0700, antonio.ma...@gmail.com ha scritto:

> tutto quello che serve e' [...]

mai sentito parlare di Processing?

https://processing.org/

Faty Scent

unread,
Jul 17, 2021, 11:01:47 AM7/17/21
to
> mai sentito parlare di Processing?
>
> https://processing.org/

Un programma fantastico, peccato che il .exe che genera credo
sia poco meno di un'intera macchina virtuale o comunque si
porta appresso l'ambiente java; però fa cose fantastiche con
una manciata di linee di codice....


--
Eelon disassemblami
Reply all
Reply to author
Forward
0 new messages