displacements and message passing in renderman


This page shows the results of using displacement and message passing
in combination to create a planet maker.






Basic Idea:

Let's make a tool that makes a variety of planets!
We want to be able to control displacement to give
variation insurface height, as well as pass this information
to a surface shader to control ocean, grass, mountain, and
snow/peak coloring, as well as give snow and ocean
a specular hit.



		





Fractal noise:

This function allows us to make fractal noise, which is
noise that repeats upon itself (just google mandlebrot set).
It is important to orient PP to object space, so the noise
sticks to the object instead of defaulting to world space.


float fnc_fractal  (
    point   P_turb; 
    float   ampl_scale;
   	float   freq_scale;
	float 	amp;
	float	freq;
    float   octaves;
)
{
	float a = amp, 
		  f = freq,
		  i;
		
	#define snoise(P)	((noise(P)-0.33)*amp)
	
	varying float turb = 0;

	for ( i= 1; i <= octaves; i += 1){
	turb += a * snoise(P_turb*f);
	a /= ampl_scale;
	f *= freq_scale;
	}
	return turb;
}

point PP = transform("object",P);	/* put noise in object space. */
hump = fnc_fractal(PP, Amp_scale, Freq_scale, amplitude, Frequency, Octaves);
		





Controling the noise:

Now that we can make some fractal noise, we can clamp them
based on an ocean_height variable that the user controls.
This allows the various layers of bump to not cross
into the flat ocean. This is multiplied and passed
to the surface shader pipe.


vector Nn = normalize(N);  
point PP = transform("object",P);	/* put noise in object space. */
hump = fnc_fractal(PP, Amp_scale, Freq_scale, amplitude, Frequency, Octaves);
grasshump = fnc_fractal(PP, Grass_Amp_scale, Grass_Freq_scale, Grass_amplitude, Grass_Frequency, Grass_Octaves);
snowhump = fnc_fractal(PP, Snow_Amp_scale, Snow_Freq_scale, Snow_amplitude, Snow_Frequency, Snow_Octaves);

// These bump values are clamped to not go into the ocean
newbump = clamp(hump,ocean_height,1);
float newgrassbump = clamp(grasshump,ocean_height,1);
float newsnowhump = clamp(snowhump,ocean_height,1);

//Put them Together
P = P + Nn * (newgrassbump * Grass_amplitude)
* (newbump * amplitude)
* (newsnowhump * Snow_amplitude)
;
N = calculatenormal(P);

//Output these to be used by the surface shader for lighting + layering reasons.
Ocean_Height = ocean_height;
Grass_Height = grasshump;
		





Adding color based on displacement to surface shader:
Here, we have the functionality of adding mountains
to our planet. It's controlled by a user variable,
Mountain_ht, which drives when the mountains start
appearing.


float   height = 0;
float mountain_offset = 0;
float mountain_height = Mountain_ht;  /* note: noise is mostly btwn .3 and .8 */
/* Check for "Ocean_Offset" in displacement shader, and if it does, put it in mountain_offset and execute if statement */ 
if(displacement("Ocean_Height", mountain_offset) == 0.5)
{
    mountain_height += mountain_offset;
}

color surfcolor = ocean_color;
if(displacement("hump", height) == 1)
{
    float blend = smoothstep(mountain_height-0.1,mountain_height+0.1,height);
    surfcolor += mix(ocean_color,mountain_color,blend);  
}

		





Adding grass:
Similar to the above, we have grass being added
on top of the mountains.


float grass_offset = 0;
float grass_height = Grass_ht;
/* Check for "Ocean_Offset" in displacement shader, and if it does, put it in grass_offset and execute if statement */  
if(displacement("Ocean_Height", grass_offset) == 0.5)
{
    grass_height += grass_offset;
}

/*** Same, but with grass and snow ***/
if(displacement("grasshump", height) == 1)
{
	if(displacement("hump", height) == 1)
	{
		float grass_blend = smoothstep(grass_height+0.05,grass_height-0.05,height);
		surfcolor += mix(grass_color, mountain_color, grass_blend);

	}
}

		





Adding snow:
Again, we add snow.


float snow_offset = 0;
float snow_height = Snow_ht; 
/* Check for "Grass_Height" in displacement shader, and if it does, put it in snow_offset and execute if statement */ 
if(displacement("Grass_Height", snow_offset) == 0.5)
{
    snow_height += snow_offset;
}

color snow_spec = 1;	
if(displacement("snowhump", height) == 1)
{
	if(displacement("hump", height) == 1)
	{
		float snow_blend = smoothstep(snow_height+0.03,snow_height-0.03,height);
		surfcolor += mix(mountain_color, snow_color, snow_blend);
	}
}
		





Adding specularity:
I had trouble figuring out how to isolate a specular.
We need to isolate just the snow and the ocean areas
to add specularity. Since no ocean area is defined,
we add a specularity to the whole thing at the beginning,
and where we have isolated just all of the land we
subtract it back, giving just ocean spec. We also
do a specularity in just the snow section.


/* Initialize a specular highlight, this will be subtracted at the end of bump equations
to give a specular ocean */
ocean_spec = Specular_color * Ks * glossy_specular(Nf,Vo,roughness, glossiness);

color snow_spec = 1;	
if(displacement("snowhump", height) == 1)
	{
		if(displacement("hump", height) == 1)
		{
			float snow_blend = smoothstep(snow_height+0.03,snow_height-0.03,height);
			surfcolor += mix(mountain_color, snow_color, snow_blend);
			/* Add a snow specular */
			snow_spec = snow_blend * (Specular_color * Ks * glossy_specular(Nf,Vo,roughness, glossiness));
			
			/* Subtract back the ocean specular based on total bumpiness above the ocean */
			float ocean_blend = smoothstep(mountain_height-0.1,mountain_height+0.1,height);
			ocean_spec -= ocean_blend * (Specular_color * Ks * glossy_specular(Nf,Vo,roughness, glossiness));
		}
	}

color  diffusecolor = Kd * diffuse(nf); 

Ci = Oi * Cs * diffusecolor * surfcolor
	 + ocean_spec
	 + snow_spec;
		





Clouds!
Clouds are easy, but without a rim function they
look awkward on a planet, so we plug in my_cloud_rim,
which is a reversed function of my_rim used before.

You can get a lot of different planet looks with this
shader, I had fun making up some alien worlds. :)


point PP = transform("object",P);
//It's messy, but the rim is being multiplied by a cloud noise that is being cut into by another noise.
Oi = (my_cloud_rim(Nf, Vo, opacity_rim_width) * opacity_rim_strength)
* (opacity * fnc_fractal(PP, Noise2_Amp_scale, Noise2_Freq_scale, Noise2_amplitude, Noise2_Frequency, Noise2_Octaves))
* fnc_fractal(PP, Amp_scale, Freq_scale, amplitude, Frequency, Octaves); 
Ci = Oi * Cloud_color;
		

Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player






Lava Planet


		





Rocky, Cold Planet


		





Polluted Planet


		





Flat, Dusty Alien World


		




Conclusion:
Message passing is very powerful for the user to control and
perform look development on a given shader. The code ended up
working pretty well, the next things I would do is clean it
up a tad and add controls to get sharper peaks in the mountains.