Granite_21 macro: How does it work?

General introduction to granites

Figure 1
Fig.1: QAPF diagram with granite field highlighted (after Kent G. Budge).

Granites are classified as intrusive, or plutonic, igneous rocks. Slow cooling of plutonic magma beneath the surface of the Earth results in macroscopic assemblages of juxtaposed and closely packed minerals that show different forms, colours, sizes, and compositions. In contrast, volcanic glasses such as obsidian, are the amorphous product of rapidly cooling volcanic igneous rocks which solidify before crystallization can occur.

The overall colour of granites (white, pink, or grey) is the result of the relative proportion of each mineral, which facilitates the optical classification of a given rock sample. Sometimes, particularly large crystals (phenocrysts, often plagioclase) are present, and can help with the identification.

Figure 1 shows a QAPF diagram (Quartz, Alkali feldspar, Plagioclase, Feldspathoids, also known as a Streckeisen diagram) which is used by the scientific community for the classification of igneous rocks. More information on this can be found here, and for granites in general, see here. The International Union of Geological Sciences IUGS, approved the QAPF diagram in 1974.

The modelling of granites: maps and masks

To simulate a real world granite in POV-Ray, we make use of a colour map representing the different minerals/colours of the granite as basis for its pigment, and a colour mask, a colour_map-based pigment_pattern used within the granite texture, which controls the distribution of those same minerals/colours. Necessarily, there is a close relationship between maps and masks as mineral/colour boundaries within a particular granite must correspond to their mask boundaries. The final texture is pretty complex as additional differential scaling perturbs the final aspect of the texture. In the following paragraphs we shall explain how this is achieved by the macro, illustrated by comprehensive examples and diagrams. To make things easier to understand, the different parts of the macro are described separately.

Granite pigment creation

Figure 2
Fig. 2: Pigment generation (sections 1 to 3).
Table 1
Table 1: Correspondence between the colour_map (column 1) and pigment_pattern
(column 3) arrays. Visualisation of both arrays is shown in column 2.

Sections 1 through 3 of the macro concerns the creation of granite pigments (Fig. 2). The input to this part of the macro – independent from the different parameters which will be described later – consists of three different colour map arrays (prefixed with A_) for each granite type file:

  1. A_Granite_map1: describing the different minerals/colours.
  2. A_Granite_map2: describing the veins crossing the granites.
  3. A_Granite_mask: describing the (spatial) distribution of the different minerals/colours.

All examples shown below use the (default) Dakota Red Granite data (Table 1).

The close-packed, discrete assemblages typical of granites can be simulated by sharply-bounded groups of colours, with each group representing a different mineral (Table 1). The first array (A_Granite_map1) is read into the macro's C_Granite_map1 colour map. The second array (A_Granite_mask) is read into the macro's C_Granite_mask colour map. This last one controls either the cells or the step noise (SN) pigment patterns, while the crackle pattern uses its own colour_map (Fig. 2). These pigment_patterns controlling the C_Granite_map1 colour map, then generate one of the following pigments: P_Granite_crackle, P_Granite_cells, or P_Granite_SN.

Figure 3
Fig. 3: Reversing the RGB colour map values of the A_Granite_mask array, changes the visual aspect of the final granite texture.
(a) is the original array;(b) has the RGB-values inverted.

Note that mask maps do not always have the same number of indices as their corresponding colour maps, though the indices representing the boundaries between minerals are identical (of necessity); see Table and the file data in Annexes.

An additional pattern, Blend (blend_mask, Fig. 2), developed originally by Tekno Frannansa (aka Tek), makes use of the generated pigments to provide a blended version. This can be very useful to simulate a weathered aspect of the granite, for example.

As the granite mask is used as a pigment_pattern, changing the RGB-values of its colour_map changes the aspect of the granite pigment and, as explained later, the aspect of the granite texture. How pigment patterns work exactly is explained in the POV-Ray documentation. The user is invited to experiment by making changes to the mask's colour_map when choosing the cells or the step noise pigment pattern (remember that the crackle pattern uses its own map), for instance by reversing the RGB-values in the list, and compare the rendered texture with the original one (Fig. 3). A very large number of different granites can thus be generated from a single basic concept. Do not change the colour_map entries in the A_Granite_mask array however, without also changing the corresponding entries in the A_Granite_mask1 array!

A_Granite_map2, which controls the appearance of the (quartz) veins intersecting a given granite, is a mixed array with the following format:

  #declare Map2_entries = 5;
  #declare A_Granite_map2 =
  array mixed [Map2_entries][3] {
    {0.000, <0.800, 0.800, 0.800>, 0.150},  
    {0.005, <0.800, 0.800, 0.800>, 0.000},  
    {0.010, <0.800, 0.800, 0.800>, 0.150},  
    {0.011, <1.000, 1.000, 1.000>, 1.000},  
    {1.000, <1.000, 1.000, 1.000>, 1.000}  
  }
      

This array describes the colour map of the quartz. It is a bit different from the minerals colour map in that it also contains filter and transmit information. Especially the filter information is highly experimental at this stage and may substantially change in the future. When enabled, a veins texture will be layered over the main granite texture. As this feature is still in an experimental phase, for the time being simply copy the array without modification, when you use it.

In section 4 of the macro, the data from this array are fed into the internal C_Granite_map2 colour map, which in turn is the core of the P_Granite_veins (marble pattern) pigment.

Granite texture creation

Figure 4
Fig. 4: Texture generation (sections 5).

In section 5 of the macro (Fig. 4), the texture generation, we employ the same pigment patterns used in section 3 (Fig. 2). However, they are implemented for a different reason, and in a different way. This time they control the distribution of the granite pigments at different scales throughout the granite texture. An array (A_Granite_var) serves as input for additional variations. It has the following format:

  #declare Var_entries = 8;  
  #declare A_Granite_var =
  array [Var_entries][3] {
    {0.20, 0.50, 0.15},
    {0.25, 1.00, 0.18},
    {0.35, 1.00, 0.18},
    {0.40, 0.50, 0.15},
    {0.60, 1.00, 0.15},
    {0.65, 0.50, 0.18},
    {0.75, 1.00, 0.18},
    {0.80, 0.50, 0.15}
  }
      

Like in the arrays discussed previously, the first elements are the pigment or normal map entries. The second elements control the strength of the normal pattern (only for the frosted version of the granite) in the normal map. The third elements scale both the pigments in the pigment map, and the normal patterns in the normal map. The purpose is to provide visual variation of the granite minerals in the texture. When experimenting with these values, be careful to keep the variations relatively small, and close to each other. A large variation may rapidly become 'artificial' (fig. 5).

Figure 5
Fig. 5: Changing the scale and normal strength values in the A_Granite_var array. Original array (left);
switching normal strength values and changing scales (right).

Also in this section, different finish blocks are generated, corresponding to either the polished or the frosted versions of the granite, and whether or not the granite contains veins (layered texture). As the final step, the normal block for the frosted version of the granite is generated.

The veins texture (Fig. 4) has its own finish blocks (polished and frosted) and a normal block where the normal map is controlled by the same pigment (P_Granite_veins) used in the pigment pattern.

Still experimental is the use of subsurface light transmission. The macro parameter SubS enables the feature in this section's finish blocks. This needs to be developed further in the future.



A note on real-world dimension correspondences

The granite textures have been structured and scaled in such a way that they correspond to a fairly fine to medium-grained real-world granite. This means that applying this texture to an arbitrarily-sized object without any further scaling will show a real-world-scale granite texture. One POV-unit corresponds to 100 cm (fig. 3 and 5). This may need some more explanation. In the examples shown in this documentation, the objects have been scaled to a one POV-unit cubic size (mostly for convenience). Applied to these objects and without further scaling, the granite pattern will appear to be as a real-world one cubic meter granitic rock from which an object (the Bunny!) had been sculpted. Similarly, any POV-Ray object, whatever its size, with the granite texture applied and without further scaling, will simulate real-world granitic objects. In other words: Scale the object and THEN apply the Granite_21() macro. This is exemplified by Figure 6. Evidently, for each scene, the user has to determine what the "real-world" dimensions of his or her world are and maybe scale the granite texture accordingly.

Figure 6
Fig. 6: Relationship between the "real-world" dimensions of the granite texture and the the dimensions of the objects within a same scene.

Granite material creation

In section 6 of the macro, everything is pulled together into the final material. An interior block is added with an ior 1.6 value chosen as a good compromise for feldspars and quartz. Further development of the interior may include media, to be combined with the subsurface light transport.

Still within the macro structure, the users can apply internal transformations to the texture. They may for instance want to rotate the texture (can be useful when using veins), translate it (also useful with veins enabled), or scale the complete texture. The parameters M_scale (defaults to <1,1,1>), M_rotat (defaults to <0,0,0>), and M_trans (defaults to <0,0,0>) are provided as input parameters (see below).

Macro parameters and their use

Required parameters

Granite_file
The include file that describes the granite through (user-defined) arrays and read into the macro. Default: "DakotaRedGranite.inc"

CSC
Colour Space Conversion: Assuming that the input colour vectors are defined as RGB, conversion to sRGB is possible by using value 1 to convert directly to a "raw" sRGB vector (middle), or 2 by using a conversion macro (right). Any other value just keeps the RGB vectors (left). Default: 2;

Pol
Switch to turn on/off the polished version of the granite (image is 'on'). When 'off', the frosted version is rendered. Default: off;

Type
Switch to turn on/off the veins crossing the granite (image is 'on'). Warning! This parameter is still in an experimental stage. Default: off;

Pat1
Pat1 (pigment pattern at the pigment level) and Pat2 (pigment pattern at the texture level) are described here together. Three patterns are proposed: (1) cells; (2) step noise; (3) crackle solid. The Pat1 patterns are the fundamental building blocks of the granite at the pigment level, simulating the mineral assemblages. The image shows the following combinations: Pat1=1 & Pat2=3 (left); Pat1=2 & Pat2=2 (centre); Pat1=3 & Pat2=1 (right). Default: 2;

Pat2
At the texture level, the Pat2 patterns are used to modulate the aspect of the granite. As such, they can be different from the Pat1 patterns (increasing the number of different possible granites). The image shows the following combinations: Pat1=1 & Pat2=1 (left); Pat1=3 & Pat2=2 (centre); Pat1=2 & Pat2=3 (right). Default: 3;

Blend
When 'on', the granite pigments are 'blended' using the internal blended cells pattern macro by Tekno Frannansa. This simulates a weathered granite. See also the optional BC_Blur parameter below. Default: off;

Optional parameters

SN_Start; SN_End; SN_Turb
The step noise pattern can be controlled by these three parameters. The two first set to the same value (0-1) the pattern corresponds to the cells pattern. With SN_Start = 0 and SN_End = 1, the pattern comes as close as it can get to f_noise3d(). SN_Turb controls the warp turbulence of the pattern. It is best to leave these parameters alone. An example is given here with default SN_Start & SN_End at (left), SN_Start=SN_End=0.2 (centre), SN_Start=0 & SN_End=1 (right). default SN_Start: 0.2; default SN_End: 0.8; default SN_Turb: 0.325;

BC_Blur
This parameter controls the amount of blurring used in the blended cells macro. The example uses a value of 0.5; compare with the default 'Blend' example above. Default: 2;

Optional transformations of the material

M_scale; M_rotat; M_trans
The end material can be scaled, rotated, and translated, at will. Scaling in particular will break the default relationship with real-world granite dimensions, however. Rotation and translation can be of help when veins are enabled. default M_scale: <1.0, 1.0, 1.0>; default M_rotat: <0.0, 0.0, 0.0>; default M_trans: <0.0, 0.0, 0.0>;

Subsurface light transport (experimental parameters)

SubS
This feature is still experimental and may change in the future. The default translucency value is based on the Dakota Red granite. Default: off;

Translucency
Default: <0.669, 0.229, 0.198>*1;

Gallery of macro parameters

param_file param_CSC param_pol param_type param_pat1
Required: Granite_file. Required: CSC. Required: Pol. Required: Type. Required: Pat1.
param_pat2 param_blend param_stepnoise param_blendblur param_SSLT
Required: Pat2. Required: Blend. Optional: SN_Start; SN_End;
SN_Turb.
Optional: BC_Blur. SSLT: SubS.

Annexes

The following annexes describe seven granites based on the original code by Daniel Mecklenburg Jr. Not all annexes however, describe true granites. Of the seven, Annex 1 (Dakota Red Granite) and Annex 2 (North American Pink Granite) can be considered as true granites according to scientific standards. Annex 3 (Southern Gray Granite) and Annex 4 (Medium Barre Gray Granite) can be considered as belonging to the diorite or gabbro groups. Annex 5 (Saint-André Green Granite) and Annex 6 (Saint-André Green Dark Granite) from Quebec, Canada, are difficult to classify and may represent special cases within the plutonic rocks group, possibly a monzonite equivalent. Finally, Annex 7 (Impala Black Granite) which describes a very dark when polished, stone from the Bushveld in South Africa, represents a gabbronorite. These last three granites contain significant additions of dark minerals.

Note that the use of "not_0" in the arrays represents a value of 1/265, small enough to render a completely black pixel, but which retains the ability to contribute to the multiplicative result of colour and intensity calculations resulting from strong illumination, radiosity, etc.).

Acknowledgments

The POV-Ray macro tabulated.inc by jr has been used to visualize the granite arrays in Table 1 and Figures 5. Likewise, his ruled.inc macro was used in most illustrations to visualise the dimensions of the shown objects. Last but not least, jr threw in his not negligible webpage building skills to improve this document.

The "Stanford Bunny" which appears profusely throughout this documentation, was gratefully downloaded from here.

Colophon

The Scene Description Language (SDL) code was written for the Persistence of Vision Raytracer version 3.8, or later. Because the Granite_21 macro uses version 3.8 specific features, in particular in the granite arrays, it cannot be used as is in the earlier versions.

In January 1996, Daniel Mecklenburg Jr. (aka Code Warrior), posted the first known version of the original set of code for POV-Ray that lies at the basis of the present macro. Somehow, this set of code found its way into early include files developed at the time by different users. It is probable that one of us (TdeG) found the set late in the nineteen nineties or early in the twenty first century. Nothing really important happened after then until the early months of 2021. The Granite_21 macro is the result.

July 2021