3.4.1 Finite Solid Primitives |
POV-Ray 3.6 for UNIX documentation 3.4.2 Finite Patch Primitives |
3.4.3 Infinite Solid Primitives |
There are six totally thin, finite objects which have no well-defined inside. They are bicubic patch, disc, smooth
triangle, triangle, polygon and mesh / mesh2. They may be combined in CSG union but cannot be used in other types of
CSG (or inside a clipped_by
statement). Because these types are finite POV-Ray can use automatic bounding
on them to speed up rendering time. As with all shapes they can be translated, rotated and scaled.
A bicubic_patch
is a 3D curved surface created from a mesh of triangles. POV-Ray supports a type of
bicubic patch called a Bezier patch. A bicubic patch is defined as follows:
BICUBIC_PATCH: bicubic_patch { PATCH_ITEMS... <Point_1>,<Point_2>,<Point_3>,<Point_4>, <Point_5>,<Point_6>,<Point_7>,<Point_8>, <Point_9>,<Point_10>,<Point_11>,<Point_12>, <Point_13>,<Point_14>,<Point_15>,<Point_16> [OBJECT_MODIFIERS...] } PATCH_ITEMS: type Patch_Type | u_steps Num_U_Steps | v_steps Num_V_Steps | flatness Flatness
flatness : 0.0 u_steps : 0 v_steps : 0
The keyword type
is followed by a float Patch_Type
which currently must be
either 0 or 1. For type 0 only the control points are retained within POV-Ray. This means that a minimal amount of
memory is needed but POV-Ray will need to perform many extra calculations when trying to render the patch. Type 1
preprocesses the patch into many subpatches. This results in a significant speedup in rendering at the cost of memory.
The four parameters type
, flatness
, u_steps
and v_steps
may
appear in any order. Only type
is required. They are followed by 16 vectors (4 rows of 4) that define the
x, y, z coordinates of the 16 control points which define the patch. The patch touches the four corner points
<Point_1>
, <Point_4>
, <Point_13>
and
<Point_16>
while the other 12 points pull and stretch the patch into shape. The Bezier surface is
enclosed by the convex hull formed by the 16 control points, this is known as the convex hull property.
The keywords u_steps
and v_steps
are each followed by integer values which tell how many
rows and columns of triangles are the minimum to use to create the surface, both default to 0. The maximum number of
individual pieces of the patch that are tested by POV-Ray can be calculated from the following: pieces = 2^u_steps
* 2^v_steps.
This means that you really should keep u_steps
and v_steps
under 4. Most patches look
just fine with u_steps 3
and v_steps 3
, which translates to 64 subpatches (128 smooth
triangles).
As POV-Ray processes the Bezier patch it makes a test of the current piece of the patch to see if it is flat enough
to just pretend it is a rectangle. The statement that controls this test is specified with the flatness
keyword followed by a float. Typical flatness values range from 0 to 1 (the lower the slower). The default if none is
specified is 0.0.
If the value for flatness is 0 POV-Ray will always subdivide the patch to the extend specified by u_steps
and v_steps
. If flatness is greater than 0 then every time the patch is split, POV-Ray will check to see
if there is any need to split further.
There are both advantages and disadvantages to using a non-zero flatness. The advantages include:
- If the patch is not very curved, then this will be detected and POV-Ray will not waste a lot of time looking at the wrong pieces.
- If the patch is only highly curved in a couple of places, POV-Ray will keep subdividing there and concentrate its efforts on the hard part.
The biggest disadvantage is that if POV-Ray stops subdividing at a particular level on one part of the patch and at a different level on an adjacent part of the patch there is the potential for cracking. This is typically visible as spots within the patch where you can see through. How bad this appears depends very highly on the angle at which you are viewing the patch.
Like triangles, the bicubic patch is not meant to be generated by hand. These shapes should be created by a special utility. You may be able to acquire utilities to generate these shapes from the same source from which you obtained POV-Ray. Here is an example:
bicubic_patch { type 0 flatness 0.01 u_steps 4 v_steps 4 <0, 0, 2>, <1, 0, 0>, <2, 0, 0>, <3, 0,-2>, <0, 1 0>, <1, 1, 0>, <2, 1, 0>, <3, 1, 0>, <0, 2, 0>, <1, 2, 0>, <2, 2, 0>, <3, 2, 0>, <0, 3, 2>, <1, 3, 0>, <2, 3, 0>, <3, 3, -2> }
The triangles in a POV-Ray bicubic_patch
are automatically smoothed using normal interpolation but it
is up to the user (or the user's utility program) to create control points which smoothly stitch together groups of
patches.
Another flat, finite object available with POV-Ray is the disc
. The disc is infinitely thin, it has
no thickness. If you want a disc with true thickness you should use a very short cylinder. A disc shape may be defined
by:
DISC: disc { <Center>, <Normal>, Radius [, Hole_Radius] [OBJECT_MODIFIERS...] }
HOLE RADIUS : 0.0
The vector <Center>
defines the x, y, z coordinates of the center of the disc. The
<Normal>
vector describes its orientation by describing its surface normal vector. This is followed
by a float specifying the Radius
. This may be optionally followed by another float specifying
the radius of a hole to be cut from the center of the disc.
Note: The inside of a disc is the inside of the plane that contains the disc. Also note that it is not constrained by the radius of the disc.
The mesh
object can be used to efficiently store large numbers of triangles. Its syntax is:
MESH: mesh { MESH_TRIANGLE... [MESH_MODIFIER...] } MESH_TRIANGLE: triangle { <Corner_1>, <Corner_2>, <Corner_3> [uv_vectors <uv_Corner_1>, <uv_Corner_2>, <uv_Corner_3>] [MESH_TEXTURE] } | smooth_triangle { <Corner_1>, <Normal_1>, <Corner_2>, <Normal_2>, <Corner_3>, <Normal_3> [uv_vectors <uv_Corner_1>, <uv_Corner_2>, <uv_Corner_3>] [MESH_TEXTURE] } MESH_TEXTURE: texture { TEXTURE_IDENTIFIER } texture_list { TEXTURE_IDENTIFIER TEXTURE_IDENTIFIER TEXTURE_IDENTIFIER } MESH_MODIFIER: inside_vector <direction> | hierarchy [ Boolean ] | OBJECT_MODIFIER
hierarchy : on
Any number of triangle
and/or smooth_triangle
statements can be used and each of those
triangles can be individually textured by assigning a texture identifier to it. The texture has to be declared before
the mesh is parsed. It is not possible to use texture definitions inside the triangle or smooth triangle statements.
This is a restriction that is necessary for an efficient storage of the assigned textures. See "Triangle
and Smooth Triangle" for more information on triangles.
The mesh
object can support uv_mapping
. For this, per triangle the keyword uv_vectors
has to be given, together with three 2D uv-vectors. Each vector specifies a location in the xy-plane from which the
texture has to be mapped to the matching points of the triangle. Also see the section uv_mapping.
Copies of a mesh object refer to the same triangle data and thus consume very little memory. You can easily trace a hundred copies of a 10000 triangle mesh without running out of memory (assuming the first mesh fits into memory). The mesh object has two advantages over a union of triangles: it needs less memory and it is transformed faster. The memory requirements are reduced by efficiently storing the triangles vertices and normals. The parsing time for transformed meshes is reduced because only the mesh object has to be transformed and not every single triangle as it is necessary for unions.
The mesh object can currently only include triangle and smooth triangle components. That restriction may change, allowing polygonal components, at some point in the future.
Triangle mesh objects (mesh
and mesh2
) can now be used in CSG objects such as difference
and intersect, because, after adding inside_vector
, they do have a defined 'inside'. This will only work
for well-behaved meshes, which are completely closed volumes. If meshes have any holes in them, this might work, but
the results are not guaranteed.
To determine if a point is inside a triangle mesh, POV-Ray shoots a ray from the point in some arbitrary direction.
If this vector intersects an odd number of triangles, the point is inside the mesh. If it intersects an even number of
triangles, the point is outside of the mesh. You can specify the direction of this vector. For example, to use +z
as the direction, you would add the following line to the triangle mesh description (following all other mesh data,
but before the object modifiers).
inside_vector <0, 0, 1>
This change does not have any effect on unions of triangles... these will still be always hollow.
The new mesh syntax is designed for use in conversion from other file formats.
MESH2 : mesh2{ VECTORS... LISTS... | INDICES... | MESH_MODIFIERS } VECTORS : vertex_vectors { number_of_vertices, <vertex1>, <vertex2>, ... }| normal_vectors { number_of_normals, <normal1>, <normal2>, ... }| uv_vectors { number_of_uv_vectors, <uv_vect1>, <uv_vect2>, ... } LISTS : texture_list { number_of_textures, texture { Texture1 }, texture { Texture2 }, ... }| INDICES : face_indices { number_of_faces, <index_a, index_b, index_c> [,texture_index [, texture_index, texture_index]], <index_d, index_e, index_f> [,texture_index [, texture_index, texture_index]], ... }| normal_indices { number_of_faces, <index_a, index_b, index_c>, <index_d, index_e, index_f>, ... }| uv_indices { number_of_faces, <index_a, index_b, index_c>, <index_d, index_e, index_f>, ... } MESH_MODIFIER : inside_vector <direction> | OBJECT_MODIFIERS
mesh2
has to be specified in the order VECTORS..., LISTS..., INDICES....
The normal_vectors
, uv_vectors
, and texture_list
sections are optional. If the
number of normals equals the number of vertices then the normal_indices section is optional and the indexes from the face_indices
section are used instead. Likewise for the uv_indices
section.
Note: that the numbers of uv_indices must equal number of faces.
The indexes are ZERO-BASED! So the first item in each list has an index of zero.
You can specify both flat and smooth triangles in the same mesh. To do this, specify the smooth triangles first in
the face_indices
section, followed by the flat triangles. Then, specify normal indices (in the normal_indices
section) for only the smooth triangles. Any remaining triangles that do not have normal indices associated with them
will be assumed to be flat triangles.
To specify a texture for an individual mesh triangle, specify a single integer texture index following the face-index vector for that triangle.
To specify three textures for vertex-texture interpolation, specify three integer texture indices (separated by commas) following the face-index vector for that triangle.
Vertex-texture interpolation and textures for an individual triangle can be mixed in the same mesh
The polygon
object is useful for creating rectangles, squares and other planar shapes with more than
three edges. Their syntax is:
POLYGON: polygon { Number_Of_Points, <Point_1> <Point_2>... <Point_n> [OBJECT_MODIFIER...] }
The float Number_Of_Points
tells how many points are used to define the polygon. The points
<Point_1>
through <Point_n>
describe the polygon or polygons. A polygon
can contain any number of sub-polygons, either overlapping or not. In places where an even number of polygons overlaps
a hole appears. When you repeat the first point of a sub-polygon, it closes it and starts a new sub-polygon's point
sequence. This means that all points of a sub-polygon are different.
If the last sub-polygon is not closed a warning is issued and the program automatically closes the polygon. This is useful because polygons imported from other programs may not be closed, i.e. their first and last point are not the same.
All points of a polygon are three-dimensional vectors that have to lay on the same plane. If this is not the case an error occurs. It is common to use two-dimensional vectors to describe the polygon. POV-Ray assumes that the z value is zero in this case.
A square polygon that matches the default planar image map is simply:
polygon { 4, <0, 0>, <0, 1>, <1, 1>, <1, 0> texture { finish { ambient 1 diffuse 0 } pigment { image_map { gif "test.gif" } } } //scale and rotate as needed here }
The sub-polygon feature can be used to generate complex shapes like the letter "P", where a hole is cut into another polygon:
#declare P = polygon { 12, <0, 0>, <0, 6>, <4, 6>, <4, 3>, <1, 3>, <1,0>, <0, 0>, <1, 4>, <1, 5>, <3, 5>, <3, 4>, <1, 4> }
The first sub-polygon (on the first line) describes the outer shape of the letter "P". The second sub-polygon (on the second line) describes the rectangular hole that is cut in the top of the letter "P". Both rectangles are closed, i.e. their first and last points are the same.
The feature of cutting holes into a polygon is based on the polygon inside/outside test used. A point is considered to be inside a polygon if a straight line drawn from this point in an arbitrary direction crosses an odd number of edges (this is known as Jordan's curve theorem).
Another very complex example showing one large triangle with three small holes and three separate, small triangles is given below:
polygon { 28, <0, 0> <1, 0> <0, 1> <0, 0> // large outer triangle <.3, .7> <.4, .7> <.3, .8> <.3, .7> // small outer triangle #1 <.5, .5> <.6, .5> <.5, .6> <.5, .5> // small outer triangle #2 <.7, .3> <.8, .3> <.7, .4> <.7, .3> // small outer triangle #3 <.5, .2> <.6, .2> <.5, .3> <.5, .2> // inner triangle #1 <.2, .5> <.3, .5> <.2, .6> <.2, .5> // inner triangle #2 <.1, .1> <.2, .1> <.1, .2> <.1, .1> // inner triangle #3 }
The triangle
primitive is available in order to make more complex objects than the built-in shapes
will permit. Triangles are usually not created by hand but are converted from other files or generated by utilities. A
triangle is defined by
TRIANGLE: triangle { <Corner_1>, <Corner_2>, <Corner_3> [OBJECT_MODIFIER...] }
where <Corner_n>
is a vector defining the x, y, z coordinates of each corner of the
triangle.
Because triangles are perfectly flat surfaces it would require extremely large numbers of very small triangles to approximate a smooth, curved surface. However much of our perception of smooth surfaces is dependent upon the way light and shading is done. By artificially modifying the surface normals we can simulate a smooth surface and hide the sharp-edged seams between individual triangles.
The smooth_triangle
primitive is used for just such purposes. The smooth
triangles use a formula called Phong normal interpolation to calculate the surface normal for any point on the
triangle based on normal vectors which you define for the three corners. This makes the triangle appear to be a smooth
curved surface. A smooth triangle is defined by
SMOOTH_TRIANGLE: smooth_triangle { <Corner_1>, <Normal_1>, <Corner_2>, <Normal_2>, <Corner_3>, <Normal_3> [OBJECT_MODIFIER...] }
where the corners are defined as in regular triangles and <Normal_n>
is a vector
describing the direction of the surface normal at each corner.
These normal vectors are prohibitively difficult to compute by hand. Therefore smooth triangles are almost always generated by utility programs. To achieve smooth results, any triangles which share a common vertex should have the same normal vector at that vertex. Generally the smoothed normal should be the average of all the actual normals of the triangles which share that point.
The mesh
object is a way to combine many triangle
and smooth_triangle
objects together in a very efficient way. See "Mesh" for details.
3.4.1 Finite Solid Primitives | 3.4.2 Finite Patch Primitives | 3.4.3 Infinite Solid Primitives |