Thursday, February 13, 2020

algorithm - Space nebula cloud generation?


I found a cool kickstarter project called "Skywanders". It's an minecraft like space game with a lego like building system and pretty cool graphics.


One thing I noticed are the "nebula clouds". They are procedurally generated 3D Objects and they look amazing.


enter image description here


How do I generate such nebulas? I bet there's a way to do that. And is it possible to convert a 2D nebula into a 3D one? I didn't found any algorithm yet or other sources.



Answer



I've done something similar in the past through glsl's Fragment Shaders:



Nebula with Stars


https://www.shadertoy.com/view/lsyfWy


And a Processing version:


https://github.com/felipunky/Stars


It is basically a Fractional Brownian Motion or several layers of noise at different frequencies and amplitudes stacked together:


#define HASHSCALE .1031
// We create the pseudo-random number generator.
// https://www.shadertoy.com/view/4djSRW
float hash(float p)
{


vec3 p3 = fract(vec3(p) * HASHSCALE);
p3 += dot(p3, p3.yzx + 19.19);
return fract((p3.x + p3.y) * p3.z);

}

// This function is by @Inigo Quilez.
// We create the 3D noise by generating pseudo-random numbers in the x, y and z directions and then interpolating between them.
float noise( in vec3 x )

{

vec3 p = floor( x );
vec3 k = fract( x );

k *= k * k * ( 3.0 - 2.0 * k );

float n = p.x + p.y * 57.0 + p.z * 113.0;

float a = hash( n );

float b = hash( n + 1.0 );
float c = hash( n + 57.0 );
float d = hash( n + 58.0 );

float e = hash( n + 113.0 );
float f = hash( n + 114.0 );
float g = hash( n + 170.0 );
float h = hash( n + 171.0 );

float res = mix( mix( mix ( a, b, k.x ), mix( c, d, k.x ), k.y ),

mix( mix ( e, f, k.x ), mix( g, h, k.x ), k.y ),
k.z
);

return res;

}

// Here we do the stacking of noise at different octaves.
float fbm( in vec3 p )

{

float f = 0.0;
f += 0.5000 * noise( p ); p *= 2.02; p -= iTime * 0.5;
f += 0.2500 * noise( p ); p *= 2.03; p += iTime * 0.4;
f += 0.1250 * noise( p ); p *= 2.01; p -= iTime * 0.5;
f += 0.0625 * noise( p );
f += 0.0125 * noise( p );
return f / 0.9375;


}

I find this fbm function more readable and easier to tweak:


float fbm( in vec3 p )
{

float res = 0.0, fre = 1.0, amp = 1.0, div = 0.0;

for( int i = 0; i < 5; ++i )
{


res += amp * noise( p * fre );
div += amp;
amp *= 0.7;
fre *= 1.7;

}

res /= div;


return res;

}

Rendered through a Sphere Tracing Algorithm that accumulates for a volumetric look:


// This is our ray marching algorithm.
float ray( vec3 ro, vec3 rd, out float den )
{

float t = 0.0, maxD = 0.0, d = 1.0; den = 0.0;


// The more STEPS the more accurate the marching.
for( int i = 0; i < STEPS; ++i )
{

// Here we compute our Position p by the formula RayOrigin + RayDirection * our RayMarchStep.
vec3 p = ro + rd * t;

// This is our density, it is simply calling the Fractional Brownian Motion fbm function.
den = fbm( p );


// This allows us to put a limit in our accumulation of density.
maxD = maxD < den ? den : maxD;

// Here we bail on our marching according to MaximumDensity or our FAR threshold.
if( maxD > 1.0 || t > FAR ) break;

// We increment our RayMarchingSteps.
t += 0.05;


}

den = maxD;

return t;

}

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...