POV-Ray : Newsgroups : povray.text.tutorials : (long) Using HFLab to create slope and curvature dependent textures Server Time
18 May 2024 09:52:54 EDT (-0400)
  (long) Using HFLab to create slope and curvature dependent textures (Message 1 to 1 of 1)  
From: Jerry Anning
Subject: (long) Using HFLab to create slope and curvature dependent textures
Date: 18 Jul 1998 23:51:14
Message: <35B15F10.B2825F26@dhol.com>
In response to a blizzard of requests (one - thanks Guillermo!) I am
presenting a minitutorial on the above mentioned subject.  If time and
health ever let me revive my moribund web page I will post this with
illustrations there.  Meanwhile, here it is.  I apologize abjectly for
the length of this post and the time it took to present it.

Slope and curvature dependent textures for heightfields via HFLab - a
minitutorial

*Note* The code in this tutorial assumes POV 3.1 Beta, but can easily be
modified to work in 3.02.

In addition to its obvious uses to create realistic heightfield
geography, bevelled text etc., John Beale's HFLab can be used to
generate processed versions of heightfields that allow the creation of
image maps that simulate advanced procedural texturing functions.  In
this case, I am using it to create slope and curvature dependent
textures with standard POV 3.1 Beta.  Even with the existence of Tmpov
and Hans Detlev-Fink's excellent slope dependent textures patch, this
can come in handy.  

A normal y gradient could be called a height dependent texture.  Which
part of the color map you use depends on how large your y coordinate
is.  A slope dependent texture doesn't care about the absolute height,
but about how fast it is changing.  A sheer cliff would receive a
different texture than a gentle slope or a flat plateau.  A curvature
dependent texture treats areas where the slope is changing differently
than areas where it is constant.  Examples might be the rounded rubble
at the bottom of a cliff or the worn lip at the top, a rounded bevel at
the top of a height field letter, the rounded profile of a dry stream
bed, a ripply area in height field water, etc.  

Mathematically, the slopes of a heightfield are calculated by taking the
first derivative of the heightfield.  This is the HFLab diff function. 
The curvature is calculated by taking either the first derivative of the
slopes, diff again, or equivalently the second derivative of the
heightfield, dif2.  I promise, no more calculus past this point so don't
get upset ;).  In any case, the basic procedure is to create and save or
load the base heightfield, smooth it so that the slope and curvature
fields respond only to significant changes and not every tiny bump (in
most cases, this is what you want), take the diff, scale it to a useful
size, smooth it, save it (the slope field), take the diff of the slope
field, scale, smooth, and save that (the curvature field).  If this
summary is confusing, don't worry.  An annotated HFLab script is
forthcoming.

Once you have the height field, the slope field, and the curvature
field, you use them with the POV orthographic camera to generate image
maps.  We are creating a simple mountainous terrain scene, so we will
generate four image maps.  Two maps will be generated from the height
field.  One for water and one for dry land.  The reason for this is that
the slope and curvature maps will generate structures that override the
dry land material in a layered texture, but cliffs and curves will not
be visible underwater, so we will apply the water separately on top of
the other maps.  The slope field will be used to generate a map that
will replace vegetation or snow in steep areas with bare rock.  The
curvature field will be used to generate a map that will put dirt on
rounded knobs, at the top and base of cliffs, etc.  The "textures" in
this demo are just simple colors for purposes of illustration, but it is
obvious how to enhance them.  Note that since we are layering image
maps, we need transparency.  The best way to get this is to use .png
image maps with an alpha channel.  The POV docs claim that you can use
.tga image maps with alpha, but I have never had any luck with that.

Variations of this procedure can naturally be used with other HFLab
functions such as max, min, pow, zedge, twist, etc.  ***Note to Jamis
Buck,if he reads this: You could set up the slope field in an invisible
area in a Tmpov scene and use hf_height_at info from it carried back to
the main height field to differentially *populate* slopes.***  In any
case, here are demonstration HFLab and POV scripts.  The result isn't
great art by any means, but it demonstrates the principles.  Simply cut
out the scripts and .ini file and execute them with HFLab and POV. 
Watch for run-on comments due to text formatting.

# Begin Slopcurv.scr - HFLab slope map and curvature map script.

# The first part allows you to duplicate my test image.
# To use your own hf, say load base.tga instead.

seed 2317
gforge 256 2
save base.tga

# The next line insures that the slope and curvature fields respond
# only to terrain features and not little bumps by smoothing the
# little bumps out.

nsmooth 10 0 1

# generate the slope map

diff

# move the numbers to a suitable range

norm

# clean up noise

nsmooth 10 0 1

# save the slope field

save slope.tga

# generate the curvature field from the smoothed slope field

diff
norm
nsmooth 10 0 1

# save the curvature field

save curve.tga

quit

# End Slopcurv.scr


; Begin Mapgen.ini - .ini file for Mapgen.pov

Input_File_Name=Mapgen

; Uncomment the proper output file name for each map
;Output_File_Name=Wetmap
;Output_File_Name=Drymap
;Output_File_Name=Slopmap
;Output_File_Name=Curvmap

; Make a square image map of the same resolution as the height field.
; This isn't really necessary, but it makes visualization of results
; somewhat easier.

Height=256
Width=256

; Make POV output an alpha (transparency) channel

Output_Alpha=On

; Set file type to .png

Output_File_Type=n

; End Mapgen.ini


// Begin Mapgen.pov

#version 3.1;

#declare Rock = color rgb <0.380, 0.204, 0.063>;
#declare Dirt = color rgb <0.698, 0.484, 0.341>;
#declare Tree = color rgb <0.259, 0.396, 0.192>;
#declare Grass = color rgb <0.067, 0.851, 0.259>;
#declare Lichen = color rgb <0.000, 0.294, 0.275>;
#declare Slush = color rgb <0.933, 0.933, 0.933>;
#declare Snow = color rgb <1.000, 1.000, 1.000>;
#declare Water = color rgb <0.106, 0.298, 0.808>;
#declare Deep = color rgb <0.000, 0.153, 0.561>;
#declare Shallow = color rgb <0.486, 0.576, 0.808>;
#declare Sand = color rgb <1.000, 0.933, 0.380>;
#declare Clear = color rgbt <1.000, 1.000, 1.000, 1.000>;

#declare Curvgrad =
pigment
	{
		gradient y
		color_map
			{
				[ 0.00 color Clear ]
				[ 0.20 color Clear ]
				[ 0.25 color Dirt ]
				[ 0.30 color Dirt ]
				[ 0.35 color Clear ]
				[ 1.00 color Clear ]
			}
	}

#declare Slopgrad =
pigment
	{
		gradient y
		color_map
			{
				[ 0.00 color Clear ]
				[ 0.55 color Clear ]
				[ 0.60 color Rock ]
				[ 1.00 color Rock ]
			}
	}

#declare Drygrad =
pigment
	{
		gradient y
		color_map
			{
				[ 0.00 color Clear ]
				[ 0.30 color Clear ]
				[ 0.35 color Sand ]
				[ 0.37 color Sand ]
				[ 0.40 color Grass ]
				[ 0.45 color Grass ]
				[ 0.55 color Tree ]
				[ 0.60 color Tree ]
				[ 0.70 color Lichen ]
				[ 0.73 color Lichen ]
				[ 0.75 color Slush ]
				[ 0.80 color Snow ]
				[ 1.00 color Snow ]
			}
	}

#declare Wetgrad =
pigment
	{
		gradient y
		color_map
			{
				[ 0.00 color Deep ]
				[ 0.05 color Deep ]
				[ 0.10 color Water ]
				[ 0.20 color Shallow ]
				[ 0.35 color Shallow ]
				[ 0.35 color Clear ]
				[ 1.00 color Clear ]
			}
	}
	

// Colors were designed externally on a standard pc clone monitor.

global_settings { assumed_gamma 2.2 }

// The orthographic camera and ambient lighting let us create an
// image map with no lighting or shadow artifacts that exactly
// fits the selected frame.

camera
	{  
  	orthographic

// With orthographic, up and right set not only aspect ratio but
// visible area size, so we have no alignment problems.

  	          up < 0.0,  1.0,  0.0>
  	       right < 1.0,  0.0,  0.0>

// The odd numbers on location keep POV from choking.
  	    
  	    location < 0.500001,  1.0, 0.500001>
  	     look_at < 0.5,  0.0,  0.5>
	}

height_field
	{
		
		// Uncomment the proper line for the map you are making.
		
		// tga "base.tga" // for Wetmap and Drymap
		// tga "slope.tga" // for Slopmap
		// tga "curve.tga" // for Curvmap

		smooth
		texture
			{

				// Uncomment the proper line for the map you are making.
				
				// pigment { Wetgrad } // for Wetmap
				// pigment { Drygrad } // for Drymap
				// pigment { Slopgrad } // for Slopmap
				// pigment { Curvgrad } // for Curvmap

				finish { ambient 1.0 }
			}
	}

// End Mapgen.pov


// Begin SCDemo.pov

#version 3.1;

#declare Sky = color rgb <0.062, 0.063, 0.750>;
#declare Surf = color rgbt <0.827, 0.906, 0.922, 0.900>;
#declare Solar = color rgb <1.000, 1.000, 0.950>;

global_settings { assumed_gamma 2.2 ambient_light Solar * .7 }

camera { up <0, 1, 0> right <4/2, 0, 0> 
	location <-3, 6, -3> look_at <.5, 0, .5> }

// the "Sun"

light_source { <20, 50, -100> color Solar }

// fill lights

light_source { <20, 50, 100> color Solar * .8 shadowless }
light_source { <-3, 6, -3> color Solar * .8 shadowless spotlight
point_at <.5, 0, .5> radius 90 falloff 90 tightness 1 }
light_source { <-20, 50, 100> color Solar * .7 shadowless }

sky_sphere { pigment { color Sky } }

union
	{
		height_field
			{

				// our original height field
				
				tga "Base.tga"
				smooth

				// Starting a layered texture.  The first layer written is the
				// bottommost layer.
				
				// This layer is sand, grass, trees, snow etc. based on height.
				
				texture { pigment { image_map { png "Drymap.png" } rotate <90, 0, 0>
} }
	
				// This layer is dirt and rubble, based on curvature.
				// It covers some of the previous layer where the curvature is too
				// sharp for plants or snow to stick.
				
				texture { pigment { image_map { png "Curvmap.png" } rotate <90, 0,
0> } }

				// This layer is rock, based on slope.
				// It covers some of the previous layers where you have a face too
				// sheer for even dirt.
		
				texture { pigment { image_map { png "Slopmap.png" } rotate <90, 0,
0> } }
				
				// This layer is the water, based on height.  It covers
				// anything when the height is low enough.

				texture { pigment { image_map { png "Wetmap.png" } rotate <90, 0, 0>
} }
			}
			
		// This plane cuts the height field at water level and puts a
"surface" of
		// sorts on it.  I didn't trim it, because it also fills the outside a
bit.
		// I borrowed it from an experiment in visualizing the "luminiferous
ether"
		// as part of a projected image for the current IRTC stills round.
		
		plane
			{
				y, .35
				interior { ior 1.33 }
				texture
					{
						pigment { color Surf }
						normal { ripples 2 scale <0.10, 1.00, 0.10> }
						finish { specular 1 roughness .05 brilliance 2 reflection .1 }
					}
			}
		scale <6, 3.5, 6>
		translate <-3, -1.5, -1>
	}

// End SCDemo.pov

I hope someone finds this useful.

Jerry Anning
cle### [at] dholcom


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.