POV-Ray : Newsgroups : povray.advanced-users : Phase 2: cutting a mask of height field style mesh Server Time
29 Jul 2024 08:17:54 EDT (-0400)
  Phase 2: cutting a mask of height field style mesh (Message 1 to 3 of 3)  
From: normdoering
Subject: Phase 2: cutting a mask of height field style mesh
Date: 16 Nov 2002 19:10:03
Message: <web.3dd6de06ccdca5b11a927f560@news.povray.org>
Okay, I'm not as finished as I hoped. I've got a problem in that I'm
doubling up the triangles, or facets, that make up the array -- I think.

Here's the code:

//-----------------------------------------------------------
// How to cut a mask from an imported picture before making mesh
#version 3.5;
#include "colors.inc"
global_settings { assumed_gamma 1.0 }
// ----------------------------------------

camera
{ location  <0, 0, -850.0>
  look_at   <0, 0, 0>
  angle 35
}

background {rgb <0.25, 0.25, 0.5>}
//No light source needed to test these assumptions use ambient finish

// -----------------------------
//test assumption: Cutting pictures with a mask and making meshes
//==============================

#declare xPixels = 271; // 271 is number of pixels in x dimension
#declare yPixels = 496; // 496 in y dimension
// These numbers are the size of the image in pixels, you have to get these
// from a paint program or such. POV can't get them for you.

#declare ScX = 1;    // scale has to be declared because it's shared with
the
#declare ScY = 1.83; // #while loops. Difference in scale because the
function
                     // wants to create a square picture and fills the
square
                     // area from (x,y) coordinates (0,0) to (1,1)
regardless
                     // of the image's original size in pixels.
#declare MsclX = 50;  // The mesh itself needs to be scaled on x, y and z
#declare MsclY = 50;  // All these might be variables for a macro later.
#declare MsclZ = 30;

// these mark how the picture goes exactly to upper right
cylinder {-200*x, 200*x, 1 pigment {rgb <1,1,0>} finish {ambient 1}}
cylinder {-200*y, 200*y, 1 pigment {rgb <1,1,0>} finish {ambient 1}}


#declare thePicture = function   // To get the picture we wish to use as a
{ pigment                        // mesh height field we declare it as a
  { image_map                    // function.
    { jpeg "12.jpg" map_type 0   // This pigment function returns a vector,
3 numbers at least <r,g,b>.
      once                       // 3 numbers at least: <r,g,b>.
    }                            // We have to convert its output to a
single float.
    scale <ScX, ScY, 1>          // a float between 0 and 1
  }
}
#declare HFChn = function {thePicture(x,y,z).hf}
#declare Mask = function {thePicture(x,y,z).blue}
   // This assumes that .blue will be used as our cutting mask
   // and .hf is red and green combined to get a 16 bit hieght value.
   // The dot-operators used below are explained in the POV help docs.

#declare Resx = xPixels/6; // actual size takes too long to render
#declare Resy = yPixels/6; // so we scale it down till were ready to do
                           // the whole thing and mesh it.

#declare Pary = array[(Resy*ScY)+1][(Resx*ScX)+1];

#declare incx = 1/Resx; // This is how far we travel to check the next pixel
#declare incy = 1/Resy; // in our tiny <0,0> to <1,1> square.


//Step 1: count up unmasked "pixels" to size mesh array: Mary
#declare xloc = 0;     // xloc & yloc are coordinates for scanning the
picture
#declare yloc = 0;
#declare totalV = 0;   // size of mesh array
#declare ycnt = 0;     // loop counter
#while (ycnt <= (Resy*ScY))
#declare xcnt = 0;
#declare xloc = 0;
   #while (xcnt <= (Resx*ScX))       // scan a horizontal line.

      #if (Mask(xloc,yloc,0) > 0.08) // If it's black, less than 0.08, we
                                     // cut it out and don't count it.
      #declare totalV = totalV + 1;  // Count vertices to be used only.
      #end

   #declare xloc = xloc+incx;
   #declare xcnt = xcnt+1;
   #end
#declare yloc = yloc+incy;
#declare ycnt = ycnt+1;
#end

#declare Mary = array[totalV];    // vertices of mesh2 array
#declare triang = array[totalV+totalV];
 // represents facet making data for mesh2
 // The size of the triang array is too large, my code must be doubling
 // up the triangles -- no time to fix it today -- help needed here.

//Step 2: Load the arrays
#declare xloc = 0;
#declare yloc = 0;
#declare totalV = 0;
#declare ycnt = 0;
#while (ycnt <= (Resy*ScY))
#declare xcnt = 0;
#declare xloc = 0;
   #while (xcnt <= (Resx*ScX)) // scan a horizontal line.

      #if (Mask(xloc,yloc,0) > 0.08) // If it's black, less than 0.08, we
                                     // cut it out and didn't count it.
        #declare Mary[totalV] = < xloc*MsclX,
                                  yloc*MsclY,
                                  HFChn(xloc,yloc,0)*MsclZ
                                >;
        #declare Pary[ycnt][xcnt] = totalV;
        #declare totalV = totalV+1;

      #else
        #declare Pary[ycnt][xcnt] = -1000; // negative flag

      #end //if

   #declare xloc = xloc+incx;
   #declare xcnt = xcnt+1;
   #end //while(x)
#declare yloc = yloc+incy;
#declare ycnt = ycnt+1;
#end //while(y)

// * --- use something like this only if testing small, low res pictures
#declare checkMary = union
{
#declare cnt = 0;
#while (cnt < totalV)
sphere
{ <Mary[cnt].x, Mary[cnt].y, 0> 0.83
  texture
   { pigment
     { rgb <Mary[cnt].z/MsclZ, Mary[cnt].z/MsclZ, Mary[cnt].z/MsclZ>
     }
   }
  finish{ambient 0.7}
}
#declare cnt = cnt+1;
#end
}

object {checkMary translate <0,0,0>}
//*/


// Step 3: Make the triangles
#declare totalF = 0;
#declare ycnt = 1;
#while (ycnt < (Resy*ScY))  //A
   #declare xcnt = 0;
   #while (xcnt < (Resx*ScX)) //B

       #if(xcnt < (Resx-1)) // C
       #if(Pary[ycnt][xcnt] > -10 & Pary[ycnt-1][xcnt] > -10
            & Pary[ycnt-1][xcnt+1] > -10
           ) // D // <y,x><y-,x><y-,x+>
            #declare triang[totalF] =
             < Pary[ycnt][xcnt], Pary[ycnt-1][xcnt], Pary[ycnt-1][xcnt+1] >;
                 // <y,x> <y-,x> <y-,x+> is a triangle with
                 // right angle on upper right
             #declare totalF = totalF+1;
           #end // D

           #if( Pary[ycnt][xcnt] > -10 & Pary[ycnt][xcnt+1] > -10 &
                Pary[ycnt-1][xcnt+1] > -10
                ) // E
             #declare triang[totalF] =
             < Pary[ycnt][xcnt], Pary[ycnt][xcnt+1], Pary[ycnt-1][xcnt+1] >;
                 // <y,x> <y,x+> <y-,x+> is a triangle with
                 // right angle on lower left
             #declare totalF = totalF+1;
             #end // E

             //----- These two triangles use another diagonal -----:
             #if( Pary[ycnt][xcnt] > -10 & Pary[ycnt][xcnt+1] > -10 &
                Pary[ycnt-1][xcnt+1] < -10 & Pary[ycnt-1][xcnt] > -10
                ) // E
             #declare triang[totalF] =
             < Pary[ycnt][xcnt], Pary[ycnt][xcnt+1], Pary[ycnt-1][xcnt] >;
             #declare totalF = totalF+1;
             #end // E
             // ---
             #if( Pary[ycnt][xcnt] < -10 & Pary[ycnt][xcnt+1] > -10 &
                Pary[ycnt-1][xcnt+1] > -10 & Pary[ycnt-1][xcnt] > -10
                ) // E
             #declare triang[totalF] =
             < Pary[ycnt-1][xcnt+1], Pary[ycnt][xcnt+1], Pary[ycnt-1][xcnt]
>;
             #declare totalF = totalF+1;
             #end // E
             // ---

        #end // C


   #declare xcnt = xcnt+1;
   #end // B
#declare ycnt = ycnt+1;
#end // A

/* ---- check the data ----
#declare cnt = 0;
#while (cnt < totalF)
  cylinder
  { Mary[triang[cnt].x], Mary[triang[cnt].y], 0.14
    pigment {rgb <1,1,0>} finish {ambient 0.7}
  }
  cylinder
  { Mary[triang[cnt].x], Mary[triang[cnt].z], 0.14
    pigment {rgb <1,0,1>} finish {ambient 0.7}
  }
  cylinder
  { Mary[triang[cnt].y], Mary[triang[cnt].z], 0.14
    pigment {rgb <0,1,1>} finish {ambient 0.7}
  }
#declare cnt = cnt+1;
#end
*/


/*
//==========================================================================

The meshes I need usually don't have square edges, so I've developed a
method
for pre-cutting the mesh. The final system will work this way:

1) Draw a picture or a few that represents a height-feild portion of the
   mesh sculpture you wish to make. Draw it in pencil and scan at least
   one of them as a color image.
2) Take the picture into a photo-paint program like Corel's Photopaint
   and split it into red, green and blue channels.
3) Turn the blue channel into a mask by painting all unwanted areas black
   and all desired areas white. This is what an #if statement above tests
   for. If the value in the blue channel is less than 0.08 it's considered
   black enough to cut. In the future, areas that measure above 0.08 and
   below 0.93 might be used to describe more grey info or "undercutting."
   Undercutting means bending the mesh back under itself.
4) Because a color scan of a black and white drawing doesn't really give
   you 16 bits worth of grey scale information the .hf dot operator can use,
   but only 3 repeated 8 bit grey scale images, one for each color channel,
   a second drawing can replace either the red or green channel that the
   height field.
5) Then you will import your drawing into POV-ray as done above and an as
   yet unfinished series of macros will turn it into a "mesh sheet."
6) The final mesh sculpture will be made from a series of these sheets
   that are translated, rotated, warped, bent and joined together to make
   something more 3 dimensional.

*/

--normdoering


Post a reply to this message

From: Dennis Miller
Subject: Re: Phase 2: cutting a mask of height field style mesh
Date: 18 Nov 2002 20:43:26
Message: <3dd9973e$1@news.povray.org>
Love to see this when it is done.
Best,
D.

"normdoering" <nor### [at] yahoocom> wrote in message
news:web.3dd6de06ccdca5b11a927f560@news.povray.org...
> Okay, I'm not as finished as I hoped. I've got a problem in that I'm
> doubling up the triangles, or facets, that make up the array -- I think.
>
> Here's the code:
>
> //-----------------------------------------------------------
> // How to cut a mask from an imported picture before making mesh
> #version 3.5;
> #include "colors.inc"
> global_settings { assumed_gamma 1.0 }
> // ----------------------------------------
>
> camera
> { location  <0, 0, -850.0>
>   look_at   <0, 0, 0>
>   angle 35
> }
>
> background {rgb <0.25, 0.25, 0.5>}
> //No light source needed to test these assumptions use ambient finish
>
> // -----------------------------
> //test assumption: Cutting pictures with a mask and making meshes
> //==============================
>
> #declare xPixels = 271; // 271 is number of pixels in x dimension
> #declare yPixels = 496; // 496 in y dimension
> // These numbers are the size of the image in pixels, you have to get
these
> // from a paint program or such. POV can't get them for you.
>
> #declare ScX = 1;    // scale has to be declared because it's shared with
> the
> #declare ScY = 1.83; // #while loops. Difference in scale because the
> function
>                      // wants to create a square picture and fills the
> square
>                      // area from (x,y) coordinates (0,0) to (1,1)
> regardless
>                      // of the image's original size in pixels.
> #declare MsclX = 50;  // The mesh itself needs to be scaled on x, y and z
> #declare MsclY = 50;  // All these might be variables for a macro later.
> #declare MsclZ = 30;
>
> // these mark how the picture goes exactly to upper right
> cylinder {-200*x, 200*x, 1 pigment {rgb <1,1,0>} finish {ambient 1}}
> cylinder {-200*y, 200*y, 1 pigment {rgb <1,1,0>} finish {ambient 1}}
>
>
> #declare thePicture = function   // To get the picture we wish to use as a
> { pigment                        // mesh height field we declare it as a
>   { image_map                    // function.
>     { jpeg "12.jpg" map_type 0   // This pigment function returns a
vector,
> 3 numbers at least <r,g,b>.
>       once                       // 3 numbers at least: <r,g,b>.
>     }                            // We have to convert its output to a
> single float.
>     scale <ScX, ScY, 1>          // a float between 0 and 1
>   }
> }
> #declare HFChn = function {thePicture(x,y,z).hf}
> #declare Mask = function {thePicture(x,y,z).blue}
>    // This assumes that .blue will be used as our cutting mask
>    // and .hf is red and green combined to get a 16 bit hieght value.
>    // The dot-operators used below are explained in the POV help docs.
>
> #declare Resx = xPixels/6; // actual size takes too long to render
> #declare Resy = yPixels/6; // so we scale it down till were ready to do
>                            // the whole thing and mesh it.
>
> #declare Pary = array[(Resy*ScY)+1][(Resx*ScX)+1];
>
> #declare incx = 1/Resx; // This is how far we travel to check the next
pixel
> #declare incy = 1/Resy; // in our tiny <0,0> to <1,1> square.
>
>
> //Step 1: count up unmasked "pixels" to size mesh array: Mary
> #declare xloc = 0;     // xloc & yloc are coordinates for scanning the
> picture
> #declare yloc = 0;
> #declare totalV = 0;   // size of mesh array
> #declare ycnt = 0;     // loop counter
> #while (ycnt <= (Resy*ScY))
> #declare xcnt = 0;
> #declare xloc = 0;
>    #while (xcnt <= (Resx*ScX))       // scan a horizontal line.
>
>       #if (Mask(xloc,yloc,0) > 0.08) // If it's black, less than 0.08, we
>                                      // cut it out and don't count it.
>       #declare totalV = totalV + 1;  // Count vertices to be used only.
>       #end
>
>    #declare xloc = xloc+incx;
>    #declare xcnt = xcnt+1;
>    #end
> #declare yloc = yloc+incy;
> #declare ycnt = ycnt+1;
> #end
>
> #declare Mary = array[totalV];    // vertices of mesh2 array
> #declare triang = array[totalV+totalV];
>  // represents facet making data for mesh2
>  // The size of the triang array is too large, my code must be doubling
>  // up the triangles -- no time to fix it today -- help needed here.
>
> //Step 2: Load the arrays
> #declare xloc = 0;
> #declare yloc = 0;
> #declare totalV = 0;
> #declare ycnt = 0;
> #while (ycnt <= (Resy*ScY))
> #declare xcnt = 0;
> #declare xloc = 0;
>    #while (xcnt <= (Resx*ScX)) // scan a horizontal line.
>
>       #if (Mask(xloc,yloc,0) > 0.08) // If it's black, less than 0.08, we
>                                      // cut it out and didn't count it.
>         #declare Mary[totalV] = < xloc*MsclX,
>                                   yloc*MsclY,
>                                   HFChn(xloc,yloc,0)*MsclZ
>                                 >;
>         #declare Pary[ycnt][xcnt] = totalV;
>         #declare totalV = totalV+1;
>
>       #else
>         #declare Pary[ycnt][xcnt] = -1000; // negative flag
>
>       #end //if
>
>    #declare xloc = xloc+incx;
>    #declare xcnt = xcnt+1;
>    #end //while(x)
> #declare yloc = yloc+incy;
> #declare ycnt = ycnt+1;
> #end //while(y)
>
> // * --- use something like this only if testing small, low res pictures
> #declare checkMary = union
> {
> #declare cnt = 0;
> #while (cnt < totalV)
> sphere
> { <Mary[cnt].x, Mary[cnt].y, 0> 0.83
>   texture
>    { pigment
>      { rgb <Mary[cnt].z/MsclZ, Mary[cnt].z/MsclZ, Mary[cnt].z/MsclZ>
>      }
>    }
>   finish{ambient 0.7}
> }
> #declare cnt = cnt+1;
> #end
> }
>
> object {checkMary translate <0,0,0>}
> //*/
>
>
> // Step 3: Make the triangles
> #declare totalF = 0;
> #declare ycnt = 1;
> #while (ycnt < (Resy*ScY))  //A
>    #declare xcnt = 0;
>    #while (xcnt < (Resx*ScX)) //B
>
>        #if(xcnt < (Resx-1)) // C
>        #if(Pary[ycnt][xcnt] > -10 & Pary[ycnt-1][xcnt] > -10
>             & Pary[ycnt-1][xcnt+1] > -10
>            ) // D // <y,x><y-,x><y-,x+>
>             #declare triang[totalF] =
>              < Pary[ycnt][xcnt], Pary[ycnt-1][xcnt], Pary[ycnt-1][xcnt+1]
>;
>                  // <y,x> <y-,x> <y-,x+> is a triangle with
>                  // right angle on upper right
>              #declare totalF = totalF+1;
>            #end // D
>
>            #if( Pary[ycnt][xcnt] > -10 & Pary[ycnt][xcnt+1] > -10 &
>                 Pary[ycnt-1][xcnt+1] > -10
>                 ) // E
>              #declare triang[totalF] =
>              < Pary[ycnt][xcnt], Pary[ycnt][xcnt+1], Pary[ycnt-1][xcnt+1]
>;
>                  // <y,x> <y,x+> <y-,x+> is a triangle with
>                  // right angle on lower left
>              #declare totalF = totalF+1;
>              #end // E
>
>              //----- These two triangles use another diagonal -----:
>              #if( Pary[ycnt][xcnt] > -10 & Pary[ycnt][xcnt+1] > -10 &
>                 Pary[ycnt-1][xcnt+1] < -10 & Pary[ycnt-1][xcnt] > -10
>                 ) // E
>              #declare triang[totalF] =
>              < Pary[ycnt][xcnt], Pary[ycnt][xcnt+1], Pary[ycnt-1][xcnt] >;
>              #declare totalF = totalF+1;
>              #end // E
>              // ---
>              #if( Pary[ycnt][xcnt] < -10 & Pary[ycnt][xcnt+1] > -10 &
>                 Pary[ycnt-1][xcnt+1] > -10 & Pary[ycnt-1][xcnt] > -10
>                 ) // E
>              #declare triang[totalF] =
>              < Pary[ycnt-1][xcnt+1], Pary[ycnt][xcnt+1],
Pary[ycnt-1][xcnt]
> >;
>              #declare totalF = totalF+1;
>              #end // E
>              // ---
>
>         #end // C
>
>
>    #declare xcnt = xcnt+1;
>    #end // B
> #declare ycnt = ycnt+1;
> #end // A
>
> /* ---- check the data ----
> #declare cnt = 0;
> #while (cnt < totalF)
>   cylinder
>   { Mary[triang[cnt].x], Mary[triang[cnt].y], 0.14
>     pigment {rgb <1,1,0>} finish {ambient 0.7}
>   }
>   cylinder
>   { Mary[triang[cnt].x], Mary[triang[cnt].z], 0.14
>     pigment {rgb <1,0,1>} finish {ambient 0.7}
>   }
>   cylinder
>   { Mary[triang[cnt].y], Mary[triang[cnt].z], 0.14
>     pigment {rgb <0,1,1>} finish {ambient 0.7}
>   }
> #declare cnt = cnt+1;
> #end
> */
>
>
> /*
>
//==========================================================================
>
> The meshes I need usually don't have square edges, so I've developed a
> method
> for pre-cutting the mesh. The final system will work this way:
>
> 1) Draw a picture or a few that represents a height-feild portion of the
>    mesh sculpture you wish to make. Draw it in pencil and scan at least
>    one of them as a color image.
> 2) Take the picture into a photo-paint program like Corel's Photopaint
>    and split it into red, green and blue channels.
> 3) Turn the blue channel into a mask by painting all unwanted areas black
>    and all desired areas white. This is what an #if statement above tests
>    for. If the value in the blue channel is less than 0.08 it's considered
>    black enough to cut. In the future, areas that measure above 0.08 and
>    below 0.93 might be used to describe more grey info or "undercutting."
>    Undercutting means bending the mesh back under itself.
> 4) Because a color scan of a black and white drawing doesn't really give
>    you 16 bits worth of grey scale information the .hf dot operator can
use,
>    but only 3 repeated 8 bit grey scale images, one for each color
channel,
>    a second drawing can replace either the red or green channel that the
>    height field.
> 5) Then you will import your drawing into POV-ray as done above and an as
>    yet unfinished series of macros will turn it into a "mesh sheet."
> 6) The final mesh sculpture will be made from a series of these sheets
>    that are translated, rotated, warped, bent and joined together to make
>    something more 3 dimensional.
>
> */
>
> --normdoering
>
>


Post a reply to this message

From: normdoering
Subject: Re: Phase 2: cutting a mask of height field style mesh
Date: 19 Nov 2002 07:05:05
Message: <web.3dda278e17353994cc8d8d00@news.povray.org>
Dennis Miller wrote:
>Love to see this when it is done.
>Best,
>D.

Thanks. I hope to make it very easy to use and do a lot more.

However, it's probably going to take me awhile if I can't get help here. At
present I am very stumped on the smoothing with normals. Code I am writing
just isn't working. I'll eventually figure it out reading Warp's C code and
playing with copies of the HF_ macros, but my time is limited and I can
only put in a couple hours or less a day... and not every day.

Anybody know how to do that with this kind of irregular mesh2? You can't be
as systematic as in the HF_ macros (I don't think at any rate).

Are there any good tutorials on this out there?

So far I gather I have to use vcross() and vnormalize(), something like
this:

#declare Normz[cnt] = vnormalize
 ( vcross
   (  Mary[triang[cnt].y].x - Mary[triang[cnt].x].x, //vector 1
      Mary[triang[cnt].y].y - Mary[triang[cnt].x].y,
      Mary[triang[cnt].y].z - Mary[triang[cnt].x].z,

      Mary[triang[cnt].z].x - Mary[triang[cnt].x].x, //vector 2
      Mary[triang[cnt].z].y - Mary[triang[cnt].x].y,
      Mary[triang[cnt].z].z - Mary[triang[cnt].x].z
    )
  );


--normdoering

PS - and why does text disappear when you place it between angle brackets? I
removed them from above code.


Post a reply to this message

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