Two of the three parts of a texture describe how light behaves on a surface. A normal changes the surface normal vector at each point, so a flat surface looks bumpy; the shape of the object does not change. A finish sets how the surface reflects light: how much ambient, diffuse, highlight and mirror reflection it has. The third part, the pigment, is on Textures and pigments; the patterns that normals use are on Patterns and maps.
A scene with no #version directive runs as language version 3.62. The default ambient is 0.1 there and 0 from language version 3.8 on. Defaults below are those of the parser source of POV-Ray 3.8.
The normal statement
normal {
[normal identifier]
[pattern type [amount]]
[pattern modifiers]
[normal_map { … } | slope_map { … }]
[bump_size amount] [accuracy delta] [no_bump_scale]
}
The statement is used inside a texture, or directly in an object (sphere { … normal { bumps 0.5 } }, which builds a texture from the default pigment and finish). An identifier first, if present, supplies the starting normal; the other items modify it. An empty normal { } is the error “No normal type given.” After the pattern type an optional number gives the apparent depth of the bumps (bumps 0.4); a comma may separate it (gradient x, -0.5; the comma is needed when the number is negative). Negative values invert the bumps.
| Item | Value | Default | Meaning |
|---|---|---|---|
| pattern type | any pattern | none (error) | all patterns of Patterns and maps except image_map, user_defined and the plain colour. facets and bump_map are normal-only |
amount / bump_size | number | 0.5 | apparent depth of the bumps. bump_size can come anywhere among the modifiers and overrides an earlier amount (also in an identifier); it is also accepted inside bump_map { … } |
accuracy | number | 0.02 | distance of the sample points used to find the slope of a pattern that has no normal of its own (see pattern normals). A smaller value for close-ups, a larger one to smooth sharp edges (for instance a solid crackle). It makes no difference for the bump patterns with their own formula. An error in a pigment or texture |
no_bump_scale | off | scaling of the texture or object does not change the depth of the bumps. In a nested normal (in a map) it only affects that normal; at the top level it affects the whole normal | |
slope_map | map | none | shapes the height profile of a pattern, see below. The parser refuses it with average and with block patterns; the manual also excludes the bump patterns with their own formula |
normal_map | map | none | blends or selects normals, see below. Not with facets |
| pattern modifiers | frequency, phase, wave types, turbulence, warp, transformations, noise_generator and so on (see Patterns and maps) |
The items color_map, pigment_map, quick_color and texture_map are errors in a normal (“Only in pigment” and similar). A normal can be declared: #declare Name = normal { … }. Normals nested in a block pattern are written normal { … } each: normal { checker normal { bumps 0.2 } normal { granite 0.3 } }.
Patterns with their own normal formula
These six patterns do not use a height at all. They add a vector directly to the normal (the normal is then normalised). Because of that they cannot use slope_map, normal_map or wave types in a normal. As pigment or texture patterns they are ordinary patterns with a value.
| Pattern | What is added to the normal (A is the amount) |
|---|---|
bumps | A times the vector noise at the point. Smooth rolling hills when scaled large, an orange peel when scaled small. Bumps are about one unit apart |
dents | A times (noise at the point)³ times the vector noise: sharp dents with flat plateaus. Good on metal |
wrinkles | A times the sum over ten octaves of |vector noise at (point × 2k)| / 2k: sharp ridges like cellophane or stucco |
ripples | for each wave centre (number_of_waves centres, default 10, set in global_settings, at random places in the unit cube and repeating), the vector from the centre multiplied by A × cycloidal(distance × frequency + phase) divided by the distance and the number of centres. frequency changes the spacing and phase moves the ripples outward |
waves | like ripples, but each centre also has its own frequency, so the waves are rounder and broader |
quilted | for the unit cell around the point, the offset v of the point from the cell centre, multiplied by A and by a cubic curve of |v| that is bent with control0 and control1 (default 1 and 1; 0 and 0 gives a straight slope and a sharp seam, 1 and 1 an S-shaped, soft seam) |
facets | snaps the normal to the closest vector of a perturbed grid, so a surface looks cut into flat facets. size f (default 0.1) for curved surfaces, coords s (default 0, off) for any surface, metric m (default 2). Normal only |
All other patterns
Any other pattern is turned into a normal through its value used as a height. The parser samples the pattern at the four corners of a small pyramid around the point (the size is accuracy, 0.02), runs each value through the slope_map (or a built-in one if there is none), and adds the four weighted pyramid vectors to the normal. The weight is A × −5 × 0.02 / accuracy (two fudge factors in the source). The pattern value includes the wave type, frequency and phase, so sine_wave, scallop_wave and so on act as a built-in slope map. Block patterns (checker, brick, hexagon, square, triangular, cubic, object) and other jump patterns (cells, crackle with solid) have no slope, so they are poor normals: the edges appear. Their default accuracy is 0.02 as well.
slope_map
slope_map { [ value <height, slope> ] ... } // or an identifier
The pattern value (0 to 1) is looked up in the map. height is the apparent height at that value (normally 0 to 1) and slope the apparent change of height per unit of distance: 0 is flat, 1 is a rise at 45 degrees, −1 a fall. Keep slopes in the range −3 to 3. Between two entries a cubic curve through the two heights and slopes is used, so smooth profiles are possible; two entries at the same value give a sudden change. Entries must be in ascending order; there is at least one entry and no upper limit in version 3.8. The parser refuses a slope map with average and with the block patterns (brick, checker, object, hexagon, square, triangular, cubic); the manual also excludes the patterns with their own formula.
normal_map
normal_map { [ value normal body ] ... } // or an identifier
Each entry is what could stand inside normal { … }. Where two entries meet the two perturbed normals are mixed in proportion; otherwise one normal is used. With average the weights are optional numbers (default 1) and the perturbed normals are weighted, added and normalised. A normal_map cannot be used with bump_map (use a texture map instead). The general map grammar is on Patterns and maps.
bump_map
normal {
bump_map {
[bitmap_type] "file" | function w, h { body }
[gamma g] [premultiplied bool]
[map_type n] [once] [interpolate n]
[bump_size amount] [use_colour | use_color | use_index]
[repeat <u, v>] [offset <u, v>]
}
[normal modifiers]
}
A bump map wraps an image around the surface like an image map, but uses its brightness as a height: black is low, white is high, so the picture looks embossed. File types, gamma, premultiplied, map_type, once, interpolate, repeat and offset work as for image_map on Textures and pigments (the bump map does not check the values of map_type and interpolate). The image fills the square <0,0> to <1,1> of the x-y plane. The colour of each pixel is converted to grey. use_index uses the palette index as height instead (palette images only); use_colour selects the default again. With once the area outside the unit square stays flat. Images with an alpha channel are treated as if they had a black background. A bump map does no gamma adjustment of the file unless gamma is given. bump_size is the depth (typically 0.1 to 5; any value but 0).
sphere { 0, 1
pigment { rgb 1 }
normal { bumps 0.6 scale 0.2 }
}
sphere { <2.5, 0, 0>, 1
pigment { rgb 1 }
normal {
gradient x, 0.5
slope_map {
[0 <0, 1>]
[0.5 <1, 1>]
[0.5 <1, -1>]
[1 <0, -1>]
}
accuracy 0.01
scale 0.25
}
}
sphere { <-2.5, 0, 0>, 1
pigment { rgb 1 }
normal {
gradient y
normal_map {
[0.0 bumps 0.3 scale 0.1]
[0.5 ripples 0.4 frequency 6]
[1.0 granite 0.2]
}
scale 0.5
}
}
plane { y, -1.5
pigment { rgb 1 }
normal {
bump_map {
function 64, 64 { pattern { wood } }
interpolate 2
bump_size 2
}
no_bump_scale
scale 2
}
}
The finish statement
finish {
[finish identifier]
[items]
}
An identifier first, if present, is the starting point; the items modify it. Without an identifier the items modify the finish of the default texture. A finish is declared with #declare Name = finish { … }. Transformations are not allowed in a finish. Colour-valued items accept a single number, which is used for red, green and blue (the filter and transmit parts of a colour are not used).
| Keyword | Value | Default | Meaning |
|---|---|---|---|
ambient | colour | 0.1 (0 from language version 3.8) | light that reaches every point, multiplied by the global ambient_light (default <1,1,1>). It is switched off when radiosity is on (language version 3.7 and later). A value of 0.3 or more (as a grey value) without emission gives a possible-error message in version 3.7 and later, because it is often used to make glowing materials; use emission for that |
emission | colour | 0 | light the material gives off. It is not scaled by ambient_light and is not switched off by radiosity. It does not light other objects without radiosity |
diffuse | [albedo] number [, number] | 0.6, 0 | how much direct light is scattered in all directions. The first number is the front side; the optional second number (default 0, experimental) is the amount of light that comes from the back, for thin translucent surfaces such as paper (it uses the “backside illumination” experimental feature and is best kept smaller than the first). With albedo the first number is the total reflectance, not the peak: the value is multiplied by (brilliance + 1) / 2 and the radiosity amount stays 1. Without albedo the radiosity amount is scaled by 2 / (brilliance + 1). With brilliance 1 albedo changes nothing |
brilliance | number | 1.0 | the diffuse intensity is |cos θ| ^ brilliance (θ = angle of incidence). Higher values (5 to 10) make the light fall off less at flat angles and the surface look more metallic. Any value is allowed |
crand | number | 0 | random graininess: a random number times crand is subtracted from the diffuse intensity for each pixel. Typical 0.01 to 0.5. Do not use it in animations (it flickers) |
phong | [albedo] number | 0 (no highlight) | strength of the Phong highlight; 1 saturates the light colour at the centre. With albedo the value is multiplied by (phong_size + 1) / 2 |
phong_size | number | 40 | the highlight is phong × cos^phong_size of the angle between the mirror direction and the light. 1 is dull, 250 highly polished. No effect without phong |
specular | [albedo] number | 0 | strength of the specular highlight, a model with a halfway vector and a more credible highlight near the horizon. With albedo the value is multiplied by (E + 2) / (4 × (2 − 2^(−E/2))), where E = 1 / roughness |
roughness | number | 0.05 | size of the specular highlight: the intensity is specular × cos^(1/roughness) of the angle between the normal and the halfway vector. 1 is very rough, 0.0005 very smooth. 0 is the warning “Zero roughness used.” (and no highlight shape). No effect without specular |
metallic | [number] | 0; 1 if written without a number | tints the highlights of phong and specular with the pigment colour through an empirical function of the angle: 1 + metallic × (1 − F) × (colour − 1) with F from a Fresnel-like curve. No effect without a highlight |
fresnel | [number] | 0; 1 if written without a number | finish level Fresnel (since 3.8): ambient, diffuse and emission are reduced at shallow angles (by the Fresnel reflectance of the interior ior, both where light enters and where it leaves) and the highlights are limited to the reflected part. A value between 0 and 1 models an anti-reflective coating. Writing it also switches reflection Fresnel on (non-zero) or off (zero), unless a reflection block that follows decides otherwise. It needs an interior { ior … } on the object. With it, diffuse albedo 1, phong albedo 0 and specular albedo 1 give the most realistic result |
reflection | colour, or a block (below) | 0 (none) | mirror reflection |
reflection_exponent | number | 1 | old keyword of the reflection exponent (outside the block) |
conserve_energy | off | multiplies the filter and transmit of the layer by what is left after the reflection (reflection 0.8 leaves 20 per cent), so the surface does not give out more light than it receives | |
irid | block (below) | 0 (none) | thin-film interference |
subsurface | block (below) | off | subsurface light transport |
use_alpha | [bool] | off; on if written without a value | with on the filter and transmit of the pigment also hide the highlights and the specular reflection. By default they hide only the ambient, diffuse and emission components |
ior, caustics, refraction | number | unset | old forms of the interior keywords (a warning in version 3.8). The values are copied to the interior of the object when the texture is plain. refraction is not needed to turn refraction on. Use interior |
reflection
reflection colour // old syntax: min = max = colour
reflection {
min [, max]
[fresnel bool] [falloff f] [exponent e] [metallic [m]]
}
| Item | Value | Default | Meaning |
|---|---|---|---|
| min | colour | 0 | reflectivity seen along the normal (a view straight on). A number is a grey. Without max it is also the maximum |
| max | colour | = min | reflectivity at grazing angles (90 degrees to the normal). Less than min is allowed but not seen in nature |
fresnel | bool | off (on if written without a value) | use the Fresnel formula with the ior of the interior instead of the linear blend, so an interior { ior … } is needed even for an opaque object. If min equals max, the minimum is set to 0, so that a single value is the maximum |
falloff | number | 1 | exponent of the blend: the share of max is (1 − cos θ) ^ falloff, θ being the angle between the ray and the normal; 1 is linear, 2 squared. Not with fresnel |
exponent | number | 1 | non-linear reflection intensity (stored as 1 / e). Values below 1 darken mid and low intensities. For artistic use; with assumed_gamma 1 it is not needed |
metallic | [number] | 0; 1 without a number | multiplies the reflected colour by the pigment colour, with the same Fresnel-like function of the angle as the highlight keyword. The number is the amount of that effect |
Reflection adds rays and so render time. Reflected light can be tinted: reflection rgb <1, 0, 0> reflects only red.
irid
irid { amount [thickness t] [turbulence v] }
| Item | Value | Default | Meaning |
|---|---|---|---|
| amount | number | 0 | how much the film changes the colour (in 1 + amount × cos(phase)). About 0.25 or less; lower diffuse and ambient if the surface comes out too white |
thickness | number (microns) | 0 | film thickness. A thin film gives fast colour changes, a thick one large areas of colour. The phase is 2π × thickness × (cos θ_light + cos θ_eye) divided by the wavelengths of the global irid_wavelength |
turbulence | number (a vector is accepted and only its x value used) | 0 | varies the thickness with noise (octaves 5, lambda 2, omega 0.5 are fixed) by a factor 1 + (2 × noise − 1) × turbulence |
Bump patterns on the surface change the angles and so the colours of the film. The amount and the thickness are in microns since version 3.7.
subsurface
finish { subsurface { translucency colour anisotropy colour } }
| Item | Value | Default | Meaning |
|---|---|---|---|
translucency | colour | 0 | strength of subsurface light transport; values above 1 are allowed. It does not scale with the object: set mm_per_unit in global_settings first, then adjust this value |
anisotropy | colour | 0 | anisotropy of the scattering, in the parser source; not described in the manual |
Writing the block turns on the experimental flag, and the render prints a warning that experimental features are used. The effect works only when global_settings { subsurface { } } is present (it also takes samples diffuse, single and radiosity bool, see Global settings) and at render quality 9 or more. The object needs an interior { ior … }. The manual lists these limits: pigments with a zero colour component and a zero diffuse value can fail; unions of overlapping objects give unexpected results (use merge); meshes should be closed; parts that should not show seams must share one interior.
Finish presets in the include files
Include files declare finishes that can be used by name (finish { Shiny }), see Include files.
| File | Identifier | Definition |
|---|---|---|
finish.inc | Dull | specular 0.5 roughness 0.15 |
Shiny | specular 1 roughness 0.001 | |
Phong_Dull | phong 0.5 phong_size 1 | |
Phong_Shiny | phong 1 phong_size 200 | |
Glossy | specular 1 roughness 0.0001 reflection 0.13 | |
Phong_Glossy | phong 1 phong_size 300 reflection 0.13 | |
Luminous | ambient 1 diffuse 0 | |
Mirror | ambient 0 diffuse 0 reflection 1 | |
metals.inc | F_MetalA | ambient 0.35, brilliance 2, diffuse 0.3, metallic, specular 0.8, roughness 1/20, reflection 0.1 (very soft and dull) |
F_MetalB | ambient 0.3, brilliance 3, diffuse 0.4, metallic, specular 0.7, roughness 1/60, reflection 0.25 | |
F_MetalC | ambient 0.25, brilliance 4, diffuse 0.5, metallic, specular 0.8, roughness 1/80, reflection 0.5 | |
F_MetalD | ambient 0.15, brilliance 5, diffuse 0.6, metallic, specular 0.8, roughness 1/100, reflection 0.65 | |
F_MetalE | ambient 0.1, brilliance 6, diffuse 0.7, metallic, specular 0.8, roughness 1/120, reflection 0.8 (very polished) | |
glass.inc, glass_old.inc | F_Glass1 to F_Glass10 | glass finishes: specular, small roughness, reflection (F_Glass5 to F_Glass10 have reflection with a minimum and maximum, most with fresnel on, and conserve_energy) |
#declare Plastic = finish {
ambient 0.05
diffuse albedo 0.7
phong albedo 0.3
phong_size 60
}
#declare Metal = finish {
ambient 0.1
diffuse 0.4
brilliance 3
specular 0.7
roughness 0.02
metallic 0.8
reflection { 0.1, 0.6 falloff 2 exponent 1.5 metallic 0.5 }
}
#declare Film = finish {
diffuse 0.5
irid { 0.25 thickness 0.5 turbulence 0.3 }
crand 0.01
emission rgb <0.02, 0.02, 0.05>
}
#declare Glassy = finish {
ambient 0
diffuse 0
specular 0.8
roughness 0.001
reflection { 0.0, 1.0 fresnel on }
conserve_energy
use_alpha on
}
#declare Skin = finish {
diffuse 0.6, 0.1
subsurface { translucency rgb <0.5, 0.2, 0.1> anisotropy rgb 0.1 }
}
sphere { <-3, 0, 0>, 1 pigment { rgb <0.8, 0.2, 0.2> } finish { Plastic } }
sphere { <-1, 0, 0>, 1 pigment { rgb <0.9, 0.7, 0.3> } finish { Metal } }
sphere { <1, 0, 0>, 1 pigment { rgb <0.5, 0.5, 0.8> } finish { Film } }
sphere { <3, 0, 0>, 1 pigment { rgbf <1, 1, 1, 0.9> } finish { Glassy } interior { ior 1.5 } }
sphere { <0, 2, 0>, 0.7 pigment { rgb <0.9, 0.8, 0.7> } finish { Skin } interior { ior 1.4 } }
sphere { <0, -2, 0>, 0.7
pigment { rgb 0.8 }
finish { fresnel 0.5 specular albedo 1 roughness 0.01 }
interior { ior 1.5 }
}
albedo, a metal with a variable reflection, a thin film, a glass, a skin with a diffuse backside value and subsurface (the program warns that these two are experimental features), and a finish-level Fresnel.How the finish is used in lighting
For each layer of a texture, and for each light source that reaches the point, the renderer adds:
- the diffuse part:
diffuse × adjust × |cos θ|^brilliance × pigment colour × light colour × attenuation, minus the randomcrandterm, times(1 − f1)(1 − f2)whenfresnelis set; - the Phong highlight, if
phongis not 0:phong × cos^phong_size, for a positive cosine, tinted withmetallicandfresnelif set, in the colour of the light; - the specular highlight, if
specularis not 0, from the halfway vector, tinted the same way; - the iridescence, which multiplies the result by
1 + irid × cos(phase / wavelength)for each colour component.
The ambient and emission are added once, not per light: emission + ambient × ambient_light (the ambient part only when radiosity is off or the scene is older than 3.7), multiplied by the pigment colour for the ambient part. The reflection ray is traced with the weight of the reflectivity, computed for the angle of incidence; the result is added to the colour.
Not described
Known, not yet covered
- Reference: the exact vector formulas of
facetsand of thebump_mapheight lookup are not written out (their parameters and effect are); the full subsurface algorithm insource/core/lighting/subsurface.cppis not described. - Reference: whether the normal-only bump patterns reject a
slope_mapornormal_mapat parse time was not tested; the manual says they cannot use them.