|
|
|
|
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 11/23/2016 8:51 PM, clipka wrote:
> 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.
>
Next issue: What is the best way to create an accurate pigment to paint
the isosurface?
I was thinking of repurposing the following:
//------------------------------
// HSL Cylinder
#declare CSolid_HSLCylinder_Hue = pigment
{
function {-f_th(x,y,z)/pi/2}
color_map
{
// need to replace these with calls to CHSL2RGB() or CH2RGB(), then
increase the number of steps
[0/6 srgb <1,0,0,>]
[1/6 srgb <1,1,0,>]
[2/6 srgb <0,1,0,>]
[3/6 srgb <0,1,1,>]
[4/6 srgb <0,0,1,>]
[5/6 srgb <1,0,1,>]
[6/6 srgb <1,0,0,>]
}
}
#declare CSolid_HSLCylinder_Saturation = pigment
{
cylindrical
pigment_map
{
[0 CSolid_HSLCylinder_Hue]
[1 color srgb 1/2]
}
scale (1 + CSolid_Offset)
}
#declare CSolid_HSLCylinder_Lightness = pigment
{
gradient y
pigment_map
{
[0/2 color srgb 0]
[1/2 CSolid_HSLCylinder_Saturation]
[2/2 color srgb 1]
}
scale (1 + CSolid_Offset)
translate -y * CSolid_Offset/2
}
#declare CSolid_HSLCylinder_Pigment = pigment {CSolid_HSLCylinder_Lightness}
Except, in this case using LCH conversion formula to create the gradients:
[0/6 srgb <convertLCH2RGBb1(50, 50, 0),convertLCH2RGBb2(50, 50,
0),convertLCH2RGBb3(50, 50, 0)>]
[1/6 srgb <convertLCH2RGBb1(50, 50, 60),convertLCH2RGBb2(50, 50,
60),convertLCH2RGBb3(50, 50, 60)>]
[2/6 srgb <convertLCH2RGBb1(50, 50, 120),convertLCH2RGBb2(50, 50,
120),convertLCH2RGBb3(50, 50, 120)>]
[3/6 srgb <convertLCH2RGBb1(50, 50, 180),convertLCH2RGBb2(50, 50,
180),convertLCH2RGBb3(50, 50, 180)>]
[4/6 srgb <convertLCH2RGBb1(50, 50, 240),convertLCH2RGBb2(50, 50,
240),convertLCH2RGBb3(50, 50, 240)>]
[5/6 srgb <convertLCH2RGBb1(50, 50, 300),convertLCH2RGBb2(50, 50,
300),convertLCH2RGBb3(50, 50, 300)>]
[6/6 srgb <convertLCH2RGBb1(50, 50, 360),convertLCH2RGBb2(50, 50,
360),convertLCH2RGBb3(50, 50, 360)>]
Is this maybe a bad idea?
Mike
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 11/24/2016 2:07 PM, Mike Horvath wrote:
> On 11/23/2016 8:51 PM, clipka wrote:
>> 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.
>>
>
> Next issue: What is the best way to create an accurate pigment to paint
> the isosurface?
>
> I was thinking of repurposing the following:
>
> //------------------------------
> // HSL Cylinder
>
> #declare CSolid_HSLCylinder_Hue = pigment
> {
> function {-f_th(x,y,z)/pi/2}
> color_map
> {
> // need to replace these with calls to CHSL2RGB() or CH2RGB(),
> then increase the number of steps
> [0/6 srgb <1,0,0,>]
> [1/6 srgb <1,1,0,>]
> [2/6 srgb <0,1,0,>]
> [3/6 srgb <0,1,1,>]
> [4/6 srgb <0,0,1,>]
> [5/6 srgb <1,0,1,>]
> [6/6 srgb <1,0,0,>]
> }
> }
> #declare CSolid_HSLCylinder_Saturation = pigment
> {
> cylindrical
> pigment_map
> {
> [0 CSolid_HSLCylinder_Hue]
> [1 color srgb 1/2]
> }
> scale (1 + CSolid_Offset)
> }
> #declare CSolid_HSLCylinder_Lightness = pigment
> {
> gradient y
> pigment_map
> {
> [0/2 color srgb 0]
> [1/2 CSolid_HSLCylinder_Saturation]
> [2/2 color srgb 1]
> }
> scale (1 + CSolid_Offset)
> translate -y * CSolid_Offset/2
> }
> #declare CSolid_HSLCylinder_Pigment = pigment
> {CSolid_HSLCylinder_Lightness}
>
> Except, in this case using LCH conversion formula to create the gradients:
>
> [0/6 srgb <convertLCH2RGBb1(50, 50, 0),convertLCH2RGBb2(50, 50,
> 0),convertLCH2RGBb3(50, 50, 0)>]
> [1/6 srgb <convertLCH2RGBb1(50, 50, 60),convertLCH2RGBb2(50, 50,
> 60),convertLCH2RGBb3(50, 50, 60)>]
> [2/6 srgb <convertLCH2RGBb1(50, 50, 120),convertLCH2RGBb2(50, 50,
> 120),convertLCH2RGBb3(50, 50, 120)>]
> [3/6 srgb <convertLCH2RGBb1(50, 50, 180),convertLCH2RGBb2(50, 50,
> 180),convertLCH2RGBb3(50, 50, 180)>]
> [4/6 srgb <convertLCH2RGBb1(50, 50, 240),convertLCH2RGBb2(50, 50,
> 240),convertLCH2RGBb3(50, 50, 240)>]
> [5/6 srgb <convertLCH2RGBb1(50, 50, 300),convertLCH2RGBb2(50, 50,
> 300),convertLCH2RGBb3(50, 50, 300)>]
> [6/6 srgb <convertLCH2RGBb1(50, 50, 360),convertLCH2RGBb2(50, 50,
> 360),convertLCH2RGBb3(50, 50, 360)>]
>
>
> Is this maybe a bad idea?
>
> Mike
Disregard. I will ask this in the proper thread.
Mike
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
|
|