POV-Ray : Newsgroups : povray.unofficial.patches : Question about applying a user defined function into density functions : Question about applying a user defined function into density functions Server Time
28 Apr 2024 15:47:06 EDT (-0400)
  Question about applying a user defined function into density functions  
From: Antonio Ferrari
Date: 5 Oct 2007 09:30:00
Message: <web.47063b40f8b04a964e64f15d0@news.povray.org>
I'd like that the density is a function
of the minimal distance of V from the external surface of O: for V internal,
density[V] = density_function(minimal_distance(O,V)). In particular I'd like
a function the make the density greater when moving toward the interior of
O, where the increment could be linear, exponential, logarithmic, etc.

Is there a function for calculating the minimal distance of an internal
point V from the contour of O?

Some time ago I had the following idea: calculating the dimensions X, Y and
Z of the box containing O. Subdivide both X, Y and Z into n segments. Use
of 3 innested loops for x, y and z axis in order to cycle the segments and
see if the are or are not part of the interior of O. This is a sort of
sampling method. The greater n is, the more accurate the samples are. Then
I needed an algorithm for finding interior points at first level,
second level, third level, etc. The greater the level, the higher the
density, for example.

Let suppose that the intersection of the object with a plane is (in 2D) as
follows:

  @@@@@@@@@
 @         @
@           @
@           @
 @         @
  @@@@@@@@@

Let's do our considerations in 2D, but they can be extended in 3D easily.

  @@@@@@@@@
 @111111111@
@12222222221@
@123333333321@
@12222222221@
 @111111111@
  @@@@@@@@@

What I'd want isn't a generic Your_Function with parameters x, y or z. What
I want is a density function with only a parameter d, where d is the
distance of the vector V=<x,y,z> from the contour of the surface, V inside
the object. It's obvious that there are some preconditions to impose...

Look at the 2D section... Let's consider a linear density function.
Your_Function conincide with the distance. So, for point at distance 1,
density is 1; for points at distance 2, density is 2; and so on...........


NOW Tim have suggested another an interesting idea... follow his answer:

"Tim Attwood" <tim### [at] comcastnet> wrote:
> There isn't a built in function for this, because there isn't a single
> answer
> to how far a minimal distance point is from the surface. You can use
> trace to collect a sample of distances from the surface in random
> directions to appoximate the minimal distance of a voxel from the
> surface.
>
> #include "rand.inc"
> #macro distToSurface(Obj, vec, samp, rsd)
>    #local dist = 1000000;
>    #local c=0;
>    #while (c<samp)
>       #local rdir = VRand_On_Sphere(rsd);
>       #declare Norm = <0, 0, 0>;
>       #local hit = trace(Obj, vec, rdir, Norm);
>       #if (vlength(Norm) != 0)
>          #local dist = min(dist, vlength(hit - vec));
>       #end
>       #local c=c+1;
>    #end
> #end

Inspired by this macro I've tried to write a patch in order to "cable" it
into source code. So, I've modified express.cpp and I've added a new token
similar to TRACE_TOKEN. Substancially I've added the function "mdistance"
that takes four parameters:

mdistance(OBJECT_IDENTIFIER, V, nr_samples, [VECTOR_IDENTIFIER])

Parameters are:

- An object ID
- A vector V
- samples is an integer greater than 0
- VECTOR_IDENTIFIER is an optional vector ID

What the function do: it generates nr_samples in random directions trying to
find the minimal distance of the point V from the surface of the Object. At
every iteration uses the code of trace and vlength function for calculating
the distance from the Object. At the end it returns the minimal distance. If
a vector_identifier is given, the point on the surface with minimal distance
from V is stored into it.

What TO DO:

1 - Check if V is inside or outside the object -> if outside, always returns
0;
2 - Improve random number generator
3 - Add some optimization passes. At first step a rough minimal distance is
found; at second step further rays are traced in a space closed to what is
found at step 1.
4 - Some check, for some particular / complex objects (I dont't know how to
do it...)

I haven't tested the code yet, because I'm out of Linux and with Cygwin I've
no time to play.

Now my question: could such a function be used in density functions? For
example could I write a density function like A+B*mdistance(x, y, z)^C,
with A, B, C real values ????

If such a function would work, I'd have found a method for calculating the
density as a function of the (minimal) distance of a point from the
surface. This could help me to better USE medias BETTER for having
subsurface scattering results...

If the function can't be used, I'll have to find other solutions or
pathes...


static void Parse_MDistance(DBL & mdist) {

   OBJECT *Object;
   INTERSECTION Intersect;
   RAY    Ray;
   VECTOR Local_Normal;
   VECTOR Res;

   GET (LEFT_PAREN_TOKEN);

   EXPECT
     CASE (OBJECT_ID_TOKEN)
       Object = (OBJECT *)Token.Data;
       EXIT
     END_CASE

     OTHERWISE
       Object = NULL;
       UNGET
       EXIT
     END_CASE
   END_EXPECT

   if (Object == NULL) Error ("Object identifier expected.");

   Parse_Comma();

   Initialize_Ray_Containers( &Ray );
   Parse_Vector(Ray.Initial);
   Parse_Comma();
   int nr_iterations = (int)Parse_Float();
   if (nr_iterations < 1) nr_iterations = 1; // 1 or a greater value ??

   srand( (unsigned int)time(0) );
   mdist = 999999; // how much big ??
   VECTOR MVect;

   for (int itr = 0; itr < nr_iterations; itr = itr + 1) {

  Ray.Direction[X]=((DBL)rand()/INT_MAX)-0.5; // is there a better random
generator (srad48, etc.) ??
  Ray.Direction[Y]=((DBL)rand()/INT_MAX)-0.5;
 Ray.Direction[Z]=((DBL)rand()/INT_MAX)-0.5;
 VNormalizeEq( Ray.Direction );

 VECTOR normal_vector;
 normal_vector[X]=0.0;
 normal_vector[Y]=0.0;
  normal_vector[Z]=0.0;

 if ( Intersection( &Intersect, Object, &Ray ) ) {
        Assign_Vector( Res, Intersect.IPoint );
        Normal( Local_Normal, Intersect.Object, &Intersect );
  }
  else {
        Res[X]=Res[Y]=Res[Z]=0;
        Local_Normal[X] = Local_Normal[Y] = Local_Normal[Z] = 0;
  }

 Destroy_IStacks(); // this line here or out of FOR cycle ????

  if ( sqrt(Local_Normal[X] * Local_Normal[X] + Local_Normal[Y] *
Local_Normal[Y] + Local_Normal[Z] * Local_Normal[Z]) != 0 ) {
     VECTOR vect2;
     vect2[X] = Res[X] - Ray.Initial[X];
     vect2[Y] = Res[Y] - Ray.Initial[Y];
     vect2[Z] = Res[Z] - Ray.Initial[Z];
     DBL vl = sqrt(vect2[X] * vect2[X] + vect2[Y] * vect2[Y] + vect2[Z] *
vect2[Z]);
            if ( vl < mdist) {
               mdist = vl;
              MVect[X] = Res[X];
              MVect[Y] = Res[Y];
              MVect[Z] = Res[Z];
           }
     }

  }

  EXPECT
     CASE (VECTOR_FUNCT_TOKEN)
       /* All of these functions return a VECTOR result */
       if(Token.Function_Id == VECTOR_ID_TOKEN)
       {
         Assign_Vector((DBL *)Token.Data, MVect);
       }
       else
       {
         UNGET
       }
       EXIT
     END_CASE

     OTHERWISE
       UNGET
       EXIT
     END_CASE
  END_EXPECT

  GET (RIGHT_PAREN_TOKEN);

}



Bye,
Antonio Ferrari


Post a reply to this message

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