Tutorial: Realistic Rocks and Stones in POV-Ray

As an average user who wants to create for fun nice 3D pictures to share with friends and who has neither knowledge nor any desire to study mathematics I want to share my exploration on this subject. Let's leave mathematics as a brain exercise and mind training to programmers and other interested persons. It doesn't guarantee that your pictures made this way will be really nice. I mean POV-Ray, the only decent free raytracer available. And that's all what can be said about it. I mean, how it would be nice to use a free mesh modeler Blender to create a basic shape and convert it later to a realistic looking stone! But no, this is impossible. In ideal it would be perfect to have such a modeler that describes the surface of the model as a math function . But in reality I don't know any program capable of this. That's why there nothing else to do but to use POV-Ray isosurface.

The basic syntax is:

isosurface {
function { surface -noise }
contained_by { container }
}

Where surface and noise are mathematical functions.
Container is a POV-Ray primitive, sphere or box.

Surface can be any function that is supported by Pov-Ray and the one that can occur to you.
Read also Isosurfase Manual.

Noise can be either built in POV-Ray functions or pigment.

The relevant internal functions are:

  • f_noise3d(x,y,z)
    uses the noise generator specified in global_settings{} and generates structures like the bozo pattern.

  • f_noise_generator(x, y, z, noise_generator)
    generates noise with a specified noise generator.

  • f_ridged_mf(x, y, z, H, Lacunarity, Octaves, Offset, Gain, noise_generator)
    generates a ridged multifractal pattern.

  • f_ridge(x, y, z, Lambda, Octaves, Omega, Offset, Ridge, noise_generator)
    generates another noise with ridges.

  • f_hetero_mf(x, y, z, H, Lacunarity, Octaves, Offset, T, noise_generator)
    generates heterogenic multifractal noise.

This all sounds like a bunch of gibberish and actually it is. Don't try to understand anything from it. Except x, y, and z the other stuff is just bare digits. Noise generator is 1, 2 and 3. H, T, Lacunarity, Octaves, Omega, Offset, Ridge and Gain are digits, too.

I guess, now you have a lot of digits to play with.

f_noise3d

f_noise_generator

f_ridged_mf.

f_ridge

f_hetero_mf

As you see, simple combination of digits creates weird forms.

Pigment, the basic syntax:

#declare fn_Pigm=function {
pigment {
agate
color_map {
[0 color rgb 0]
[1 color rgb 1]
}
}
}

A color vector has five components. Supported dot types to access these components are:

  • F( ).x | F( ).u | F( ).red
    to get the red value of the color vector

  • F( ).y | F( ).v | F( ).green
    to get the green value of the color vector

  • F( ).z | F( ).blue
    to get the blue value of the color vector

  • F( ).filter | F( ).t
    to get the filter value of the color vector

  • F( ).transmit
    to get the transmit value of the color vector

  • F( ).gray
    to get the gray value of the color vector,
    gray value = Red*29.7% + Green*58.9% + Blue*11.4%

  • F( ).hf
    to get the height_field value of the color vector,
    hf value = (Red + Green/255)*0.996093,
    the .hf operator is experimental and will generate a warning.
function { f_sphere(x, y, z, 1.6)-fn_Pigm(x/2, y/2, z/2).gray*0.5 }

Let's apply some noise to the iso sphere we have.
Function f_noise3d uses noise generator that is specified in global settings:

global_settings {noise_generator 2}

If you apply a too big noise, you will get some separate pieces.

stage 1
function { f_sphere(x, y, z, 1) -f_noise3d(x,y,z)*0.8}

It's too round. Let scale it a bit.

stage 2
scale <0.200000,0.100000,0.200000>

That's better, but it doesn't look like a stone. Lets apply some more fine pigment noise.

stage 3
function { f_sphere(x, y, z, 1) -f_noise3d(x,y,z)*0.8 -fn_Pigm(x, y, z).gray*0.1}

OK. Does it look like a real stone? Well, my wife says it looks like a piece of poop.

Let's try some other functions.

Cylinder. Agate as pattern modifier for pigment noise.

cylinder agat
function { sqrt(pow(x,2) +pow(z,2)) - 1 -f_noise3d(x,y,z)*0.5 -fn_Pigm(x, y, z).gray*0.1}

Cylinder. Granite as pattern modifier for pigment noise.

cylinder granite
function { sqrt(pow(x,2) +pow(z,2)) - 1 -f_ridged_mf(x, y, z, 1, 0.5,0.5, 1.2, 1, 2)/5 -fn_Pigm(x, y, z).gray*0.025}

Let's try something more square.

Box. Bozo as pattern modifier for pigment noise

box granite
function { x -f_noise3d(x,y,z)*0.5 -fn_Pigm(x, y, z).gray*0.1}
 

You can obtain the POV code by clicking on the image.

sphere

function { sqrt(pow(x,2) + pow(y,2) + pow(z,2)) - 1 }

"1" is the radius here.

The code for s sphere will be:

isosurface { function { sqrt(pow(x,2) +pow(y,2) +pow(z,2)) - 1 } contained_by { box { -2, 2 } } }

But it also can be:

#include "functions.inc"

isosurface {
 function { f_sphere(x, y, z, 1) } contained_by { box { -2, 2 } } }

Box

Box

function { x }

Cylinder

cylinder

function { sqrt(pow(x,2) +pow(z,2)) - 1 }

f_rounded_box 0.1

f_rounded_box0.1

#include "functions.inc"

function { f_rounded_box (x,
y, z, 0.1, 1, 1, 1 ) }

f_rounded_box 1

f_rounded_box1

#include "functions.inc"

function { f_rounded_box (x,
y, z, 1, 1, 1, 1 ) }

Weird! Isn't it?


  

There are a lot of things possible with pigment as a noise function. Read POV-Ray documentation about pigment and pattern modifiers for better understanding. But some examples are here.

f_rounded_box with crackle modifier

rounded box crackles

function { f_rounded_box (x, y, z, 0.1, 0.2, 1.2, 0.7 ) -f_noise3d(x,y,z)*0.4 -fn_Pigm(x, y, z).gray*0.1}

f_rounded_box with onion modifier

rounded box onion

function { f_rounded_box (x, y, z, 0.1, 0.2, 1.2, 0.7 ) -f_noise3d(x,y,z)*0.4 -fn_Pigm(x, y, z).gray*0.2}

f_rounded_box with wood modifier

rounded box wood

function { f_rounded_box (x, y, z, 0.1, 0.2, 1.2, 0.7 ) -f_noise3d(x,y,z)*0.4 -fn_Pigm(x, y, z).gray*0.2}

As we see POV-Ray is more suitable for creation of weird surrealistic forms. But what about realism? Let's try.

rounded box granite 2

function { f_rounded_box (x, y, z, 0.1, 0.2, 1.2, 0.7 ) -f_noise3d(x,y,z)*0.4 -fn_Pigm(x, y, z).gray*0.3}

rounded box granite 3

function { f_rounded_box (x, y, z, 0.1, 0.2, 1.2, 0.7 ) -f_ridged_mf(x, y, z, 1, 0.5,0.5, 1.2, 1, 2)/5 -fn_Pigm(x, y, z).gray*0.05}

granite 0

function { f_rounded_box (x, y, z, 0.1, 0.2, 1.2, 0.7 ) -f_noise3d(x,y,z)*0.4 -fn_Pigm(x, y, z).gray*0.1}

OK. This was the final attempt. Can this stone be suitable for somebody's grave? Not really. It is still too round. We have made the investigation and found out that it is not hard to deform the surface of a function object the way we want, the problem is where to get a suitable object made of isosurface.

Valid XHTML 1.0 Transitional Copyright  2007   ©   Alex Ivanov      www.3dplumbing.net       contact me