//pref
lightAmount|float|0.0|0.3|1
edgeThresh|float|0.0|0.01|1
edgeExp|float|0.0|0.15|1
boundExp|float|0.0|0.0|3
Diffuse lighting with edge shading.|note
//vert
void main() {
	gl_TexCoord[1] = gl_MultiTexCoord1;
	gl_Position = ftransform();
}
//frag
uniform int loops;
uniform float stepSize, sliceSize, viewWidth, viewHeight;
uniform sampler3D intensityVol; //3DTexture containing brightness
uniform sampler3D gradientVol; //3DTexture containing gradient direction and magnitude
uniform sampler2D backFace;
uniform vec3 clearColor,lightPosition, clipPlane;
uniform float clipPlaneDepth;
uniform float edgeThresh, edgeExp, boundExp, lightAmount;
void main() {
	// get normalized pixel coordinate in view port (e.g. [0,1]x[0,1])
	vec2 pixelCoord = gl_FragCoord.st;
	pixelCoord.x /= viewWidth;
	pixelCoord.y /= viewHeight;	
	// starting position of the ray is stored in the texture coordinate
	vec3 start = gl_TexCoord[1].xyz;
	vec3 backPosition = texture2D(backFace,pixelCoord).xyz;
	vec3 dir = backPosition - start;
	float len = length(dir);
	dir = normalize(dir);
	//next see if clip plane intersects ray
	if (clipPlaneDepth > -0.5) {
		gl_FragColor.rgb = vec3(1.0,0.0,0.0);
		//next, see if clip plane faces viewer
		bool frontface = (dot(dir , clipPlane) > 0.0);
		//next, distance from ray origin to clip plane
		float dis = dot(dir,clipPlane);
		if (dis != 0.0  )  dis = (-clipPlaneDepth - dot(clipPlane, start.xyz-0.5)) / dis;
		//we set "len = 0.0"  instead of "discard" or "return": return fails on 2006MacBookPro10.4ATI1900, discard fails on MacPro10.5NV8800 will not discard
		if ((frontface) && (dis >= len)) len = 0.0;
		if ((!frontface) && (dis <= 0.0)) len = 0.0;
		if ((dis > 0.0) && (dis < len)) {
			if (frontface) {
				start = start + dir * dis;
			} else {
				backPosition =  start + dir * (dis); 
			}
			dir = backPosition - start;
			len = length(dir);
			dir = normalize(dir);		
		}
	}	

	vec3 deltaDir = dir * stepSize;
	vec4 colorSample,gradientSample,colAcc = vec4(0.0,0.0,0.0,0.0);
	float lengthAcc = 0.0;
	//We need to calculate the ray's starting position. We add a random
	//fraction of the stepsize to the original starting point to dither the output
	vec3 samplePos = start.xyz + deltaDir* (fract(sin(gl_FragCoord.x * 12.9898 + gl_FragCoord.y * 78.233) * 43758.5453));
	//float specularColor = 1.0; //pure white, for red... vec3 specularColor= vec3(1.0,0.0,0.0); 
	vec4 prevNorm = vec4(0.0,0.0,0.0,0.0);
	vec3 lightDirHeadOn =  normalize(gl_ModelViewMatrixInverse * vec4(0.0,0.0,1.0,0.0)).xyz ;
	float stepSizex2 = stepSize * 2.0;
	for(int i = 0; i < loops; i++) {

		colorSample = texture3D(intensityVol,samplePos);
		colorSample.a = 1.0-pow((1.0 - colorSample.a), stepSize/sliceSize);//opacity correction
		if ((colorSample.a > 0.01) && (lengthAcc > stepSizex2)  ) {	
			gradientSample= texture3D(gradientVol,samplePos); //interpolate gradient direction and magnitude
			gradientSample.rgb = normalize(gradientSample.rgb*2.0 - 1.0); //direction saved as 0..1, rescale to -1..1
			//re-use previous normal if it has larger magnitude
			if (gradientSample.a < prevNorm.a)
				gradientSample.rgb = prevNorm.rgb;
			prevNorm = gradientSample;
			//Edge shading - darken edges parallel with viewing direction
			float lightNormDot = dot(gradientSample.rgb, lightDirHeadOn); //with respect to viewer
			float edgeVal = pow(1.0-abs(lightNormDot),edgeExp);
			edgeVal = edgeVal * pow(gradientSample.a,0.3);
	    		if (edgeVal >= edgeThresh) 
				colorSample.rgb = mix(colorSample.rgb, vec3(0.0,0.0,0.0), pow((edgeVal-edgeThresh)/(1.0-edgeThresh),4.0));
			if (boundExp > 0.0)
				colorSample.a = colorSample.a * pow(gradientSample.a,boundExp);		  	
			//diffuse
		  	if (lightAmount > 0.0)
				colorSample.rgb += lightAmount*dot(normalize(lightPosition), gradientSample.rgb);
		}

		colorSample.rgb *= colorSample.a; 
		//accumulate color
		colAcc= (1.0 - colAcc.a) * colorSample + colAcc;
		samplePos += deltaDir;
		lengthAcc += stepSize;
		// terminate if opacity > 1 or the ray is outside the volume
		if ( lengthAcc >= len || colAcc.a > 0.95 )
			break;
	}
	colAcc.a = colAcc.a/0.95;
	if ( colAcc.a < 1.0 )
		colAcc.rgb = mix(clearColor,colAcc.rgb,colAcc.a);
	if (len == 0.0) colAcc.rgb = clearColor;
	gl_FragColor = colAcc;
}