Author Topic: [RESOURCE] Infinite Terrain Generation Algorithm  (Read 3854 times)

I've been asked for this before, and since I don't even mod for blockland anymore I thought it might be a nice little thing to give out.

yeah
so basically you have the global variables that define the max height and the min height (not even sure if those work, never cared to look, it looks like it works). I never really forgeted with the quality, so you can just leave that.

it is super 100% the hardest thing in the world. it takes so much time and effort to generate a single chunk it's not even funny
getsimplexZ(%x,%y) ==> z
Made for simplicity and fun. I know about the little glitch about certain threads of terrain being a little off. I fixed it on my old comp but lost that. iirc changing the numbers in the perm. table fixed it.

oh yeah the code.

Save this as simplex.cs
exec("./simplex2.cs");


$Terragen::Max = 64;
$Terragen::Min = 0;
$Terragen::Quality = 256 / 2;
function strToSeed(%str)
{
   %abc = "abcdefghijklmnopqrstuvwxyz";
   %abc = %abc @ strUpr(%abc);
   %abc = %abc @ "`1234567890-=~!@#$%^&*()_+[]\\;',./{}|:\"<>? ";
   %seed = "0.";
   for(%i=0;%i<strLen(%str);%i++)
   {
      %letter = getSubStr(%str,%i,%i);
      %pos = strPos(%abc,%letter);
      if(%pos == -1)
         %pos = getRandom(0,strLen(%abc));
      %seed = %seed @ %pos;
   }
   if(trim(%seed) $= "")
      %seed = getRandom() @ "2";
   else
      %seed = %seed @ "2";
   return %seed;
}
function getMasterSimplex()
{
   if(!isObject($simplexMaster))
   {
      talk("Creating Terrain Master");
      $simplexMaster = new ScriptObject()
      {
         seed = strToSeed("i like to eat");
         quality = $Terragen::Quality;
         max = $Terragen::Max;
         min = $Terragen::Min;
      };
   }
   return $simplexMaster;
}
function getsimplexZ(%x,%y)
{
   %simplex = getMastersimplex();
   if(%simplex.gen[%x,%y] !$= "")
   {
      return %simplex.gen[%x,%y];
   }
   %seed = %simplex.seed;
   %quality = %simplex.quality;
   %z = 0;
   %delta = %quality + %seed;
   %noise = snoise((%x / %seed) / %delta, (%y / %seed) / %delta,%z);
   %noise = (%noise + 1 ) / 2 * (%simplex.max - %simplex.min) + %simplex.min;
   %simplex.gen[%x,%y] = %noise;
   return %noise;
}


save this as simplex2.cs
%list = "151\t160\t137\t91\t90\t15\t131\t13\t201\t95\t96\t53\t194\t233\t7\t225\t140\t36" TAB
        "103\t30\t69\t142\t8\t99\t37\t240\t21\t10\t23\t190\t6\t148\t247\t120\t234\t75\t0" TAB
        "26\t197\t62\t94\t252\t219\t203\t117\t35\t11\t32\t57\t177\t33\t88\t237\t149\t56" TAB
        "87\t174\t20\t125\t136\t171\t168\t68\t175\t74\t165\t71\t134\t139\t48\t27\t166" TAB
        "77\t146\t158\t231\t83\t111\t229\t122\t60\t211\t133\t230\t220\t105\t92\t41\t55" TAB
        "46\t245\t40\t244\t102\t143\t54\t65\t25\t63\t161\t1\t216\t80\t73\t209\t76\t132" TAB
        "187\t208\t89\t18\t169\t200\t196\t135\t130\t116\t188\t159\t86\t164\t100\t109" TAB
        "198\t173\t186\t3\t64\t52\t217\t226\t250\t124\t123\t5\t202\t38\t147\t118\t126" TAB
        "255\t82\t85\t212\t207\t206\t59\t227\t47\t16\t58\t17\t182\t189\t28\t42\t223\t183" TAB
        "170\t213\t119\t248\t152\t2\t44\t154\t163\t70\t221\t153\t101\t155\t167\t43\t172" TAB
        "9\t129\t22\t39\t253\t19\t98\t108\t110\t79\t113\t224\t232\t178\t185\t112\t104" TAB
        "218\t246\t97\t228\t251\t34\t242\t193\t238\t210\t144\t12\t191\t179\t162\t241" TAB
        "81\t51\t145\t235\t249\t14\t239\t107\t49\t192\t214\t31\t181\t199\t106\t157\t184" TAB
        "84\t204\t176\t115\t121\t50\t45\t127\t4\t150\t254\t138\t236\t205\t93\t222\t114" TAB
        "67\t29\t24\t72\t243\t141\t128\t195\t78\t66\t215\t61\t156\t180";

// Store permutation array from the precomputed permutations.

for(%i = 0; %i < 256; %i++) {
    %field = getField(%list, %i);
    $Simplex::P[%i] = %field;
    $Simplex::P[256 + %i] = %field;
}
function lerp(%t, %a, %b)
{
   return %a + %t * (%b - %a);
}
function fade(%t)
{
   return %t * %t * %t * (%t * (%t * 6 - 15) + 10);
}

function grad(%hash,%x,%y,%z)
{
   %h = %hash & 15;
   %u = %h < 8 ? %x : %y;
   %v = %h < 4 ? %y : %h == 12 || %h == 14 ? %x : %z;
   
   return ((%h & 1) == 0 ? %u : -%u) + ((%h & 2) == 0 ? %v : -%v);
}

function snoise(%x,%y,%z)
{
   %floopX = mFloor(%x) & 255;
   %floopY = mFloor(%y) & 255;
   %floopZ = mFloor(%z) & 255;
   %x -= mFloor(%x);
   %y -= mFloor(%y);
   %z -= mFloor(%z);

   %u = fade(%x);
   %v = fade(%y);
   %w = fade(%z);

   %a = $Simplex::P[%floopX] + %floopY;
   %aa = $Simplex::P[%a] + %floopZ;
   %ab = $Simplex::P[%a + 1] + %floopZ;
   %b = $Simplex::P[%floopX + 1] + %floopY;
   %ba = $Simplex::P[%b] + %floopZ;
   %bb = $Simplex::P[%b + 1] + %floopZ;

   %pAA = $Simplex::P[%aa];
   %pAB = $Simplex::P[%ab];
   %pBA = $Simplex::P[%ba];
   %pBB = $Simplex::P[%bb];
   %pAA1 = $Simplex::P[%aa + 1];
   %pBA1 = $Simplex::P[%ba + 1];
   %pBB1 = $Simplex::P[%bb + 1];

   %gradAA = grad(%pAA,%x,%y,%z);
   %gradBA = grad(%pBA, %x-1,%y,%z);
   %gradAB = grad(%pAB,%x,%y-1,%z);
   %gradBB = grad(%pBB,%x-1,%y-1,%z);
   %gradAA1 = grad(%pAA1,%x,%y,%z-1);
   %gradBA1 = grad(%pBA1,%x-1,%y,%z-1);
   %gradAB1 = grad(%pAB1,%x,%y-1,%z-1);
   %gradBB1 = grad(%pBB1,%x-1,%y-1,%z-1);

   return lerp(%w,
      lerp(%v, lerp(%u, %gradAA, %gradBA), lerp(%u, %gradAB, %gradBB)),
      lerp(%v, lerp(%u, %gradAA1, %gradBA1), lerp(%u,%gradAB1,%gradBB1))
      );

}


Right, so just execute simplex.cs and you are good.

oh yeah and I have that weird strtoseed thing. Don't know if it works so if you figure out if it does / doesn't then post.

if you use this, pls give me credit. thanks ;).

I have also written this in some other languages. The next post has those

Python
get it here - bbc was being a bbitch

returns
(x,y,z,type)
where type == dirt or grass (above ground or below ground)



Rust
fn floor(a: float) -> float {
   let mut b = a as f64;
   b = float::floor(b);
   let c = b as float;
   return c;
}
fn permentation() -> ~[int] {
   let list = ~[151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,
               103,30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,
               26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,
               87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,
               77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,
               46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,
               187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,109,
               198,173,186,3,64,52,217,226,250,124,123,5,202,38,147,118,126,
               255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,
               170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,
               9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,
               218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,
               81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,184,
               84,204,176,115,121,50,45,127,4,150,254,138,236,205,93,222,114,
               67,29,24,72,243,141,128,195,78,66,215,61,156,180];

   return vec::concat([copy list, copy list]);
}
fn lerp(t: float, a: float,  b: float) -> float {
   return a + t * (b - a);
}
fn fade(t: float) -> float {
   return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
}
fn grad(hash: int, x: float, y: float, z: float) -> float {
   let hi = hash as int;
   let h = hi & 15;
   let u = if h < 8 { x } else { y };
   let v = if h < 4 { y } else { if h == 12 || h == 14 { x } else { z } };
   return (if h & 1 == 0 { u } else { -u }) + (if h & 2 == 0 { v } else { -v });
}
fn snoise(nx: float, ny: float, nz: float, p: ~[int]) -> float {
   let nxi = nx as int;
   let nyi = ny as int;
   let nzi = nz as int;

   let floopXi = nxi & 255;
   let floopYi = nyi & 255;
   let floopZi = nzi & 255;

   let x = floor(nx)-nx;
   let y = floor(ny)-ny;
   let z = floor(nz)-nz;

   let u = fade(x);
   let v = fade(y);
   let w = fade(z);

   let a = p[floopXi] + floopYi;
   let ai = a as int;
   let aa = p[ai] + floopZi;
   let ab = p[ai+1] + floopZi;
   let b = p[floopXi + 1] + floopYi;
   let bi = b as int;
   let ba = p[bi] + floopZi;
   let bb = p[bi + 1] + floopZi;

   let pAA = p[aa];
   let pAB = p[ab];
   let pBA = p[ba];
   let pBB = p[bb];
   let pAA1 = p[aa+1];
   let pAB1 = p[ab+1];
   let pBA1 = p[ba+1];
   let pBB1 = p[bb+1];

   let gradAA = grad(pAA, x, y, z);
   let gradBA = grad(pBA, x-1.0, y, z);
   let gradAB = grad(pAB, x, y-1.0, z);
   let gradBB = grad(pBB,x-1.0,y-1.0,z);
   let gradAA1 = grad(pAA1, x, y , z-1.0);
   let gradBA1 = grad(pBA1,x-1.0,y,z-1.0);
   let gradAB1 = grad(pAB1,x,y-1.0,z-1.0);
   let gradBB1 = grad(pBB1,x-1.0,y-1.0,z-1.0);

   return lerp(w,
      lerp(v, lerp(u, gradAA, gradBA), lerp(u, gradAB, gradBB)),
      lerp(v, lerp(u, gradAA1, gradBA1), lerp(u, gradAB1, gradBB1))
      );
}
fn main() {
   let x = 11.0;
   let y = 5.0;
   let z = 1.0;

   let max = 30;
   let min = 10;

   let seed = 0.12312313512341;
   let quality = 128.0;
   let delta = quality + seed;
   let perm = permentation();
   
   let sn = snoise((x / seed) / delta, (y / seed) / delta, (z / seed) / delta,perm);

   let sni = sn as int;

   let noise = (sni + 1) / 2 * (max - min) + min;
   
   io::println(fmt!("%?",noise));
}


Not extensively tested, this was my first program lol in Rust.


JavaScript
simplex.js

not tested very much but probably works.



If you'd like any other language I'll gladly write it up.
« Last Edit: May 31, 2013, 10:37:17 PM by Brian Smithers »






why is no one talking :(

because there aren't very many people that actually care about terrain generation, at least not in the blockland community

why is no one talking :(
How do we talk, when our minds are blown?