POV-Ray : Newsgroups : povray.general : Constructing isosurface functions Server Time
29 Dec 2024 13:33:26 EST (-0500)
  Constructing isosurface functions (Message 1 to 10 of 11)  
Goto Latest 10 Messages Next 1 Messages >>>
From: David Given
Subject: Constructing isosurface functions
Date: 14 Jul 2011 19:28:45
Message: <4e1f7bad$1@news.povray.org>
I wish to do some stupidly complicated things with isosurfaces. Does
anyone have a set of rules (or even a library) for manipulating isosurfaces?

The kind of thing I'm looking for is to be able to take a shape f(x, y,
z) and then produce another function that, when rendered, produces many
shapes distributed according to another function.

I have found this very useful page:

http://www.econym.demon.co.uk/isotut/combine.htm

It looks like the standard way to union two shapes in an isosurface is
to use min(), so min(f(x, y, z), f(x', y', z')). However, I need to
union an arbitrary number of functions so can't do it by brute force,
and min() is not very conducive to mathematical analysis...

The exact use case is: I am trying to place a very large number of
objects on a terrain. I can describe one object as an isosurface, but
the number of objects is so high that I can't model them as CSG. So, I
need to be able to create a single isosurface that will model all my
objects in one go.

Is this kind of thing feasible?

-- 
┌─── dg@cowlark.com ─────
http://www.cowlark.com ─────
│
│ "I have a mind like a steel trap. It's rusty and full of dead mice."
│ --- Anonymous, on rasfc


Post a reply to this message

From: Alain
Subject: Re: Constructing isosurface functions
Date: 15 Jul 2011 10:55:08
Message: <4e2054cc@news.povray.org>
Le 2011/07/14 19:28, David Given a écrit :
> I wish to do some stupidly complicated things with isosurfaces. Does
> anyone have a set of rules (or even a library) for manipulating isosurfaces?
>
> The kind of thing I'm looking for is to be able to take a shape f(x, y,
> z) and then produce another function that, when rendered, produces many
> shapes distributed according to another function.
>
> I have found this very useful page:
>
> http://www.econym.demon.co.uk/isotut/combine.htm
>
> It looks like the standard way to union two shapes in an isosurface is
> to use min(), so min(f(x, y, z), f(x', y', z')). However, I need to
> union an arbitrary number of functions so can't do it by brute force,
> and min() is not very conducive to mathematical analysis...
>
> The exact use case is: I am trying to place a very large number of
> objects on a terrain. I can describe one object as an isosurface, but
> the number of objects is so high that I can't model them as CSG. So, I
> need to be able to create a single isosurface that will model all my
> objects in one go.
>
> Is this kind of thing feasible?
>

Strictly speaking, it's feasible. You only need to use tons of min(...). 
Keep in mind that there is a limit on how many function you can nest 
this way.

Practical, is another thing. It will be extremely slow as you need to 
evaluate each and every function for every test points, several per 
pixel within the container shape.
It also mean that your final "function" will be helplessly complicated.

If you have a very large number of similar objects, it's probably beter 
to make it as a mesh object and instanciate it as needed. Prety fast and 
light on memory requirement.

A single function can produce an extremely large number of individual 
shapes, but those shapes are rather simple. Also fast and light on 
memory. You can use another function to modify the distribution and shapes.

As you already have your basic isosurface, you can use it multiple times 
and rotate / scale / translate it as any other object.
Use a #while()...#end loop to iterate the process and the trace() 
function to place them on the surface of your terrain. A loop can be 
used to place 10000's of objects. If you have enough memory, on a 64 
bits system, it can shoot in the millions of objects.
The advantage is that each object will have it's own container and won't 
affect the evaluation of the others.



Alain


Post a reply to this message

From: Roman Reiner
Subject: Re: Constructing isosurface functions
Date: 15 Jul 2011 11:25:00
Message: <web.4e205ba8f8af7d509211d7b00@news.povray.org>
David Given <dg### [at] cowlarkcom> wrote:
> but the number of objects is so high that I can't model them as CSG.

In that case you surely wouldn't want to use isosurfaces!


Post a reply to this message

From: Christian Froeschlin
Subject: Re: Constructing isosurface functions
Date: 15 Jul 2011 16:05:20
Message: <4e209d80@news.povray.org>
> The exact use case is: I am trying to place a very large number of
> objects on a terrain. I can describe one object as an isosurface, but
> the number of objects is so high that I can't model them as CSG. So, I
> need to be able to create a single isosurface that will model all my
> objects in one go.
> 
> Is this kind of thing feasible?

It depends whether you can express the placement pattern with
a simple function. Generating millions of min and selects will
make the result much slower than using object copies. On the other
hand, a function that has a periodicity can be used to multiply
object instances. For example, here's a million object copies
placed in a grid that renders reasonably fast:

#declare f_obj  = function(x,y,z) {f_sphere(x,y,z,0.05)}

#declare f_grid = function(x,y,z) {f_obj(sin(x*10)/10,y,sin(z*10)/10)}

isosurface
{
   function { f_grid(x,y,z) }
   contained_by { box {<-50,0,0>,<50,1,100>} }
   accuracy 0.001
   max_gradient 1
   pigment {color White}
}

Randomizing locations with f_noise3d and the likes without
deforming the objects will be tricky, although its probably
possible by discretizing the noise (modulo, rounding?) so
it will be constant around the domain of your object.


Post a reply to this message

From: Christian Froeschlin
Subject: Re: Constructing isosurface functions
Date: 15 Jul 2011 16:36:28
Message: <4e20a4cc$1@news.povray.org>
After seeing the animation in p.b.a, you can of course
try to generate interesting structure by exploiting pattern
functions based, e.g. on crackle.

Here is a sample how you can wrap a pattern around a sphere
and control locations where it should appear:


// This basically defines a repeating pattern
// of spherical cones wrapped around a sphere
#declare f_obj_depth = function
{
   pattern
   {
     spherical
     translate 1
     warp {repeat 2*x} warp {repeat 2*y}
     scale <0.005,0.005,1>
     warp {spherical dist_exp 0}
   }
}

// Some sort of bozo continents
#declare f_placement = function
{
   pattern
   {
     bozo
     translate 1
     scale <0.1,0.1,1>
     warp {spherical dist_exp 0}
   }
}

#declare f_placement_clipped = function
{
   select(f_placement(x,y,z)-0.5,0,2*f_placement(x,y,z)-1)
}

#declare f_planet  = function(x,y,z)
{
   f_sphere(x,y,z,1+0.04*f_placement_clipped(x,y,z)*f_obj_depth(x,y,z))
}

isosurface
{
   function { f_planet(x,y,z) }
   contained_by { box {<-2,0,-2>,<2,2,2>} }
   accuracy 0.001
   max_gradient 2
   pigment {color White}
   scale 2
}


Post a reply to this message

From: David Given
Subject: Re: Constructing isosurface functions
Date: 15 Jul 2011 17:32:38
Message: <4e20b1f6$1@news.povray.org>
On 15/07/11 21:05, Christian Froeschlin wrote:
[...]
> It depends whether you can express the placement pattern with
> a simple function. Generating millions of min and selects will
> make the result much slower than using object copies. On the other
> hand, a function that has a periodicity can be used to multiply
> object instances. For example, here's a million object copies
> placed in a grid that renders reasonably fast:

Yes, precisely!

(I'm particularly impressed by this image:

http://news.povray.org/povray.binaries.images/attachment/%3C47ec0047%40news.povray.org%3E/isocity-part.jpg?ttop=333517&toff=800

...which demonstrates what you can do with isosurfaces. Alas, I haven't
found source for that one...)

What I've got are two massive heightfield images that contain
displacement and distribution density. I want to randomly place my
objects on the terrain, at the correct height for the terrain,
distributed according to the density. Just to make life more
interesting, my terrain is spherical. (Yes, it's a planet.)

[...]
> #declare f_grid = function(x,y,z) {f_obj(sin(x*10)/10,y,sin(z*10)/10)}

This is just the kind of thing I'm looking for. Except... how does it
work? I know that y=sin(x) repeatedly crosses the X axis, so I assume
you're using this to control the location of the balls, but I'll admit
that I have trouble with the bizarrely reverse thinking needed to
understand isosurfaces.

For example, if I replacing the sin(x) with mod(x, 2)-1 then I get the
same result... but now I only get half the balls, and those balls have
in turn been halved. Given that mod(x, 2)-1 and sin(x) both return
values in the domain [-1..1] I'm slightly confused by this.

-- 
┌─── dg@cowlark.com ─────
http://www.cowlark.com ─────
│
│ "I have a mind like a steel trap. It's rusty and full of dead mice."
│ --- Anonymous, on rasfc


Post a reply to this message

From: Christian Froeschlin
Subject: Re: Constructing isosurface functions
Date: 16 Jul 2011 09:48:05
Message: <4e219695@news.povray.org>
David Given wrote:

> ...which demonstrates what you can do with isosurfaces. Alas, I haven't
> found source for that one...)

I made a less impressive cityscape here:

http://news.povray.org/povray.binaries.images/thread/%3C4a358a3b@news.povray.org%3E/?ttop=341111&toff=300

I wasn't too happy with it but the height function is just:

#local f_cells = function {pattern {cells}}

#local f_base  = function {pattern {hexagon rotate 90*x scale 0.005 
turbulence 0.5}}

#local f_scape = function(x,y,z)
{
   0.6* f_cells(x*30,y*30,z*30) *
   select( f_base(x,y,z)-0.2, 0, 1.0)
}

The scene used a height_field but an isosurface should also work.

The windows are just texture (using slope pattern you can give
different textures to vertical walls).

> For example, if I replacing the sin(x) with mod(x, 2)-1 then I get the
> same result... but now I only get half the balls, and those balls have
> in turn been halved. Given that mod(x, 2)-1 and sin(x) both return
> values in the domain [-1..1] I'm slightly confused by this.

The problem with mod is that returns negative fractions for
negative numbers so your expression actually returns values
in the domain [-3,-1] for negative x. That's why half of the
balls are missing. You can use abs(mod(x,2))-1.

But I didn't see the ball halving problem. Note that the
lower part of the spheres was missing in my example due to
the contained_by clipping at the y=0 plane.

Also I shied away from using mod because it has undefined
gradient at the boundaries that may or may not be a problem
for the isosurface rendering later. Of course, it probably
evaluates faster than sin.


Post a reply to this message

From: David Given
Subject: Re: Constructing isosurface functions
Date: 16 Jul 2011 18:09:21
Message: <4e220c11@news.povray.org>
On 16/07/11 14:47, Christian Froeschlin wrote:
[...]
> The problem with mod is that returns negative fractions for
> negative numbers so your expression actually returns values
> in the domain [-3,-1] for negative x. That's why half of the
> balls are missing. You can use abs(mod(x,2))-1.

Yes, of course. (That works fine.)

> But I didn't see the ball halving problem. Note that the
> lower part of the spheres was missing in my example due to
> the contained_by clipping at the y=0 plane.

Yes, this was it; I had failed to notice the clipping in your original.

I appear to be totally failing to get my head around the way these work;
I can look at a function and (eventually) figure out why it's producing
the result it is, but I can't figure out what function I need to produce
the result.

Here's a fascinatingly failed attempt to perturb the spheres into random
locations:

http://twitpic.com/5r9ejh/full

#declare f_obj  = function(x,y,z) {f_sphere(x,y,z,0.05)}
#declare f_grid = function(x,y,z) {f_obj(2*f_noise3d(x, y, z)-1, y,
2*f_noise3d(x, y, z)-1)}

Which is cool, and an effect worth remembering, but not what I was
looking for.

I've been having a look at pigment functions instead; as I can think
about these in a forwards direction I'm having better luck. I can create
a perturbed terrain that's just below my planet's surface which sticks
out above at particular points. Given that my trees are only going to be
viewed from a distance, extended ovoids will do fine, and something like
crackle would help here.

This just gives me the problem of how to try and vary the density of
trees according to some external function (probably going to be a
heightmap lookup table combined with random noise). This requires me to
make my crackle lumps get closer or further apart from each other. So
far this is evading me...

Here's another interesting image I managed to generate:

http://twitpic.com/5r29s1/full

The isosurface that's modelling the spheres is, more or less:

  terrain - 10m + leopard(x, y, z)

Leopard produces a rectilinear grid of blobs, and right now the camera's
at about 20⁰N, so you can see the lines are all slanted. (Life would be
so, *so* much easier if planets were flat.) The blobs are all about 100m
across, and I hate to think how many of them are visible in that image.

-- 
┌─── dg@cowlark.com ─────
http://www.cowlark.com ─────
│
│ "I have a mind like a steel trap. It's rusty and full of dead mice."
│ --- Anonymous, on rasfc


Post a reply to this message

From: Christian Froeschlin
Subject: Re: Constructing isosurface functions
Date: 17 Jul 2011 08:01:40
Message: <4e22cf24@news.povray.org>
David Given wrote:

> Here's a fascinatingly failed attempt to perturb the spheres into random
> locations:

well the reason I said that was tricky is because I didn't
see the solution either ;) Basically you need a noise function
that is constant over intervals, such as cells, but then marry
it to the periodic function in such a way that the jumps will
never split an object.

> Which is cool, and an effect worth remembering, but not what I was
> looking for.

Just say that alien vines took off in low gravity.

> This just gives me the problem of how to try and vary the density of
> trees according to some external function.

If you don't mind that some of your objects get partially
removed you can do something like

#local f_base  = function {pattern {hexagon rotate 90*x scale 0.005}}
#local f_scape = function(x,y,z)
{
   select(
     // Large scale density distribution
     f_bozo(x*10,y*10,z*10) *
     // Small scale nulling pattern (but still > object scale)
     f_bozo(x*40,y*40,z*40)-0.2, 1.0, 0.0
     ) *
   // Base pattern that get's nulled by density
   select(f_base(x,y,z)-0.2, 1.0, 0.0)
}

It's probably not so bad for distant geometry. You could also
replace the first 0.0 by a linear interpolation from 1.0 to 0.0
depending on the bozo values to avoid hard vertical cutoffs.

> Life would be so, *so* much easier if planets were flat.

Note the use of warp {spherical} in the spiked planet example
I posted here earlier, it might help for some cases.


Post a reply to this message

From: David Given
Subject: Re: Constructing isosurface functions
Date: 17 Jul 2011 20:00:49
Message: <4e2377b1$1@news.povray.org>
On 17/07/11 13:01, Christian Froeschlin wrote:
[...]
> well the reason I said that was tricky is because I didn't
> see the solution either ;) Basically you need a noise function
> that is constant over intervals, such as cells, but then marry
> it to the periodic function in such a way that the jumps will
> never split an object.

I managed radial spikes by using a bumps in polar coordinates, using a
colormap to take only the very tips, and then stretchin infinitely in
the r direction; after much fiddling I managed to clip it at 200m above
the terrain (big trees). The results look promising:

http://twitpic.com/5rt3z5/full

...but in order to make it render at all I had to use max_gradient of
1e5 and accuracy of 1e-3. As a result that measly, non-antialiased,
non-radiosity, 320x240 image took 3 hours 45 minutes to render. That's
not a success, to my mind.

My actual isosurface function is:

#local Spikes_Density = 64000;
#local Tree_Height = 0.2;
#local Spikes =
  function
  {
    max(
      f_bumps(f_th(x, y, z)*Spikes_Density, 0, f_ph(x, y,
z)*Spikes_Density) - 0.2,
      f_r(x, y, z) - (1+Tree_Height*km)*Moon_Altitude(x, y, z)/Lunar_Sphere
    )
  }

(Lunar_Sphere is the radius of my terrain isosurface container. km is a
scaling factor mapping from kilometres to 0..1 radius of that container.)

No doubt the function could be hugely improved --- using a pigment
rather than doing it in code would probably be faster --- but I suspect
the real pain is just because my isosurface is so insanely complicated
and so *huge*. The floating balls image I posted early had much smaller
gradients.

Are there any alternate approaches that are plausible? Could I achieve a
similar effect using a media density function, for example?

[...]
> Note the use of warp {spherical} in the spiked planet example
> I posted here earlier, it might help for some cases.

The big problem I have with spherical warps (and manual polar coordinate
conversions as above) is the distortion I get around the poles. There
must be a function somewhere that produces random spikes radiating out
from a centre; can't find it, though...

-- 
┌─── dg@cowlark.com ─────
http://www.cowlark.com ─────
│
│ "I have a mind like a steel trap. It's rusty and full of dead mice."
│ --- Anonymous, on rasfc


Post a reply to this message

Goto Latest 10 Messages Next 1 Messages >>>

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