new files
This commit is contained in:
parent
3af7344581
commit
86c034bb8b
1364 changed files with 21352 additions and 0 deletions
3
Task/Death-Star/0DESCRIPTION
Normal file
3
Task/Death-Star/0DESCRIPTION
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Death Star is a task to display a region that consists of a large sphere with part of a smaller sphere removed from it as a result of geometric subtraction. (This will basically produce a shape like a "death star".)
|
||||
|
||||
See also: [[Draw a sphere]].
|
||||
6
Task/Death-Star/1META.yaml
Normal file
6
Task/Death-Star/1META.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
category:
|
||||
- Geometric Subtraction
|
||||
note: Constructive Solid Geometry
|
||||
requires:
|
||||
- Graphics
|
||||
112
Task/Death-Star/C/death-star.c
Normal file
112
Task/Death-Star/C/death-star.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const char *shades = ".:!*oe&#%@";
|
||||
|
||||
double light[3] = { -50, 0, 50 };
|
||||
void normalize(double * v)
|
||||
{
|
||||
double len = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
||||
v[0] /= len; v[1] /= len; v[2] /= len;
|
||||
}
|
||||
|
||||
double dot(double *x, double *y)
|
||||
{
|
||||
double d = x[0]*y[0] + x[1]*y[1] + x[2]*y[2];
|
||||
return d < 0 ? -d : 0;
|
||||
}
|
||||
|
||||
typedef struct { double cx, cy, cz, r; } sphere_t;
|
||||
|
||||
/* positive shpere and negative sphere */
|
||||
sphere_t pos = { 20, 20, 0, 20 }, neg = { 1, 1, -6, 20 };
|
||||
|
||||
/* check if a ray (x,y, -inf)->(x, y, inf) hits a sphere; if so, return
|
||||
the intersecting z values. z1 is closer to the eye */
|
||||
int hit_sphere(sphere_t *sph, double x, double y, double *z1, double *z2)
|
||||
{
|
||||
double zsq;
|
||||
x -= sph->cx;
|
||||
y -= sph->cy;
|
||||
zsq = sph->r * sph->r - (x * x + y * y);
|
||||
if (zsq < 0) return 0;
|
||||
zsq = sqrt(zsq);
|
||||
*z1 = sph->cz - zsq;
|
||||
*z2 = sph->cz + zsq;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void draw_sphere(double k, double ambient)
|
||||
{
|
||||
int i, j, intensity, hit_result;
|
||||
double b;
|
||||
double vec[3], x, y, zb1, zb2, zs1, zs2;
|
||||
for (i = floor(pos.cy - pos.r); i <= ceil(pos.cy + pos.r); i++) {
|
||||
y = i + .5;
|
||||
for (j = floor(pos.cx - 2 * pos.r); j <= ceil(pos.cx + 2 * pos.r); j++) {
|
||||
x = (j - pos.cx) / 2. + .5 + pos.cx;
|
||||
|
||||
/* ray lands in blank space, draw bg */
|
||||
if (!hit_sphere(&pos, x, y, &zb1, &zb2))
|
||||
hit_result = 0;
|
||||
|
||||
/* ray hits pos sphere but not neg, draw pos sphere surface */
|
||||
else if (!hit_sphere(&neg, x, y, &zs1, &zs2))
|
||||
hit_result = 1;
|
||||
|
||||
/* ray hits both, but pos front surface is closer */
|
||||
else if (zs1 > zb1) hit_result = 1;
|
||||
|
||||
/* pos sphere surface is inside neg sphere, show bg */
|
||||
else if (zs2 > zb2) hit_result = 0;
|
||||
|
||||
/* back surface on neg sphere is inside pos sphere,
|
||||
the only place where neg sphere surface will be shown */
|
||||
else if (zs2 > zb1) hit_result = 2;
|
||||
else hit_result = 1;
|
||||
|
||||
switch(hit_result) {
|
||||
case 0:
|
||||
putchar('+');
|
||||
continue;
|
||||
case 1:
|
||||
vec[0] = x - pos.cx;
|
||||
vec[1] = y - pos.cy;
|
||||
vec[2] = zb1 - pos.cz;
|
||||
break;
|
||||
default:
|
||||
vec[0] = neg.cx - x;
|
||||
vec[1] = neg.cy - y;
|
||||
vec[2] = neg.cz - zs2;
|
||||
}
|
||||
|
||||
normalize(vec);
|
||||
b = pow(dot(light, vec), k) + ambient;
|
||||
intensity = (1 - b) * (sizeof(shades) - 1);
|
||||
if (intensity < 0) intensity = 0;
|
||||
if (intensity >= sizeof(shades) - 1)
|
||||
intensity = sizeof(shades) - 2;
|
||||
putchar(shades[intensity]);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
double ang = 0;
|
||||
|
||||
while (1) {
|
||||
printf("\033[H");
|
||||
light[1] = cos(ang * 2);
|
||||
light[2] = cos(ang);
|
||||
light[0] = sin(ang);
|
||||
normalize(light);
|
||||
ang += .05;
|
||||
|
||||
draw_sphere(2, .3);
|
||||
usleep(100000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
103
Task/Death-Star/Go/death-star.go
Normal file
103
Task/Death-Star/Go/death-star.go
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"math"
|
||||
"os"
|
||||
)
|
||||
|
||||
type vector [3]float64
|
||||
|
||||
func (v *vector) normalize() {
|
||||
invLen := 1 / math.Sqrt(dot(v, v))
|
||||
v[0] *= invLen
|
||||
v[1] *= invLen
|
||||
v[2] *= invLen
|
||||
}
|
||||
|
||||
func dot(x, y *vector) float64 {
|
||||
return x[0]*y[0] + x[1]*y[1] + x[2]*y[2]
|
||||
}
|
||||
|
||||
type sphere struct {
|
||||
cx, cy, cz int
|
||||
r int
|
||||
}
|
||||
|
||||
func (s *sphere) hit(x, y int) (z1, z2 float64, hit bool) {
|
||||
x -= s.cx
|
||||
y -= s.cy
|
||||
if zsq := s.r*s.r - (x*x + y*y); zsq >= 0 {
|
||||
zsqrt := math.Sqrt(float64(zsq))
|
||||
return float64(s.cz) - zsqrt, float64(s.cz) + zsqrt, true
|
||||
}
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
func deathStar(pos, neg *sphere, k, amb float64, dir *vector) *image.Gray {
|
||||
w, h := pos.r*4, pos.r*3
|
||||
bounds := image.Rect(pos.cx-w/2, pos.cy-h/2, pos.cx+w/2, pos.cy+h/2)
|
||||
img := image.NewGray(bounds)
|
||||
vec := new(vector)
|
||||
for y, yMax := pos.cy-pos.r, pos.cy+pos.r; y <= yMax; y++ {
|
||||
for x, xMax := pos.cx-pos.r, pos.cx+pos.r; x <= xMax; x++ {
|
||||
zb1, zb2, hit := pos.hit(x, y)
|
||||
if !hit {
|
||||
continue
|
||||
}
|
||||
zs1, zs2, hit := neg.hit(x, y)
|
||||
if hit {
|
||||
if zs1 > zb1 {
|
||||
hit = false
|
||||
} else if zs2 > zb2 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if hit {
|
||||
vec[0] = float64(neg.cx - x)
|
||||
vec[1] = float64(neg.cy - y)
|
||||
vec[2] = float64(neg.cz) - zs2
|
||||
} else {
|
||||
vec[0] = float64(x - pos.cx)
|
||||
vec[1] = float64(y - pos.cy)
|
||||
vec[2] = zb1 - float64(pos.cz)
|
||||
}
|
||||
vec.normalize()
|
||||
s := dot(dir, vec)
|
||||
if s < 0 {
|
||||
s = 0
|
||||
}
|
||||
lum := 255 * (math.Pow(s, k) + amb) / (1 + amb)
|
||||
if lum < 0 {
|
||||
lum = 0
|
||||
} else if lum > 255 {
|
||||
lum = 255
|
||||
}
|
||||
img.SetGray(x, y, color.Gray{uint8(lum)})
|
||||
}
|
||||
}
|
||||
return img
|
||||
}
|
||||
|
||||
func main() {
|
||||
dir := &vector{20, -40, -10}
|
||||
dir.normalize()
|
||||
pos := &sphere{0, 0, 0, 120}
|
||||
neg := &sphere{-90, -90, -30, 100}
|
||||
|
||||
img := deathStar(pos, neg, 1.5, .2, dir)
|
||||
f, err := os.Create("dstar.png")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
if err = png.Encode(f, img); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if err = f.Close(); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
75
Task/Death-Star/Perl/death-star.pl
Normal file
75
Task/Death-Star/Perl/death-star.pl
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
use strict;
|
||||
|
||||
sub sq {
|
||||
my $s = 0;
|
||||
$s += $_ ** 2 for @_;
|
||||
$s;
|
||||
}
|
||||
|
||||
sub hit {
|
||||
my ($sph, $x, $y) = @_;
|
||||
$x -= $sph->[0];
|
||||
$y -= $sph->[1];
|
||||
|
||||
my $z = sq($sph->[3]) - sq($x, $y);
|
||||
return if $z < 0;
|
||||
|
||||
$z = sqrt $z;
|
||||
return $sph->[2] - $z, $sph->[2] + $z;
|
||||
}
|
||||
|
||||
sub normalize {
|
||||
my $v = shift;
|
||||
my $n = sqrt sq(@$v);
|
||||
$_ /= $n for @$v;
|
||||
$v;
|
||||
}
|
||||
|
||||
sub dot {
|
||||
my ($x, $y) = @_;
|
||||
my $s = $x->[0] * $y->[0] + $x->[1] * $y->[1] + $x->[2] * $y->[2];
|
||||
$s > 0 ? $s : 0;
|
||||
}
|
||||
|
||||
my $pos = [ 120, 120, 0, 120 ];
|
||||
my $neg = [ -77, -33, -100, 190 ];
|
||||
my $light = normalize([ -12, 13, -10 ]);
|
||||
sub draw {
|
||||
my ($k, $amb) = @_;
|
||||
binmode STDOUT, ":raw";
|
||||
print "P5\n", $pos->[0] * 2 + 3, " ", $pos->[1] * 2 + 3, "\n255\n";
|
||||
for my $y (($pos->[1] - $pos->[3] - 1) .. ($pos->[1] + $pos->[3] + 1)) {
|
||||
my @row = ();
|
||||
for my $x (($pos->[0] - $pos->[3] - 1) .. ($pos->[0] + $pos->[3] + 1)) {
|
||||
my ($hit, @hs) = 0;
|
||||
my @h = hit($pos, $x, $y);
|
||||
|
||||
if (!@h) { $hit = 0 }
|
||||
elsif (!(@hs = hit($neg, $x, $y))) { $hit = 1 }
|
||||
elsif ($hs[0] > $h[0]) { $hit = 1 }
|
||||
elsif ($hs[1] > $h[0]) { $hit = $hs[1] > $h[1] ? 0 : 2 }
|
||||
else { $hit = 1 }
|
||||
|
||||
my ($val, $v);
|
||||
if ($hit == 0) { $val = 0 }
|
||||
elsif ($hit == 1) {
|
||||
$v = [ $x - $pos->[0],
|
||||
$y - $pos->[1],
|
||||
$h[0] - $pos->[2] ];
|
||||
} else {
|
||||
$v = [ $neg->[0] - $x,
|
||||
$neg->[1] - $y,
|
||||
$neg->[2] - $hs[1] ];
|
||||
}
|
||||
if ($v) {
|
||||
normalize($v);
|
||||
$val = int((dot($v, $light) ** $k + $amb) * 255);
|
||||
$val = ($val > 255) ? 255 : ($val < 0) ? 0 : $val;
|
||||
}
|
||||
push @row, $val;
|
||||
}
|
||||
print pack("C*", @row);
|
||||
}
|
||||
}
|
||||
|
||||
draw(2, 0.2);
|
||||
67
Task/Death-Star/Python/death-star.py
Normal file
67
Task/Death-Star/Python/death-star.py
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import sys, math, collections
|
||||
|
||||
Sphere = collections.namedtuple("Sphere", "cx cy cz r")
|
||||
V3 = collections.namedtuple("V3", "x y z")
|
||||
|
||||
def normalize((x, y, z)):
|
||||
len = math.sqrt(x**2 + y**2 + z**2)
|
||||
return V3(x / len, y / len, z / len)
|
||||
|
||||
def dot(v1, v2):
|
||||
d = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z
|
||||
return -d if d < 0 else 0.0
|
||||
|
||||
def hit_sphere(sph, x0, y0):
|
||||
x = x0 - sph.cx
|
||||
y = y0 - sph.cy
|
||||
zsq = sph.r ** 2 - (x ** 2 + y ** 2)
|
||||
if zsq < 0:
|
||||
return (False, 0, 0)
|
||||
szsq = math.sqrt(zsq)
|
||||
return (True, sph.cz - szsq, sph.cz + szsq)
|
||||
|
||||
def draw_sphere(k, ambient, light):
|
||||
shades = ".:!*oe&#%@"
|
||||
pos = Sphere(20.0, 20.0, 0.0, 20.0)
|
||||
neg = Sphere(1.0, 1.0, -6.0, 20.0)
|
||||
|
||||
for i in xrange(int(math.floor(pos.cy - pos.r)),
|
||||
int(math.ceil(pos.cy + pos.r) + 1)):
|
||||
y = i + 0.5
|
||||
for j in xrange(int(math.floor(pos.cx - 2 * pos.r)),
|
||||
int(math.ceil(pos.cx + 2 * pos.r) + 1)):
|
||||
x = (j - pos.cx) / 2.0 + 0.5 + pos.cx
|
||||
|
||||
(h, zb1, zb2) = hit_sphere(pos, x, y)
|
||||
if not h:
|
||||
hit_result = 0
|
||||
else:
|
||||
(h, zs1, zs2) = hit_sphere(neg, x, y)
|
||||
if not h:
|
||||
hit_result = 1
|
||||
elif zs1 > zb1:
|
||||
hit_result = 1
|
||||
elif zs2 > zb2:
|
||||
hit_result = 0
|
||||
elif zs2 > zb1:
|
||||
hit_result = 2
|
||||
else:
|
||||
hit_result = 1
|
||||
|
||||
if hit_result == 0:
|
||||
sys.stdout.write(' ')
|
||||
continue
|
||||
elif hit_result == 1:
|
||||
vec = V3(x - pos.cx, y - pos.cy, zb1 - pos.cz)
|
||||
elif hit_result == 2:
|
||||
vec = V3(neg.cx-x, neg.cy-y, neg.cz-zs2)
|
||||
vec = normalize(vec)
|
||||
|
||||
b = dot(light, vec) ** k + ambient
|
||||
intensity = int((1 - b) * len(shades))
|
||||
intensity = min(len(shades), max(0, intensity))
|
||||
sys.stdout.write(shades[intensity])
|
||||
print
|
||||
|
||||
light = normalize(V3(-50, 30, 50))
|
||||
draw_sphere(2, 0.5, light)
|
||||
75
Task/Death-Star/REXX/death-star.rexx
Normal file
75
Task/Death-Star/REXX/death-star.rexx
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*REXX program to draw a "deathstar", a sphere with another subtracted. */
|
||||
signal on syntax; signal on novalue /*handle REXX program errors. */
|
||||
numeric digits 20 /*use a fair amount of precision.*/
|
||||
lightSource = norm('-50 30 50')
|
||||
call drawSphereM 2, .5, lightSource
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────drawSphereM subroutine──────────────*/
|
||||
drawSphereM: procedure; parse arg k,ambient,lightSource
|
||||
z1=0; z2=0
|
||||
parse var lightSource s1 s2 s3 /*break-apart the light source. */
|
||||
|
||||
shading='·:!ºoe@░▒▓' /*shading chars for ASCI machines*/
|
||||
if 1=='f1'x then shading='.:!*oe&#%@' /*shading chars for EBCDIC machs.*/
|
||||
|
||||
shadesLength=length(shading)
|
||||
shades.=' '; do i=1 for shadesLength
|
||||
shades.i=substr(shading,i,1)
|
||||
end /*i*/
|
||||
|
||||
ship= 20 20 0 20 ; parse var ship ship.cx ship.cy ship.cz ship.radius
|
||||
hole=' 1 1 -6 20'; parse var hole hole.cx hole.cy hole.cz hole.radius
|
||||
|
||||
do i=floor(ship.cy-ship.radius) to ceil(ship.cy+ship.radius)+1; y=i+.5; aLine=
|
||||
do j=trunc(floor(ship.cx - 2*ship.radius) ) to,
|
||||
trunc( ceil(ship.cx + 2*ship.radius) +1)
|
||||
x=.5*(j-ship.cx) + .5 + ship.cx; !bg=0; !pos=0; !neg=0; z1=0; z2=0
|
||||
?=hitSphere(ship, x, y); zb1=z1; zb2=z2
|
||||
|
||||
if \? then !bg=1 /*ray lands in blank space, draw the background. */
|
||||
else do
|
||||
?=hitsphere(hole, x, y); zs1=z1; zs2=z2
|
||||
if \? then !pos=1 /*ray hits ship but not the hole, draw ship surface. */
|
||||
else if zs1>zb1 then !pos=1 /*ray hits both, but ship front surface is closer. */
|
||||
else if zs2>zb2 then !bg=1 /*ship surface is inside hole, show background. */
|
||||
else if zs2>zb1 then !neg=1 /*back surface in hole is inside ship, the only place hole surface will be shown.*/
|
||||
else !pos=1
|
||||
end
|
||||
select
|
||||
when !bg then do; aLine=aLine' '; iterate j; end
|
||||
when !pos then vec_=V3(x-ship.cx y-ship.cy zb1-ship.cz)
|
||||
when !neg then vec_=V3(hole.cx-x hole.cy-y hole.cz-zs2)
|
||||
end /*select*/
|
||||
|
||||
nvec=norm(vec_)
|
||||
b=dot.(lightSource,nvec)**k + ambient
|
||||
intensity=trunc((1-b) * shadesLength)
|
||||
intensity=min(shadesLength, max(0, intensity)) + 1
|
||||
aLine=aLine || shades.intensity
|
||||
end /*j*/
|
||||
|
||||
if aline\='' then say strip(aLine,'T')
|
||||
end /*i*/
|
||||
|
||||
return
|
||||
/*──────────────────────────────────hitSphere subroutine────────────────*/
|
||||
hitSphere: procedure expose z1 z2; parse arg $.cx $.cy $.cz $.radius, x0, y0
|
||||
x=x0-$.cx
|
||||
y=y0-$.cy
|
||||
zsq=$.radius**2 - (x**2 + y**2); if zsq<0 then return 0
|
||||
_=sqrt(zsq)
|
||||
z1=$.cz-_
|
||||
z2=$.cz+_
|
||||
return 1
|
||||
/*──────────────────────────────────"1-liner" subroutines───────────────*/
|
||||
V3: procedure; parse arg v; return norm(v)
|
||||
dot.: procedure; parse arg x,y; d=dot(x,y); if d<0 then return -d; return 0
|
||||
dot: procedure; parse arg x,y; s=0; do j=1 for words(x); s=s+word(x,j)*word(y,j); end; return s
|
||||
err: say; say; say center(' error! ',max(40,linesize()%2),"*"); say; do j=1 for arg(); say arg(j); say; end; say; exit 13
|
||||
novalue: syntax: call err 'REXX program' condition('C') "error", condition('D'),'REXX source statement (line' sigl"):",sourceline(sigl)
|
||||
ceil: procedure; parse arg x; _=trunc(x); return _ + (x>0) * (x\=_)
|
||||
floor: procedure; parse arg x; _=trunc(x); return _ - (x<0) * (x\=_)
|
||||
norm: parse arg _1 _2 _3; _=sqrt(_1**2+_2**2+_3**2); return _1/_ _2/_ _3/_
|
||||
sqrt: procedure; parse arg x; if x=0 then return 0; return .sqrt(x)/1
|
||||
.sqrt: d=digits();numeric digits 11;g=.sqrtG();do j=0 while p>9;m.j=p;p=p%2+1;end;do k=j+5 by -1 to 0;if m.k>11 then numeric digits m.k;g=.5*(g+x/g);end;return g
|
||||
.sqrtG: numeric form; m.=11; p=d+d%4+2; v=format(x,2,1,,0) 'E0'; parse var v g 'E' _ .; return g*.5'E'_%2
|
||||
115
Task/Death-Star/Tcl/death-star-1.tcl
Normal file
115
Task/Death-Star/Tcl/death-star-1.tcl
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
package require Tcl 8.5
|
||||
|
||||
proc normalize vec {
|
||||
upvar 1 $vec v
|
||||
lassign $v x y z
|
||||
set len [expr {sqrt($x**2 + $y**2 + $z**2)}]
|
||||
set v [list [expr {$x/$len}] [expr {$y/$len}] [expr {$z/$len}]]
|
||||
return
|
||||
}
|
||||
|
||||
proc dot {a b} {
|
||||
lassign $a ax ay az
|
||||
lassign $b bx by bz
|
||||
return [expr {-($ax*$bx + $ay*$by + $az*$bz)}]
|
||||
}
|
||||
|
||||
# Intersection code; assumes that the vector is parallel to the Z-axis
|
||||
proc hitSphere {sphere x y z1 z2} {
|
||||
dict with sphere {
|
||||
set x [expr {$x - $cx}]
|
||||
set y [expr {$y - $cy}]
|
||||
set zsq [expr {$r**2 - $x**2 - $y**2}]
|
||||
if {$zsq < 0} {return 0}
|
||||
upvar 1 $z1 _1 $z2 _2
|
||||
set zsq [expr {sqrt($zsq)}]
|
||||
set _1 [expr {$cz - $zsq}]
|
||||
set _2 [expr {$cz + $zsq}]
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
# How to do the intersection with our scene
|
||||
proc intersectDeathStar {x y vecName} {
|
||||
global big small
|
||||
if {![hitSphere $big $x $y zb1 zb2]} {
|
||||
# ray lands in blank space
|
||||
return 0
|
||||
}
|
||||
upvar 1 $vecName vec
|
||||
# ray hits big sphere; check if it hit the small one first
|
||||
set vec [if {
|
||||
![hitSphere $small $x $y zs1 zs2] || $zs1 > $zb1 || $zs2 <= $zb1
|
||||
} then {
|
||||
dict with big {
|
||||
list [expr {$x - $cx}] [expr {$y - $cy}] [expr {$zb1 - $cz}]
|
||||
}
|
||||
} else {
|
||||
dict with small {
|
||||
list [expr {$cx - $x}] [expr {$cy - $y}] [expr {$cz - $zs2}]
|
||||
}
|
||||
}]
|
||||
normalize vec
|
||||
return 1
|
||||
}
|
||||
|
||||
# Intensity calculators for different lighting components
|
||||
proc diffuse {k intensity L N} {
|
||||
expr {[dot $L $N] ** $k * $intensity}
|
||||
}
|
||||
proc specular {k intensity L N S} {
|
||||
# Calculate reflection vector
|
||||
set r [expr {2 * [dot $L $N]}]
|
||||
foreach l $L n $N {lappend R [expr {$l-$r*$n}]}
|
||||
normalize R
|
||||
# Calculate the specular reflection term
|
||||
return [expr {[dot $R $S] ** $k * $intensity}]
|
||||
}
|
||||
|
||||
# Simple raytracing engine that uses parallel rays
|
||||
proc raytraceEngine {diffparms specparms ambient intersector shades renderer fx tx sx fy ty sy} {
|
||||
global light
|
||||
for {set y $fy} {$y <= $ty} {set y [expr {$y + $sy}]} {
|
||||
set line {}
|
||||
for {set x $fx} {$x <= $tx} {set x [expr {$x + $sx}]} {
|
||||
if {![$intersector $x $y vec]} {
|
||||
# ray lands in blank space
|
||||
set intensity end
|
||||
} else {
|
||||
# ray hits something; we've got the normalized vector
|
||||
set b [expr {
|
||||
[diffuse {*}$diffparms $light $vec]
|
||||
+ [specular {*}$specparms $light $vec {0 0 -1}]
|
||||
+ $ambient
|
||||
}]
|
||||
set intensity [expr {int((1-$b) * ([llength $shades]-1))}]
|
||||
if {$intensity < 0} {
|
||||
set intensity 0
|
||||
} elseif {$intensity >= [llength $shades]-1} {
|
||||
set intensity end-1
|
||||
}
|
||||
}
|
||||
lappend line [lindex $shades $intensity]
|
||||
}
|
||||
{*}$renderer $line
|
||||
}
|
||||
}
|
||||
|
||||
# The general scene settings
|
||||
set light {-50 30 50}
|
||||
set big {cx 20 cy 20 cz 0 r 20}
|
||||
set small {cx 7 cy 7 cz -10 r 15}
|
||||
normalize light
|
||||
|
||||
# Render as text
|
||||
proc textDeathStar {diff spec lightBrightness ambient} {
|
||||
global big
|
||||
dict with big {
|
||||
raytraceEngine [list $diff $lightBrightness] \
|
||||
[list $spec $lightBrightness] $ambient intersectDeathStar \
|
||||
[split ".:!*oe&#%@ " {}] {apply {l {puts [join $l ""]}}} \
|
||||
[expr {$cx+floor(-$r)}] [expr {$cx+ceil($r)+0.5}] 0.5 \
|
||||
[expr {$cy+floor(-$r)+0.5}] [expr {$cy+ceil($r)+0.5}] 1
|
||||
}
|
||||
}
|
||||
textDeathStar 3 10 0.7 0.3
|
||||
18
Task/Death-Star/Tcl/death-star-2.tcl
Normal file
18
Task/Death-Star/Tcl/death-star-2.tcl
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Render as a picture (with many hard-coded settings)
|
||||
package require Tk
|
||||
proc guiDeathStar {photo diff spec lightBrightness ambient} {
|
||||
set row 0
|
||||
for {set i 255} {$i>=0} {incr i -1} {
|
||||
lappend shades [format "#%02x%02x%02x" $i $i $i]
|
||||
}
|
||||
raytraceEngine [list $diff $lightBrightness] \
|
||||
[list $spec $lightBrightness] $ambient intersectDeathStar \
|
||||
$shades {apply {l {
|
||||
upvar 2 photo photo row row
|
||||
$photo put [list $l] -to 0 $row
|
||||
incr row
|
||||
update
|
||||
}}} 0 40 0.0625 0 40 0.0625
|
||||
}
|
||||
pack [label .l -image [image create photo ds]]
|
||||
guiDeathStar ds 3 10 0.7 0.3
|
||||
Loading…
Add table
Add a link
Reference in a new issue