Skip to content
Snippets Groups Projects
rockgen.py 64.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • # Blender rock creation tool
    #
    # Based on BlenderGuru's asteroid tutorial and personal experimentation.
    #   Tutorial: http://www.blenderguru.com/how-to-make-a-realistic-asteroid/
    # Update with another tutorial shared by "rusted" of BlenderArtists:
    #   Tutorial: http://saschahenrichs.blogspot.com/2010/03/3dsmax-environment-modeling-1.html
    #
    # Uses the NumPy Gaussian random number generator to generate a
    # a rock within a given range and give some randomness to the displacement
    # texture values.  NumPy's gaussian generator was chosen as, based on
    # profiling I performed, it runs in about half the time as the built in
    # Python gaussian equivalent.  I would like to shift the script to use the
    # NumPy beta distribution as it ran in about half the time as the NumPy
    # gaussian once the skew calculations are added.
    #
    # Set lower and upper bounds to the same for no randomness.
    #
    # Tasks:
    #   Generate meshes with random scaling between given values.
    #       - Allow for a skewed distribution
    #           *** Completed on 4/17/2011 ***
    #       - Create a set of meshes that can be used
    #   Give the user the ability to set the subsurf level (detail level)
    #       *** Completed on 4/29/2011 ***
    #       - Set subsurf modifiers to default at view:3, render:3.
    #           *** Completed on 4/17/2011 ***
    #       - Set crease values to allow for hard edges on first subsurf.
    #           *** Completed on 4/29/2011 ***
    #   Be able to generate and add a texture to the displacement modifiers.
    #       *** Completed 5/17/2011 ***
    #       - Generate three displacement modifiers.
    #           - The first only uses a Musgrave for initial intentations.
    #           *** Now generating four displacement modifiers ***
    #           *** Completed on 5/17/2011 ***
    #       - Set a randomness for the type and values of the displacement texture.
    #           *** Completed 5/9/2011 ***
    #       - Allow the user to set a value for the range of displacement.
    #           -> Modification: have user set "roughness" and "roughness range".
    #           *** Compleded on 4/23/2011 ***
    #   Set material settings and assign material textures
    #       *** Completed 6/9/2011 ***
    #       - Mossiness of the rocks.
    #           *** Completed 6/9/2011 ***
    #       - Color of the rocks.
    #           *** Completed 5/16/2011 ***
    #       - Wetness/shinyness of the rock.
    #           *** Completed 5/6/2011 ***
    #       - For all the user provides a mean value for a skewed distribution.
    #           *** Removed to lessen usage complexity ***
    #   Add some presets (mesh) to make it easier to use
    #       - Examples: river rock, asteroid, quaried rock, etc
    #           *** Completed 7/12/2011 ***
    #
    # Code Optimization:
    #   Remove all "bpy.ops" operations with "bpy.data" base operations.
    #   Remove material/texture cataloging with building a list of
    #       returned values from bpy.data.*.new() operations.
    
    #       *** Completed on 9/6/2011 ***
    
    #   Search for places where list comprehensions can be used.
    #   Look for alternate methods
    #       - Possible alternate and more efficient data structures
    #       - Possible alternate algorithms may realize greater performance
    #       - Look again at multi-processing.  Without bpy.ops is might
    #           be viable.
    #
    # Future tasks:
    #   Multi-thread the script
    #       *** Will not be implemented.  Multi-processing is adding to much
    #           overhead to realize a performance increase ***
    #       - Learn basic multi-threading in Python (multiprocessing)
    #       - Break material generation into separate threads (processes)
    #       - Break mesh generation into separate threads (processes)
    #       - Move name generation, texture ID generation, etc to process first
    #       - Roll version to 2.0 on completion
    #
    # Paul "BrikBot" Marshall
    # Created: April 17, 2011
    # Last Modified: September 18, 2011
    # Homepage (blog): http://post.darkarsenic.com/
    #                       //blog.darkarsenic.com/
    # Thanks to Meta-Androco, RickyBlender, Ace Dragon, and PKHG for ideas
    #   and testing.
    #
    # Coded in IDLE, tested in Blender 2.59.  NumPy Recommended.
    # Search for "@todo" to quickly find sections that need work.
    #
    # Remeber -
    #   Functional code comes before fast code.  Once it works, then worry about
    #   making it faster/more efficient.
    #
    # ##### BEGIN GPL LICENSE BLOCK #####
    #
    #  The Blender Rock Creation tool is for rapid generation of mesh rocks.
    #  Copyright (C) 2011  Paul Marshall
    #
    #  This program is free software: you can redistribute it and/or modify
    #  it under the terms of the GNU General Public License as published by
    #  the Free Software Foundation, either version 3 of the License, or
    #  (at your option) any later version.
    #
    #  This program is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #
    #  You should have received a copy of the GNU General Public License
    #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    #
    # ##### END GPL LICENSE BLOCK #####
    
    
    import (bpy,
            math,
            time)
    
    from add_mesh_rocks import (settings,
                                utils)
    from bpy_extras import object_utils
    from mathutils import (Color,
                           Vector)
    from bpy.props import (BoolProperty,
                           IntProperty,
                           FloatProperty,
                           FloatVectorProperty,
                           EnumProperty)
    
    # This try block allows for the script to psudo-intelligently select the
    # appropriate random to use.  If Numpy's random is present it will use that.
    # If Numpy's random is not present, it will through a "module not found"
    # exception and instead use the slower built-in random that Python has.
    try:
        from numpy.random import random_integers as randint
        from numpy.random import normal as gauss
        from numpy.random import (beta,
                                  uniform,
                                  seed,
                                  weibull)
        print("Rock Generator: Numpy found.")
        numpy = True
    except:
        from random import (randint,
                            gauss,
                            uniform,
                            seed)
        from random import betavariate as beta
        from random import weibullvariate as weibull
        print("Rock Generator: Numpy not found.  Using Python's random.")
        numpy = False
    
    # Global variables:
    lastRock = 0
    
    
    # Creates a new mesh:
    #
    # param: verts - Vector of vertices for the mesh.
    #        edges - Edges for the mesh.  Can be "[]".
    #        faces - Face tuples corresponding to vertices.
    #        name  - Name of the mesh.
    def create_mesh_object(context, verts, edges, faces, name):
        # Create new mesh
        mesh = bpy.data.meshes.new(name)
    
        # Make a mesh from a list of verts/edges/faces.
        mesh.from_pydata(verts, edges, faces)
    
        # Set mesh to use auto smoothing:
        mesh.use_auto_smooth = True
    
        # Update mesh geometry after adding stuff.
        mesh.update()
    
        return object_utils.object_data_add(context, mesh, operator=None)
    
    
    # Set the values for a texture from parameters.
    #
    # param: texture - bpy.data.texture to modify.
    #        level   - designated tweaked settings to use
    #                   -> Below 10 is a displacment texture
    #                   -> Between 10 and 20 is a base material texture
    def randomizeTexture(texture, level=1):
        noises = ['BLENDER_ORIGINAL', 'ORIGINAL_PERLIN', 'IMPROVED_PERLIN',
                  'VORONOI_F1', 'VORONOI_F2', 'VORONOI_F3', 'VORONOI_F4',
                  'VORONOI_F2_F1', 'VORONOI_CRACKLE']
        if texture.type == 'CLOUDS':
            if randint(0, 1) == 0:
                texture.noise_type = 'SOFT_NOISE'
            else:
                texture.noise_type = 'HARD_NOISE'
            if level != 11:
                tempInt = randint(0, 6)
            else:
                tempInt = randint(0, 8)
            texture.noise_basis = noises[tempInt]
            texture.noise_depth = 8
    
            if level == 0:
    
                texture.noise_scale = gauss(0.625, 1 / 24)
    
            elif level == 2:
                texture.noise_scale = 0.15
            elif level == 11:
    
                texture.noise_scale = gauss(0.5, 1 / 24)
    
                if texture.noise_basis in ['BLENDER_ORIGINAL', 'ORIGINAL_PERLIN',
    
                                           'IMPROVED_PERLIN', 'VORONOI_F1']:
    
                    texture.intensity = gauss(1, 1 / 6)
                    texture.contrast = gauss(4, 1 / 3)
    
                elif texture.noise_basis in ['VORONOI_F2', 'VORONOI_F3', 'VORONOI_F4']:
    
                    texture.intensity = gauss(0.25, 1 / 12)
                    texture.contrast = gauss(2, 1 / 6)
    
                elif texture.noise_basis == 'VORONOI_F2_F1':
    
                    texture.intensity = gauss(0.5, 1 / 6)
                    texture.contrast = gauss(2, 1 / 6)
    
                elif texture.noise_basis == 'VORONOI_CRACKLE':
    
                    texture.intensity = gauss(0.5, 1 / 6)
                    texture.contrast = gauss(2, 1 / 6)
    
        elif texture.type == 'MUSGRAVE':
            musgraveType = ['MULTIFRACTAL', 'RIDGED_MULTIFRACTAL',
                            'HYBRID_MULTIFRACTAL', 'FBM', 'HETERO_TERRAIN']
            texture.musgrave_type = 'MULTIFRACTAL'
            texture.dimension_max = abs(gauss(0, 0.6)) + 0.2
            texture.lacunarity = beta(3, 8) * 8.2 + 1.8
    
            if level == 0:
    
                texture.noise_scale = gauss(0.625, 1 / 24)
    
                texture.noise_intensity = 0.2
                texture.octaves = 1.0
            elif level == 2:
    
                texture.intensity = gauss(1, 1 / 6)
    
                texture.contrast = 0.2
                texture.noise_scale = 0.15
                texture.octaves = 8.0
            elif level == 10:
    
                texture.intensity = gauss(0.25, 1 / 12)
                texture.contrast = gauss(1.5, 1 / 6)
    
                texture.noise_scale = 0.5
                texture.octaves = 8.0
            elif level == 12:
                texture.octaves = uniform(1, 3)
            elif level > 12:
                texture.octaves = uniform(2, 8)
            else:
    
                texture.intensity = gauss(1, 1 / 6)
    
                texture.contrast = 0.2
                texture.octaves = 8.0
        elif texture.type == 'DISTORTED_NOISE':
            tempInt = randint(0, 8)
            texture.noise_distortion = noises[tempInt]
            tempInt = randint(0, 8)
            texture.noise_basis = noises[tempInt]
            texture.distortion = skewedGauss(2.0, 2.6666, (0.0, 10.0), False)
    
            if level == 0:
    
                texture.noise_scale = gauss(0.625, 1 / 24)
    
            elif level == 2:
                texture.noise_scale = 0.15
            elif level >= 12:
    
                texture.noise_scale = gauss(0.2, 1 / 48)
    
        elif texture.type == 'STUCCI':
            stucciTypes = ['PLASTIC', 'WALL_IN', 'WALL_OUT']
            if randint(0, 1) == 0:
                texture.noise_type = 'SOFT_NOISE'
            else:
                texture.noise_type = 'HARD_NOISE'
            tempInt = randint(0, 2)
            texture.stucci_type = stucciTypes[tempInt]
    
            if level == 0:
                tempInt = randint(0, 6)
                texture.noise_basis = noises[tempInt]
    
                texture.noise_scale = gauss(0.625, 1 / 24)
    
            elif level == 2:
                tempInt = randint(0, 6)
                texture.noise_basis = noises[tempInt]
                texture.noise_scale = 0.15
            elif level >= 12:
                tempInt = randint(0, 6)
                texture.noise_basis = noises[tempInt]
    
                texture.noise_scale = gauss(0.2, 1 / 30)
    
            else:
                tempInt = randint(0, 6)
                texture.noise_basis = noises[tempInt]
        elif texture.type == 'VORONOI':
            metrics = ['DISTANCE', 'DISTANCE_SQUARED', 'MANHATTAN', 'CHEBYCHEV',
                       'MINKOVSKY_HALF', 'MINKOVSKY_FOUR', 'MINKOVSKY']
            # Settings for first dispalcement level:
            if level == 0:
                tempInt = randint(0, 1)
                texture.distance_metric = metrics[tempInt]
    
                texture.noise_scale = gauss(0.625, 1 / 24)
    
                texture.contrast = 0.5
                texture.intensity = 0.7
            elif level == 2:
                texture.noise_scale = 0.15
                tempInt = randint(0, 6)
                texture.distance_metric = metrics[tempInt]
            elif level >= 12:
                tempInt = randint(0, 1)
                texture.distance_metric = metrics[tempInt]
    
                texture.noise_scale = gauss(0.125, 1 / 48)
    
                texture.contrast = 0.5
                texture.intensity = 0.7
            else:
                tempInt = randint(0, 6)
                texture.distance_metric = metrics[tempInt]
    
    # Generates an object based on one of several different mesh types.
    # All meshes have exactly eight vertices, and may be built from either
    # tri's or quads.
    #
    # param: muX        - mean X offset value
    #        sigmaX     - X offset standard deviation
    #        scaleX     - X upper and lower bounds
    #        upperSkewX - Is the distribution upperskewed?
    #        muY        - mean Y offset value
    #        sigmaY     - Y offset standard deviation
    #        scaleY     - Y upper and lower bounds
    #        upperSkewY - Is the distribution upperskewed?
    #        muZ        - mean Z offset value
    #        sigmaZ     - Z offset standard deviation
    #        scaleZ     - Z upper and lower bounds
    #        upperSkewY - Is the distribution upperskewed?
    #        base       - base number on the end of the object name
    #        shift      - Addition to the base number for multiple runs.
    #        scaleDisplace - Scale the displacement maps
    #
    # return: name      - the built name of the object
    def generateObject(context, muX, sigmaX, scaleX, upperSkewX, muY, sigmaY,
                       scaleY, upperSkewY, muZ, sigmaZ, scaleZ, upperSkewZ, base,
                       shift, scaleDisplace, scale_fac):
        x = []
        y = []
        z = []
    
        shape = randint(0, 11)
    
    
        # Cube
        # Use parameters to re-scale cube:
        # Reversed if/for nesting.  Should be a little faster.
        if shape == 0:
            for j in range(8):
                if sigmaX == 0:
                    x.append(scaleX[0] / 2)
                else:
                    x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                if sigmaY == 0:
                    y.append(scaleY[0] / 2)
                else:
                    y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                if sigmaZ == 0:
                    z.append(scaleZ[0] / 2)
                else:
                    z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
        elif shape == 1:
            for j in range(8):
                if j in [0, 1, 3, 4]:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 2)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                    if sigmaY == 0:
                        y.append(scaleY[0] / 2)
                    else:
                        y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
                elif j in [2, 5]:
                    if sigmaX == 0:
                        x.append(0)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 4)
                    if sigmaY == 0:
                        y.append(scaleY[0] / 2)
                    else:
                        y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
                elif j in [6, 7]:
                    if sigmaX == 0:
                        x.append(0)
                    else:
                        x.append(skewedGauss(0, sigmaX, scaleX, upperSkewX) / 4)
                    if sigmaY == 0:
                        y.append(0)
                    else:
                        y.append(skewedGauss(0, sigmaY, scaleY, upperSkewY) / 4)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
        elif shape == 2:
            for j in range(8):
                if j in [0, 2, 5, 7]:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 4)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 4)
                    if sigmaY == 0:
                        y.append(0)
                    else:
                        y.append(skewedGauss(0, sigmaY, scaleY, upperSkewY) / 4)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 4)
                elif j in [1, 3, 4, 6]:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 2)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                    if sigmaY == 0:
                        y.append(scaleY[0] / 2)
                    else:
                        y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
        elif shape == 3:
            for j in range(8):
                if j > 0:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 2)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                    if sigmaY == 0:
                        y.append(scaleY[0] / 2)
                    else:
                        y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
                else:
                    if sigmaX == 0:
                        x.append(0)
                    else:
                        x.append(skewedGauss(0, sigmaX, scaleX, upperSkewX) / 8)
                    if sigmaY == 0:
                        y.append(0)
                    else:
                        y.append(skewedGauss(0, sigmaY, scaleY, upperSkewY) / 8)
                    if sigmaZ == 0:
                        z.append(0)
                    else:
                        z.append(skewedGauss(0, sigmaZ, scaleZ, upperSkewZ) / 8)
        elif shape == 4:
            for j in range(10):
                if j in [0, 9]:
                    if sigmaX == 0:
                        x.append(0)
                    else:
                        x.append(skewedGauss(0, sigmaX, scaleX, upperSkewX) / 2)
                    if sigmaY == 0:
                        y.append(0)
                    else:
                        y.append(skewedGauss(0, sigmaY, scaleY, upperSkewY) / 2)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
                elif j in [1, 2, 3, 4]:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 2)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                    if sigmaY == 0:
                        y.append(scaleY[0] / 2)
                    else:
                        y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
                elif j in [5, 7]:
                    if sigmaX == 0:
                        x.append(0)
                    else:
                        x.append(skewedGauss(0, sigmaX, scaleX, upperSkewX) / 3)
                    if sigmaY == 0:
                        y.append(scaleY[0] / 3)
                    else:
                        y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 3)
                    if sigmaZ == 0:
                        z.append(0)
                    else:
                        z.append(skewedGauss(0, sigmaZ, scaleZ, upperSkewZ) / 6)
                elif j in [6, 8]:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 3)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 3)
                    if sigmaY == 0:
                        y.append(0)
                    else:
                        y.append(skewedGauss(0, sigmaY, scaleY, upperSkewY) / 3)
                    if sigmaZ == 0:
                        z.append(0)
                    else:
                        z.append(skewedGauss(0, sigmaZ, scaleZ, upperSkewZ) / 6)
        elif shape == 5:
            for j in range(10):
    
                    if sigmaX == 0:
                        x.append(0)
                    else:
                        x.append(skewedGauss(0, sigmaX, scaleX, upperSkewX) / 8)
                    if sigmaY == 0:
                        y.append(0)
                    else:
                        y.append(skewedGauss(0, sigmaY, scaleY, upperSkewY) / 8)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
                elif j in [1, 2]:
                    if sigmaX == 0:
                        x.append(scaleZ[0] * .125)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) * 0.125)
                    if sigmaY == 0:
                        y.append(scaleZ[0] * 0.2165)
                    else:
                        y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) * 0.2165)
                    if sigmaZ == 0:
                        z.append(0)
                    else:
                        z.append(skewedGauss(0, sigmaZ, scaleZ, upperSkewZ) / 4)
                elif j == 3:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 4)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 4)
                    if sigmaY == 0:
                        y.append(0)
                    else:
                        y.append(skewedGauss(0, sigmaY, scaleY, upperSkewY) / 4)
                    if sigmaZ == 0:
                        z.append(0)
                    else:
                        z.append(skewedGauss(0, sigmaZ, scaleZ, upperSkewZ) / 4)
                elif j in [4, 6]:
                    if sigmaX == 0:
                        x.append(scaleX[0] * 0.25)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) * 0.25)
                    if sigmaY == 0:
                        y.append(scaleY[0] * 0.433)
                    else:
                        y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) * 0.433)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
                elif j == 5:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 4)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 4)
                    if sigmaY == 0:
                        y.append(0)
                    else:
                        y.append(skewedGauss(0, sigmaY, scaleY, upperSkewY) / 2)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
                elif j in [7, 9]:
                    if sigmaX == 0:
                        x.append(scaleX[0] * 0.10825)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) * 0.10825)
                    if sigmaY == 0:
                        y.append(scaleY[0] * 0.2165)
                    else:
                        y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) * 0.2165)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
                elif j == 8:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 2)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                    if sigmaY == 0:
                        y.append(0)
                    else:
                        y.append(skewedGauss(0, sigmaY, scaleY, upperSkewY) / 4)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
        elif shape == 6:
            for j in range(7):
                if j > 0:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 2)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                    if sigmaY == 0:
                        y.append(scaleY[0] / 2)
                    else:
                        y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
                else:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 2)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                    if sigmaY == 0:
                        y.append(0)
                    else:
                        y.append(skewedGauss(0, sigmaY, scaleY, upperSkewY) / 2)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
        elif shape == 7:
            for j in range(10):
                if j in [1, 3, 4, 5, 8, 9]:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 2)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                    if sigmaY == 0:
                        y.append(scaleY[0] / 2)
                    else:
                        y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
                else:
                    if sigmaX == 0:
                        x.append(scaleX[0] / 2)
                    else:
                        x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                    if sigmaY == 0:
                        y.append(0)
                    else:
                        y.append(skewedGauss(0, sigmaY, scaleY, upperSkewY) / 2)
                    if sigmaZ == 0:
                        z.append(scaleZ[0] / 2)
                    else:
                        z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
        elif shape == 8:
            for j in range(7):
                if sigmaX == 0:
                    x.append(scaleX[0] / 2)
                else:
                    x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                if sigmaY == 0:
                    y.append(scaleY[0] / 2)
                else:
                    y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                if sigmaZ == 0:
                    z.append(scaleZ[0] / 2)
                else:
                    z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
        elif shape == 9:
            for j in range(8):
                if sigmaX == 0:
                    x.append(scaleX[0] / 2)
                else:
                    x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                if sigmaY == 0:
                    y.append(scaleY[0] / 2)
                else:
                    y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                if sigmaZ == 0:
                    z.append(scaleZ[0] / 2)
                else:
                    z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
        elif shape == 10:
            for j in range(7):
                if sigmaX == 0:
                    x.append(scaleX[0] / 2)
                else:
                    x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                if sigmaY == 0:
                    y.append(scaleY[0] / 2)
                else:
                    y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                if sigmaZ == 0:
                    z.append(scaleZ[0] / 2)
                else:
                    z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
        elif shape == 11:
            for j in range(7):
                if sigmaX == 0:
                    x.append(scaleX[0] / 2)
                else:
                    x.append(skewedGauss(muX, sigmaX, scaleX, upperSkewX) / 2)
                if sigmaY == 0:
                    y.append(scaleY[0] / 2)
                else:
                    y.append(skewedGauss(muY, sigmaY, scaleY, upperSkewY) / 2)
                if sigmaZ == 0:
                    z.append(scaleZ[0] / 2)
                else:
                    z.append(skewedGauss(muZ, sigmaZ, scaleZ, upperSkewZ) / 2)
    
        # This is for scaling the displacement textures.
        # Scale the vertices so that their average is equal to 1 * scale factor.
        if scaleDisplace:
            averageX = (sum(x) / len(x)) * scale_fac[0]
            for i in range(len(x)):
                x[i] /= averageX
            averageY = (sum(y) / len(y)) * scale_fac[1]
            for i in range(len(y)):
                y[i] /= averageY
            averageZ = (sum(z) / len(z)) * scale_fac[2]
            for i in range(len(z)):
                z[i] /= averageZ
    
        # Build vertex and face arrays:
        if shape == 1:
            verts = [(-x[0],-y[0],-z[0]),(x[1],-y[1],-z[1]),(x[2],-y[2],z[2]),
                 (-x[3],y[3],-z[3]),(x[4],y[4],-z[4]),(x[5],y[5],z[5]),
                 (x[6],y[6],z[6]),(x[7],y[7],-z[7])]
            faces = [[0,1,2],[0,1,7],[3,0,7],[3,4,7],[1,4,7],[3,4,5],[1,2,6],
                     [1,4,6],[4,5,6],[0,2,6],[0,3,6],[3,5,6]]
        elif shape == 2:
            verts = [(-x[0],y[0],-z[0]),(x[1],-y[1],-z[1]),(x[2],y[2],-z[2]),
                 (-x[3],y[3],-z[3]),(-x[4],-y[4],z[4]),(x[5],y[5],z[5]),
                 (x[6],y[6],z[6]),(-x[7],y[7],z[7])]
            faces = [[0,1,2],[0,2,3],[0,3,7],[0,7,4],[1,4,5],[0,1,4],[5,1,2],
                     [5,2,6],[3,2,6],[3,6,7],[5,4,7],[5,6,7]]
        elif shape == 3:
            verts = [(x[0],y[0],z[0]),(x[1],-y[1],-z[1]),(x[2],y[2],-z[2]),
                 (-x[3],y[3],-z[3]),(x[4],-y[4],z[4]),(x[5],y[5],z[5]),
                 (-x[6],y[6],z[6]),(-x[7],-y[7],z[7])]
            faces = [[0,1,2],[0,2,3],[0,3,6],[0,6,7],[0,7,4],[0,4,1],[5,4,1,2],
                     [5,6,3,2],[5,4,7,6]]
        elif shape == 4:
            verts = [(x[0],y[0],z[0]),(x[1],-y[1],-z[1]),(x[2],y[2],-z[2]),
                 (-x[3],y[3],-z[3]),(-x[4],-y[4],-z[4]),(x[5],-y[5],-z[5]),
                 (x[6],y[6],-z[6]),(x[7],y[7],-z[7]),(-x[8],y[8],-z[8]),
                 (x[9],y[9],-z[9])]
            faces = [[0,1,6],[0,6,2],[0,2,7],[0,7,3],[0,3,8],[0,8,4],[0,4,5],
                     [0,5,1],[1,9,2],[2,9,3],[3,9,4],[4,9,1],[1,6,2],[2,7,3],
                     [3,8,4],[4,5,1]]
        elif shape == 5:
            verts = [(x[0],y[0],z[0]),(x[1],-y[1],z[1]),(x[2],y[2],z[2]),
                 (-x[3],y[3],z[3]),(x[4],-y[4],-z[4]),(x[5],y[5],-z[5]),
                 (x[6],y[6],-z[6]),(-x[7],y[7],-z[7]),(-x[8],y[8],-z[8]),
                 (-x[9],-y[9],-z[9])]
            faces = [[0,1,2],[0,2,3],[0,3,1],[1,4,5],[1,5,2],[2,5,6],[2,6,7],
                     [2,7,3],[3,7,8],[3,8,9],[3,9,1],[1,9,4],[4,5,9],[5,6,7],
                     [7,8,9],[9,5,7]]
        elif shape == 6:
            verts = [(x[0],y[0],z[0]),(x[1],-y[1],-z[1]),(x[2],y[2],-z[2]),
                 (-x[3],y[3],-z[3]),(-x[4],y[4],z[4]),(-x[5],-y[5],z[5]),
                 (-x[6],-y[6],-z[6])]
            faces = [[0,1,2],[0,2,3,4],[0,1,6,5],[0,4,5],[1,2,3,6],[3,4,5,6]]
        elif shape == 7:
            verts = [(x[0],y[0],z[0]),(x[1],-y[1],-z[1]),(x[2],y[2],-z[2]),
                 (x[3],y[3],-z[3]),(-x[4],y[4],-z[4]),(-x[5],y[5],z[5]),
                 (-x[6],y[6],z[6]),(-x[7],y[7],-z[7]),(-x[8],-y[8],-z[8]),
                 (-x[9],-y[9],z[9])]
            faces = [[0,1,2],[0,2,3],[0,5,6],[0,6,9],[0,1,8,9],[0,3,4,5],
                     [1,2,7,8],[2,3,4,7],[4,5,6,7],[6,7,8,9]]
        elif shape == 8:
            verts = [(x[0],y[0],z[0]),(x[1],-y[1],-z[1]),(x[2],y[2],-z[2]),
                 (-x[3],y[3],-z[3]),(-x[4],-y[4],-z[4]),(-x[5],-y[5],z[5]),
                 (-x[6],y[6],z[6])]
            faces = [[0,2,1],[0,1,4],[0,4,5],[0,5,6],[0,6,3,2],[2,1,4,3],
                     [3,6,5,4]]
        elif shape == 9:
            verts = [(-x[0],-y[0],-z[0]),(-x[1],y[1],-z[1]),(-x[2],y[2],z[2]),
                 (-x[3],-y[3],z[3]),(x[4],-y[4],-z[4]),(x[5],y[5],-z[5]),
                 (x[6],y[6],z[6]),(x[7],-y[7],z[7])]
            faces = [[0,1,6,2],[1,5,7,6],[5,4,3,7],[4,0,2,3],[0,1,5,4],[3,2,6,7]]
        elif shape == 10:
            verts = [(-x[0],-y[0],-z[0]),(-x[1],y[1],-z[1]),(-x[2],y[2],z[2]),
                 (x[3],-y[3],z[3]),(x[4],y[4],z[4]),(x[5],y[5],-z[5]),
                 (x[6],-y[6],-z[6])]
            faces = [[0,2,3],[0,3,6],[0,1,5,6],[2,3,4],[0,1,2],[1,2,4,5],[3,4,5,6]]
        elif shape == 11:
            verts = [(-x[0],-y[0],-z[0]),(-x[1],y[1],-z[1]),(-x[2],y[2],z[2]),
                 (x[3],-y[3],z[3]),(x[4],y[4],z[4]),(x[5],y[5],-z[5]),
                 (x[6],-y[6],-z[6])]
            faces = [[0,2,3],[0,3,6],[0,1,5,6],[2,3,4],[5,6,3],[1,5,3,4],[0,1,4,2]]
        else:
            verts = [(-x[0],-y[0],-z[0]),(-x[1],y[1],-z[1]),(-x[2],-y[2],z[2]),
                 (-x[3],y[3],z[3]),(x[4],-y[4],-z[4]),(x[5],y[5],-z[5]),
                 (x[6],-y[6],z[6]),(x[7],y[7],z[7])]
            faces = [[0,1,3,2],[0,1,5,4],[0,4,6,2],[7,5,4,6],[7,3,2,6],[7,5,1,3]]
    
        name = "Rock." + str(base + shift).zfill(3)
    
        # Make object:
        obj = create_mesh_object(context, verts, [], faces, name)
    
        if scaleDisplace:
            bpy.data.objects[name].scale = Vector((averageX, averageY, averageZ))
    
        # For a slight speed bump / Readability:
        mesh = bpy.data.meshes[name]
    
        # Apply creasing:
        if shape == 0:
            for i in range(12):
                # todo: "0.375 / 3"?  WTF?  That = 0.125. . . .
                #   *** Completed 7/15/2011: Changed second one ***
                mesh.edges[i].crease = gauss(0.125, 0.125)
        elif shape == 1:
    
            for i in [0, 2]:
    
                mesh.edges[i].crease = gauss(0.5, 0.125)
    
            for i in [6, 9, 11, 12]:
    
                mesh.edges[i].crease = gauss(0.25, 0.05)
    
            for i in [5, 7, 15, 16]:
    
                mesh.edges[i].crease = gauss(0.125, 0.025)
        elif shape == 2:
            for i in range(18):
                mesh.edges[i].crease = gauss(0.125, 0.025)
        elif shape == 3:
    
            for i in [0, 1, 6, 10, 13]:
    
                mesh.edges[i].crease = gauss(0.25, 0.05)
            mesh.edges[8].crease = gauss(0.5, 0.125)
        elif shape == 4:
    
            for i in [5, 6, 7, 10, 14, 16, 19, 21]:
    
                mesh.edges[i].crease = gauss(0.5, 0.125)
        elif shape == 7:
            for i in range(18):
    
                if i in [0, 1, 2, 3, 6, 7, 8, 9, 13, 16]:
    
                    mesh.edges[i].crease = gauss(0.5, 0.125)
                elif i in [11,17]:
                    mesh.edges[i].crease = gauss(0.25, 0.05)
                else:
                    mesh.edges[i].crease = gauss(0.125, 0.025)
        elif shape == 8:
            for i in range(12):
    
                if i in [0, 3, 8, 9, 10]:
    
                    mesh.edges[i].crease = gauss(0.5, 0.125)
                elif i == 11:
                    mesh.edges[i].crease = gauss(0.25, 0.05)
                else:
                    mesh.edges[i].crease = gauss(0.125, 0.025)
        elif shape == 9:
            for i in range(12):
    
                if i in [0, 3, 4, 11]:
    
                    mesh.edges[i].crease = gauss(0.5, 0.125)
                else:
                    mesh.edges[i].crease = gauss(0.25, 0.05)
        elif shape == 10:
            for i in range(12):
    
                if i in [0, 2, 3, 4, 8, 11]:
    
                    mesh.edges[i].crease = gauss(0.5, 0.125)
    
                elif i in [1, 5, 7]:
    
                    mesh.edges[i].crease = gauss(0.25, 0.05)
                else:
                    mesh.edges[i].crease = gauss(0.125, 0.025)
        elif shape == 11:
            for i in range(11):
    
                if i in [1, 2, 3, 4, 8, 11]:
    
                    mesh.edges[i].crease = gauss(0.25, 0.05)
                else:
                    mesh.edges[i].crease = gauss(0.125, 0.025)
    
        return name
    
    
    # Randomizes the given material given base values.
    #
    # param: Material to randomize
    def randomizeMaterial(material, color, dif_int, rough,
                          spec_int, spec_hard, mossiness, spec_IOR):
        skew = False
        stddev = 0.0
        lastUsedTex = 1
        numTex = 6
        baseColor = []
    
        # Diffuse settings:
        material.diffuse_shader = 'OREN_NAYAR'
        if 0.5 > dif_int:
            stddev = dif_int / 3
            skew = False
        else:
            stddev = (1 - dif_int) / 3
            skew = True
        material.diffuse_intensity = skewedGauss(dif_int, stddev, (0.0, 1.0), skew)
        if 1.57 > rough:
            stddev = rough / 3
            skew = False
        else:
            stddev = (3.14 - rough) / 3
            skew = True
        material.roughness = skewedGauss(rough, stddev, (0.0, 3.14), skew)
    
        for i in range(3):
            if color[i] > 0.9 or color[i] < 0.1:
    
                baseColor.append(skewedGauss(color[i], color[i] / 30,
                                             (0, 1), color[i] > 0.9))
    
                baseColor.append(gauss(color[i], color[i] / 30))
    
        material.diffuse_color = baseColor
    
        # Specular settings:
        material.specular_shader = 'BLINN'
        if 0.5 > spec_int:
            variance = spec_int / 3
            skew = False
        else:
            variance = (1 - spec_int) / 3
            skew = True
    
        material.specular_intensity = skewedGauss(spec_int, stddev,
                                                  (0.0, 1.0), skew)
    
        if 256 > spec_hard:
            variance = (spec_hard - 1) / 3
            skew = False
        else:
            variance = (511 - spec_hard) / 3
            skew = True
    
        material.specular_hardness = int(round(skewedGauss(spec_hard, stddev,
                                                           (1.0, 511.0), skew)))
    
        if 5.0 > spec_IOR:
            variance = spec_IOR / 3
            skew = False
        else:
            variance = (10.0 - spec_IOR) / 3
            skew = True
        material.specular_ior = skewedGauss(spec_IOR, stddev, (0.0, 10.0), skew)
    
        # Rock textures:
        # Now using slot.texture for texture access instead of
        #   bpy.data.textures[newTex[<index>]]
        #   *** Completed on 9/6/2011 ***
        # Create the four new textures:
    
        textureTypes = ['MUSGRAVE', 'CLOUDS', 'DISTORTED_NOISE',
                        'STUCCI', 'VORONOI']
    
    
        for i in range(numTex):
            texColor = []
    
            # Set the active material slot:
            material.active_texture_index = i
            # Assign a texture to the active material slot:
            material.active_texture = bpy.data.textures.new(name = 'stone_tex',
                                                            type = 'NONE')
            # Store the slot to easy coding access:
            slot = material.texture_slots[i]
    
            # If the texture is not a moss texture:
            if i > 1:
                slot.texture.type = textureTypes[randint(0, 3)]
    
                # Set the texture's color (RGB):
                for j in range(3):
                    if color[j] > 0.9 or color[j] < 0.1:
    
                        texColor.append(skewedGauss(color[j], color[j] / 30,
                                                    (0, 1), color[j] > 0.9))
    
                        texColor.append(gauss(color[j], color[j]/ 30))
    
                slot.color = texColor
                # Randomize the value (HSV):
                v = material.diffuse_color.v
                if v == 0.5:
                    slot.color.v = gauss(v, v / 3)
                elif v > 0.5:
                    slot.color.v = skewedGauss(v, v / 3, (0, 1), True)
                else:
                    slot.color.v = skewedGauss(v, (1 - v) / 3, (0, 1), False)
    
                # Adjust scale and normal based on texture type:
                if slot.texture.type == 'VORONOI':
                    slot.scale = (gauss(5, 1), gauss(5, 1), gauss(5, 1))
                    slot.normal_factor = gauss(rough / 10, rough / 30)
                elif slot.texture.type == 'STUCCI':
    
                    slot.scale = (gauss(1.5, 0.25), gauss(1.5, 0.25),
                                  gauss(1.5, 0.25))
    
                    slot.normal_factor = gauss(rough / 10, rough / 30)
                elif slot.texture.type == 'DISTORTED_NOISE':
    
                    slot.scale = (gauss(1.5, 0.25), gauss(1.5, 0.25),
                                  gauss(1.5, 0.25))
    
                    slot.normal_factor = gauss(rough / 10, rough / 30)
                elif slot.texture.type == 'MUSGRAVE':
    
                    slot.scale = (gauss(1.5, 0.25), gauss(1.5, 0.25),
                                  gauss(1.5, 0.25))
    
                    slot.normal_factor = gauss(rough, rough / 3)
                elif slot.texture.type == 'CLOUDS':
    
                    slot.scale = (gauss(1.5, 0.25), gauss(1.5, 0.25),
                                  gauss(1.5, 0.25))
    
                    slot.normal_factor = gauss(rough, rough / 3)
    
    
                # Set the color influence to 0.5.
                # This allows for the moss textures to show:
    
                slot.diffuse_color_factor = 0.5
                # Set additional influence booleans:
                slot.use_stencil = True