Home < Solutions < Generic Tutorial Rev2.0
The POV-Ray Cyclopedia
www.spiritone.com/~english/cyclopedia/

Mega Pov introduced UV-Mapping, and POV-Ray Beta 3.5 incorporated it. This tutorial looks at the POV 3.5 methods for uv mapping. At this points I am not promising that the code described here will work with MegaPov.

The three files you need are:

Part One
UV-Mapping

Lets start with a basic bicubic patch and an image map of some cranes that I rendered several years ago.

bicubic_patch { 
  type 0 flatness 0.01
  u_steps 3 v_steps 3
  uv_vectors <0,0>,<1,0>,<1,1>,<0,1>
  <-1.5,-1.5,-0.3>, <-0.5,-1.5,0>, <0.5,-1.5,0>, <1.5,-1.5,0.3>,
  <-1.5,-0.5,   0>, <-0.5,-0.5,0>, <0.5,-0.5,0>, <1.5,-0.5,  0>,
  <-1.5, 0.5,   0>, <-0.5, 0.5,0>, <0.5, 0.5,0>, <1.5, 0.5,  0>,
  <-1.5, 1.5,-0.3>, <-0.5, 1.5,0>, <0.5, 1.5,0>, <1.5, 1.5,-0.3>
  uv_mapping
  texture { 
    pigment { image_map { tga "uvdragon.tga" } } } }

The first thing to notice is the order of vectors that follows the uv_vectors keyword, and the order of the points in the bicubic_patch. The first point is in the "lower left" corner, and first four points are along the bottom of the grid from left to right. The last line is the top of the grid, from left to right. This matches the standard planar image map where the u and v coordinates match the x and y coordinates.

So when we look at uv mappin in this simple example, the uv points at each of the 16 points in the curve are:

<  0,  0>, <1/3,  0>, <2/3,  0>, <  1,  0>,
<  0,1/3>, <1/3,1/3>, <2/3,1/3>, <  1,1/3>,
<  0,2/3>, <1/3,2/3>, <2/3,2/3>, <  1,2/3>,
<  0,  1>, <1/3,  1>, <2/3,  1>, <  1,  1>

We can use the uv vectors to create some effects. Image two uses the uv cooridates <1,0>,<2,0>,<1,1>,<0,1> to create the shearing effect. The third image uses the original uv vectors, but the control points are the following:

<-1.5,-1.5,-0.3>, <-0.5,-1.5,0>, <0.5,-1.5,0>, <1.5,-1.5,0.3>,
<-1.5,-0.5,   0>, <-0.9,-0.5,0>, <-.5,-0.5,0>, <1.5,-0.5,  0>,
<-1.5, 0.5,   0>, <-0.9, 0.5,0>, <-.5, 0.5,0>, <1.5, 0.5,  0>,
<-1.5, 1.5,-0.3>, <-0.5, 1.5,0>, <0.5, 1.5,0>, <1.5, 1.5,-0.3>

By moving the middle four points we warp the image in a particular way. This leads to the conclusion that the distance between the control points is important in uv mapping. If you imagine the sixteen points of the bicupic patch forming nine "squares", then each "square" is mapped with one ninth of the image.

If we use the original vectors for the control points but use <0,0>,<1,0>,<0,0>,<0,1> as the uv_vectors we get the odd image 4. POV-Ray is forced to mirror the image around one diagonal.

Headache Saver It is important to keep track of how the uv_vectors relate to the control points.

Alt Tag 1. A Patch with uv mapping

Alt Tag 2. Shearing the uv map

Alt Tag 3. Distoring the image

Alt Tag 4. Starting a kaleidoscope?

Part Two
Mutliple Patches

If you have created multiple smooth bezier patches and want to use one image_map on all of them you have to keep the warning in mind. I store the points on a surface in a two dimensional array and use the CreateSkinPoints macro from makeskin.inc. This gives me a larger array that I can feed into the MakeSkin macro, which builds the bezier patches and uses uv mapping by default with uv_vectors of <0,0>,<1,0>,<1,1>, and <0,1>. Image 5 shows nine patches with one image map, plus the borders between the patches drawn in. Here is the code:

#declare grid = array[4][4]

#declare uc = 0;
#while (uc < dimension_size(grid,1))
  #declare vc = 0;
  #while (vc < dimension_size(grid,2))
    #declare grid[uc][vc] = <uc-1.5,vc-1.5,cos(2*pi*(uc+vc)/4)*0.4>;
    #declare vc = vc + 1;
  #end
  #declare uc = uc + 1;
#end
#include "makeskin.inc"
#declare WireFrameColor = <1,1,1>;
#declare WireFrameRadius = 0.05;
DrawWireFrame(grid,0)
#declare SkinPigment = pigment { image_map { tga "uv_cranes.tga" } }
#declare SkinFinish = finish { diffuse 0.6 } 
#declare Grid =CreateSkinPoints(grid,0)
MakeSkin(Grid)

Image 6 shows what happens when one group of patches is much shorter than the others. The whole image is there, but the right edge has been moved about half the width of the patches, so the right hand side of the image is shrunk down.

Alt Tag 5. A grid of patches

Alt Tag 5. A uneven grid of patches

Part Three
The Code

Here is the code of the MakeSkin macro:

#macro MakeSkin(F)
  #ifndef(SkinPigment)
    #declare SkinPigment =  pigment { marble }
  #end
  #ifndef(SkinNormal)
    #declare SkinNormal =  normal { bumps 0 }
  #end
  #ifndef(SkinFinish)
    #declare SkinFinish = finish { specular 1 } 
  #end
  #ifndef(SkinTexture)
    #declare SkinTexture = texture {
      pigment { SkinPigment }
      normal { SkinNormal }
      finish { SkinFinish } }
  #end
  #declare uc = 0;
  #declare ulim = (dimension_size(F,1)+2)/3-1;
  #declare vlim = (dimension_size(F,2)+2)/3-1;
  #while (uc < ulim )
    #declare vc = 0;
    #while (vc < vlim )
      #declare UC=uc*3;
      #declare VC=vc*3;
      #declare umin = uc/ulim;
      #declare umax =(uc+1)/ulim;
      #declare vmin =vc/vlim;
      #declare vmax =(vc+1)/vlim;

      bicubic_patch { type 0 flatness 0.01
                      u_steps 4 v_steps 4
                      uv_vectors ,,,
                      F[UC][VC],   F[UC+1][VC],   F[UC+2][VC],   F[UC+3][VC],
                      F[UC][VC+1], F[UC+1][VC+1], F[UC+2][VC+1], F[UC+3][VC+1],
                      F[UC][VC+2], F[UC+1][VC+2], F[UC+2][VC+2], F[UC+3][VC+2],
                      F[UC][VC+3], F[UC+1][VC+3], F[UC+2][VC+3], F[UC+3][VC+3]
                      uv_mapping
                      texture { SkinTexture}
                      }
      #declare vc = vc + 1;
    #end
    #declare uc = uc + 1;
  #end
#end

Note that as it is presented here, there is no error checking, so if the dimensions of the array are not the right size, the macro will fail and stop the rendering process. Valid dimension sizes n*3-2 for any integer n greater than three, so 7,10,13,16,19,.... The macro also doesn't allow for uv mapping to be turned off. The next versions of makeskin.inc will have these features.

Part Four
A common pitfall

When I work with bezier patches I find that frequently I use the text file to order the points in a way that their position in my code tells me the relative position of the control point. For example:

#declare grid = array[4][4]
{{<-1.5, 1.5,0>,<-0.5, 1.5,   0>,<0.5, 1.5,   0>, <1.5, 1.5,0> },
 {<-1.5, 0.5,0>,<-0.5, 0.5, 0.1>,<0.5, 0.5,-0.1>, <1.5, 0.5,0> },
 {<-1.5,-0.5,0>,<-0.5,-0.5,-0.1>,<0.5,-0.5, 0.1>, <1.5,-0.5,0> },
 {<-1.5,-1.5,0>,<-0.5,-1.5,   0>,<0.5,-1.5,   0>, <1.5,-1.5,0> } }

#include "makeskin.inc"

#declare SkinPigment = pigment { image_map { tga "uv_cranes.tga" }  }
#declare SkinFinish = finish { diffuse 0.6 } 
#declare Grid =CreateSkinPoints(grid,0)
MakeSkin(Grid)

This leads to Image 7. The image is rotated. To fix it, all I have to do is rotate the pigment by 90*z.

Alt Tag 7. A "logical" grid arrangement.


Send feedback, or head back to the Cyclopedia.

This page was last updated on 31 Aug 2001 15:19 .

Valid HTML 4.01! Valid CSS! Powered by Python