The objects on this page are not built from a list of points. Some are infinite (plane, and the polynomial surfaces and quadrics unless you clip them). Some are the set of points where a formula has a given value (poly, cubic, quartic, polynomial, quadric, isosurface). One is a surface drawn by two parameters (parametric) and one comes from the pixels of an image or from a function (height_field). The shapes with a fixed size are on Finite objects. The modifiers every object accepts are on Object modifiers. The functions used in function { ... } are on Functions and constants.
The objects at a glance
| Object | What defines it | Size | Solid | sturm | hierarchy | open |
|---|---|---|---|---|---|---|
plane | normal and distance | infinite | half-space | no | no | no |
poly, cubic, quartic | coefficients of a polynomial in x, y, z | infinite unless clipped | yes | yes | no | no |
polynomial | named coefficients | infinite unless clipped | yes | yes | no | no |
quadric | 10 coefficients | infinite unless clipped | yes | no | no | no |
isosurface | a function of x, y, z | the container | yes | no | no | yes |
parametric | three functions of u, v | the container | no (a shell) | no | no | no |
height_field | an image or a function | one unit cube | yes, below the surface | no | yes | no |
plane
plane { <normal>, distance [modifiers] }
| Item | Default | Meaning |
|---|---|---|
<normal> | required | the direction the plane faces. The parser makes it a unit vector. A vector with no length is the error Degenerate plane normal. |
distance | required | how far the plane is from the origin, measured along the normal. The surface is the set of points P where the dot product of P and the unit normal equals the distance. After the vector is made a unit vector, the distance is not scaled |
An infinite flat surface that splits space in two. A ray is intersected with the plane by one division. The inside is the half-space behind the plane: the points where the dot product with the normal is smaller than the distance. That makes a plane usable in CSG, for example to cut an object in half with intersection, and as the floor of a scene. A plane has no finite bounding box, so it is never bounded; a clipped_by can limit it.
poly, cubic, quartic and polynomial
These objects are the surface where a polynomial in x, y and z is zero. The inside is where it is negative. They are infinite: the parser gives them a very large bounding box unless the object has a clipped_by, in which case the box of the first clipping object is used. All four accept sturm (default off), which uses a slower and more accurate root solver for the equation along each ray.
poly
poly { order, <a1, a2, ... an> [sturm] [modifiers] }
| Item | Meaning |
|---|---|
order | the degree of the polynomial, an integer from 2 to 35. Other values are the error Order of poly is out of range. |
<a1, ... an> | the coefficients, written as one vector of any length: exactly n = (order+1)(order+2)(order+3)/6 numbers (10 for order 2, 20 for 3, 35 for 4, 56 for 5, 84 for 6, 120 for 7). The commas are optional but the count must be right |
cubic
cubic { <a1, a2, ... a20> [sturm] [modifiers] }
A poly of order 3 with the order left out.
quartic
quartic { <a1, a2, ... a35> [sturm] [modifiers] }
A poly of order 4 with the order left out.
The order of the coefficients
Each coefficient belongs to a term xa yb zc with a + b + c at most the order. The terms are listed in this order, for every order from 2 to 35: the power a of x counts down from the order to 0; for each a, the power b of y counts down from order - a to 0; for each b, the power c of z counts down from order - a - b to 0. The last coefficient is the constant. So the first term is always the highest power of x, and the list ends with z2, z, 1.
| Order 2 (10 terms) | Order 3 (20 terms) |
|---|---|
| A1 x2, A2 xy, A3 xz, A4 x, A5 y2, A6 yz, A7 y, A8 z2, A9 z, A10 1 | A1 x3, A2 x2y, A3 x2z, A4 x2, A5 xy2, A6 xyz, A7 xy, A8 xz2, A9 xz, A10 x, A11 y3, A12 y2z, A13 y2, A14 yz2, A15 yz, A16 y, A17 z3, A18 z2, A19 z, A20 1 |
| Order | Terms | First coefficients | Last coefficients |
|---|---|---|---|
| 2 | 10 | x2, xy, xz, x | z2, z, 1 |
3 (cubic) | 20 | x3, x2y, x2z, x2 | z3, z2, z, 1 |
4 (quartic) | 35 | x4, x3y, x3z, x3, x2y2 | z4, z3, z2, z, 1 |
| 5 | 56 | x5, x4y, x4z, x4, x3y2 | z5, z4, z3, z2, z, 1 |
| 6 | 84 | x6, x5y, x5z, x5, x4y2 | z6, z5, z4, z3, z2, z, 1 |
| 7 | 120 | x7, x6y, x6z, x6, x5y2 | z7, z6, z5, z4, z3, z2, z, 1 |
The position of a term in the list is the number of terms before it. You can compute it from the powers, or avoid the whole question with polynomial below. For example, in a quartic the term x2y2 is number 5 and the term x2 is number 10.
polynomial
polynomial { order, xyz(a, b, c): value [,] ... [sturm] [modifiers] }
| Item | Default | Meaning |
|---|---|---|
order | required | the degree, an integer from 2 to 35 (Order of polynom is out of range. otherwise) |
xyz(a, b, c): value | every coefficient is 0 | sets the coefficient of xa yb zc. The three powers are numbers; the colon is required; a comma after the value is optional. The terms can come in any order. A term that is set twice keeps its last value. If a + b + c is more than the order, the parser stops with Coefficient of polynom is out of range. |
It builds the same object as poly and is easier to write by hand.
plane { y, -1 pigment { checker rgb 1, rgb 0 } }
// the unit sphere as a second order poly: x2 xy xz x y2 yz y z2 z 1
poly { 2, <1, 0, 0, 0, 1, 0, 0, 1, 0, -1> pigment { rgb <1, 0, 0> } translate -x*3 }
// the same sphere as a polynomial
polynomial {
2,
xyz(2, 0, 0): 1,
xyz(0, 2, 0): 1,
xyz(0, 0, 2): 1,
xyz(0, 0, 0): -1
pigment { rgb <0, 1, 0> }
}
// the same sphere as a quadric
quadric { <1, 1, 1>, <0, 0, 0>, <0, 0, 0>, -1 pigment { rgb <0, 0, 1> } translate x*3 }
// a torus as a quartic
quartic {
< 1, 0, 0, 0, 2, 0, 0, 2, 0, -104,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 2, 0, 56, 0, 0, 0, 0,
1, 0, -104, 0, 784 >
sturm
pigment { rgb 1 }
scale 0.2 translate y*2
}
quadric
quadric { <A, B, C>, <D, E, F>, <G, H, I>, J [modifiers] }
| Part | Terms |
|---|---|
first vector <A, B, C> | the squares: A x2, B y2, C z2 |
second vector <D, E, F> | the mixed terms: D xy, E xz, F yz |
third vector <G, H, I> | the linear terms: G x, H y, I z |
J | the constant |
The surface is the set of points where A x² + B y² + C z² + D xy + E xz + F yz + G x + H y + I z + J = 0. Points where the value is negative or zero are inside. The parser reads three vectors and a number, so the ten numbers can be any expressions. A second order polynomial renders much faster than poly but makes only simple shapes: spheres, ellipsoids, cylinders, cones, paraboloids and hyperboloids. A quadric is infinite. If it has a clipped_by, the parser computes a bounding box from the clipping object before the transformations; the box is used only when it is smaller than the default one.
| Quadric | Shape |
|---|---|
<1,1,1>, 0, 0, -1 | unit sphere |
<1,1,0>, 0, 0, -1 | infinite cylinder along the z axis |
<1,1,-1>, 0, 0, 0 | infinite double cone along the z axis |
isosurface
isosurface {
function { f(x, y, z) }
[contained_by { sphere { <c>, r } | box { <corner1>, <corner2> } }]
[threshold t] [accuracy a] [max_gradient g] [evaluate p0, p1, p2]
[max_trace n | all_intersections] [open] [polarity p]
[modifiers] }
| Keyword | Value | Default | Meaning |
|---|---|---|---|
function { ... } | expression in x, y, z | required, and it must come first | the field. The surface is where the function equals the threshold |
contained_by | box or sphere block | box { -1, 1 } | the region in which the function is sampled. A box block holds two corners (the parser puts each axis in order); a sphere block holds a centre and a radius. The bounding box of the object is taken from it |
threshold | float | 0 | the value of the function on the surface |
accuracy | float | 0.001 | the subdivision of the search for a surface stops when the interval is shorter than this. A value of 0 or less gives a warning and the default is used |
max_gradient | float | 1.1 | an upper bound for the steepness of the function. A value too low leaves holes in the surface; too high makes rendering slow. A value of 0 or less gives a warning and the default is used |
evaluate | three floats | off | lets the program change the gradient as it renders. p0 is the lowest max_gradient of the search, p1 an over-estimating factor and p2 an attenuation factor of 1 or less. A start for the values: p0 is the found gradient times a number between 0 and 1 (about 0.6), p1 is the square root of the found gradient divided by p0, and p2 is 0.7 |
max_trace | integer 1 to 10 | 1 | the number of surface hits found along a ray. The default finds only the first one, which is not enough inside CSG. A number outside 1 to 10 is an error |
all_intersections | flag | off | sets max_trace to its largest value, 10 |
open | flag | closed | when the surface is cut by the container, the cut is closed by a cap that shows the container. open leaves the cap off. It slows rendering and is not for CSG |
polarity | number | off (0) | which side is inside. A value above 0 (on is 1) takes the points where the function is larger than the threshold as inside; zero or below (off) takes the points where it is smaller, which is the default. It also turns the normals round |
The keywords after the function may come in any order. The surface is found by a recursive subdivision along each ray that uses the gradient bound to know how far it can step. The default inside is where the function is below the threshold, inside the container.
parametric
parametric {
function { fx(u, v) }, function { fy(u, v) }, function { fz(u, v) }
<umin, vmin>, <umax, vmax>
[contained_by { sphere { <c>, r } | box { <corner1>, <corner2> } }]
[max_gradient g] [accuracy a] [precompute depth, x, y, z]
[modifiers] }
| Keyword | Value | Default | Meaning |
|---|---|---|---|
three function { ... } | expressions in u and v | required | the x, y and z coordinates of the surface point for each pair of u and v. Only the form function { expression } is accepted |
| two 2D vectors | <umin, vmin>, <umax, vmax> | required | the range of u and v. The parser swaps the two values of an axis if the minimum is above the maximum |
contained_by | box or sphere block | box { -1, 1 } | the region in which the surface is searched |
max_gradient | float | 1 | the largest absolute value of the six partial derivatives of the three functions over the range. A value that is too small gives holes |
accuracy | float | 0.001 | a smaller value gives a more accurate surface and takes longer |
precompute | depth, then any of x, y, z | off | divides the surface in advance into smaller parts to speed up the render. The depth is at most 20 (manual); the variables list which coordinate ranges are precomputed. A large depth uses much memory |
The object is a thin shell with no inside, so it is not usable in the inside tests of CSG. It cannot be inverted.
#include "functions.inc"
isosurface {
function { x*x + y*y + z*z - 1.5 + 0.3*sin(4*x)*sin(4*y)*sin(4*z) }
contained_by { sphere { 0, 2 } }
threshold 0
accuracy 0.001
max_gradient 4
max_trace 2
open
pigment { rgb <1, 0.6, 0.2> }
}
isosurface {
function { f_torus(x, y, z, 1.2, 0.4) }
contained_by { box { <-2, -2, -2>, <2, 2, 2> } }
evaluate 5, 1.2, 0.9
all_intersections
pigment { rgb 1 }
translate x*3
}
parametric {
function { sin(u) * cos(v) }
function { sin(u) * sin(v) }
function { cos(u) }
<0, 0>, <pi, 2*pi>
contained_by { sphere { 0, 1.1 } }
max_gradient 2
accuracy 0.001
precompute 10, x, y, z
pigment { rgb <0, 0.7, 1> }
translate -x*3
}
height_field
height_field {
[type] "file" [gamma g] [premultiplied b]
| function width, height { f(x, y, z) }
[smooth] [water_level w] [hierarchy [b]]
[modifiers] }
| Item | Value | Default | Meaning |
|---|---|---|---|
| file type | gif, tga, png, pgm, ppm, jpeg, tiff, bmp, exr, hdr, pot, sys | from the file name's extension; without an extension, the type of the output file | the image format. A file name with an extension of an unknown format is the error Could not determine valid image file type from extension. The type iff is not allowed for height fields (File type not supported here.) |
"file" | string | required (unless function) | the image file, searched in the current directory and the library paths |
gamma | number, srgb, bt709 or bt2020 | none: the data is taken as it is | tells the parser the file is encoded with that gamma, so that it decodes it before building the height field. A number of 0 or less is an error. Without it, no gamma correction is done on the height data and no warning is given |
premultiplied | number | from the file | says whether the alpha channel is premultiplied; 0 is false |
function w, h { ... } | two numbers and a function block | a function instead of a file: it is sampled on a grid of w by h points (rounded to whole numbers), as if it were an image. The function can use pattern { ... } | |
smooth | flag | off | interpolates the normals, so that the triangles look smooth |
water_level | float, 0 to 1 | 0 | parts of the field below this fraction of the full height are ignored. In a scene that declares a version before 2.0 the number is divided by 256 |
hierarchy | flag, optional number | on | a one-level bounding hierarchy over the field. hierarchy off turns it off, which helps for small fields |
The field is a mesh over one unit square in the x-z plane, from <0, 0, 0> to <1, 1, 1>, whatever the size of the image. The height of the point is the number stored for the pixel, scaled so the largest possible value is 1. Each square of four neighbouring pixels is two triangles, so an image of N by M pixels makes 2(N-1)(M-1) triangles. A smooth surface needs a bigger image or smooth. The inside is below the surface and inside the unit square.
| File type | How the height is taken from a pixel |
|---|---|
gif | the palette index (0 to 255); the colour of the palette entry is not used. Only 256 levels |
pot | like a GIF file with a 16 bit palette; up to 65536 levels |
tga, ppm | the red and green bytes of the pixel are the high and low bytes of a 16 bit height |
png | a grey scale image is the height; a 16 bit grey image gives 65536 levels. A colour PNG is used like a TGA or PPM image |
pgm, tiff, jpeg, bmp, exr, hdr | read as an image; the grey or colour value gives the height. sys is platform specific |
The setting that makes a program write a 16 bit height field from a render is not an object keyword in 3.8. The word hf_gray_16 is still recognised in a scene, but it is ignored (the parser says it must be given as a command-line option such as +FNg or as the INI setting Grayscale_Output=true). See Global settings and INI options.
height_field {
function 64, 64 { pattern { wrinkles } }
smooth
water_level 0.1
pigment { rgb <0.4, 0.7, 0.3> }
translate <-0.5, 0, -0.5>
scale <4, 1, 4>
}
height_field {
png "Mount1.png"
gamma 1.0
smooth
pigment { rgb 1 }
translate <-0.5, 0, -0.5>
}
Notes
- There is no other infinite or implicit object word in the parser. The complete list of words that start an object is on Constructive solid geometry.
- Where the manual calls
parametric,isosurfaceandheight_field"solid finite objects", note that a parametric surface is a shell and has no inside, and that the isosurface is finite only through its container.
Not described
Known, not yet covered
- Reference: the exact way
max_gradientandevaluatechange the step of the isosurface search, and the details of the height values of the less common image formats (pgm,tiff,bmp,exr,hdr,sys) are not described; only the manual's description of GIF, POT, TGA, PPM and PNG is given.