Mgfractal: Add 3D and 4D fractals
authorparamat <mat.gregory@virginmedia.com>
Tue, 8 Dec 2015 05:40:36 +0000 (05:40 +0000)
committerparamat <mat.gregory@virginmedia.com>
Tue, 15 Dec 2015 04:18:19 +0000 (04:18 +0000)
3D Mandelbrot/Mandelbar
3D Christmas Tree
3D Mandelbulb
3D Cosine Mandelbulb
4D Mandelbulb
Plus corresponding julia set for each
Add credits for formulas
Rename parameter 'formula' to 'fractal'
Speed optimisations

builtin/settingtypes.txt
minetest.conf.example
src/mapgen_fractal.cpp
src/mapgen_fractal.h

index 4a714e1aaf0fb8740dbb95ef75d3c64cc6daec73..62f817062dbc6a8259bd59a0e9e706913e110b62 100644 (file)
@@ -970,49 +970,60 @@ mgflat_np_cave2 (Mapgen flat cave2 noise parameters) noise_params 0, 12, (128, 1
 
 [***Mapgen fractal]
 
-#    Choice of 8 4-dimensional fractals.
-#    1 = "Roundy" mandelbrot set.
-#    2 = "Roundy" julia set.
-#    3 = "Squarry" mandelbrot set.
-#    4 = "Squarry" julia set.
-#    5 = "Mandy Cousin" mandelbrot set.
-#    6 = "Mandy Cousin" julia set.
-#    7 = "Variation" mandelbrot set.
-#    8 = "Variation" julia set.
-mgfractal_formula (Mapgen fractal formula) int 1 1 8
+#    Choice of 18 fractals from 9 formulas.
+#    1 = 4D "Roundy" mandelbrot set.
+#    2 = 4D "Roundy" julia set.
+#    3 = 4D "Squarry" mandelbrot set.
+#    4 = 4D "Squarry" julia set.
+#    5 = 4D "Mandy Cousin" mandelbrot set.
+#    6 = 4D "Mandy Cousin" julia set.
+#    7 = 4D "Variation" mandelbrot set.
+#    8 = 4D "Variation" julia set.
+#    9 = 3D "Mandelbrot/Mandelbar" mandelbrot set.
+#    10 = 3D "Mandelbrot/Mandelbar" julia set.
+#    11 = 3D "Christmas Tree" mandelbrot set.
+#    12 = 3D "Christmas Tree" julia set.
+#    13 = 3D "Mandelbulb" mandelbrot set.
+#    14 = 3D "Mandelbulb" julia set.
+#    15 = 3D "Cosine Mandelbulb" mandelbrot set.
+#    16 = 3D "Cosine Mandelbulb" julia set.
+#    17 = 4D "Mandelbulb" mandelbrot set.
+#    18 = 4D "Mandelbulb" julia set.
+mgfractal_fractal (Mapgen fractal fractal) int 1 1 18
 
 #    Iterations of the recursive function.
-#    Controls scale of finest detail.
+#    Controls the amount of fine detail.
 mgfractal_iterations (Mapgen fractal iterations) int 11
 
 #    Approximate (X,Y,Z) scale of fractal in nodes.
 mgfractal_scale (Mapgen fractal scale) v3f (4096.0, 1024.0, 4096.0)
 
-#    (X,Y,Z) offset of fractal from world centre.
+#    (X,Y,Z) offset of fractal from world centre in units of 'scale'.
 #    Used to move a suitable spawn area of low land close to (0, 0).
-#    The default is suitable for mandelbrot sets, it needs to be edited for julia sets,
-#    do this by greatly reducing 'scale' and setting 'offset' initially to (0, 0, 0).
+#    The default is suitable for mandelbrot sets, it needs to be edited for julia sets.
 #    Range roughly -2 to 2. Multiply by 'scale' for offset in nodes.
 mgfractal_offset (Mapgen fractal offset) v3f (1.79, 0.0, 0.0)
 
-#    W co-ordinate of the generated 3D slice of the 4D shape.
-#    Alters the generated 3D shape.
+#    W co-ordinate of the generated 3D slice of a 4D fractal.
+#    Determines which 3D slice of the 4D shape is generated.
+#    Has no effect on 3D fractals.
 #    Range roughly -2 to 2.
 mgfractal_slice_w (Mapgen fractal slice w) float 0.0
 
-#    Julia set only: X value determining the 4D shape.
+#    Julia set only: X component of hypercomplex constant determining julia shape.
 #    Range roughly -2 to 2.
 mgfractal_julia_x (Mapgen fractal julia x) float 0.33
 
-#    Julia set only: Y value determining the 4D shape.
+#    Julia set only: Y component of hypercomplex constant determining julia shape.
 #    Range roughly -2 to 2.
 mgfractal_julia_y (Mapgen fractal julia y) float 0.33
 
-#    Julia set only: Z value determining the 4D shape.
+#    Julia set only: Z component of hypercomplex constant determining julia shape.
 #    Range roughly -2 to 2.
 mgfractal_julia_z (Mapgen fractal julia z) float 0.33
 
-#    Julia set only: W value determining the 4D shape.
+#    Julia set only: W component of hypercomplex constant determining julia shape.
+#    Has no effect on 3D fractals.
 #    Range roughly -2 to 2.
 mgfractal_julia_w (Mapgen fractal julia w) float 0.33
 
index 34d618fd55ee60673a3953930f29ab58bf2ec983..40456f9530e5be41919c87cd7f0ff0bb3f7f8683 100644 (file)
 
 #### Mapgen fractal
 
-#    Choice of 8 4-dimensional fractals.
-#    1 = "Roundy" mandelbrot set.
-#    2 = "Roundy" julia set.
-#    3 = "Squarry" mandelbrot set.
-#    4 = "Squarry" julia set.
-#    5 = "Mandy Cousin" mandelbrot set.
-#    6 = "Mandy Cousin" julia set.
-#    7 = "Variation" mandelbrot set.
-#    8 = "Variation" julia set.
-#    type: int min: 1 max: 8
-# mgfractal_formula = 1
+#    Choice of 18 fractals from 9 formulas.
+#    1 = 4D "Roundy" mandelbrot set.
+#    2 = 4D "Roundy" julia set.
+#    3 = 4D "Squarry" mandelbrot set.
+#    4 = 4D "Squarry" julia set.
+#    5 = 4D "Mandy Cousin" mandelbrot set.
+#    6 = 4D "Mandy Cousin" julia set.
+#    7 = 4D "Variation" mandelbrot set.
+#    8 = 4D "Variation" julia set.
+#    9 = 3D "Mandelbrot/Mandelbar" mandelbrot set.
+#    10 = 3D "Mandelbrot/Mandelbar" julia set.
+#    11 = 3D "Christmas Tree" mandelbrot set.
+#    12 = 3D "Christmas Tree" julia set.
+#    13 = 3D "Mandelbulb" mandelbrot set.
+#    14 = 3D "Mandelbulb" julia set.
+#    15 = 3D "Cosine Mandelbulb" mandelbrot set.
+#    16 = 3D "Cosine Mandelbulb" julia set.
+#    17 = 4D "Mandelbulb" mandelbrot set.
+#    18 = 4D "Mandelbulb" julia set.
+#    type: int min: 1 max: 18
+# mgfractal_fractal = 1
 
 #    Iterations of the recursive function.
-#    Controls scale of finest detail.
+#    Controls the amount of fine detail.
 #    type: int
 # mgfractal_iterations = 11
 
 #    type: v3f
 # mgfractal_scale = (4096.0, 1024.0, 4096.0)
 
-#    (X,Y,Z) offset of fractal from world centre.
+#    (X,Y,Z) offset of fractal from world centre in units of 'scale'.
 #    Used to move a suitable spawn area of low land close to (0, 0).
-#    The default is suitable for mandelbrot sets, it needs to be edited for julia sets,
-#    do this by greatly reducing 'scale' and setting 'offset' initially to (0, 0, 0).
+#    The default is suitable for mandelbrot sets, it needs to be edited for julia sets.
 #    Range roughly -2 to 2. Multiply by 'scale' for offset in nodes.
 #    type: v3f
 # mgfractal_offset = (1.79, 0.0, 0.0)
 
-#    W co-ordinate of the generated 3D slice of the 4D shape.
-#    Alters the generated 3D shape.
+#    W co-ordinate of the generated 3D slice of a 4D fractal.
+#    Determines which 3D slice of the 4D shape is generated.
+#    Has no effect on 3D fractals.
 #    Range roughly -2 to 2.
 #    type: float
 # mgfractal_slice_w = 0.0
 
-#    Julia set only: X value determining the 4D shape.
+#    Julia set only: X component of hypercomplex constant determining julia shape.
 #    Range roughly -2 to 2.
 #    type: float
 # mgfractal_julia_x = 0.33
 
-#    Julia set only: Y value determining the 4D shape.
+#    Julia set only: Y component of hypercomplex constant determining julia shape.
 #    Range roughly -2 to 2.
 #    type: float
 # mgfractal_julia_y = 0.33
 
-#    Julia set only: Z value determining the 4D shape.
+#    Julia set only: Z component of hypercomplex constant determining julia shape.
 #    Range roughly -2 to 2.
 #    type: float
 # mgfractal_julia_z = 0.33
 
-#    Julia set only: W value determining the 4D shape.
+#    Julia set only: W component of hypercomplex constant determining julia shape.
+#    Has no effect on 3D fractals.
 #    Range roughly -2 to 2.
 #    type: float
 # mgfractal_julia_w = 0.33
index 14dfe5c851b934ca2db2c3c9223b8e9e39eb6f18..6c03c4ca95d59d0d507388c99c423d28ec7966f2 100644 (file)
@@ -66,7 +66,7 @@ MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *
        MapgenFractalParams *sp = (MapgenFractalParams *)params->sparams;
        this->spflags = sp->spflags;
 
-       this->formula    = sp->formula;
+       this->fractal    = sp->fractal;
        this->iterations = sp->iterations;
        this->scale      = sp->scale;
        this->offset     = sp->offset;
@@ -77,6 +77,9 @@ MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *
        this->julia_z = sp->julia_z;
        this->julia_w = sp->julia_w;
 
+       this->formula = fractal / 2 + fractal % 2;
+       this->julia   = fractal % 2 == 0;
+
        //// 2D terrain noise
        noise_seabed       = new Noise(&sp->np_seabed, seed, csize.X, csize.Z);
        noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
@@ -141,7 +144,7 @@ MapgenFractalParams::MapgenFractalParams()
 {
        spflags = 0;
 
-       formula = 1;
+       fractal = 1;
        iterations = 11;
        scale = v3f(4096.0, 1024.0, 4096.0);
        offset = v3f(1.79, 0.0, 0.0);
@@ -163,7 +166,7 @@ void MapgenFractalParams::readParams(const Settings *settings)
 {
        settings->getFlagStrNoEx("mgfractal_spflags", spflags, flagdesc_mapgen_fractal);
 
-       settings->getU16NoEx("mgfractal_formula", formula);
+       settings->getU16NoEx("mgfractal_fractal", fractal);
        settings->getU16NoEx("mgfractal_iterations", iterations);
        settings->getV3FNoEx("mgfractal_scale", scale);
        settings->getV3FNoEx("mgfractal_offset", offset);
@@ -185,7 +188,7 @@ void MapgenFractalParams::writeParams(Settings *settings) const
 {
        settings->setFlagStr("mgfractal_spflags", spflags, flagdesc_mapgen_fractal, U32_MAX);
 
-       settings->setU16("mgfractal_formula", formula);
+       settings->setU16("mgfractal_fractal", fractal);
        settings->setU16("mgfractal_iterations", iterations);
        settings->setV3F("mgfractal_scale", scale);
        settings->setV3F("mgfractal_offset", offset);
@@ -368,7 +371,7 @@ bool MapgenFractal::getFractalAtPoint(s16 x, s16 y, s16 z)
 {
        float cx, cy, cz, cw, ox, oy, oz, ow;
 
-       if (formula % 2 == 0) {  // Julia sets, formula = 2, 4, 6, 8
+       if (julia) {  // Julia set
                cx = julia_x;
                cy = julia_y;
                cz = julia_z;
@@ -377,7 +380,7 @@ bool MapgenFractal::getFractalAtPoint(s16 x, s16 y, s16 z)
                oy = (float)y / scale.Y - offset.Y;
                oz = (float)z / scale.Z - offset.Z;
                ow = slice_w;
-       } else {  // Mandelbrot sets, formula = 1, 3, 5, 7
+       } else {  // Mandelbrot set
                cx = (float)x / scale.X - offset.X;
                cy = (float)y / scale.Y - offset.Y;
                cz = (float)z / scale.Z - offset.Z;
@@ -388,32 +391,87 @@ bool MapgenFractal::getFractalAtPoint(s16 x, s16 y, s16 z)
                ow = 0.0f;
        }
 
+       float nx = 0.0f;
+       float ny = 0.0f;
+       float nz = 0.0f;
+       float nw = 0.0f;
+
        for (u16 iter = 0; iter < iterations; iter++) {
-               float nx = 0.0f;
-               float ny = 0.0f;
-               float nz = 0.0f;
-               float nw = 0.0f;
 
-               if (formula == 1 || formula == 2) {  // 4D "Roundy" Mandelbrot/Julia Set
+               if (formula == 1) {  // 4D "Roundy"
                        nx = ox * ox - oy * oy - oz * oz - ow * ow + cx;
                        ny = 2.0f * (ox * oy + oz * ow) + cy;
                        nz = 2.0f * (ox * oz + oy * ow) + cz;
                        nw = 2.0f * (ox * ow + oy * oz) + cw;
-               } else if (formula == 3 || formula == 4) {  // 4D "Squarry" Mandelbrot/Julia Set
+               } else if (formula == 2) {  // 4D "Squarry"
                        nx = ox * ox - oy * oy - oz * oz - ow * ow + cx;
                        ny = 2.0f * (ox * oy + oz * ow) + cy;
                        nz = 2.0f * (ox * oz + oy * ow) + cz;
                        nw = 2.0f * (ox * ow - oy * oz) + cw;
-               } else if (formula == 5 || formula == 6) {  // 4D "Mandy Cousin" Mandelbrot/Julia Set
+               } else if (formula == 3) {  // 4D "Mandy Cousin"
                        nx = ox * ox - oy * oy - oz * oz + ow * ow + cx;
                        ny = 2.0f * (ox * oy + oz * ow) + cy;
                        nz = 2.0f * (ox * oz + oy * ow) + cz;
                        nw = 2.0f * (ox * ow + oy * oz) + cw;
-               } else if (formula == 7 || formula == 8) {  // 4D "Variation" Mandelbrot/Julia Set
+               } else if (formula == 4) {  // 4D "Variation"
                        nx = ox * ox - oy * oy - oz * oz - ow * ow + cx;
                        ny = 2.0f * (ox * oy + oz * ow) + cy;
                        nz = 2.0f * (ox * oz - oy * ow) + cz;
                        nw = 2.0f * (ox * ow + oy * oz) + cw;
+               } else if (formula == 5) {  // 3D "Mandelbrot/Mandelbar"
+                       nx = ox * ox - oy * oy - oz * oz + cx;
+                       ny = 2.0f * ox * oy + cy;
+                       nz = -2.0f * ox * oz + cz;
+               } else if (formula == 6) {  // 3D "Christmas Tree"
+                       // Altering the formula here is necessary to avoid division by zero
+                       if (fabs(oz) < 0.000000001f) {
+                               nx = ox * ox - oy * oy - oz * oz + cx;
+                               ny = 2.0f * oy * ox + cy;
+                               nz = 4.0f * oz * ox + cz;
+                       } else {
+                               float a = (2.0f * ox) / (sqrt(oy * oy + oz * oz));
+                               nx = ox * ox - oy * oy - oz * oz + cx;
+                               ny = a * (oy * oy - oz * oz) + cy;
+                               nz = a * 2.0f * oy * oz + cz;
+                       }
+               } else if (formula == 7) {  // 3D "Mandelbulb"
+                       if (fabs(oy) < 0.000000001f) {
+                               nx = ox * ox - oz * oz + cx;
+                               ny = cy;
+                               nz = -2.0f * oz * sqrt(ox * ox) + cz;
+                       } else {
+                               float a = 1.0f - (oz * oz) / (ox * ox + oy * oy);
+                               nx = (ox * ox - oy * oy) * a + cx;
+                               ny = 2.0f * ox * oy * a + cy;
+                               nz = -2.0f * oz * sqrt(ox * ox + oy * oy) + cz;
+                       }
+               } else if (formula == 8) {  // 3D "Cosine Mandelbulb"
+                       if (fabs(oy) < 0.000000001f) {
+                               nx = 2.0f * ox * oz + cx;
+                               ny = 4.0f * oy * oz + cy;
+                               nz = oz * oz - ox * ox - oy * oy + cz;
+                       } else {
+                               float a = (2.0f * oz) / sqrt(ox * ox + oy * oy);
+                               nx = (ox * ox - oy * oy) * a + cx;
+                               ny = 2.0f * ox * oy * a + cy;
+                               nz = oz * oz - ox * ox - oy * oy + cz;
+                       }
+               } else if (formula == 9) {  // 4D "Mandelbulb"
+                       float rxy = sqrt(ox * ox + oy * oy);
+                       float rxyz = sqrt(ox * ox + oy * oy + oz * oz);
+                       if (fabs(ow) < 0.000000001f && fabs(oz) < 0.000000001f) {
+                               nx = (ox * ox - oy * oy) + cx;
+                               ny = 2.0f * ox * oy + cy;
+                               nz = -2.0f * rxy * oz + cz;
+                               nw = 2.0f * rxyz * ow + cw;
+                       } else {
+                               float a = 1.0f - (ow * ow) / (rxyz * rxyz);
+                               float b = a * (1.0f - (oz * oz) / (rxy * rxy));
+                               nx = (ox * ox - oy * oy) * b + cx;
+                               ny = 2.0f * ox * oy * b + cy;
+                               nz = -2.0f * rxy * oz * a + cz;
+                               nw = 2.0f * rxyz * ow + cw;
+                       }
                }
 
                if (nx * nx + ny * ny + nz * nz + nw * nw > 4.0f)
index 7d31a43b8241926bf7642746928c9013ecf735c6..3d4f7ee8ff9620bd95961744627ed77f7d45c3c8 100644 (file)
@@ -3,6 +3,9 @@ Minetest
 Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
 Copyright (C) 2010-2015 paramat, Matt Gregory
 
+Fractal formulas from http://www.bugman123.com/Hypercomplex/index.html
+by Paul Nylander, and from http://www.fractalforums.com, thank you.
+
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
 the Free Software Foundation; either version 2.1 of the License, or
@@ -33,7 +36,7 @@ extern FlagDesc flagdesc_mapgen_fractal[];
 struct MapgenFractalParams : public MapgenSpecificParams {
        u32 spflags;
 
-       u16 formula;
+       u16 fractal;
        u16 iterations;
        v3f scale;
        v3f offset;
@@ -63,14 +66,17 @@ public:
 
        int ystride;
        int zstride;
-       u32 spflags;
+       u16 formula;
+       bool julia;
 
        v3s16 node_min;
        v3s16 node_max;
        v3s16 full_node_min;
        v3s16 full_node_max;
 
-       u16 formula;
+       u32 spflags;
+
+       u16 fractal;
        u16 iterations;
        v3f scale;
        v3f offset;