Difference between revisions of "Documentation Talk:Reference Section 4.2"
Le Forgeron (talk | contribs) (Adding polynomial syntax & updating order maximum to 35) |
Jholsenback (talk | contribs) m (add isosurface section for user editting) |
||
Line 793: | Line 793: | ||
begin to list or describe them all. We suggest you find a good reference | begin to list or describe them all. We suggest you find a good reference | ||
or text book if you want to investigate the subject further.</p> | or text book if you want to investigate the subject further.</p> | ||
+ | |||
+ | ===Isosurface Object=== | ||
+ | <!--<indexentry primary "isosurface" "isosurface, keyword">---> | ||
+ | <!--<indexentry "Keyword, isosurface">---> | ||
+ | <!--<indexentry primary "function, isosurface">---> | ||
+ | <!--<indexentry "Keyword, function">---> | ||
+ | <!--<indexentry primary "contained_by, isosurface">---> | ||
+ | <!--<indexentry "Keyword, contained_by">---> | ||
+ | <!--<indexentry primary "threshold, isosurface">---> | ||
+ | <!--<indexentry "Keyword, threshold">---> | ||
+ | <!--<indexentry primary "accuracy, isosurface">---> | ||
+ | <!--<indexentry "Keyword, accuracy">---> | ||
+ | <!--<indexentry primary "max_gradient, isosurface">---> | ||
+ | <!--<indexentry "Keyword, max_gradient">---> | ||
+ | <!--<indexentry primary "evaluate, isosurface">---> | ||
+ | <!--<indexentry "Keyword, evaluate">---> | ||
+ | <!--<indexentry primary "open, isosurface">---> | ||
+ | <!--<indexentry "Keyword, open">---> | ||
+ | <!--<indexentry primary "max_trace, isosurface">---> | ||
+ | <!--<indexentry "Keyword, max_trace">---> | ||
+ | <!--<indexentry primary "all_intersections, isosurface">---> | ||
+ | <!--<indexentry "Keyword, all_intersections">---> | ||
+ | |||
+ | <p>Details about many of the things that can be done with the isosurface object are | ||
+ | discussed in the isosurface tutorial section. Below you will only find the syntax basics:</p> | ||
+ | |||
+ | <pre> | ||
+ | isosurface { | ||
+ | function { FUNCTION_ITEMS } | ||
+ | [contained_by { SPHERE | BOX }] | ||
+ | [threshold FLOAT_VALUE] | ||
+ | [accuracy FLOAT_VALUE] | ||
+ | [max_gradient FLOAT_VALUE] | ||
+ | [evaluate P0, P1, P2] | ||
+ | [open] | ||
+ | [max_trace INTEGER] | [all_intersections] | ||
+ | [OBJECT_MODIFIERS...] | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | <p> | ||
+ | Isosurface default values:</p> | ||
+ | <!--<indexentry "Default values, isosurface" "isosurface, default values">---> | ||
+ | <pre> | ||
+ | contained_by : box{-1,1} | ||
+ | threshold : 0.0 | ||
+ | accuracy : 0.001 | ||
+ | max_gradient : 1.1 | ||
+ | </pre> | ||
+ | |||
+ | |||
+ | <p><code>function { ... }</code> This must be specified and be the first item of the | ||
+ | <code>isosurface</code> statement. Here you place all the mathematical functions that | ||
+ | will describe the surface.</p> | ||
+ | |||
+ | <!--<indexentry primary "contained_by">---> | ||
+ | <!--<indexentry "contained_by, isosurface">---> | ||
+ | <p><code>contained_by { ... }</code> The <code>contained_by</code> <em>object</em> limits the | ||
+ | area where POV-Ray samples for the surface of the function. This container can either be a | ||
+ | sphere or a box, both of which use the standard POV-Ray syntax. If not specified a | ||
+ | <code>box {<-1,-1,-1>, <1,1,1>}</code> will be used as default.</p> | ||
+ | <pre> | ||
+ | contained_by { sphere { CENTER, RADIUS } } | ||
+ | contained_by { box { CORNER1, CORNER2 } } | ||
+ | </pre> | ||
+ | |||
+ | <!--<indexentry "threshold, isosurface">---> | ||
+ | <p><code>threshold</code> This specifies how much strength, or substance to give the | ||
+ | <code>isosurface</code>. The surface appears where the <code>function</code> value | ||
+ | equals the <code>threshold</code> value. The default threshold is 0.</p> | ||
+ | <pre>function = threshold</pre> | ||
+ | |||
+ | <!--<indexentry primary "accuracy">---> | ||
+ | <p><code>accuracy</code> The isosurface finding method is a recursive subdivision method. | ||
+ | This subdivision goes on until the length of the interval where POV-Ray finds a surface | ||
+ | point is less than the specified <code>accuracy</code>. The default value is 0.001. | ||
+ | <br>Smaller values produces more accurate surfaces, but it takes longer to render.</p> | ||
+ | |||
+ | <!--<indexentry primary "max_gradient">---> | ||
+ | <!--<indexentry "max_gradient, isosurface">---> | ||
+ | <p><code>max_gradient</code> POV-Ray can find the first intersecting point between a ray and | ||
+ | the <code>isosurface</code> of any continuous function if the maximum gradient of the function | ||
+ | is known. Therefore you can specify a <code>max_gradient</code> for the function. | ||
+ | The default value is 1.1. When the <code>max_gradient</code> used to find the | ||
+ | intersecting point is too high, the render slows down considerably. When it is too | ||
+ | low, artefacts or holes may appear on the isosurface. When it is way too low, the surface | ||
+ | does not show at all. While rendering the isosurface POV-Ray records the found gradient values | ||
+ | and prints a warning if these values are higher or much lower than the specified | ||
+ | <code>max_gradient</code>:</p> | ||
+ | |||
+ | <pre> | ||
+ | Warning: The maximum gradient found was 5.257, but max_gradient of | ||
+ | the isosurface was set to 5.000. The isosurface may contain holes! | ||
+ | Adjust max_gradient to get a proper rendering of the isosurface. | ||
+ | </pre> | ||
+ | |||
+ | <pre> | ||
+ | Warning: The maximum gradient found was 5.257, but max_gradient of | ||
+ | the isosurface was set to 7.000. Adjust max_gradient to | ||
+ | get a faster rendering of the isosurface. | ||
+ | </pre> | ||
+ | |||
+ | <p>For best performance you should specify a value close to the real maximum gradient.</p> | ||
+ | |||
+ | <!--<indexentry primary "evaluate">---> | ||
+ | <!--<indexentry "dynamic max_gradient">---> | ||
+ | <p><code>evaluate</code> POV-Ray can also dynamically adapt the used max_gradient. | ||
+ | To activate this technique you have to specify the <code>evaluate</code> keyword | ||
+ | followed by three parameters:</p> | ||
+ | <ul> | ||
+ | <li> P0: the minimum max_gradient in the estimation process,</li> | ||
+ | <li> P1: an over-estimating factor. This means that the max_gradient is | ||
+ | multiplied by the P1 parameter.</li> | ||
+ | <li> P2: an attenuation parameter (1 or less)</li> | ||
+ | </ul> | ||
+ | <p>In this case POV-Ray starts with the <code>max_gradient</code> value <code>P0</code> | ||
+ | and dynamically changes it during the render using <code>P1</code> and <code>P2</code>. | ||
+ | In the evaluation process, the P1 and P2 parameters are used in | ||
+ | quadratic functions. This means that over-estimation increases more | ||
+ | rapidly with higher values and attenuation more rapidly with lower | ||
+ | values. Also with dynamic <code>max_gradient</code>, there can be artefacts and holes.</p> | ||
+ | |||
+ | <p>If you are unsure what values to use, start a render without <code>evaluate</code> to get | ||
+ | a value for <code>max_gradient</code>. Now you can use it with <code>evaluate</code> like this:</p> | ||
+ | <ul> | ||
+ | <li>P0 : found max_gradient * min_factor<br> | ||
+ | <em>min_factor</em> being a float between 0 and 1 to reduce the | ||
+ | <code>max_gradient</code> to a <em>minimum max_gradient</em>. The ideal value for P0 | ||
+ | would be the average of the found max_gradients, but we do not | ||
+ | have access to that information.<br> | ||
+ | A good starting point is 0.6 for the min_factor</li> | ||
+ | <li>P1 : sqrt(found max_gradient/(found max_gradient * min_factor))<br> | ||
+ | <em>min_factor</em> being the same as used in P0 | ||
+ | this will give an over-estimation factor of more than 1, based | ||
+ | on your minimum max_gradient and the found max_gradient.</li> | ||
+ | <li>P2 : 1 or less<br> | ||
+ | 0.7 is a good starting point.</li> | ||
+ | </ul> | ||
+ | <p> | ||
+ | When there are artifacts / holes in the isosurface, increase the min_factor and / or P2 a bit. | ||
+ | Example: when the first run gives a found max_gradient of 356, start with</p> | ||
+ | <pre> | ||
+ | #declare Min_factor= 0.6; | ||
+ | isosurface { | ||
+ | ... | ||
+ | evaluate 356*Min_factor, sqrt(356/(356*Min_factor)), 0.7 | ||
+ | //evaluate 213.6, 1.29, 0.7 | ||
+ | ... | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | <p> | ||
+ | This method is only an approximation of what happens internally, but it | ||
+ | gives faster rendering speeds with the majority of isosurfaces.</p> | ||
+ | |||
+ | <!--<indexentry "open, isosurface">---> | ||
+ | <p><code>open</code> When the isosurface is not fully contained within the contained_by object, | ||
+ | there will be a cross section. Where this happens, you will see the surface of the container. | ||
+ | With the <code>open</code> keyword, these cross section surfaces are removed. The inside of the isosurface | ||
+ | becomes visible.</p> | ||
+ | <p class="Note"><strong>Note:</strong> Using <code>open</code> slows down the render speed, and it is not recommended to use it with CSG operations.</p> | ||
+ | |||
+ | <!--<indexentry primary "max_trace">---> | ||
+ | <!--<indexentry primary "all_intersections">---> | ||
+ | <p><code>max_trace</code> Isosurfaces can be used in CSG shapes since they are solid finite objects | ||
+ | - if not finite by themselves, they are through the cross section with the container. | ||
+ | <br>By default POV-Ray searches only for the first surface which the ray intersects. But when using an | ||
+ | <code>isosurface</code> in CSG operations, the other surfaces must also be found. Therefore, | ||
+ | the keyword <code>max_trace</code> must be added to the <code>isosurface</code> statement. | ||
+ | It must be followed by an integer value. To check for all surfaces, use the keyword <code>all_intersections</code> instead. | ||
+ | <br>With <code>all_intersections</code> POV-Ray keeps looking until all surfaces are found. | ||
+ | With a <code>max_trace</code> it only checks until that number is reached.</p> |
Latest revision as of 10:52, 19 May 2011
Next is the updated section about poly & polynomial, from 2 to 35 --Le Forgeron 18:22, 21 December 2010 (UTC)
Poly, Cubic and Quartic
Higher order polynomial surfaces may be defined by the use of a
poly
shape. The syntax is
POLY: poly { Order, <A1, A2, A3,... An> [POLY_MODIFIERS...] } POLY_MODIFIERS: sturm | OBJECT_MODIFIER
Poly default values:
sturm : off
where Order
is an integer number from 2 to 35
inclusively that specifies the order of the equation. A1, A2, ...
An
are float values for the coefficients of the equation. There
are n
such terms where n = ((Order+1)*(Order+2)*(Order+3))/6.
The cubic
object
is an alternate way to specify 3rd order polys. Its syntax is:
CUBIC: cubic { <A1, A2, A3,... A20> [POLY_MODIFIERS...] }
Also 4th order equations may be specified with the quartic
object. Its syntax is:
QUARTIC: quartic { <A1, A2, A3,... A35> [POLY_MODIFIERS...] }
The following table shows which polynomial terms correspond to which x,y,z
factors for the orders 2 to 7. Remember cubic
is actually a 3rd order polynomial and
quartic
is 4th order.
2nd | 3rd | 4th | 5th | 6th | 7th | 5th | 6th | 7th | 6th | 7th | |||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
A1 | x2 | x3 | x4 | x5 | x6 | x7 | A41 | y3 | xy3 | x2y3 | A81 | z3 | xz3 |
A2 | xy | x2y | x3y | x4y | x5y | x6y | A42 | y2z3 | xy2z3 | x2y2z3 | A82 | z2 | xz2 |
A3 | xz | x2z | x3z | x4z | x5z | x6z | A43 | y2z2 | xy2z2 | x2y2z2 | A83 | z | xz |
A4 | x | x2 | x3 | x4 | x5 | x6 | A44 | y2z | xy2z | x2y2z | A84 | 1 | x |
A5 | y2 | xy2 | x2y2 | x3y2 | x4y2 | x5y2 | A45 | y2 | xy2 | x2y2 | A85 | y7 | |
A6 | yz | xyz | x2yz | x3yz | x4yz | x5yz | A46 | yz4 | xyz4 | x2yz4 | A86 | y6z | |
A7 | y | xy | x2y | x3y | x4y | x5y | A47 | yz3 | xyz3 | x2yz3 | A87 | y6 | |
A8 | z2 | xz2 | x2z2 | x3z2 | x4z2 | x5z2 | A48 | yz2 | xyz2 | x2yz2 | A88 | y5z2 | |
A9 | z | xz | x2z | x3z | x4z | x5z | A49 | yz | xyz | x2yz | A89 | y5z | |
A10 | 1 | x | x2 | x3 | x4 | x5 | A50 | y | xy | x2y | A90 | y5 | |
A11 | y3 | xy3 | x2y3 | x3y3 | x4y3 | A51 | z5 | xz5 | x2z5 | A91 | y4z3 | ||
A12 | y2z | xy2z | x2y2z | x3y2z | x4y2z | A52 | z4 | xz4 | x2z4 | A92 | y4z2 | ||
A13 | y2 | xy2 | x2y2 | x3y2 | x4y2 | A53 | z3 | xz3 | x2z3 | A93 | y4z | ||
A14 | yz2 | xyz2 | x2yz2 | x3yz2 | x4yz2 | A54 | z2 | xz2 | x2z2 | A94 | y4 | ||
A15 | yz | xyz | x2yz | x3yz | x4yz | A55 | z | xz | x2z | A95 | y3z4 | ||
A16 | y | xy | x2y | x3y | x4y | A56 | 1 | x | x2 | A96 | y3z3 | ||
A17 | z3 | xz3 | x2z3 | x3z3 | x4z3 | A57 | y6 | xy6 | A97 | y3z2 | |||
A18 | z2 | xz2 | x2z2 | x3z2 | x4z2 | A58 | y5z | xy5z | A98 | y3z | |||
A19 | z | xz | x2z | x3z | x4z | A59 | y5 | xy5 | A99 | y3 | |||
A20 | 1 | x | x2 | x3 | x4 | A60 | y4z2 | xy4z2 | A100 | y2z5 | |||
A21 | y4 | xy4 | x2y4 | x3y4 | A61 | y4z | xy4z | A101 | y2z4 | ||||
A22 | y3z | xy3z | x2y3z | x3y3z | A62 | y4 | xy4 | A102 | y2z3 | ||||
A23 | y3 | xy3 | x2y3 | x3y3 | A63 | y3z3 | xy3z3 | A103 | y2z2 | ||||
A24 | y2z2 | xy2z2 | x2y2z2 | x3y2z2 | A64 | y3z2 | xy3z2 | A104 | y2z | ||||
A25 | y2z | xy2z | x2y2z | x3y2z | A65 | y3z | xy3z | A105 | y2 | ||||
A26 | y2 | xy2 | x2y2 | x3y2 | A66 | y3 | xy3 | A106 | yz6 | ||||
A27 | yz3 | xyz3 | x2yz3 | x3yz3 | A67 | y2z4 | xy2z4 | A107 | yz5 | ||||
A28 | yz2 | xyz2 | x2yz2 | x3yz2 | A68 | y2z3 | xy2z3 | A108 | yz4 | ||||
A29 | yz | xyz | x2yz | x3yz | A69 | y2z2 | xy2z2 | A109 | yz3 | ||||
A30 | y | xy | x2y | x3y | A70 | y2z | xy2z | A110 | yz2 | ||||
A31 | z4 | xz4 | x2z4 | x3z4 | A71 | y2 | xy2 | A111 | yz | ||||
A32 | z3 | xz3 | x2z3 | x3z3 | A72 | yz5 | xyz5 | A112 | y | ||||
A33 | z2 | xz2 | x2z2 | x3z2 | A73 | yz4 | xyz4 | A113 | z7 | ||||
A34 | z | xz | x2z | x3z | A74 | yz3 | xyz3 | A114 | z6 | ||||
A35 | 1 | x | x2 | x3 | A75 | yz2 | xyz2 | A115 | z5 | ||||
A36 | y5 | xy5 | x2y5 | A76 | yz | xyz | A116 | z4 | |||||
A37 | y4z | xy4z | x2y4z | A77 | y | xy | A117 | z3 | |||||
A38 | y4 | xy4 | x2y4 | A78 | z6 | xz6 | A118 | z2 | |||||
A39 | y3z2 | xy3z2 | x2y3z2 | A79 | z5 | xz5 | A119 | z | |||||
A40 | y3z | xy3z | x2y3z | A80 | z4 | xz4 | A120 | 1 |
Polynomial shapes can be used to describe a large class of shapes
including the torus, the lemniscate, etc. For example, to declare a quartic
surface requires that each of the coefficients (A1 ...
A35
) be placed in order into a single long vector of 35 terms. As an example let's define a torus the hard way. A Torus can be represented by the equation: x4 + y4 + z4 + 2 x2 y2 + 2 x2 z2 + 2 y2 z2 - 2 (r_02 + r_12)
x2 + 2 (r_02 - r_12) y2 - 2 (r_02 + r_12) z2 + (r_02 - r_12)2 = 0
Where r_0 is the major radius of the torus, the distance from the hole of the donut to the middle of the ring of the donut, and r_1 is the minor radius of the torus, the distance from the middle of the ring of the donut to the outer surface. The following object declaration is for a torus having major radius 6.3 minor radius 3.5 (Making the maximum width just under 20).
// Torus having major radius sqrt(40), minor radius sqrt(12) 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 }
If you are afraid of messing up with the numerous coefficients, an alternative syntax is available as polynomial
which does not care about the order of the coefficients (as long as you do not define one more than once, otherwise only the value of the last definition is kept) and default with all coefficients to 0 (so you can hopefully also save some typing if you have a lot of 0):
POLYNOMIAL: polynomial { Order, [COEFFICIENTS...] [POLY_MODIFIERS...] } COEFFICIENTS: xyz(<x_power>,<y_power>,<z_power>):<value>[,] POLY_MODIFIERS: sturm | OBJECT_MODIFIER
Same torus as above, with the polynomial syntax:
// Torus having major radius sqrt(40), minor radius sqrt(12) polynomial { 4, xyz(4,0,0):1, xyz(2,2,0):2, xyz(2,0,2):2, xyz(2,0,0:-104, xyz(0,4,0):1, xyz(0,2,2):2, xyz(0,2,0):56, xyz(0,0,4):1, xyz(0,0,2):-104, xyz(0,0,0):784 sturm }
Poly, cubic and quartics are just like quadrics in that you do not have
to understand one to use one. The file shapesq.inc
has
plenty of pre-defined quartics for you to play with.
Polys use highly complex computations and will not always render perfectly.
If the surface is not smooth, has dropouts, or extra random pixels, try using
the optional keyword sturm
in the definition. This will cause a
slower but more accurate calculation method to be used. Usually, but not
always, this will solve the problem. If sturm does not work, try rotating
or translating the shape by some small amount.
There are really so many different polynomial shapes, we cannot even begin to list or describe them all. We suggest you find a good reference or text book if you want to investigate the subject further.
Isosurface Object
Details about many of the things that can be done with the isosurface object are discussed in the isosurface tutorial section. Below you will only find the syntax basics:
isosurface { function { FUNCTION_ITEMS } [contained_by { SPHERE | BOX }] [threshold FLOAT_VALUE] [accuracy FLOAT_VALUE] [max_gradient FLOAT_VALUE] [evaluate P0, P1, P2] [open] [max_trace INTEGER] | [all_intersections] [OBJECT_MODIFIERS...] }
Isosurface default values:
contained_by : box{-1,1} threshold : 0.0 accuracy : 0.001 max_gradient : 1.1
function { ... }
This must be specified and be the first item of the
isosurface
statement. Here you place all the mathematical functions that
will describe the surface.
contained_by { ... }
The contained_by
object limits the
area where POV-Ray samples for the surface of the function. This container can either be a
sphere or a box, both of which use the standard POV-Ray syntax. If not specified a
box {<-1,-1,-1>, <1,1,1>}
will be used as default.
contained_by { sphere { CENTER, RADIUS } } contained_by { box { CORNER1, CORNER2 } }
threshold
This specifies how much strength, or substance to give the
isosurface
. The surface appears where the function
value
equals the threshold
value. The default threshold is 0.
function = threshold
accuracy
The isosurface finding method is a recursive subdivision method.
This subdivision goes on until the length of the interval where POV-Ray finds a surface
point is less than the specified accuracy
. The default value is 0.001.
Smaller values produces more accurate surfaces, but it takes longer to render.
max_gradient
POV-Ray can find the first intersecting point between a ray and
the isosurface
of any continuous function if the maximum gradient of the function
is known. Therefore you can specify a max_gradient
for the function.
The default value is 1.1. When the max_gradient
used to find the
intersecting point is too high, the render slows down considerably. When it is too
low, artefacts or holes may appear on the isosurface. When it is way too low, the surface
does not show at all. While rendering the isosurface POV-Ray records the found gradient values
and prints a warning if these values are higher or much lower than the specified
max_gradient
:
Warning: The maximum gradient found was 5.257, but max_gradient of the isosurface was set to 5.000. The isosurface may contain holes! Adjust max_gradient to get a proper rendering of the isosurface.
Warning: The maximum gradient found was 5.257, but max_gradient of the isosurface was set to 7.000. Adjust max_gradient to get a faster rendering of the isosurface.
For best performance you should specify a value close to the real maximum gradient.
evaluate
POV-Ray can also dynamically adapt the used max_gradient.
To activate this technique you have to specify the evaluate
keyword
followed by three parameters:
- P0: the minimum max_gradient in the estimation process,
- P1: an over-estimating factor. This means that the max_gradient is multiplied by the P1 parameter.
- P2: an attenuation parameter (1 or less)
In this case POV-Ray starts with the max_gradient
value P0
and dynamically changes it during the render using P1
and P2
.
In the evaluation process, the P1 and P2 parameters are used in
quadratic functions. This means that over-estimation increases more
rapidly with higher values and attenuation more rapidly with lower
values. Also with dynamic max_gradient
, there can be artefacts and holes.
If you are unsure what values to use, start a render without evaluate
to get
a value for max_gradient
. Now you can use it with evaluate
like this:
- P0 : found max_gradient * min_factor
min_factor being a float between 0 and 1 to reduce themax_gradient
to a minimum max_gradient. The ideal value for P0 would be the average of the found max_gradients, but we do not have access to that information.
A good starting point is 0.6 for the min_factor - P1 : sqrt(found max_gradient/(found max_gradient * min_factor))
min_factor being the same as used in P0 this will give an over-estimation factor of more than 1, based on your minimum max_gradient and the found max_gradient. - P2 : 1 or less
0.7 is a good starting point.
When there are artifacts / holes in the isosurface, increase the min_factor and / or P2 a bit. Example: when the first run gives a found max_gradient of 356, start with
#declare Min_factor= 0.6; isosurface { ... evaluate 356*Min_factor, sqrt(356/(356*Min_factor)), 0.7 //evaluate 213.6, 1.29, 0.7 ... }
This method is only an approximation of what happens internally, but it gives faster rendering speeds with the majority of isosurfaces.
open
When the isosurface is not fully contained within the contained_by object,
there will be a cross section. Where this happens, you will see the surface of the container.
With the open
keyword, these cross section surfaces are removed. The inside of the isosurface
becomes visible.
Note: Using open
slows down the render speed, and it is not recommended to use it with CSG operations.
max_trace
Isosurfaces can be used in CSG shapes since they are solid finite objects
- if not finite by themselves, they are through the cross section with the container.
By default POV-Ray searches only for the first surface which the ray intersects. But when using an
isosurface
in CSG operations, the other surfaces must also be found. Therefore,
the keyword max_trace
must be added to the isosurface
statement.
It must be followed by an integer value. To check for all surfaces, use the keyword all_intersections
instead.
With all_intersections
POV-Ray keeps looking until all surfaces are found.
With a max_trace
it only checks until that number is reached.