POV-Ray : Newsgroups : povray.advanced-users : Isosurface Rocks, using a single iso; could use a bit of help : Isosurface Rocks, using a single iso; could use a bit of help Server Time
25 Apr 2024 01:49:26 EDT (-0400)
  Isosurface Rocks, using a single iso; could use a bit of help  
From: [GDS|Entropy]
Date: 8 Dec 2016 05:10:01
Message: <web.584930896adf4b231c3f31c90@news.povray.org>
Hello,

I have a macro adapted from a nice rock Tek posted, and wish to merge this
technique with one by PM 2 Ring that uses a single Isosurface but grants
multiple objects. The problem is that I have tried, and I don't know what I am
doing, so I lose 99% of the detail from the nice function.

There are a few things which will determine the utility of what I am doing, one
being that I wish to include an automatic trace function which will be used to
position the things. That is easy and I already have macros for it, but I am not
sure that it can be done with the single Isosurface method without passing in
the Isosurface to be used for the terrain and combining its function with the
rock function somehow and I have no earthly idea how to do it.

The other thing is the whole loss of detail. I am intentionally reducing the
octaves/detail of my rocks based on distance from camera, and I am not sure that
can be done with the single method, but then again, it is so dang fast that
might make up for it. My attempts to merge the two methods result in basically
no detail beyond that of the original rocks by PM 2 Ring, likely because I have
no idea what I am doing.

The last thing is that I am planning to use a function select method with this
to allow each rock to use a different function or combination thereof, I have
this already working with a stone floor macro I made, which will be released
with this one. If I convert both of these to use the single Isosurface method,
that isn't going to work, will it? I also use variable sized containers for the
isosurfaces to modify brick shape...which will not work with the single method.

Those points above are just to give you some context, and maybe you can tell me
I am being dumb in many ways and guide me properly for it. ;-)

I expect the rotation/scaling and translation perturbations will suffer or
become immensely complex as well...

So, I defer to those more experienced than I for advice and such.

The end result of this is to be a set of rock, terrain, volumetric sky,
volumetric fog and stone block macros for the community, which I have made a
whole ton of progress on. These are intended to augment my corrosion,
snow/ice/icicle and moss macros which I am also updating, as part of a kind of
"natural elements" macro pack for folks to use...though I am as yet unaware of
any of my previous macros ever having been used by anyone lol! :p

Note:
The rocks in RockTest are fairly repetitive in shape, and I am working on this.
If you look at the bit where you see "crackle form" there are a number of lines
commented out, I am playing with variations here but so far the best results
come from <9.0, 0, 0> in conjunction with max gradient 70, just FYI.

I will post an image in PBI which corresponds with the RockTest.pov file, for
reference, when it is done rendering.

Here are the scenes:

---------------------------------------------------------------
RandomTools.mcr:
//    Randomization macros.

#macro SRand(RS)
    (rand(RS) * 2 - 1)
#end

#macro RRand(RS, Min, Max)
    (rand(RS) * (Max - Min) + Min)
#end

#macro Clamp(V, Min, Max)
    (min(Max, max(Min, V)))
#end

#macro Range(V, Rmn, Rmx)
    (V * (Rmx - Rmn) + Rmn)
#end

#macro RClamp(V, Rmn, Rmx, Min, Max)
    (Clamp(Range(V, Rmn, Rmx), Min, Max))
#end

#macro Displace_Line(pos, p0, p1, len, rad, scatter)
    #local w = pos - p0;
    #local ul = vnormalize(p1-p0);
    #local dist = vlength(vcross(ul, w));
    #local uv = vnormalize(VPerp_To_Vector(ul));
    #local vv = vnormalize(VPerp_To_Plane(ul, uv));
    #local trans = ul*len*exp(-(len/rad)*dist);
    #local rang = vlength(trans);
    #local u_ad = uv*rang*tan(radians(scatter));
    #local v_ad = vv*rang*tan(radians(scatter));
    #local trans = trans + rand(r1)*u_ad-u_ad/2 + rand(r1)*v_ad-v_ad/2;

    (trans)
#end

--------------------------------------------------------------------

The RockTest.pov file:

#include "RandomTools.mcr"

#local RsA = seed(112080);

global_settings
{
    assumed_gamma 1.0
}

/*
camera
{
    location <0, 0, -10>
    look_at <0, 0, 0>
}
*/

camera
{
    location <0, 10, -10>
    look_at <0, 0, 0>
}

background
{
    rgb <0.8, 0.8, 1>
}

light_source
{
    <-30, 100, -30>
    color rgb 0.5
}

light_source
{
    <0, 10, -30>
    color rgb 0.5
}

//    Macro for the generation of Isosurface rocks utilizing a pattern based on
work by Tek and Mike Williams.
//    While a value of 1 for Octaves is perfectly valid, there is little
differentiation
//    between the various patterns.
#macro IsoRock(Position, Octaves)

    //    This setting is internal due to
    //    its effect being interesting but
    //    distinctly very un rock-like in
    //    nature. It makes a 3d fractal.
    #local UsePavement = !true;

    //    Disallow 0 as a value for octaves.
    #local Octaves = max(1, Octaves);

    #local P =
    function
    {
        pigment
        {
            //    Small values make it look porous.
            #local Curve = 2 / 8;
            #local Omega = 0.5;
            #local Lambda = 2.5;
            #local Octaves = Octaves;

            pigment_pattern
            {

                //    Octaves:    [1-3]    Foamy, smooth rock with cavities of
varying scale.
                //    Octaves:    [4-8]    Foamy, smooth rock with cavities of
varying scale.
                average

                //    Octaves:    [1-3]    Angular boulder like faces are
produced, which may be good targets for combination with other functions
                //    Octaves:    [4-8]    Very accurate representation of open
cell foam, completely fills container object.
                //granite

                pigment_map
                {
                    #local octave = 0;
                    #while (octave < Octaves)

                        [pow(Omega, octave)
                            pigment_pattern
                            {

                                #if (UsePavement)
                                    pavement form 1
                                #else
                                    //    X:    [0.1 - 0.9]    Smooth ridges ->
Very cratered ridges
                                    //    Y:    [0.1 - 0.9]    Smooth wrinkles
-> Very wrinkly with voids
                                    //    Z:    [0.1 - 0.7]    Very smooth ->
Very jagged
                                    //    The values above are valid only alone;
their range is decreased when used in concert.
                                    //crackle form <RRand(RsA, 0.1, 0.9),
RRand(RsA, 0.1, 0.9), RRand(RsA, 0.1, 0.7)> * 0.125

                                    crackle form <RRand(RsA, 0.3, 0.9),
RRand(RsA, 0.3, 0.9), RRand(RsA, 0.3, 0.7)> * 0.5

                                    //    Default; creates a foamy looking rock.
                                    //crackle form <0.9, 0.0, 0.0>

                                    //crackle form <0.1, 0.1, 0.1>

                                    //crackle form <0.0, 0.1, 0.5>    //
Smooth crinkly wrinkles.
                                #end

                                scale pow(Lambda, -octave)

                                color_map
                                {
                                    [0 rgb 1]
                                    [1 rgb 0]
                                }
                            }

                            poly_wave 1 / Curve
                        ]

                    #local octave = octave + 1;
                    #end
                }
            }

            poly_wave Curve

            color_map
            {
                [0 rgb 1]
                [1 rgb 0]
            }
        }
    }

    #local S =
    function
    {
        x * x + y * y +  z *z - 1
    }

    #declare Iso_Rock =
    isosurface
    {
        function
        {
            S(x, y, z) - P(x, z, y).grey * 2
        }

        //max_gradient 3
        max_gradient 34    //    Somewhat rough, but acceptable and has
interesting branching lace-like features.
        //max_gradient 70   //    Generally smooth and highly porous, similar to
Tufa rock or Pumice.

        //    Useful for the construction of a large number of rocks from within
a loop.
        //max_gradient RRand(RsA, 2, 70)

        //    This needs to be a randomly perturbed mesh primitive.
        //    The rock generation algorithm from River 2017 might be a good
candidate if we can figure it out.
        contained_by
        {
            sphere
            {
                0,
                1.5 * 2.5 //   Perhaps basing scale on the parameters which fill
the container utterly will prevent that issue?
            }
        }

        pigment
        {
            rgb 1
        }

        //scale 3
        scale <RRand(RsA, 0.3, 0.9), RRand(RsA, 0.3, 0.9), RRand(RsA, 0.3, 0.9)>
        rotate <RRand(RsA, 0, 360), RRand(RsA, 0, 360), RRand(RsA, 0, 360)>
    }

    object
    {
        Iso_Rock

        scale 1
        translate <Position.x, Position.y, Position.z>
    }

#end

//    Single Rock.
//#local RockPosition = <0, 0, 0>;
//IsoRock(RockPosition, 4)

//    Build tracing into this, along with pigment pattern placement.
#macro DistributeRocks(Extent, CameraLocation)
    #local RsA = seed(112080);

    #local Types = array[4];
    #local Types[0] = !true;    //    Fairly normal.
    #local Types[1] = true;    //    Vein mounds.
    #local Types[2] = true;    //    Sparse.
    #local Types[3] = !true;    //    Stones.

    #local Floor =
    union
    {
        #local I = -Extent;
        #while(I < Extent)
            #local J = -Extent;
            #while(J < Extent)

                #local rockLocation = <I, 0, J> * 3;
                #local camDist = vlength(CameraLocation - rockLocation);

                //    This is a guess, and should be improved to be a smooth
curve.
                #if (camDist > 50)
                    #local camDist = camDist * 0.01;
                #else
                    #local camDist = camDist * 0.1;
                #end

                //#debug concat("Distance from Camera: ", str(camDist, 0, 1), "
Adjusted Octaves: ", str(8 / camDist, 0, 2))
                //#debug "\n\n"

                //    Reduce octaves/detail with distance from camera.
                IsoRock(rockLocation, 8 / camDist)

            #local J = J + 1;
            #end
        #local I = I + 1;
        #end
    }

    object
    {
        Floor
        translate <Extent * 0.5, 0, Extent * 0.5>
    }
#end

//    Many Rocks.
#local Extent = 5;
DistributeRocks(Extent, <0, 10, -10>)

-----------------------------------------------------

Chunk of the scene by PM 2 Ring that uses the single iso technique:
//Stone parameters
#declare GridSize = 4;            //Total number of stones =
#local GridSize = GridSize * GridSize;
#declare Width = 1 / GridSize;      //Cell width.
#declare Radius = Width * 0.70;      //Stone radius
#declare DRate = 0.875 / Radius;     //Radius deformation rate
#declare Height = 0.55;            //Stone height

//---Functions------------------------------------------------

//    Positive modulus: never returns negative values
#declare smod =
function(A, B)
{
    mod(B + mod(A, B), B)
}

//    Centered modulus
#declare cmod =
function(A, B)
{
    smod(A, 2 * B) - B
}

//    2D cells: returns a random value for each unit square
#declare f_cell2D =
function(x, z)
{
    f_snoise3d(floor(x), 0, floor(z))
}

//    Noisy modulus. Makes a random centre for each stone
#declare f_modnoise =
function(x,z)
{
    cmod(x, Width) + (Width - Radius) * f_cell2D(x * 0.5 / Width, z * 0.5 /
Width)
}


//    Randomized radius for tumbled stone shape
#declare f_Rad =
function
{
    1 + 0.45 * f_snoise3d(x * DRate, y * DRate, z * DRate)
}

//Displaced, vertically squashed spheres
#declare f_Stone =
function
{
    f_r(f_modnoise(x, z), y / Height, f_modnoise(-z, x))
}


//    The stones. Scaled so that textures appears the same,
//    no matter how many stones are done.
isosurface
{

    function
    {
        f_Stone(x, y, z) - Radius * f_Rad(x, y, z)
    }

    //    This doesn't really work, as such:
    /*
    function
    {
        (f_Stone(x, y, z) * (P(x, z, y).grey * 2.5)) - Radius * f_Rad(x, y, z)
    }
    */

    //    Many orbs.
    /*
    function
    {
        f_r(cmod(x, Width), y / Height, cmod(z, Width)) - Radius
    }
    */

    contained_by
    {
        box
        {
            <-1, -Width * Height, -1>,
            <1, Width * Height, 1>
        }
    }

    max_gradient 30
    accuracy 5e-3

    //texture{MultiStone scale 2*Width}

    scale 5.7             //Fill view with stones
    rotate -3*y
    translate <0, 0.35 * Radius * Height - 1, 1>
}


Post a reply to this message

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