I found a perl program I wrote ages ago. This renders three-dimensional vector graphics (hollow cubes made of triangles) by hand using a z-buffer.

Redirect the output to a file. It's a ppm image. View it with an image viewer.

The rendering is not perfect, you can see some ugly horizontal stripes where two triangles are coplanar and overlapping. (Perlmonks suggests that "If something looked unlike you expected it to you might need to check out Writeup Formatting Tips" but that page doesn't help. Yes, I previewed the image again and again, but I have no idea how to fix it. So someone tell me how to fix it and improve the autosuggest system of this site.)

#!/usr/bin/env perl # # tri -- manipulation of triangles # Copyright (C) Zsban Ambrus, 2003 # # # use strict; use warnings; use POSIX; use IO::Handle; # --------------------------------------------------------- Triangle { package Triangle; # random triangle sub prand { my (@a, $n, $x, $s, $m); $m= @_>0 ? $_[1] : exp(1); @a= map rand(), 0..8; $s= 1/(1+rand($m)); $_*= $s for @a; for $n (0..2) { $x= rand (1-$s); $a[$_*3+$n]+= $x for 0..2; } $_[0]->init3 (@a); } # color handling (rgb) our $default_color= "0.8 0.8 0.8"; sub setcolor { ${$_[0]}{col}= $_[1]; } sub color { ${$_[0]}{col}; } sub shade { my (%t, @e, $a); %t= %{$_[0]}; @e= ( ($t{y2}-$t{y1})*($t{z3}-$t{z1})-($t{z2}-$t{z1})*($t{y3}-$t{y1} +), ($t{z2}-$t{z1})*($t{x3}-$t{x1})-($t{x2}-$t{x1})*($t{z3}-$t{z1} +), ($t{x2}-$t{x1})*($t{y3}-$t{y1})-($t{y2}-$t{y1})*($t{x3}-$t{x1} +), ); $a= $e[2]/$e[1]; $_[0]{col}= "<---- CONT"; } # triangle constructor sub init3 { @_==10 or die qq{internal error: Triangle init nargs=}.(0+@_); my %x= ( "x1", $_[1], "y1", $_[2], "z1", $_[3], "x2", $_[4], "y2", $_[5], "z2", $_[6], "x3", $_[7], "y3", $_[8], "z3", $_[9], "col", ref($_[0]) ? ${$_[0]}{col} : $default_color, ); bless {%x}, ref ($_[0]) || $_[0]; } # transforming triangles sub transf { my (%a, $t); $_[1]->isa("Transf") or die "error: Triangle::transf arg1 type"; %a= %{$_[0]}; $t= $_[1]; return $_[0]->init3 ( $t->call (@a{"x1","y1","z1"}), $t->call (@a{"x2","y2","z2"}), $t->call (@a{"x3","y3","z3"}), ); } } # ------------------------------------------------------- Transf # represents a projective collination transformation or whatever { package Transf; sub init { @_==17 or die "internal error: Transf::init nargs"; ref ($_[0]) and die "internal error: Transf::init aint objmethod!" +; bless [@_[1..16]], $_[0]; } sub call { @_==4 or die "error: Transf::call nargs"; my @a= @{$_[0]}; my $d= $_[1]*$a[0xc]+$_[2]*$a[0xd]+$_[3]*$a[0xe]+$a[0xf]; return ( ($_[1]*$a[0x0]+$_[2]*$a[0x1]+$_[3]*$a[0x2]+$a[0x3])/$d, ($_[1]*$a[0x4]+$_[2]*$a[0x5]+$_[3]*$a[0x6]+$a[0x7])/$d, ($_[1]*$a[0x8]+$_[2]*$a[0x9]+$_[3]*$a[0xa]+$a[0xb])/$d, ); } # mátrixszorzás: call(compose(a,b),p) === call(a,call(b,p)) sub compose { my (@a, @b, @r, $i, $j, $k); @a= @{$_[0]}; @b= @{$_[1]}; @r= ((0)x4)x4; for $i (0..3) { for $j (0..3) { for $k (0..3) { $r[$i+$k*4]+= $a[$i+$j*4] * $b[$j+$k*4]; }}} return bless [@r], ref($_[0]); } sub perspective { my (undef, $d)= @_; $_[0]->init ( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1/$d, 1, ); } sub turnx { my (undef, $d)= @_; $_[0]->init ( 1, 0, 0, 0, 0, cos($d), sin($d), 0, 0, -sin($d), cos($d), 0, 0, 0, 0, 1, ); } sub turny { my (undef, $d)= @_; $_[0]->init ( cos($d), 0, sin($d), 0, 0, 1, 0, 0, -sin($d), 0, cos($d), 0, 0, 0, 0, 1, ); } sub translate { my (undef, $x, $y, $z)= @_; $_[0]->init ( 1, 0, 0, $x, 0, 1, 0, $y, 0, 0, 1, $z, 0, 0, 0, 1, ); } sub scale { my (undef, $x, $y, $z)= @_; $_[0]->init ( $x, 0, 0, 0, 0, $y, 0, 0, 0, 0, $z, 0, 0, 0, 0, 1, ); } } # -------------------------------------------------------------- Zbuf { package Zbuf; our $bgcolor= chr(255)x3; our $INF= 1e1000; our $default_pixel= [$bgcolor, $INF]; # uj kepet hoz letre, argumentumok: szelesseg, hosszusag (pixel) sub new { my ($w, $h); (undef, $w, $h)= @_; $w>=1 && $h>=1 or die "error: Zbuf::new args"; bless [map [($default_pixel)x$w], 0..$h-1], $_[0]; } sub ins1; # ins rajzol egy haromszoget # dr rajzol egy trapezt, amelynek ket oldala vizszintes, parameterei # ($ym, $yM, $xmym, $xMym, $dxm, $dxM, $zxmym, $dzxm, $dzdy, $col, $z +b), # ahol, m=minimum, M=maximum, dF jelentese dF/dy, # dFdG jelentese dF/dG, FGm jelentese F amikor G=Gm sub dr { my ($ym, $yM, $xmym, $xMym, $dxm, $dxM, $zxmym, $dzxm, $dzdy, $col, $zb)= @_; my ($x, $xm, $xM, $xL, $y, $yL, $z, $zxm, $u); $u= $ym>0 ? POSIX::floor($ym)-$ym : -$ym; ($y, $xm, $xM, $zxm)= ($ym+$u, $xmym+$u*$dxm, $xMym+$u*$dxM, $zxmym+$u*$dzxm); $yL= $yM<@$zb ? $yM : @$zb; while ($y<$yL) { $u= $xm<0 ? -$xm : POSIX::floor($xm)-$xm; ($x, $z)= ($xm+$u, $zxm+$u*$dzxm); $xL= $xM<@{$$zb[0]}?$xM:@{$$zb[0]}; while ($x<$xL) { $$zb[$y][$x]= [$col, $z] if $z<=$$zb[$y][$x][1]; ($x, $z)= ($x+1, $z+$dzdy); } ($y, $xm, $xM, $zxm)= ($y+1, $xm+$dxm, $xM+$dxM, $zxm+$dzxm); } }; # drr ugyanaz mint dr, csak fejjel lefelé, vagyis (x,y,z)|->(x,H-y,z) sub drr { my ($ym, $yM, $xmym, $xMym, $dxm, $dxM, $zxmym, $dzxm, $dzdy, $col, $zb)= @_; my ($x, $xm, $xM, $xL, $y, $yL, $z, $zxm, $u); $u= $ym>0 ? POSIX::floor($ym)-$ym : -$ym; ($y, $xm, $xM, $zxm)= ($ym+$u, $xmym+$u*$dxm, $xMym+$u*$dxM, $zxmym+$u*$dzxm); $yL= $yM<@$zb ? $yM : @$zb; while ($y<$yL) { $u= $xm<0 ? -$xm : POSIX::floor($xm)-$xm; ($x, $z)= ($xm+$u, $zxm+$u*$dzxm); $xL= $xM<@{$$zb[0]}?$xM:@{$$zb[0]}; while ($x<$xL) { $$zb[@$zb-1-$y][$x]= [$col, $z] if $z<=$$zb[@$zb-1-$y][$x][1]; ($x, $z)= ($x+1, $z+$dzdy); } ($y, $xm, $xM, $zxm)= ($y+1, $xm+$dxm, $xM+$dxM, $zxm+$dzxm); } }; sub ins { my (@p, $t, $u, $v, $D, $zb, $col); ($zb, $t)= @_; $$t{col}=~m/([\d.]+)\s+([\d.]+)\s+([\d.]+)/ or warn "warning: wrong color, substing grey"; $col= pack ("C3", defined($1)?($1*255,$2*255,$3*255):(128,128,128) +); @p= sort {$$a[1]<=>$$b[1]} [@$t{"x1","y1","z1"}], [@$t{"x2","y2","z2"}], [@$t{"x3","y3","z3"}]; $u= ($p[2][1]-$p[1][1])/($p[2][1]-$p[0][1]); $v= ($p[1][1]-$p[0][1])/($p[2][1]-$p[0][1]); $p[3]= [$p[0][0]*$u+$p[2][0]*$v, $p[1][1], $p[0][2]*$u+$p[2][2]*$v +]; $p[3][0]<$p[1][0] or ($p[1], $p[3])= ($p[3], $p[1]); eval { dr ( #(x, xm, xM, xL, y, yL, z, zxm, u) # -+----------->x $p[0][1], $p[3][1], $p[0][0], $p[0][0], # | 0 0 ($p[3][0]-$p[0][0])/($p[3][1]-$p[0][1]), # |/ \ or / \ ($p[1][0]-$p[0][0])/($p[1][1]-$p[0][1]), # 3 _-1 3-_ 1 $p[0][2], # 2+~ ~-2 ($p[3][2]-$p[0][2])/($p[3][1]-$p[0][1]), # v y ($p[1][2]-$p[3][2])/($p[1][0]-$p[3][0]), $col, $zb ); }; $@ and do { $@=~m/division by zero/ or die $@; }; eval { drr ( @$zb-1-$p[2][1], @$zb-1-$p[3][1], $p[2][0], $p[2][0], -($p[3][0]-$p[2][0])/($p[3][1]-$p[2][1]), -($p[1][0]-$p[2][0])/($p[1][1]-$p[2][1]), $p[2][2], -($p[3][2]-$p[2][2])/($p[3][1]-$p[2][1]), ($p[1][2]-$p[3][2])/($p[1][0]-$p[3][0]), $col, $zb ); }; $@ and do { $@=~m/division by zero/ or die $@; }; } # kiirja a kepet ppm formatumban sub print { my ($w, $h, $x, $y, $a); ($a)= @_; $h= @$a; $w= @{$$a[0]}; warn "writing image w=".$w." h=".$h; print "P6 ".$w." ".$h." 255\n"; for $y (0..$h-1) { for $x (0..$w-1) { print $$a[$y][$x][0]; } } flush STDOUT; warn "image written"; } } # ------------------------------------------------------------ main { my (@t, $persp, @color); warn "creating objects"; $persp= Transf->perspective (2); @t= ( Triangle->init3 (0.1, 0.5, 0.5, 0.5, 0.1, 0.5, 0.5, 0.5, 0.1), Triangle->init3 (0.1, 0.5, 0.5, 0.5, 0.1, 0.5, 0.5, 0.5, 0.9), Triangle->init3 (0.1, 0.5, 0.5, 0.5, 0.9, 0.5, 0.5, 0.5, 0.1), Triangle->init3 (0.1, 0.5, 0.5, 0.5, 0.9, 0.5, 0.5, 0.5, 0.9), Triangle->init3 (0.9, 0.5, 0.5, 0.5, 0.1, 0.5, 0.5, 0.5, 0.1), Triangle->init3 (0.9, 0.5, 0.5, 0.5, 0.1, 0.5, 0.5, 0.5, 0.9), Triangle->init3 (0.9, 0.5, 0.5, 0.5, 0.9, 0.5, 0.5, 0.5, 0.1), Triangle->init3 (0.9, 0.5, 0.5, 0.5, 0.9, 0.5, 0.5, 0.5, 0.9), ); push @t, Triangle->init3 (0.5, 0.8, 0.2, 0.2, 0.8, 0.6, 0.6, 0.2, 0.8) +; sub paral { Triangle->init3 (@_[0..8]), Triangle->init3 (@_[3..8], $_[3]+$_[6]-$_[0], $_[4]+$_[7]-$_[1], $_[5]+$_[8]-$_[2]); } @t= ( paral (0.1, 0.1, 0.1, 0.1, 0.1, 0.9, 0.1, 0.9, 0.1), paral (0.9, 0.1, 0.1, 0.9, 0.1, 0.9, 0.9, 0.9, 0.1), paral (0.1, 0.1, 0.1, 0.1, 0.9, 0.1, 0.9, 0.1, 0.1), paral (0.1, 0.1, 0.9, 0.1, 0.9, 0.9, 0.9, 0.1, 0.9), paral (0.1, 0.1, 0.1, 0.1, 0.1, 0.9, 0.9, 0.1, 0.1), paral (0.1, 0.9, 0.1, 0.1, 0.9, 0.9, 0.9, 0.9, 0.1), ); sub pill { paral ($_[0], $_[1], $_[2], $_[0]+$_[3], $_[1]+$_[4], $_[2]+$_[5], + $_[0]+$_[9], $_[1]+$_[10], $_[2]+$_[11]), paral ($_[0], $_[1], $_[2], $_[0]+$_[6], $_[1]+$_[7], $_[2]+$_[8], + $_[0]+$_[9], $_[1]+$_[10], $_[2]+$_[11]), paral ($_[0]+$_[6], $_[1]+$_[7], $_[2]+$_[8], $_[0]+$_[6]+$_[3], $_[1]+$_[7]+$_[4], $_[2]+$_[8]+$_[5], $_[0]+$_[6]+$_[9], $_[1]+$_[7]+$_[10], $_[2]+$_[8]+$_[11]), paral ($_[0]+$_[3], $_[1]+$_[4], $_[2]+$_[5], $_[0]+$_[3]+$_[6], $_[1]+$_[4]+$_[7], $_[2]+$_[5]+$_[8], $_[0]+$_[3]+$_[9], $_[1]+$_[4]+$_[10], $_[2]+$_[5]+$_[11]); } =for noone @t= ( # | | | | | pill (1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 8), pill (7, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 8), pill (1, 7, 1, 2, 0, 0, 0, 2, 0, 0, 0, 8), pill (7, 7, 1, 2, 0, 0, 0, 2, 0, 0, 0, 8), pill (1, 1, 1, 0, 2, 0, 0, 0, 2, 8, 0, 0), pill (1, 7, 1, 0, 2, 0, 0, 0, 2, 8, 0, 0), pill (1, 1, 7, 0, 2, 0, 0, 0, 2, 8, 0, 0), pill (1, 7, 7, 0, 2, 0, 0, 0, 2, 8, 0, 0), pill (1, 1, 1, 0, 0, 2, 2, 0, 0, 0, 8, 0), pill (1, 1, 7, 0, 0, 2, 2, 0, 0, 0, 8, 0), pill (7, 1, 1, 0, 0, 2, 2, 0, 0, 0, 8, 0), pill (7, 1, 7, 0, 0, 2, 2, 0, 0, 0, 8, 0), ); =cut @t= ( # | | | | | pill (1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 8), pill (8, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 8), pill (1, 8, 1, 1, 0, 0, 0, 1, 0, 0, 0, 8), pill (8, 8, 1, 1, 0, 0, 0, 1, 0, 0, 0, 8), pill (1, 1, 1, 0, 1, 0, 0, 0, 1, 8, 0, 0), pill (1, 8, 1, 0, 1, 0, 0, 0, 1, 8, 0, 0), pill (1, 1, 8, 0, 1, 0, 0, 0, 1, 8, 0, 0), pill (1, 8, 8, 0, 1, 0, 0, 0, 1, 8, 0, 0), pill (1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 8, 0), pill (1, 1, 8, 0, 0, 1, 1, 0, 0, 0, 8, 0), pill (8, 1, 1, 0, 0, 1, 1, 0, 0, 0, 8, 0), pill (8, 1, 8, 0, 0, 1, 1, 0, 0, 0, 8, 0), Triangle->init3 (0, 2, 5, 1, 5, 0, 3, 0, 2), ); =for noone @t= ( Triangle->init3 (0.9, 0.5, 0.5, 0.1, 0.5, 0.5, 0.5, 0.9, 0.5), Triangle->init3 (0.9, 0.5, 0.5, 0.1, 0.5, 0.5, 0.5, 0.1, 0.5), Triangle->init3 (0.5, 0.9, 0.5, 0.5, 0.1, 0.5, 0.5, 0.5, 0.9), Triangle->init3 (0.5, 0.9, 0.5, 0.5, 0.1, 0.5, 0.5, 0.5, 0.1), Triangle->init3 (0.5, 0.5, 0.9, 0.5, 0.5, 0.1, 0.9, 0.5, 0.5), Triangle->init3 (0.5, 0.5, 0.9, 0.5, 0.5, 0.1, 0.1, 0.5, 0.5), # Triangle->init3 (0.9, 0.5, 0.5, 0.5, 0.9, 0.5, 0.5, 0.5, 0.9), Triangle->init3 (0.1, 0.5, 0.5, 0.5, 0.1, 0.5, 0.5, 0.5, 0.9), Triangle->init3 (0.1, 0.5, 0.5, 0.5, 0.9, 0.5, 0.5, 0.5, 0.1), Triangle->init3 (0.9, 0.5, 0.5, 0.5, 0.1, 0.5, 0.5, 0.5, 0.1), ); =cut #push @t, Triangle->prand (2); # |perl -we 'use List::Util; print List::Util::shuffle(<STDIN>);'| @color= ( "0.5 0.5 1.0", "0.8 0.5 1.0", "0.5 1.0 0.5", "1.0 0.5 0.8", "0.5 1.0 0.8", "1.0 0.8 0.5", "1.0 0.5 0.5", "1.0 1.0 0.5", "0.8 0.8 0.2", ); #$t[$_]->setcolor ($color[$_/2%@color]) for 0..$#t; $t[$_]->setcolor ($color[rand(@color)]) for 0..$#t; sub PI () { 2* atan2 (1, 0); } my ($zb, $i, $j, $rox, $roy); $zb= Zbuf->new (1000, 720); $rox= rand (); $roy= rand (); sub draw { my (@a, @b, $p); print STDERR ":"; $p= Transf->scale (0.1, 0.1, 0.1); $p= $p->compose (Transf->translate (-0.5, -0.5, -0.5)); $p= $p->compose (Transf->turnx (($_[1]+$rox)*PI/5)); $p= $p->compose (Transf->turny (($_[0]-$roy)*2*PI/5)); $p= $p->compose ($persp); $p= $p->compose (Transf->scale (140, 140, 140)); $p= $p->compose (Transf->translate (100+200*$_[0], 40+200*$_[1], 4 +00)); @a= map {$_->transf ($p)} @t; $zb->ins ($_) for @a; } warn "rendering image"; for $i (0..4) { for $j (0..3) { draw ($i, $j); } } print STDERR "\n"; $zb->print (); } __END__

In reply to Old 3-d cubes rendering code by ambrus

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.