From c26eb87aec7438d167fa2f460a3f412db09c0ac5 Mon Sep 17 00:00:00 2001 From: paramat Date: Tue, 8 Dec 2015 05:40:36 +0000 Subject: [PATCH] Mgfractal: Add 3D and 4D fractals 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 | 51 ++++++++++++++--------- minetest.conf.example | 53 ++++++++++++++---------- src/mapgen_fractal.cpp | 88 +++++++++++++++++++++++++++++++++------- src/mapgen_fractal.h | 12 ++++-- 4 files changed, 145 insertions(+), 59 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 4a714e1aa..62f817062 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -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 diff --git a/minetest.conf.example b/minetest.conf.example index 34d618fd5..40456f953 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -1234,20 +1234,30 @@ #### 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 @@ -1255,36 +1265,37 @@ # 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 diff --git a/src/mapgen_fractal.cpp b/src/mapgen_fractal.cpp index 14dfe5c85..6c03c4ca9 100644 --- a/src/mapgen_fractal.cpp +++ b/src/mapgen_fractal.cpp @@ -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; } - for (u16 iter = 0; iter < iterations; iter++) { - float nx = 0.0f; - float ny = 0.0f; - float nz = 0.0f; - float nw = 0.0f; + 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 + for (u16 iter = 0; iter < iterations; iter++) { + + 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) diff --git a/src/mapgen_fractal.h b/src/mapgen_fractal.h index 7d31a43b8..3d4f7ee8f 100644 --- a/src/mapgen_fractal.h +++ b/src/mapgen_fractal.h @@ -3,6 +3,9 @@ Minetest Copyright (C) 2010-2015 kwolekr, Ryan Kwolek 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;