6.8 The Tachyon 3D Ray Tracer

Module: sage.plot.tachyon

The Tachyon 3D Ray Tracer

Given any 3D graphics object one can compute a raytraced representation by typing show(viewer='tachyon'). For example, we draw two translucent spheres that contain a red tube, and render the result using Tachyon.

sage: S = sphere(opacity=0.8, aspect_ratio=[1,1,1])
sage: L = line3d([(0,0,0),(2,0,0)], thickness=10, color='red')
sage: M = S + S.translate((2,0,0)) + L
sage: M.show(viewer='tachyon')

One can also directly control Tachyon, which gives a huge amount of flexibility. For example, here we directly use Tachyon to draw 3 spheres on the coordinate axes. Notice that the result is gorgeous:

sage: t = Tachyon(xres=500,yres=500, camera_center=(2,0,0))
sage: t.light((4,3,2), 0.2, (1,1,1))
sage: t.texture('t2', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1,0,0))
sage: t.texture('t3', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(0,1,0))
sage: t.texture('t4', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(0,0,1))
sage: t.sphere((0,0.5,0), 0.2, 't2')
sage: t.sphere((0.5,0,0), 0.2, 't3')
sage: t.sphere((0,0,0.5), 0.2, 't4')
sage: t.show()

Author Log:

TODO: - clean up trianglefactory stuff

Module-level Functions

hue( h, [s=1], [v=1])

hue(h,s=1,v=1) where 'h' stands for hue, 's' stands for saturation, 'v' stands for value. hue returns a list of rgb intensities (r, g, b) All values are in the range 0 to 1.

Input:

h, s, v
- real numbers between 0 and 1. Note that if any are not in this range they are automatically normalized to be in this range by reducing them modulo 1.
Output: A valid RGB tuple.

sage: hue(0.6)
(0.0, 0.40000000000000036, 1.0)

hue is an easy way of getting a broader range of colors for graphics

sage: p = plot(sin, -2, 2, rgbcolor=hue(0.6))

tostr( s)

Class: Cylinder

class Cylinder
Cylinder( self, center, axis, radius, texture)

Functions: str

Special Functions: __init__

Class: FCylinder

class FCylinder
FCylinder( self, base, apex, radius, texture)

Functions: str

Special Functions: __init__

Class: Light

class Light
Light( self, center, radius, color)

Functions: str

Special Functions: __init__

Class: ParametricPlot

class ParametricPlot
ParametricPlot( self, f, t_0, t_f, tex, [r=0.1], [cylinders=True], [min_depth=4], [max_depth=8], [e_rel=0.01], [e_abs=0.01])

Functions: str,$ \,$ tol

Special Functions: __init__,$ \,$ _plot_step

Class: Plane

class Plane
Plane( self, center, normal, texture)

Functions: str

Special Functions: __init__

Class: PlotBlock

class PlotBlock
PlotBlock( self, left, left_c, top, top_c, right, right_c, bottom, bottom_c)

Special Functions: __init__

Class: Sphere

class Sphere
Sphere( self, center, radius, texture)

Functions: str

Special Functions: __init__

Class: Tachyon

class Tachyon
Create a scene the can be rendered using the Tachyon ray tracer.

Input: xres=350, yres=350, zoom = 1.0, antialiasing = False, aspectratio = 1.0, raydepth = 5, camera_center = (-3, 0, 0), updir = (0, 0, 1), look_at = (0,0,0), viewdir = None, projection = 'PERSPECTIVE'

Output: A Tachyon 3d scene.

Note that the coordinates are by default such that $ z$ is up, positive $ y$ is to the left and $ x$ is toward you. This is not oriented according to the right hand rule.

Spheres along the twisted cubic.

sage: t = Tachyon(xres=512,yres=512, camera_center=(3,0.3,0))
sage: t.light((4,3,2), 0.2, (1,1,1))
sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1.0,0,0))
sage: t.texture('t1', ambient=0.1, diffuse=0.9, specular=0.3, opacity=1.0, color=(0,1.0,0))
sage: t.texture('t2', ambient=0.2,diffuse=0.7, specular=0.5, opacity=0.7, color=(0,0,1.0))
sage: k=0
sage: for i in srange(-1,1,0.05):
...    k += 1
...    t.sphere((i,i^2-0.5,i^3), 0.1, 't%s'%(k%3))
...
sage: t.show()

Another twisted cubic, but with a white background, got by putting infinite planes around the scene.

sage: t = Tachyon(xres=512,yres=512, camera_center=(3,0.3,0), raydepth=8)
sage: t.light((4,3,2), 0.2, (1,1,1))
sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1.0,0,0))
sage: t.texture('t1', ambient=0.1, diffuse=0.9, specular=0.3, opacity=1.0, color=(0,1.0,0))
sage: t.texture('t2', ambient=0.2,diffuse=0.7, specular=0.5, opacity=0.7, color=(0,0,1.0))
sage: t.texture('white', color=(1,1,1))
sage: t.plane((0,0,-1), (0,0,1), 'white')
sage: t.plane((0,-20,0), (0,1,0), 'white')
sage: t.plane((-20,0,0), (1,0,0), 'white')

sage: k=0
sage: for i in srange(-1,1,0.05):
...    k += 1
...    t.sphere((i,i^2 - 0.5,i^3), 0.1, 't%s'%(k%3))
...    t.cylinder((0,0,0), (0,0,1), 0.05,'t1') 
...
sage: t.show()

Many random spheres:

sage: t = Tachyon(xres=512,yres=512, camera_center=(2,0.5,0.5), look_at=(0.5,0.5,0.5), raydepth=4)
sage: t.light((4,3,2), 0.2, (1,1,1))
sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1.0,0,0))
sage: t.texture('t1', ambient=0.1, diffuse=0.9, specular=0.3, opacity=1.0, color=(0,1.0,0))
sage: t.texture('t2', ambient=0.2, diffuse=0.7, specular=0.5, opacity=0.7, color=(0,0,1.0))
sage: k=0
sage: for i in range(100):
...    k += 1
...    t.sphere((random(),random(), random()), random()/10, 't%s'%(k%3))
...
sage: t.show()

Points on an elliptic curve, their height indicated by their height above the axis:

sage: t = Tachyon(camera_center=(5,2,2), look_at=(0,1,0))
sage: t.light((10,3,2), 0.2, (1,1,1))
sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1,0,0))
sage: t.texture('t1', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(0,1,0))
sage: t.texture('t2', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(0,0,1))
sage: E = EllipticCurve('37a')
sage: P = E([0,0])
sage: Q = P
sage: n = 100
sage: for i in range(n):   # increase 20 for a better plot
...    Q = Q + P
...    t.sphere((Q[1], Q[0], ZZ(i)/n), 0.1, 't%s'%(i%3))
...
sage: t.show()

A beautiful picture of rational points on a rank 1 elliptic curve.

sage: t = Tachyon(xres=1000, yres=800, camera_center=(2,7,4), look_at=(2,0,0), raydepth=4)
sage: t.light((10,3,2), 1, (1,1,1))
sage: t.light((10,-3,2), 1, (1,1,1))
sage: t.texture('black', color=(0,0,0))
sage: t.texture('red', color=(1,0,0))
sage: t.texture('grey', color=(.9,.9,.9))
sage: t.plane((0,0,0),(0,0,1),'grey')
sage: t.cylinder((0,0,0),(1,0,0),.01,'black')
sage: t.cylinder((0,0,0),(0,1,0),.01,'black')
sage: E = EllipticCurve('37a')
sage: P = E([0,0])
sage: Q = P
sage: n = 100
sage: for i in range(n):  
...    Q = Q + P
...    c = i/n + .1
...    t.texture('r%s'%i,color=(float(i/n),0,0))
...    t.sphere((Q[0], -Q[1], .01), .04, 'r%s'%i)
...          
...
sage: t.show()    # long time, e.g., 10-20 seconds

A beautiful spiral.

sage: t = Tachyon(xres=800,yres=800, camera_center=(2,5,2), look_at=(2.5,0,0))
sage: t.light((0,0,100), 1, (1,1,1))
sage: t.texture('r', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1,0,0))
sage: for i in srange(0,50,0.1):
...    t.sphere((i/10,sin(i),cos(i)), 0.05, 'r')
...
sage: t.texture('white', color=(1,1,1), opacity=1, specular=1, diffuse=1)
sage: t.plane((0,0,-100), (0,0,-100), 'white')
sage: t.show()
Tachyon( self, [xres=350], [yres=350], [zoom=1.0], [antialiasing=False], [aspectratio=1.0], [raydepth=8], [camera_center=(-3, 0, 0)], [updir=(0, 0, 1)], [look_at=(0, 0, 0)], [viewdir=None], [projection=PERSPECTIVE])

Functions: collect,$ \,$ cylinder,$ \,$ fcylinder,$ \,$ light,$ \,$ parametric_plot,$ \,$ plane,$ \,$ plot,$ \,$ save,$ \,$ show,$ \,$ smooth_triangle,$ \,$ sphere,$ \,$ str,$ \,$ texfunc,$ \,$ texture,$ \,$ texture_recolor,$ \,$ triangle

collect( self, objects)
Add a set of objects to the scene from a collection

parametric_plot( self, f, t_0, t_f, tex, [r=0.1], [cylinders=True], [min_depth=4], [max_depth=8], [e_rel=0.01], [e_abs=0.01])

Plots a space curve as a series of speheres and finite cylinders. Example (twisted cubic) :

sage: f = lambda t: (t,t^2,t^3)
sage: t = Tachyon(camera_center=(5,0,4))
sage: t.texture('t')
sage: t.light((-20,-20,40), 0.2, (1,1,1))
sage: t.parametric_plot(f,-5,5,'t',min_depth=6)

plot( self, f, ['xmin', 'xmax'], ['ymin', 'ymax'], texture, [grad_f=None], [max_bend=0.7], [max_depth=5], [initial_depth=3], [num_colors=None])

Input:

f
- Function of two variables, which returns a float (or coercable to a float) (xmin,xmax)
(ymin,ymax)
- defines the rectangle to plot over texture: Name of texture to be used Optional arguments:
grad_f
- gradient function. If specified, smooth triangles will be used.
max_bend
- Cosine of the threshold angle between triangles used to determine whether or not to recurse after the minimum depth
max_depth
- maximum recursion depth. Maximum triangles plotted = $ 2^{2*max_depth}$
initial_depth
- minimum recursion depth. No error-tolerance checking is performed below this depth. Minimum triangles plotted: $ 2^{2*min_depth}$
num_colors
- Number of rainbow bands to color the plot with. Texture supplied will be cloned (with different colors) using the texture_recolor method of the Tachyon object.

Plots a function by constructing a mesh with nonstandard sampling density without gaps. At very high resolutions (depths > 10) it becomes very slow. Cython may help. Complexity is approx. $ O(2^{2*maxdepth})$ . This algorithm has been optimized for speed, not memory - values from f(x,y) are recycled rather than calling the function multiple times. At high recursion depth, this may cause problems for some machines.

Flat Triangles:

sage: t = Tachyon(xres=512,yres=512, camera_center=(4,-4,3),viewdir=(-4,4,-3), raydepth=4)
sage: t.light((4.4,-4.4,4.4), 0.2, (1,1,1))
sage: def f(x,y): return float(sin(x*y))
sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1,  opacity=1.0, color=(1.0,0,0))
sage: t.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, num_colors=60)  # increase min_depth for better picture
sage: t.show()

Plotting with Smooth Triangles (requires explicit gradient function):

sage: t = Tachyon(xres=512,yres=512, camera_center=(4,-4,3),viewdir=(-4,4,-3), raydepth=4)
sage: t.light((4.4,-4.4,4.4), 0.2, (1,1,1))
sage: def f(x,y): return float(sin(x*y))
sage: def g(x,y): return ( float(y*cos(x*y)), float(x*cos(x*y)), 1 )
sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1,  opacity=1.0, color=(1.0,0,0))
sage: t.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, grad_f = g)  # increase min_depth for better picture
sage: t.show()

Preconditions: f is a scalar function of two variables, grad_f is None or a triple-valued function of two variables, min_x != max_x, min_y != max_y

sage: f = lambda x,y: x*y
sage: t = Tachyon()
sage: t.plot(f,(2.,2.),(-2.,2.),'')
Traceback (most recent call last):
...
ValueError: Plot rectangle is really a line.  Make sure min_x != max_x and
min_y != max_y.

save( self, [filename=sage.png], [verbose=0], [block=True], [extra_opts=])

Input:

filename
- (default: 'sage.png') output filename; the extension of the filename determines the type. Supported types include:
tga
- 24-bit (uncompressed)
bmp
- 24-bit Windows BMP (uncompressed)
ppm
- 24-bit PPM (uncompressed)
rgb
- 24-bit SGI RGB (uncompressed)
png
- 24-bit PNG (compressed, lossless)
verbose
- integer; (default: 0)
0
- silent
1
- some output
2
- very verbose output
block
- bool (default: True); if False, run the rendering command in the background.
extra_opts
- passed directly to tachyon command line. Use tachyon_rt.usage() to see some of the possibilities.

texfunc( self, [type=0], [center=(0, 0, 0)], [rotate=(0, 0, 0)], [scale=(1, 1, 1)])

Input:

type
- (default: 0) 0: No special texture, plain shading 1: 3D checkerboard function, like a rubik's cube 2: Grit Texture, randomized surface color 3: 3D marble texture, uses object's base color 4: 3D wood texture, light and dark brown, not very good yet 5: 3D gradient noise function (can't remember what it look like 6: Don't remember 7: Cylindrical Image Map, requires ppm filename (don't know how to specify name in sage?!) 8: Spherical Image Map, requires ppm filename (don't know how to specify name in sage?!) 9: Planar Image Map, requires ppm filename (don't know how to specify name in sage?!)
center
- (default: (0,0,0))
rotate
- (default: (0,0,0))
scale
- (default: (1,1,1))

We draw an infinite checkboard:

sage: t = Tachyon(camera_center=(2,7,4), look_at=(2,0,0))
sage: t.texture('black', color=(0,0,0), texfunc=1)
sage: t.plane((0,0,0),(0,0,1),'black')
sage: t.show()

texture( self, name, [ambient=0.2], [diffuse=0.8], [specular=0.0], [opacity=1.0], [color=(1.0, 0.0, 0.5)], [texfunc=0], [phong=0], [phongsize=0.5], [phongtype=PLASTIC])

Input:

name
- string; the name of the texture (to be used later)
ambient
- (default: 0.2)
diffuse
- (default: 0.8)
specular
- (default: 0.0)
opacity
- (default: 1.0)
color
- (default: (1.0,0.0,0.5))
texfunc
- (default: 0); a texture function; this is either the output of self.texfunc, or a number between 0 and 9, inclusive. See the docs for self.texfunc.
phong
- (default: 0)
phongsize
- (default: 0.5)
phongtype
- (default: "PLASTIC")

We draw a scene with 4 sphere that illustrates various uses of the texture command:

sage: t = Tachyon(camera_center=(2,5,4), look_at=(2,0,0), raydepth=6)
sage: t.light((10,3,4), 1, (1,1,1))
sage: t.texture('mirror', ambient=0.05, diffuse=0.05, specular=.9, opacity=0.9, color=(.8,.8,.8))
sage: t.texture('grey', color=(.8,.8,.8), texfunc=3)
sage: t.plane((0,0,0),(0,0,1),'grey')
sage: t.sphere((4,-1,1), 1, 'mirror')
sage: t.sphere((0,-1,1), 1, 'mirror')
sage: t.sphere((2,-1,1), 0.5, 'mirror')
sage: t.sphere((2,1,1), 0.5, 'mirror')
sage: show(t)

Special Functions: __init__,$ \,$ __repr__,$ \,$ _camera,$ \,$ _res

Class: TachyonPlot

class TachyonPlot
TachyonPlot( self, tachyon, f, ['min_x', 'max_x'], ['min_y', 'max_y'], tex, [g=None], [min_depth=4], [max_depth=8], [e_rel=0.01], [e_abs=0.01], [num_colors=None])

Functions: extrema,$ \,$ interface,$ \,$ plot_block,$ \,$ str,$ \,$ tol,$ \,$ tol_list,$ \,$ triangulate

Special Functions: __init__

Class: TachyonSmoothTriangle

class TachyonSmoothTriangle

Functions: str

Class: TachyonTriangle

class TachyonTriangle

Functions: str

Class: TachyonTriangleFactory

class TachyonTriangleFactory
TachyonTriangleFactory( self, tach, tex)

Functions: get_colors,$ \,$ smooth_triangle,$ \,$ triangle

Special Functions: __init__

Class: Texfunc

class Texfunc
Texfunc( self, [type=0], [center=(0, 0, 0)], [rotate=(0, 0, 0)], [scale=(1, 1, 1)])

Functions: str

Special Functions: __init__

Class: Texture

class Texture
Texture( self, name, [ambient=0.2], [diffuse=0.8], [specular=0.0], [opacity=1.0], [color=(1.0, 0.0, 0.5)], [texfunc=0], [phong=0], [phongsize=0], [phongtype=PLASTIC])

Functions: recolor,$ \,$ str

Special Functions: __init__

See About this document... for information on suggesting changes.