POV-Ray : Newsgroups : povray.advanced-users : Isosurface threshold 0..1 : Re: Isosurface threshold 0..1 Server Time
23 Apr 2024 08:11:03 EDT (-0400)
  Re: Isosurface threshold 0..1  
From: clipka
Date: 23 Nov 2016 20:52:29
Message: <583647dd$1@news.povray.org>
Am 24.11.2016 um 01:27 schrieb Mike Horvath:
> On 11/23/2016 7:22 PM, Christian Froeschlin wrote:
>> No threshold will give the desired result using the color
>> conversion function directly, as clipka explained you need
>> a define a "distance" function for this purpose.
>>
>> Alternatively you could try to render the clipped function
>> (set to 0 outside the gamut) as strongly scattering media but
>> it may be fiddly and you don't get the look of a "surface"
>> regarding finish and lighting etc.
>>
> 
> What is a "distance" function?
> 
> The "convertLCH2RGBb2(y*100,sqrt(x*x+z*z)*100,atan2d(x,z))" bit is what
> clipka showed me.

You may need to deconstruct the problem into easy-to-handle building
blocks, and tackle each of them separately.

One building block you need is a function that maps a single RGB colour
component to a distance-ish scalar telling you how "far away" the colour
component is from the valid range (this time, just for giggles, I'm
contructing the function in such a way that <0 is inside, >0 is outside):

    #declare fD = function(C) { abs(C-0.5)-0.5 }

Another building block you need is a function that combines three such
distance-ish scalars, such that you get a positive value if one or more
parameters is positive, or a negative value if all are negative, in a
manner that avoid steps:

    #declare fDist = function(Dr,Dg,Db) { max(Dr,Dg,Db) }


That's kind of all you need to know about the "distance" functions;
however, those functions alone don't get you anywhere.


Another necessary building block is a set of functions that map Lch to RGB:

    #declare fR = function(L,c,h) { ... }
    #declare fG = function(L,c,h) { ... }
    #declare fB = function(L,c,h) { ... }

And the final building block is a set of functions that map 3D cartesian
space to Lch:

    #declare fL = function(x,y,z) { y*100 }
    #declare fc = function(x,y,z) { sqrt(x*x+z*z)*100 }
    #declare fh = function(x,y,z) { atan2d(x,z) }


Once you have all these building blocks, all that's left is to plug them
all together.

The final result to be compared to the threshold by the isosurface is
the result of the `fDist` function, so that's where you start:

    isosurface {
      threshold 0
      function { fDist (Dr,Dg,Db) }
    }

The isosurface doesn't know what `Dr`, `Dg` and `Db` are, but we know
they are supposed to be results of the `fD` function, using the three
colour channels as input:

    isosurface {
      threshold 0
      function { fDist (
        fD (R),
        fD (G),
        fD (B)
      ) }
    }

Again the isosurface doesn't know `R`, `G` and `B`:

    isosurface {
      threshold 0
      function { fDist (
        fD ( fR (L,c,h) ),
        fD ( fG (L,c,h) ),
        fD ( fB (L,c,h) )
      ) }
    }

Still not done yet, as the isosurface doesn't know `L`, `c` and `h` either:

    isosurface {
      threshold 0
      function { fDist (
        fD ( fR (fL(x,y,z),fc(x,y,z),fh(x,y,z)) ),
        fD ( fG (fL(x,y,z),fc(x,y,z),fh(x,y,z)) ),
        fD ( fB (fL(x,y,z),fc(x,y,z),fh(x,y,z)) )
      ) }
    }

Now we have only `x`, `y` and `z` left as parameters, which is what the
isosurface can handle.


For bonus points, you could eliminate the multiple invocation of
`fL(x,y,z)`, `fc(x,y,z)` and `fh(x,y,z)`. To this end, you need to
provide a function that does not compute these values itself, but rather
takes them as parameters:

    #declare fFinal = function(L,c,h) { fDist (
      fD ( fR (L,c,h) ),
      fD ( fG (L,c,h) ),
      fD ( fB (L,c,h) )
    ) }

    isosurface {
      threshold 0
      function { fFinal (fL(x,y,z),fc(x,y,z),fh(x,y,z)) }
    }


And of course you'll want to use different names; I chose the above for
brevity.


Post a reply to this message

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