|
![](/i/fill.gif) |
The most difficult part of this post was in coming up with an appropriate title!
OBJECTS AS AIRBRUSH 'PAINT'?
'SPRAYING' OBJECTS THROUGH A SOFT-EDGED MASK, USING TRACE?
I've been trying to come up with a TRACE technique that would allow actual
objects to be 'shot' through a soft-edged mask--like airbrushing through a
frisket, but with objects as the 'paint'-- lots-of-objects 'fading out' to
no-objects, depending on some kind of blurriness factor (for example, a blurry
image_map.) I've seen POV renders in the past that may have used some kind of
similar 'fuzzy' effect--patches of grass and flowers come to mind-- but I
haven't been able to find any reference to such a technique.
A HARD-edged tracing mask can easily be made by shooting trace rays through a
height_field (on their way to another traced object); the HF has "holes" cut
into it using water_level, and some appropriate code to eliminate trace 'hits'
on the solid parts of the HF. But even if the HF's original image_map details
are blurry, the holes are still sharp-edged...as would be expected, using
water_level.
SO...I finally came up with a 'soft-edged' masking trick that is quite
simple--basically just a single line of code! It uses a height_field as well
(full-scale and made from a blurry image_map), but no water_level or holes.
This is traced in the usual way, but the y-values that are found are not used
to place objects anywhere; rather, they are used to statistically(?) determine
whether an object is made or not made at any particular x/z location...a sort
of 'chance' determination, with a HF height of 0 being a zero% chance that an
object is made, up to 1 being a 100% chance.
Here's a simple demonstration, using lots of small spheres as the 'sprayed-on'
objects (intersexion.y is the height found at any point on the masking HF):
#declare mask =
height_field{jpeg "my blurry image.jpeg"} // this is never seen, just used as a
// tracing object
#declare S1 = seed(6756);
#declare S2 = seed(704);
#declare counter = 1;
union{
#while(counter <= 150000) // many of these objects will not be made
#declare trace_position =
<rand(S1), 10, rand(S1)>; // origin of the trace rays; a 1 X 1
// random grid, to match HF dimensions
#declare intersexion =
trace(mask,trace_position, <0,-1,0>) // no norm used here, to keep things simple
#if(rand(S2) <= intersexion.y) // This is the KEY! If *true* a sphere is made.
sphere{0, .001 translate <intersexion.x,0,intersexion.z> // the many small
// spheres
#else // make NO sphere
#end
#declare counter = counter + 1;
#end
pigment{....}
}
How this works: If intersexion.y is, say, .2--corresponding to a low point on
the HF and a relatively dark pixel in the blurry image_map--and if rand(S2) has
an equal chance of being *anywhere* between 0 and 1 (which it does), then there
is only a 20% chance that rand(S2) will be <= .2, and thus only a 20% chance of
an object being made in that case. (Said another way: If rand(S2) is greater
than .2, no object is made.) If intersexion.y is .9999--representing a very
high point on the HF and a bright pixel in the image_map--then rand(S2) has a
99.99% chance of being at or below that value...meaning that an object WILL be
made, no question. Taken as a whole, the code thins out the number of objects
in the 'blur zone'--more objects in brighter areas, less in darker areas. The
result looks like objects sprayed through an airbrush!
For everything to work as-expected, the blurry image_map grayscale values need
to go from pure black to pure white, so that the resulting traced y-values of
the HF go reliably from 0 to 1. (BTW, "smooth" doesn't have any effect on a HF
when tracing it--that's purely a lighting trick based on normals.) Changing <=
in the code to >= has the effect of inverting the image_map's grayscale
values...resulting in MORE objects in the dark areas, LESS in the bright areas.
In my simple image example, the tiny spheres are just placed on a flat box. But
the found <x,y,z> values (ignoring y this time) could also be used to re-trace
the spheres onto another, *visible* HF...a two-step tracing process, with the
2nd trace finding the actual heights at which to place them. Some ideas come to
mind: A volumetric galaxy, with the stars thinning out near the edges; trees on
a mountain that thin out as the elevation increases; pebbles on a seashore.
The original y-values can be used for many other things, of course--the scale of
the objects, their colors, a choice between many different objects, etc. etc.
I typically use Photoshop--with its Gaussian Blur filter--to create blurred
image_maps. But Gaussian Blur creates a "linear" blur (for the most part). That
is, a typical HF made from this blurred image has straight, linear-sloping
angles over most of its height. (Perhaps other image editing apps allow
non-linear blurring, I don't know.) But in this soft-edged masking scheme, the
fact that a HF's height is in the range of 0 to 1 allows its y-values to be
'bent' with an exponent, while still remaining in the 0-to-1 domain. This
creates, in effect, a non-linear blur--a 'curving slope' of the HF's parts--and
a corresponding subtle change in the 'chance' of an object being made. Hard to
describe, but visually useful. Example:
#if(pow(rand(S2), .333) <= intersexion.y)
BTW, in working with this technique (and running some other experiments), I've
found that rand() doesn't actually HIT zero or one. It comes close, but doesn't
actually hit those limits. That's counter to what the POV docs say about it
being "0 to 1 inclusive." Perhaps it IS on an underlying machine-code level;
but at the "SDL level" it appears not to be. This has its advantages in the
tracing code above; the trace rays never go exactly to the edges of the HF in x
or z, thus no possibility of false hits.
Ken W.
Post a reply to this message
Attachments:
Download 'fuzzy_logic.jpg' (413 KB)
Preview of image 'fuzzy_logic.jpg'
![fuzzy_logic.jpg](/povray.binaries.images/attachment/%3Cweb.4828adc61416034978dcad930%40news.povray.org%3E/fuzzy_logic.jpg?ttop=443866&toff=3250&preview=1)
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
"somebody" <x### [at] y com> wrote:
> "Kenneth" <kdw### [at] earthlink net> wrote
>
> > BTW, in working with this technique (and running some other experiments),
> I've found that rand() doesn't actually HIT zero or one.
>
> A pseudo random generator should in practice not hit *any* given number, not
> just 0 and 1, unless you cover its period at least a few times. Further, in
> practice again, some (or many) numbers in range will simply be "unhittable".
Not sure I understand what you mean by *period*. Would that be *all* the
possible numbers between 0 and 1 that can conceivably be found in Pov_Ray? In
one test I did--looking for a 0 or 1 hit --I used a #while loop that iterated
10,000,000 times. No "hits"--though, admittedly, that's not 2^32 tries. I
thought of actually going "to the limit," but demurred because of the quite
lengthy parse time involved. Is it possible that I just
haven't tried hard enough? So by the same reasoning: If I chose some value
between 0 and 1 at random--say, .0005674836--and actually TRIED to hit that
with rand(), would the possibility of success be the same as trying to hit 0 or
1--i.e., practically nil? I'm beginning to see some light here--that "0" and "1"
constitute just two of a huge range of possible hits...and I can't expect to
pick JUST those two exact values out of such an ocean of numbers--without
searching the entire ocean, so to speak (and multiple times!) BUT, I still
harbor the sneaking thought that 0 and 1 may *in fact* be out-of-range. Hard to
prove or disprove, I suppose. As a practical matter, they just don't ever
seem to pop up. But I suppose you could say the same thing about .0005674836!
Thanks for your comment; it has made me think about this situation in depth.
As to some values being unhittable--can't say I understand why, unless it has
something to do with underlying computational processes that I don't understand
(and I don't understand plenty, when it comes to such things! :-)
Ken W.
Post a reply to this message
|
![](/i/fill.gif) |