This page shows the application of custom surface and displacement shaders to a simple Maya geometry to simulate a flickering flame.

Reference Images

			
			

First, the gradient between the blue base of the flame and the white body was set up.

color basecolor = mix(white, blue, smoothstep(blue_height - 
	blue_deviation, blue_height, tt));

This function sets that base color of the flame, over which
	the other colors will be added, and is keyed to the 
	following artist inputs: blue_height, a float that 
	establishes where the transition is between the blue 
	and white parts of the flame, blue_deviation, a float
	that establishes how large the smoothstep transition 
	from blue to white should be; and the color inputs 
	white and blue, which establish the colors for the upper
	and lower portions of the flame.
			


Then, a yellow tint around the edges.

				

float yellow_edge = (1 - smoothstep (blue_height - blue_deviation, blue_height, tt)) * smoothstep (1 - yellow_edge_width, 1.0, 1 - i.nf); This function outputs a float value to be used when mixing the yellow tint with the previously established color. It uses the blue_height and blue_height_deviation artist inputs, as well as the yellow_edge_width float, which adjusts how far into the white portion of the flame the yellow tint extends. color yellowedge = mix(basecolor, yellow, yellow_edge); This takes the yellow_edge float value, and uses it to mix the tint into the surface's color.


Next, the transparancy is achived using angle of incidence and a smoothstep.

				

float dot = 1 - smoothstep (blue_height - blue_deviation, blue_height, tt) + (1 - i.nf); This function is keyed to the same float inputs as the first color function so that it matches the location of the color gradient automatically. Oi = smoothstep (1 - rim_width, 1.0, dot) / transparancy_factor; This function takes the float value from the above function and sets it as the Oi transparancy value. The function also makes use of the rim_width float value to adjust the thickness of the opaque areas at the edge of the flame's base. It includes an extra float variable (transparancy_factor) to allow the artist to tweak the effect a bit.

I attempted to achieve an elegant solution by combining the surface and displacement functions into a single shader, which caused problems later.



The displacement function's noise input was added next.

				

dispvalue = noise(transform(spacename, P) * frequency) + displacement_magnitude_adjustment; This function is keyed to two artist inputs; frequency, which adjusts the frequency of the noise, as the name implies, and displacement_magnitude_adjustment, which is a value added to the noise output to make the displacement larger or smaller. There is also a world space input, spacename, which can be linked to a Maya place3dTexture node to animate the noise for a flickering effect.


Then a smoothstep was added to create a displacement falloff effect.

				

dispfalloff = smoothstep(displacement_adjustment, 1, t); The smoothstep is keyed to the displacemet_adjustement artist input, which acts as the start value for the smoothstep, and can be moved up or down the geometry.


There is a problem due to the Displacement Bounds defaulting to zero.

				

A problem arose when the dual purpose shader was applied to a Maya object and rendered: because RenderMan surface shaders do not come with a Displacement Bounds attribute, the renderer assumed a default value of zero, and provided no slider or other input for me to change the value. The result is a choppy, artifact filled, and unusable render.


The Displacement Bounds problem has been fixed,

				

The problem could be fixed in one of two ways: splitting the displacement functions off from the original shader and applying them separately, or by applying a 'blank' displacement shader and using its 'Displacement Bounds' attribute to make an end run around the problem.




This is the first test animation of the finished flame

For the first test, Km was set 0.57, frequency to 
0.500, displacement_adjustment to 0.25, and 
displacement_magnitude_adjustment to 0.00. The 
worldspace that the displacement's noise function 
is slaved to was moved from 0 to 36 units on the 
y-axis over the course of 48 frames.
			




The animation with a basic glow effect added in post.

An orange glow effect has been added in post to 
the animation above to closer match the original 
reference images.