raytracing in renderman


This page shows the results of using raytrace functions
in combination to create a glass shader.






Basic Idea:

The purpose of this project is to create a realistic glass shader.
Aspects of the previous project in addition to assets made were
quite useful. We start by figuring out how the trace function
works. It's good, but gather allows for more flexibility
in addition to light passing through the surface more
realistically.


fig. 1
if (Nn.V < 0) {
  Ci += trace(P, R);
}

Basically this means:
If a point is facing the camera, trace a reflection.
R is the reflection vector.
		




While the fake rim wasn't very difficult to make,
it's nice to be able to just reuse it in the future.


In the context of the final shader:
env *= Kr*(my_rim(Nf,Vo,rim_width)) * rim_strength;

This means: Take my calculated reflection, and multiply it
by my premade fake rim function.
		




This is where I was at about half a week ago,
before jumping into refractions.


		




Behold, refractions! These gave me some problems,
as it was confusing to me thinking of how transparency
is factored in. After realizing that refractions are
just a layer of light being let through and redirected,
it was easy to find where to put rim and transparency.


float eta = (In.N < 0 ? 1/IOR : IOR);
T = refract(In, Nf,eta);
R = reflect(In, Nn);

if (raytrace == 0) {
		env += environment(texturename, T,"blur", Rfr_blur, "samples", Rfr_samples)*Kt;
	} else {
		gather("illuminance", P, T, Rfr_blur, Rfr_samples, "maxdist", Rfr_maxdist, "volume:Ci", hitcolor_rfr){
			env += (hitcolor_rfr* Kt)*transparency;
		}else{	
			//Adding opacity rim and shadow opaque'ness.
			Oi = my_rim(Nf,Vo,Opacityrim_width)*Opacityrim_strength+(ShadowOpaque);
		}
	}

env = env/ Rfr_samples;

This looks like a lot, but it's not too complicated:
The top is calculating a transmission and reflection 
vector based on the index of refraction (for 
transmission).

The bottom checks for the raytracing being on or off.
If it's off, use just the environment map.
If it's on, gather using the transmission vector.
The bottom line adjusts the shadow opaqueness.

		




Behold! Fresnel reflections! Now let's take a look at what we got in terms of looks:


if (Nn.In < 0){	
	if (raytrace == 0) {
		env += environment(texturename, R,"blur", Rfl_blur, "samples", Rfl_samples)*Kr;
	} else {
		gather("illuminance", P, R, Rfl_blur, Rfl_samples, "maxdist", Rfl_maxdist, "volume:Ci", hitcolor_rfl){
			env += hitcolor_rfl* Kr 
			;
		} else {
			env += environment(texturename, R,"blur", Rfl_blur, "samples", Rfl_samples) * Kr
			;
		}
	}
}
		
	env = env / Rfl_samples;	
	env *= Kr*(my_rim(Nf,Vo,Rflrim_width)) * Rflrim_strength; // Adding rim controls to reflectivity

The shader looks for raytracing being on, and makes the appropriate choice.
Reflection looks for a raytrace target, if it doesn't find it, the map is used.

		




'Marble'
Plain, green, 75% transparent.
Strong fresnel reflection.
Low opacity fresnel.



		




'Some Sort of Glass Car Paint'
20% transparent
Rougher but toned down specular
Medium fresnel, but spread out more



		




'Vase glass'
80% transparent
Higher index of refraction
Glossy specular
Very toned down fresnel
Now let's take a look at some finalized renders on real objects:



		




Mostly shader defaults, some tinting.



		




Blurred reflection and refraction
Rougher specular highlight
Some of the shadow and body filled in to give some extra frosted-ness.



		




Conclusion:
The nesting of if statements to check for calculations
is powerful, it saves you rendertime if you only want
certain features. For future development, I would finish
the fake caustic feature in addition to adding additonal
controls for transparency.