Point Cloud Uber Shader

NOTE: This has since been moved to:
http://blog.cameronleger.com/code/ptc_uber_shader/

NOTE: I’ve shrunk the code box for the two scripts. Instead of copying them, when you hover your mouse over them you should get a little box at the top right with icons. The far left icon will open the script itself in a new window. Use that to copy the script.

This is a shader I’ve been working on for a week or so at work. I’ve tested it in a few scenes and so far it’s all working correctly. This is a .sl shader for use with 3Delight, a RenderMan compliant renderer. Although, with some tweaking, it can work with any RenderMan compliant renderer. It’s been tested using 3Delight 9.0.69

What it is, is a shader which can do really anything you want it to with a point cloud (now referred to as PTC).

It’s an atmosphere shader that you can set as an override to encompass everything, or set on a per object basis.

Functionality:
• Baking PTC, whether just the points or points with shading information as well
• Ambient Occlusion
• Reflection Occlusion
• Glossy reflections
• Glossy refractions
• Image based lighting
• Global Illumination / Color Bleeding
• SSS
• Directional Occlusion

I have pragma annotations for just about everything. So, everything is grouped into categories. In each category of functionality, you have the values at your control for the effect. The values are given “nice” names and have tooltip descriptions of what the value does, and in some cases, the best and/or default value.

The shader includes AOVs for each pass. Each pass will render out the normal image with the effect you’ve chosen on top of it. You can also use AOVs to render out the image before the effects and the bare effect for compositing. The specific AOVs are documented inside of the shader, but I’ll also list them here.

1) aov_GI - The diffuse lighting and color bleeding from the GI pass
2) aov_AO - The occlusion part of either the OC pass or the occlusion from the GI pass
3) aov_RO - The reflection occlusion
4) aov_GRefl - The blurred reflections
5) aov_GRefr - The blurred refractions
6) aov_envcolor - The environment color from the GI pass if you're using it for lighting from a texture
7) aov_IBL - The lighting from the image in the IBL pass
8) aov_pre - The scene before the effects

PTC based effects are a two passed approach. First, you bake out the PTC, then you use the PTC. When baking, you need the two following attributes under PreWorldMEL:

RiAttribute -n "cull" -p "hidden" "integer" "0" -p "backfacing" "integer" "0";
RiAttribute -n "dice" -p "rasterorient" "integer" "0";

Also, under Advanced in the Render Pass settings of all the passes utilizing this shader, you must turn the AOVs to ALL AOVs and enable Standard Atmosphere Shader.

At work and at home, I make extensive use of Maya Projects. So in each project I have to make a template for the PTC_Baking pass. I recommend you make a template for it as well, so you don’t have to keep typing in the PreWorldMEL. Since I have to do this on a per project basis, I’ve made a quick MEL script that creates a 3Delight Render Pass for PTC_Baking. You can do this easily by saving a template of your pass, and then finding that .ma template pass, opening it, and copying the contents of that file into a shelf button. Or, you could use this MEL script and save it as a shelf button.

Note: That was created using Maya 8.5, you might want to try what I said earlier to make your own shelf button if that doesn’t work for you. Also, you have to set the camera to bake from and the render set override yourself.

Because of the way the script works and the AOVs, each image you render contains a normal render and the effect. So, by rendering AO, you’re also rendering the image to composite AO on top of with it. This makes the rendertime hit seem MUCH less. Also, if you’re using GI and plan to use AO as well, it’s best to turn on the AO for GI. They’ll both be calulated at the same time and it will save a lot of rendertime. For instance:

Rendertimes
Normal: 120 seconds
Baking: 160 seconds
AO: 180 seconds
GI: 192 seconds
GI & AO: 247 seconds

The baking pass also included the normal image, so really it was +40 seconds.
The AO also included the normal image, so AO added 60 seconds. GI added 72 seconds.
Rendering those separately would give you two sets of normal images and GI and AO, at 372 seconds.
Rendering them together also gives you the normal image, thus adding 127 seconds on top of the normal render, saving you much more time.

I’ve tested this on Maya 8.5 and 2010, Mac and Windows.

Future ideas for added functionality:
• Subsurface Scattering
• Converting to a light shader so we can also use atmosphere effects
• Figuring out how to get it to work with area lights

Finally, here’s the script.

UPDATE:10/19/2010
Added SSS to the PTC usage section
Glossy Reflections now composite on top, so you can control the reflectivity amount.
Should now work with all 3Delight materials AND mia materials.

UPDATE:11/2/2010
SSS fixed for the newest version
Numerous bug fixes

UPDATE:11/9/2010
Added directional occlusion, a tweak on occlusion that makes it kind of like a soft directional light
Fixed some hints on the Max Variation parameter
IBL may not have been working before
Samplebase isn’t a PTC option, oops

UPDATE:11/22/2010
Added the ability to rebake and reuse PTC data to save rendertime when multiple renders are needed

##    Main
#pragma annotation "grouping" "MAIN/composite;"
#pragma annotation composite "gadgettype=checkbox:0:1=custom value;label=Composite;hint=Add the effect on top of RGBA, otherwise just in the AOV;"
#pragma annotation "grouping" "MAIN/AO;"
#pragma annotation AO "gadgettype=checkbox:0:1=custom value;label=Ambient Occlusion;"
#pragma annotation "grouping" "MAIN/DO;"
#pragma annotation DO "gadgettype=checkbox:0:1=custom value;label=Directional Occlusion;"
#pragma annotation "grouping" "MAIN/RO;"
#pragma annotation RO "gadgettype=checkbox:0:1=custom value;label=Reflection Occlusion;"
#pragma annotation "grouping" "MAIN/GRefl;"
#pragma annotation GRefl "gadgettype=checkbox:0:1=custom value;label=Glossy Reflections;"
#pragma annotation "grouping" "MAIN/GRefr;"
#pragma annotation GRefr "gadgettype=checkbox:0:1=custom value;label=Glossy Refractions;"
#pragma annotation "grouping" "MAIN/IBL;"
#pragma annotation IBL "gadgettype=checkbox:0:1=custom value;label=Image Based Lighting;"
#pragma annotation "grouping" "MAIN/GI;"
#pragma annotation GI "gadgettype=checkbox:0:1=custom value;label=Color Bleeding (GI);"
#pragma annotation "grouping" "MAIN/SSS;"
#pragma annotation SSS "gadgettype=checkbox:0:1=custom value;label=Subsurface Scattering;"
#pragma annotation "grouping" "MAIN/bake;"
#pragma annotation bake "gadgettype=checkbox:0:1=custom value;label=Bake PTC Map;"
#pragma annotation "grouping" "MAIN/filename;"
#pragma annotation filename "gadgettype=inputfile;label=PTC Files;hint=A previously rendered .ptc file. A .ptc with color and direct lighting baked in is needed for GI and can be used by all, but only point values are needed for AO. Also, if you have multiple PTC files, separate them with a ;"
#pragma annotation "grouping" "MAIN/rebake;"
#pragma annotation rebake "gadgettype=checkbox:0:1=custom value;label=Rebake PTC Map;"
#pragma annotation "grouping" "MAIN/reuse;"
#pragma annotation reuse "gadgettype=checkbox:0:1=custom value;label=Reuse PTC Map;"
#pragma annotation "grouping" "MAIN/coordsyst;"
#pragma annotation coordsyst "gadgettype=inputfile;label=Coordinate System;hint=Default 'world'. The coordinate system used by the point cloud."
#pragma annotation "grouping" "MAIN/envmap;"
#pragma annotation envmap "gadgettype=inputfile;label=ENV File;hint=A .tdl environment map made from 3Delight's tdlmake. If this is loaded it, it will be used for whatever you have actived and gets used if a ray doesn't hit an object.."
#pragma annotation "grouping" "MAIN/envspace;"
#pragma annotation envspace "gadgettype=inputfile;label=Coordinate System;hint=Default 'world'. The coordinate system used by the environment map."
##    AO
#pragma annotation "grouping" "AO/AO_tex;"
#pragma annotation AO_tex "gadgettype=inputfile;label=Alpha;hint=A .tdl image for controlling the AO effect, black for none and white for full."
#pragma annotation "grouping" "AO/AO_hitsides;"
#pragma annotation AO_hitsides "gadgettype=optionmenu:front:back:both;label=Hitsides;hint=Which side of point sample is used."
#pragma annotation "grouping" "AO/AO_maxdist;"
#pragma annotation AO_maxdist "gadgettype=floatfield;label=Max Distance;hint=Only consider intersections inside this distance. Default 1e2. Change this based on the scale of your scene."
#pragma annotation "grouping" "AO/AO_falloff;"
#pragma annotation AO_falloff "gadgettype=floatfield;label=Falloff;hint=Shapes the curve of falloff. Set to 1 for linear falloff."
#pragma annotation "grouping" "AO/AO_falloffmode;"
#pragma annotation AO_falloffmode "gadgettype=floatslider;min=0;max=1;label=Falloff Mode;hint=0 is exponential. 1 is polynomial."
#pragma annotation "grouping" "AO/AO_coneangle;"
#pragma annotation AO_coneangle "gadgettype=floatslider;min=0;max=360;label=Cone Angle;hint=Solid angle considered per point. Default is a hemishpere (180 degrees)."
#pragma annotation "grouping" "AO/AO_bias;"
#pragma annotation AO_bias "gadgettype=floatfield;label=Bias;hint=Offsets points above surface to prevent self-occlusion on curved surfaces. Usually 0.0 - 0.01. Lower values will get rid of white lines in corners."
#pragma annotation "grouping" "AO/AO_clamp;"
#pragma annotation AO_clamp "gadgettype=checkbox:0:1=custom value;label=Clamping;hint=Reducing over-occlusion. Doubles render time but much better results."
#pragma annotation "grouping" "AO/AO_maxsolidangle;"
#pragma annotation AO_maxsolidangle "gadgettype=floatfield;label=Max Solid Angle;hint=Time vs Quality. Good values between 0.03 and 0.2 Higher values are faster."
#pragma annotation "grouping" "AO/AO_maxvariation;"
#pragma annotation AO_maxvariation "gadgettype=floatfield;label=Max Variation;hint=Interpolates low variations. Values around 30 are up to twice as fast to render but look almost the same."
##    DO
#pragma annotation "grouping" "DO/DO_tex;"
#pragma annotation DO_tex "gadgettype=inputfile;label=Alpha;hint=A .tdl image for controlling the DO effect, black for none and white for full."
#pragma annotation "grouping" "DO/DO_hitsides;"
#pragma annotation DO_hitsides "gadgettype=optionmenu:front:back:both;label=Hitsides;hint=Which side of point sample is used."
#pragma annotation "grouping" "DO/DO_dir;"
#pragma annotation DO_dir "label=Direction;hint=Direction of occlusion in world space, coming from the point at XYZ."
#pragma annotation "grouping" "DO/DO_maxdist;"
#pragma annotation DO_maxdist "gadgettype=floatfield;label=Max Distance;hint=Only consider intersections inside this distance. Default 1e2. Change this based on the scale of your scene."
#pragma annotation "grouping" "DO/DO_falloff;"
#pragma annotation DO_falloff "gadgettype=floatfield;label=Falloff;hint=Shapes the curve of falloff. Set to 1 for linear falloff."
#pragma annotation "grouping" "DO/DO_falloffmode;"
#pragma annotation DO_falloffmode "gadgettype=floatslider;min=0;max=1;label=Falloff Mode;hint=0 is exponential. 1 is polynomial."
#pragma annotation "grouping" "DO/DO_coneangle;"
#pragma annotation DO_coneangle "gadgettype=floatslider;min=0;max=360;label=Cone Angle;hint=Solid angle considered per point. Default is a hemishpere (180 degrees)."
#pragma annotation "grouping" "DO/DO_bias;"
#pragma annotation DO_bias "gadgettype=floatfield;label=Bias;hint=Offsets points above surface to prevent self-occlusion on curved surfaces. Usually 0.0 - 0.01. Lower values will get rid of white lines in corners."
#pragma annotation "grouping" "DO/DO_clamp;"
#pragma annotation DO_clamp "gadgettype=checkbox:0:1=custom value;label=Clamping;hint=Reducing over-occlusion. Doubles render time but much better results."
#pragma annotation "grouping" "DO/DO_maxsolidangle;"
#pragma annotation DO_maxsolidangle "gadgettype=floatfield;label=Max Solid Angle;hint=Time vs Quality. Good values between 0.03 and 0.2 Higher values are faster."
#pragma annotation "grouping" "DO/DO_maxvariation;"
#pragma annotation DO_maxvariation "gadgettype=floatfield;label=Max Variation;hint=Interpolates low variations. Values around 30 are up to twice as fast to render but look almost the same."
##    RO
#pragma annotation "grouping" "RO/RO_tex;"
#pragma annotation RO_tex "gadgettype=inputfile;label=Alpha;hint=A .tdl image for controlling the RO effect, black for none and white for full."
#pragma annotation "grouping" "RO/RO_hitsides;"
#pragma annotation RO_hitsides "gadgettype=optionmenu:front:back:both;label=Hitsides;hint=Which side of point sample is used."
#pragma annotation "grouping" "RO/RO_maxdist;"
#pragma annotation RO_maxdist "gadgettype=floatfield;label=Max Distance;hint=Only consider intersections inside this distance. Default 1e15. Change this based on the scale of your scene."
#pragma annotation "grouping" "RO/RO_falloff;"
#pragma annotation RO_falloff "gadgettype=floatfield;label=Falloff;hint=Shapes the curve of falloff. Set to 1 for linear falloff."
#pragma annotation "grouping" "RO/RO_falloffmode;"
#pragma annotation RO_falloffmode "gadgettype=floatslider;min=0;max=1;label=Falloff Mode;hint=0 is exponential. 1 is polynomial."
#pragma annotation "grouping" "RO/RO_coneangle;"
#pragma annotation RO_coneangle "gadgettype=floatfield;label=Cone Angle;hint=Value in radians of the cone angle. Smaller values are better for Reflection Occlusion. Default 30"
#pragma annotation "grouping" "RO/RO_bias;"
#pragma annotation RO_bias "gadgettype=floatfield;label=Bias;hint=Offsets points above surface to prevent self-occlusion on curved surfaces. Usually 0.0 - 0.01. Lower values will get rid of white lines in corners."
#pragma annotation "grouping" "RO/RO_clamp;"
#pragma annotation RO_clamp "gadgettype=checkbox:0:1=custom value;label=Clamping;hint=Reducing over-occlusion. Doubles render time but much better results."
#pragma annotation "grouping" "RO/RO_maxsolidangle;"
#pragma annotation RO_maxsolidangle "gadgettype=floatfield;label=Max Solid Angle;hint=Time vs Quality. Should use very low values for Reflection Occlusion. Default .005."
##    GRefl
#pragma annotation "grouping" "GRefl/GRefl_tex;"
#pragma annotation GRefl_tex "gadgettype=inputfile;label=Alpha;hint=A .tdl image for controlling the glossy reflection effect, black for none and white for full."
#pragma annotation "grouping" "GRefl/GRefl_amnt;"
#pragma annotation GRefl_amnt "gadgettype=floatslider;min=0;max=1;label=Amount;hint=How reflective the surface is."
#pragma annotation "grouping" "GRefl/GRefl_hitsides;"
#pragma annotation GRefl_hitsides "gadgettype=optionmenu:front:back:both;label=Hitsides;hint=Which side of point sample is used."
#pragma annotation "grouping" "GRefl/GRefl_maxdist;"
#pragma annotation GRefl_maxdist "gadgettype=floatfield;label=Max Distance;hint=Only consider intersections inside this distance. Default 1e15. Change this based on the scale of your scene."
#pragma annotation "grouping" "GRefl/GRefl_falloff;"
#pragma annotation GRefl_falloff "gadgettype=floatfield;label=Falloff;hint=Shapes the curve of falloff. Set to 1 for linear falloff."
#pragma annotation "grouping" "GRefl/GRefl_falloffmode;"
#pragma annotation GRefl_falloffmode "gadgettype=floatslider;min=0;max=1;label=Falloff Mode;hint=0 is exponential. 1 is polynomial."
#pragma annotation "grouping" "GRefl/GRefl_coneangle;"
#pragma annotation GRefl_coneangle "gadgettype=floatfield;label=Cone Angle;hint=Value of the cone angle. Smaller values are preferred. The larger the value the blurrier the reflections. Default 30"
#pragma annotation "grouping" "GRefl/GRefl_bias;"
#pragma annotation GRefl_bias "gadgettype=floatfield;label=Bias;hint=Offsets points above surface to prevent self-occlusion on curved surfaces. Usually 0.0 - 0.01. Lower values will get rid of white lines in corners."
#pragma annotation "grouping" "GRefl/GRefl_clamp;"
#pragma annotation GRefl_clamp "gadgettype=checkbox:0:1=custom value;label=Clamping;hint=Reducing over-occlusion. Doubles render time but much better results."
#pragma annotation "grouping" "GRefl/GRefl_sort;"
#pragma annotation GRefl_sort "gadgettype=checkbox:0:1=custom value;label=Sorting;hint=Clamping must be on for this to have an effect. The color bleed is sorted by distance and gives more correct colors and shadows."
#pragma annotation "grouping" "GRefl/GRefl_maxsolidangle;"
#pragma annotation GRefl_maxsolidangle "gadgettype=floatfield;label=Max Solid Angle;hint=Time vs Quality. Should use very low values. Default .005."
##    GRefr
#pragma annotation "grouping" "GRefr/GRefr_tex;"
#pragma annotation GRefr_tex "gadgettype=inputfile;label=Alpha;hint=A .tdl image for controlling the glossy refraction effect, black for none and white for full."
#pragma annotation "grouping" "GRefr/GRefr_readme;"
#pragma annotation GRefr_readme "gadgettype=floatfield;label=README;hint=For this to work properly, THE OBJECT WITH THIS EFFECT ON IT SHOULD NOT BE IN THE POINT CLOUD."
#pragma annotation "grouping" "GRefr/GRefr_int;"
#pragma annotation GRefr_int "gadgettype=floatfield;label=Intensity;hint=Intensity of the effect;"
#pragma annotation "grouping" "GRefr/GRefr_ior;"
#pragma annotation GRefr_ior "gadgettype=floatfield;label=IOR;hint=Index of Refraction;"
#pragma annotation "grouping" "GRefr/GRefr_hitsides;"
#pragma annotation GRefr_hitsides "gadgettype=optionmenu:front:back:both;label=Hitsides;hint=Which side of point sample is used."
#pragma annotation "grouping" "GRefr/GRefr_maxdist;"
#pragma annotation GRefr_maxdist "gadgettype=floatfield;label=Max Distance;hint=Only consider intersections inside this distance. Default 1e15. Change this based on the scale of your scene."
#pragma annotation "grouping" "GRefr/GRefr_falloff;"
#pragma annotation GRefr_falloff "gadgettype=floatfield;label=Falloff;hint=Shapes the curve of falloff. Set to 1 for linear falloff."
#pragma annotation "grouping" "GRefr/GRefr_falloffmode;"
#pragma annotation GRefr_falloffmode "gadgettype=floatslider;min=0;max=1;label=Falloff Mode;hint=0 is exponential. 1 is polynomial."
#pragma annotation "grouping" "GRefr/GRefr_coneangle;"
#pragma annotation GRefr_coneangle "gadgettype=floatfield;label=Cone Angle;hint=Value of the cone angle. Smaller values are preferred. The larger the value the blurrier the refractions. Default 30"
#pragma annotation "grouping" "GRefr/GRefr_bias;"
#pragma annotation GRefr_bias "gadgettype=floatfield;label=Bias;hint=Offsets points above surface to prevent self-occlusion on curved surfaces. Usually 0.0 - 0.01. Lower values will get rid of white lines in corners."
#pragma annotation "grouping" "GRefr/GRefr_clamp;"
#pragma annotation GRefr_clamp "gadgettype=checkbox:0:1=custom value;label=Clamping;hint=Reducing over-occlusion. Doubles render time but much better results."
#pragma annotation "grouping" "GRefr/GRefr_sort;"
#pragma annotation GRefr_sort "gadgettype=checkbox:0:1=custom value;label=Sorting;hint=Clamping must be on for this to have an effect. The color bleed is sorted by distance and gives more correct colors and shadows."
#pragma annotation "grouping" "GRefr/GRefr_maxsolidangle;"
#pragma annotation GRefr_maxsolidangle "gadgettype=floatfield;label=Max Solid Angle;hint=Time vs Quality. Should use very low values. Default .005."
##    IBL
#pragma annotation "grouping" "IBL/IBL_tex;"
#pragma annotation IBL_tex "gadgettype=inputfile;label=Alpha;hint=A .tdl image for controlling the IBL effect, black for none and white for full."
#pragma annotation "grouping" "IBL/IBL_int;"
#pragma annotation IBL_int "gadgettype=floatfield;label=Intensity;hint=Use this to brighten or darken the result as needed."
#pragma annotation "grouping" "IBL/IBL_hitsides;"
#pragma annotation IBL_hitsides "gadgettype=optionmenu:front:back:both;label=Hitsides;hint=Which side of point sample is used."
#pragma annotation "grouping" "IBL/IBL_maxdist;"
#pragma annotation IBL_maxdist "gadgettype=floatfield;label=Max Distance;hint=Only consider intersections inside this distance. Default 1e15. Change this based on the scale of your scene."
#pragma annotation "grouping" "IBL/IBL_falloff;"
#pragma annotation IBL_falloff "gadgettype=floatfield;label=Falloff;hint=Shapes the curve of falloff. Set to 1 for linear falloff."
#pragma annotation "grouping" "IBL/IBL_falloffmode;"
#pragma annotation IBL_falloffmode "gadgettype=floatslider;min=0;max=1;label=Falloff Mode;hint=0 is exponential. 1 is polynomial."
#pragma annotation "grouping" "IBL/IBL_coneangle;"
#pragma annotation IBL_coneangle "gadgettype=floatslider;min=0;max=360;label=Cone Angle;hint=Solid angle considered per point. Default is a hemishpere (180 degrees)."
#pragma annotation "grouping" "IBL/IBL_bias;"
#pragma annotation IBL_bias "gadgettype=floatfield;label=Bias;hint=Offsets points above surface. Usually 0.0 - 0.01. Go as low as you can go without artifacts."
#pragma annotation "grouping" "IBL/IBL_clamp;"
#pragma annotation IBL_clamp "gadgettype=checkbox:0:1=custom value;label=Clamping;hint=Doubles render time but much better results."
#pragma annotation "grouping" "IBL/IBL_maxsolidangle;"
#pragma annotation IBL_maxsolidangle "gadgettype=floatfield;label=Max Solid Angle;hint=Time vs Quality. Good values between 0.03 and 0.1 Higher values are faster."
#pragma annotation "grouping" "IBL/IBL_maxvariation;"
#pragma annotation IBL_maxvariation "gadgettype=floatfield;label=Max Variation;hint=Interpolates low variations. Values around 30 are up to twice as fast to render but look almost the same."
##    GI
#pragma annotation "grouping" "GI/GI_tex;"
#pragma annotation GI_tex "gadgettype=inputfile;label=Alpha;hint=A .tdl image for controlling the global illumination effect, black for none and white for full."
#pragma annotation "grouping" "GI/GI_intensity;"
#pragma annotation GI_intensity "gadgettype=floatfield;label=Intensity;hint=Multiplied by the GI result. Default is 1."
#pragma annotation "grouping" "GI/GI_hitsides;"
#pragma annotation GI_hitsides "gadgettype=optionmenu:front:back:both;label=Hitsides;hint=Which side of point sample is used."
#pragma annotation "grouping" "GI/GI_maxdist;"
#pragma annotation GI_maxdist "gadgettype=floatfield;label=Max Distance;hint=Only consider intersections inside this distance. Default 1e15. Change this based on the scale of your scene."
#pragma annotation "grouping" "GI/GI_falloff;"
#pragma annotation GI_falloff "gadgettype=floatfield;label=Falloff;hint=Shapes the curve of falloff. Set to 1 for linear falloff."
#pragma annotation "grouping" "GI/GI_falloffmode;"
#pragma annotation GI_falloffmode "gadgettype=floatslider;min=0;max=1;label=Falloff Mode;hint=0 is exponential. 1 is polynomial."
#pragma annotation "grouping" "GI/GI_coneangle;"
#pragma annotation GI_coneangle "gadgettype=floatslider;min=0;max=360;label=Cone Angle;hint=Solid angle considered per point. Default is a hemishpere (180 degrees)."
#pragma annotation "grouping" "GI/GI_bias;"
#pragma annotation GI_bias "gadgettype=floatfield;label=Bias;hint=Offsets points above surface. Usually 0.0 - 0.01. Go as low as you can go without artifacts."
#pragma annotation "grouping" "GI/GI_clamp;"
#pragma annotation GI_clamp "gadgettype=checkbox:0:1=custom value;label=Clamping;hint=Doubles render time but much better results."
#pragma annotation "grouping" "GI/GI_sort;"
#pragma annotation GI_sort "gadgettype=checkbox:0:1=custom value;label=Sorting;hint=Clamping must be on for this to have an effect. The color bleed is sorted by distance and gives more correct colors and shadows."
#pragma annotation "grouping" "GI/GI_maxsolidangle;"
#pragma annotation GI_maxsolidangle "gadgettype=floatfield;label=Max Solid Angle;hint=Time vs Quality. Good values between 0.03 and 0.1 Higher values are faster."
## GI AO
#pragma annotation "grouping" "GI/AO/GI_AO_tex;"
#pragma annotation GI_AO_tex "gadgettype=inputfile;label=Alpha;hint=A .tdl image for controlling the AO effect, black for none and white for full."
#pragma annotation "grouping" "GI/AO/GI_AO;"
#pragma annotation GI_AO "gadgettype=checkbox:0:1=custom value;label=Ambient Occlusion w/ GI;"
#pragma annotation "grouping" "GI/AO/GI_AO_hitsides;"
#pragma annotation GI_AO_hitsides "gadgettype=optionmenu:front:back:both;label=Hitsides;hint=Which side of point sample is used."
#pragma annotation "grouping" "GI/AO/GI_AO_maxdist;"
#pragma annotation GI_AO_maxdist "gadgettype=floatfield;label=Max Distance;hint=Only consider intersections inside this distance. Default 1e2. Change this based on the scale of your scene."
#pragma annotation "grouping" "GI/AO/GI_AO_falloff;"
#pragma annotation GI_AO_falloff "gadgettype=floatfield;label=Falloff;hint=Shapes the curve of falloff. Set to 1 for linear falloff."
#pragma annotation "grouping" "GI/AO/GI_AO_falloffmode;"
#pragma annotation GI_AO_falloffmode "gadgettype=floatslider;min=0;max=1;label=Falloff Mode;hint=0 is exponential. 1 is polynomial."
#pragma annotation "grouping" "GI/AO/GI_AO_coneangle;"
#pragma annotation GI_AO_coneangle "gadgettype=floatslider;min=0;max=360;label=Cone Angle;hint=Solid angle considered per point. Default is a hemishpere (180 degrees)."
#pragma annotation "grouping" "GI/AO/GI_AO_bias;"
#pragma annotation GI_AO_bias "gadgettype=floatfield;label=Bias;hint=Offsets points above surface. Usually 0.0 - 0.01. Go as low as you can go without artifacts."
#pragma annotation "grouping" "GI/AO/GI_AO_clamp;"
#pragma annotation GI_AO_clamp "gadgettype=checkbox:0:1=custom value;label=Clamping;hint=Doubles render time but much better results."
#pragma annotation "grouping" "GI/AO/GI_AO_maxsolidangle;"
#pragma annotation GI_AO_maxsolidangle "gadgettype=floatfield;label=Max Solid Angle;hint=Time vs Quality. Good values between 0.03 and 0.1 Higher values are faster."
#pragma annotation "grouping" "GI/AO/GI_AO_maxvariation;"
#pragma annotation GI_AO_maxvariation "gadgettype=floatfield;label=Max Variation;hint=Interpolates low variations. Values around 30 are up to twice as fast to render but look almost the same."
##    SSS
#pragma annotation "grouping" "SSS/SSS_ior;"
#pragma annotation SSS_ior "gadgettype=floatfield;label=IOR;hint=Index of Refraction. Looks-wise, lower values are more contrasty and higher values produce a more even look with more scattering."
#pragma annotation "grouping" "SSS/SSS_scale;"
#pragma annotation SSS_scale "gadgettype=floatfield;label=Scale;hint=The scale the SSS is computed at, default 1 at millimeters. Higher values produce more scattering and make it look waxier."
#pragma annotation "grouping" "SSS/SSS_type;"
#pragma annotation SSS_type "gadgettype=optionmenu:apple:chicken1:chicken2:cream:ketchup:marble:potato:skimmilk:skin1:skin2:spectralon:wholemilk:custom;label=Preset;hint=Presets. If you choose custom, you can input values in the CUSTOM section. Default CUSTOM values are for skin2"
#pragma annotation "grouping" "SSS/CUSTOM/SSS_abs;"
#pragma annotation SSS_abs "gadgettype=colorslider;label=Absorption;hint=Absorption Coefficient."
#pragma annotation "grouping" "SSS/CUSTOM/SSS_sct;"
#pragma annotation SSS_sct "gadgettype=colorslider;label=Scattering;hint=Scattering Coefficient."
#pragma annotation "grouping" "SSS/SSS_smooth;"
#pragma annotation SSS_smooth "gadgettype=floatfield;label=Smoothing;hint=How much to smooth, from 0 being not and 1 being fully smoothed."
#pragma annotation "grouping" "SSS/SSS_weight;"
#pragma annotation SSS_weight "gadgettype=floatfield;label=Diffuse Weight;hint=How much of the diffuse is considered. 1 is purely diffuse, 0 is purely SSS"
## BAKING
#pragma annotation "grouping" "BAKING/readme;"
#pragma annotation readme "gadgettype=floatfield;label=README;hint=Select one. You MUST add the attributes at the top of the shader file comments to your PreWorldMEL. Use Shading Rate and Image Resolution to control PTC Density. If you're having artifact problems, just increase the PTC density if decreasing the bias doesn't help. It's also important to pick a camera that can 'see' everything you need a PTC for in the scene."
#pragma annotation "grouping" "BAKING/bake_AREA;"
#pragma annotation bake_AREA "gadgettype=checkbox:0:1=custom value;label=Bake area data;hint=This can be used for occlusion and lighting occlusion style with HDRI."
#pragma annotation "grouping" "BAKING/bake_COLOR;"
#pragma annotation bake_COLOR "gadgettype=checkbox:0:1=custom value;label=Bake color/area data;hint=This is needed for GI but can also be used for everything else."
#pragma annotation "grouping" "BAKING/bake_file;"
#pragma annotation bake_file "gadgettype=inputfile;label=PTC Filename;hint=Where the .ptc file gets baked to."
#pragma annotation "grouping" "BAKING/bake_coordsyst;"
#pragma annotation bake_coordsyst "gadgettype=inputfile;label=Coordinate system;hint=Which coordsystem to bake to. Default world."
## REBAKING
#pragma annotation "grouping" "REUSING/rebaked_file;"
#pragma annotation rebaked_file "gadgettype=inputfile;label=PTC Filename;hint=Where the .ptc file gets baked to."
#pragma annotation "grouping" "REUSING/rebaked_coordsyst;"
#pragma annotation rebaked_coordsyst "gadgettype=inputfile;label=Coordinate system;hint=Which coordsystem to bake to. Default world."


volume
    cl_ptc_uber (
                string filename = "<project>/3delight/<scene>/ptc/<scene>.#.ptc",
                envmap = "",
                coordsyst = "world",
                envspace = "world",
                AO_hitsides = "both",
		AO_tex = "",
		DO_tex = "",
		RO_tex = "",
		GRefl_tex = "",
		GRefr_tex = "",
		IBL_tex = "",
		GI_tex = "",
		GI_AO_tex = "",
		SSS_tex = "";
                float composite = 0,
		AO_maxdist = 1e2,
                AO_coneangle = 180, 
                AO_falloff = 1, 
                AO_falloffmode = 1,
                AO_bias = 0.01,
                AO_clamp = 1, 
                AO_maxsolidangle = 0.05,
                AO_maxvariation = 0,
                AO = 0;
                string DO_hitsides = "both";
                float DO_maxdist = 1e2,
                DO_coneangle = 180, 
                DO_falloff = 1, 
                DO_falloffmode = 1,
                DO_bias = 0.01,
                DO_clamp = 1, 
                DO_maxsolidangle = 0.05,
                DO_maxvariation = 0,
                DO = 0;
                normal DO_dir = normal "world" (0,1,-2);
                string RO_hitsides = "both";
                float RO_maxdist = 1e15, 
                RO_falloff = 1, 
                RO_falloffmode = 1,
                RO_bias = 0.01,
                RO_clamp = 1, 
                RO_maxsolidangle = 0.05,
                RO_coneangle = 0.2,
                RO = 0;
                string GRefl_hitsides = "both";
                float GRefl_maxdist = 1e15,
                GRefl_amnt = 1, 
                GRefl_falloff = 1, 
                GRefl_falloffmode = 1,
                GRefl_bias = 0.01,
                GRefl_clamp = 1,
                GRefl_sort = 1, 
                GRefl_maxsolidangle = 0.05,
                GRefl_coneangle = 30,
                GRefl = 0;
                string GRefr_hitsides = "both";
                float GRefr_maxdist = 1e15,
                GRefr_readme = 0,
                GRefr_int = .3,
                GRefr_ior = 1.1,
                GRefr_falloff = 1, 
                GRefr_falloffmode = 1,
                GRefr_bias = 0.01,
                GRefr_clamp = 1,
                GRefr_sort = 1, 
                GRefr_maxsolidangle = 0.05,
                GRefr_coneangle = 30,
                GRefr = 0;
                string IBL_hitsides = "both";
                float IBL_maxdist = 1e15,
                IBL_int = 1, 
                IBL_coneangle = 180,
                IBL_falloff = 1, 
                IBL_falloffmode = 1,
                IBL_bias = 0.01,
                IBL_clamp = 1,
                IBL_maxsolidangle = 0.05, 
                IBL_maxvariation = 0,
                IBL = 0;
                string GI_hitsides = "both";
                float GI_maxdist = 1e4,
                GI_intensity = 1,
                GI_falloff = 1,
                GI_falloffmode = 1,
                GI_bias = 0.045,
                GI_clamp = 1,
                GI_sort = 1,
                GI_coneangle = 180,
                GI_maxsolidangle = .2,
                GI = 0;
                string GI_AO_hitsides = "both";
                float GI_AO_coneangle = 180,
                GI_AO_clamp = 1,
                GI_AO_maxdist = 1e2,
                GI_AO_bias = 0.045,
                GI_AO_maxsolidangle = 0.2,
                GI_AO_falloff = 3,
                GI_AO_falloffmode = 1,
                GI_AO_maxvariation = .02,
                GI_AO = 0;
                string SSS_type = "skin1";
                color SSS_sct = color(1.09, 1.59, 1.79), 
		SSS_abs = color(0.013, 0.070, 0.145);
                float SSS_ior = 1.3,
                SSS_scale = 1,
                SSS_smooth = 0,
                SSS_weight = .4,
		SSS = 0;
                string bake_file = "<project>/3delight/<scene>/ptc/<scene>.#.ptc",
                bake_coordsyst = "world";
                float reuse = 0,
                rebake = 0;
                string rebaked_file = "<project>/3delight/<scene>/ptc/<scene>.#.rebake.ptc",
                rebaked_coordsyst = "world";
                float bake = 0,
                bake_COLOR = 0,
                bake_AREA = 0,
                readme = 0;
                output varying color aov_GI = 0;
                output varying color aov_envcolor = 0;
                output varying color aov_GRefl = 0;
                output varying color aov_GRefr = 0;
                output varying color aov_RO = 0;
                output varying color aov_IBL = 0;
                output varying color aov_SSS = 0;
                output varying color aov_AO = 1;
                output varying color aov_DO = 0;) 
    {
    normal shading_normal = normalize(N);
    color white = (1,1,1); // make a white color so we can mix with AO, when we multiply it will act as null
    color black = (0,0,0); // make a black color so we can use it to block out the areas if we do an add
      
      if(AO == 1) {
        if (reuse != 1) {
        aov_AO = Oi*(1 - occlusion( // performs occlusion with parameters from GUI
                P, shading_normal, 0,
                "pointbased", 1,
                "filename", filename,
                "coordsystem", coordsyst,
                "coneangle", radians(AO_coneangle),
                "hitsides", AO_hitsides,
                "maxdist", AO_maxdist,
                "falloff", AO_falloff,
                "falloffmode", AO_falloffmode,
                "bias", AO_bias,
                "clamp", AO_clamp,
                "maxsolidangle", AO_maxsolidangle,
                "maxvariation", AO_maxvariation));

        } else {
        texture3d(rebaked_file, P, shading_normal,
        "occlusion", aov_AO,
        "coordsystem", rebaked_coordsyst);
        }
	if(AO_tex != "") {
		color AO_texture = texture(AO_tex);  // Bring in the texture
		aov_AO = mix(white, aov_AO, AO_texture); // Mix between white and AO by the texture
	}
	if(composite==1) {
		Ci *= aov_AO;
	}
        if(rebake == 1) {
            bake3d(rebaked_file, "", P, shading_normal, 
            "occlusion", aov_AO,
            "coordsystem", rebaked_coordsyst,
            "interpolate", 1);
        }
      }

      if(DO == 1) {
        if (reuse != 1) {
        aov_DO = Oi*(1 - occlusion( // performs occlusion with parameters from GUI
                P, DO_dir, 0,
                "pointbased", 1,
                "filename", filename,
                "coordsystem", coordsyst,
                "coneangle", radians(DO_coneangle),
                "hitsides", DO_hitsides,
                "maxdist", DO_maxdist,
                "falloff", DO_falloff,
                "falloffmode", DO_falloffmode,
                "bias", DO_bias,
                "clamp", DO_clamp,
                "maxsolidangle", DO_maxsolidangle,
                "maxvariation", DO_maxvariation));

        } else {
        texture3d(rebaked_file, P, DO_dir,
        "occlusion", aov_DO,
        "coordsystem", rebaked_coordsyst);
        }
	if(DO_tex != "") {
		color DO_texture = texture(DO_tex);  // Bring in the texture
		aov_DO = mix(white, aov_DO, DO_texture); // Mix between white and DO by the texture
	}
	if(composite==1) {
		Ci *= aov_DO * Oi;
	}
        if(rebake == 1) {
            bake3d(rebaked_file, "", P, DO_dir, 
            "occlusion", aov_DO,
            "coordsystem", rebaked_coordsyst,
            "interpolate", 1);
        }
      }
      
      if(RO == 1) {
        normal Nn = normalize(N); // Normalize normals
        vector RO_refl = reflect(I, Nn); // Uses the reflected vector to compute occlusion, thus reflection occlusion
        if (reuse != 1) {
        aov_RO = Oi*(1 - occlusion(P, RO_refl, 0, 
                "pointbased", 1, 
                "filename", filename,
                "coordsystem", coordsyst,
                "hitsides", RO_hitsides,
                   "clamp", RO_clamp,
                "maxdist", RO_maxdist, 
                "falloff", RO_falloff,
                "falloffmode", RO_falloffmode,
                "coneangle", radians(RO_coneangle),
                "maxsolidangle", RO_maxsolidangle,
                "bias", RO_bias));
                
        } else {
        texture3d(rebaked_file, P, RO_refl,
        "occlusion", aov_RO,
        "coordsystem", rebaked_coordsyst);
        }
	if(RO_tex != "") {
		color RO_texture = texture(RO_tex);  // Bring in the texture
		aov_RO = mix(white, aov_RO, RO_texture); // Mix between white and RO by the texture
	}
	if(composite==1) {
        	Ci = aov_RO * Oi; // Just uses RO and opacity for the final image
	}
        if(rebake == 1) {
            bake3d(rebaked_file, "", P, RO_refl, 
            "occlusion", aov_RO,
            "coordsystem", rebaked_coordsyst,
            "interpolate", 1);
        }
      }
    
      if(GRefl == 1) {
        normal Nn = normalize(N); // Normalize normals 
        vector GRefl_refl = reflect(I, Nn); // Again, using a reflection vector for computation
        if (reuse != 1) {
        aov_GRefl = Oi*(indirectdiffuse(P, GRefl_refl, 0, 
                "pointbased", 1, 
                "filename", filename,
                "coordsystem", coordsyst,
                "hitsides", GRefl_hitsides, 
                "clamp", GRefl_clamp,
                "sortbleeding", GRefl_sort,
                "maxdist", GRefl_maxdist, 
                "falloff", GRefl_falloff,
                "falloffmode", GRefl_falloffmode,
                "coneangle", radians(GRefl_coneangle),
                "bias", GRefl_bias,
                "maxsolidangle", GRefl_maxsolidangle));

        } else {
        texture3d(rebaked_file, P, GRefl_refl,
        "reflection", aov_GRefl,
        "coordsystem", rebaked_coordsyst);
        }
	if(GRefl_tex != "") {
		color GRefl_texture = texture(GRefl_tex);  // Bring in the texture
		aov_GRefl = mix(black, aov_GRefl, GRefl_texture); // Mix between black and GRefl by the texture
	}
	if(composite==1) {
         	Ci = Oi * Ci + (aov_GRefl * GRefl_amnt); // GRefl are stored on top
	}
        if(rebake == 1) {
            bake3d(rebaked_file, "", P, GRefl_refl, 
            "reflection", aov_GRefl,
            "coordsystem", rebaked_coordsyst,
            "interpolate", 1);
        }
      }
    
      if(GRefr == 1) {
        if (reuse != 1) {
        extern point P;
        extern normal N;
        extern vector I;
        // normalizing
        normal Nn = normalize(N);
        vector IN = normalize(I);
        // stores reflection and refraction vectors
        vector reflDir, refrDir;
        float eta = (IN.Nn < 0) ? 1/GRefr_ior : GRefr_ior;
        float kr, kt;
        // computes fresnel effect
        fresnel(IN, Nn, eta, kr, kt, reflDir, refrDir);
        kt = 1 - kr; 
        
        vector RF = normalize(refrDir);
        color aov_GRefr = Oi*(kt*GRefr_int*indirectdiffuse(P, RF, 0, //glossy refractions
                "filename", filename, 
                "pointbased", 1,
                "hitsides", GRefr_hitsides, 
                "coneangle", radians(GRefr_coneangle),
                   "clamp", GRefr_clamp,
                 "coordsystem", coordsyst,
                  "sortbleeding", GRefr_sort,
                 "maxdist", GRefr_maxdist, 
                "falloff", GRefr_falloff,
                  "falloffmode", GRefr_falloffmode,
                "bias", GRefr_bias,
                   "maxsolidangle", GRefr_maxsolidangle));

        vector RL = normalize(reflDir);
        aov_GRefr += Oi*(kr*GRefr_int*indirectdiffuse(P, RL, 0, //glossy reflections on top
                "filename", filename, 
                "pointbased", 1,
                "hitsides", GRefr_hitsides, 
                "coneangle", radians(GRefr_coneangle),
                "clamp", GRefr_clamp,
                "coordsystem", coordsyst,
                "sortbleeding", GRefr_sort,
                "maxdist", GRefr_maxdist, 
                "falloff", GRefr_falloff,
                "falloffmode", GRefr_falloffmode,
                "bias", GRefr_bias,
                "maxsolidangle", GRefr_maxsolidangle));

        } else {
        texture3d(rebaked_file, P,  shading_normal,
        "refraction", aov_GRefr,
        "coordsystem", rebaked_coordsyst);
        }
	if(GRefr_tex != "") {
		color GRefr_texture = texture(GRefr_tex);  // Bring in the texture
		aov_GRefr = mix(black, aov_GRefr, GRefr_texture); // Mix between black and GRefr by the texture
	}
	if(composite==1) {
		Ci = aov_GRefr; // just use the refractions/reflections for output
	}
        if(rebake == 1) {
            bake3d(rebaked_file, "", P, shading_normal, 
            "refraction", aov_GRefr,
            "coordsystem", rebaked_coordsyst,
            "interpolate", 1);
        }

      }
      
      if(IBL == 1) {
        if (reuse != 1) {
        color IBL_envcol = 0;
        vector IBL_envdir = 0;
        aov_IBL = Oi*(IBL_int*occlusion( // performs occlusion from HDRI with parameters from GUI 
                P, shading_normal, 0, 
                "pointbased", 1, 
                "filename", filename,
                "coordsystem", coordsyst,
                "hitsides", IBL_hitsides,
                "maxdist", IBL_maxdist, 
                "coneangle", radians(IBL_coneangle),
                "falloff", IBL_falloff,
                "falloffmode", IBL_falloffmode,
                "bias", IBL_bias,
                "clamp", IBL_clamp,
                "maxsolidangle", IBL_maxsolidangle,
                "maxvariation", IBL_maxvariation,
                "environmentmap", envmap,
                "environmentcolor", IBL_envcol,
                "environmentdir", IBL_envdir));
        } else {
        texture3d(rebaked_file, P, shading_normal,
        "ibl", aov_IBL,
        "coordsystem", rebaked_coordsyst);
        }
	if(IBL_tex != "") {
		color IBL_texture = texture(IBL_tex);  // Bring in the texture
		aov_IBL = mix(white, aov_IBL, IBL_texture); // Mix between white and IBL by the texture
	}
	if(composite==1) {
        	Ci *= aov_IBL;
	}
        if(rebake == 1) {
            bake3d(rebaked_file, "", P,  shading_normal, 
            "ibl", aov_IBL,
            "coordsystem", rebaked_coordsyst,
            "interpolate", 1);
        }
      }
      
      if(GI == 1) {
        if (reuse != 1) {
        aov_GI = Oi*indirectdiffuse(P,  // performs color bleeding with parameters from GUI
                shading_normal, 0, 
                "pointbased", 1, 
                "filename", filename,
                "hitsides", GI_hitsides, 
                "coneangle", radians(GI_coneangle),
                "clamp", GI_clamp,
                "coordsystem", coordsyst,
                "sortbleeding", GI_sort,
                "maxdist", GI_maxdist, 
                "falloff", GI_falloff,
                "falloffmode", GI_falloffmode,
                "bias", GI_bias,
                "maxsolidangle", GI_maxsolidangle,
                "environmentmap", envmap,
                "environmentspace", envspace,
                "environmentcolor", aov_envcolor)*GI_intensity; // multiplied by GUI intensity controller

        if(GI_AO == 1){ // performs occlusion the same time as color bleeding for faster rendering
            aov_AO = Oi*1-occlusion(  //because we set aov_AO to 1 earlier, we subtract the occlusion from 1
                P, shading_normal, 0, 
                "pointbased", 1,
                "filename", filename,
                "hitsides", GI_AO_hitsides, 
                "coneangle", radians(GI_AO_coneangle),
                "clamp", GI_AO_clamp,
                "coordsystem", coordsyst,
                "maxdist", GI_AO_maxdist,
                "bias", GI_AO_bias,
                "maxsolidangle", GI_AO_maxsolidangle,
                "maxvariation", GI_AO_maxvariation,
                "falloff", GI_AO_falloff,
                "falloffmode", GI_AO_falloffmode);
        }
        } else {
        texture3d(rebaked_file, P, shading_normal,
        "indirectdiffuse", aov_GI,
        "coordsystem", rebaked_coordsyst);
        }
	if(GI_tex != "") {
		color GI_texture = texture(GI_tex);  // Bring in the texture
		aov_GI = mix(black, aov_GI, GI_texture); // Mix between black and GI by the texture
	}
	if(GI_AO_tex != "") {
		color GI_AO_texture = texture(GI_AO_tex);  // Bring in the texture
		aov_AO = mix(white, aov_AO, GI_AO_texture); // Mix between white and AO by the texture
	}
        aov_envcolor=Oi*aov_envcolor;
	if(composite==1) {
        	Ci += aov_GI * aov_AO; // Since we're doing AO and GI at the same time, multiply them onto each other, because we set aov_AO to 1 earlier, if there's no occlusion, it's multiplied by 1
	}
        if(rebake == 1) {
            bake3d(rebaked_file, "", P,  shading_normal, 
            "indirectdiffuse", aov_GI,
            "coordsystem", rebaked_coordsyst,
            "interpolate", 1);
        }
}
        
        if(SSS == 1) {
color SSS_scatter, SSS_absorption;
if (SSS_type == "custom") {
	SSS_scatter = SSS_sct;
	SSS_absorption = SSS_abs;
} else if (SSS_type == "apple") {
	SSS_scatter = color(2.29, 2.39, 1.97);
	SSS_absorption = color(0.003, 0.0034, 0.046);
} else if (SSS_type == "chicken1") {
	SSS_scatter = color(0.15, 0.21, 0.38);
	SSS_absorption = color(0.015, 0.077, 0.19);
} else if (SSS_type == "chicken2") {
	SSS_scatter = color(0.19, 0.25, 0.32);
	SSS_absorption = color(0.018, 0.088, 0.20);
} else if (SSS_type == "cream") {
	SSS_scatter = color(7.38, 5.47, 3.15);
	SSS_absorption = color(0.0002, 0.0028, 0.0163);
} else if (SSS_type == "ketchup") {
	SSS_scatter = color(0.18, 0.07, 0.03);
	SSS_absorption = color(0.061, 0.97, 1.45);
} else if (SSS_type == "marble") {
	SSS_scatter = color(2.19, 2.62, 3.00);
	SSS_absorption = color(0.0021, 0.0041, 0.0071);
} else if (SSS_type == "potato") {
	SSS_scatter = color(0.68, 0.70, 0.55);
	SSS_absorption = color(0.0024, 0.009, 0.12);
} else if (SSS_type == "skimmilk") {
	SSS_scatter = color(0.70, 1.22, 1.9);
	SSS_absorption = color(0.0014, 0.0025, 0.0142);
} else if (SSS_type == "skin1") {
	SSS_scatter = color(0.74, 0.88, 1.01);
	SSS_absorption = color(0.032, 0.17, 0.48);
} else if (SSS_type == "skin2") {
	SSS_scatter = color(1.09, 1.59, 1.79);
	SSS_absorption = color(0.013, 0.07, 0.145);
} else if (SSS_type == "spectralon") {
	SSS_scatter = color(11.6, 20.4, 14.9);
	SSS_absorption = color(0, 0, 0);
} else if (SSS_type == "wholemilk") {
	SSS_scatter = color(2.55, 3.21, 3.77);
	SSS_absorption = color(0.0011, 0.0024, 0.014);
}
        if (reuse != 1) {
        aov_SSS = Oi*(subsurface( // performs subsurface with ptc 
                P, shading_normal, 
                "coordsystem", coordsyst,
                "filename", filename,
                "scale", SSS_scale,
                "smooth", SSS_smooth,
		"scattering", SSS_scatter,
		"absorption", SSS_absorption,
                "ior", SSS_ior));
        } else {
        texture3d(rebaked_file, P, shading_normal,
        "subsurface", aov_SSS,
        "coordsystem", rebaked_coordsyst);
        }
	if(SSS_tex != "") {
		color SSS_texture = texture(SSS_tex);  // Bring in the texture
		aov_SSS = mix(black, aov_SSS, SSS_texture); // Mix between white and DO by the texture
	}
	if(composite==1) {
        	Ci = mix( aov_SSS, Ci, SSS_weight )*Oi;
	}
        if(rebake == 1) {
            bake3d(rebaked_file, "", P,  shading_normal, 
            "subsurface", aov_SSS,
            "coordsystem", rebaked_coordsyst,
            "interpolate", 1);
        }
      }

        if(bake == 1){
            if ((bake_AREA == 1) && (bake_COLOR == 0)){ // If only AREA is selected, only give area
                float a, opacity;

                  a = area(P, "dicing"); // micropolygon area
                  opacity = 0.333333 * (Oi[0] + Oi[1] + Oi[2]); // average opacity
                 a *= opacity; // reduce area if non-opaque      

                  if (a > 0) // only bake if non-transparent
                       bake3d(bake_file, "",
                         P, N, 
                        "coordsystem", bake_coordsyst, 
                        "interpolate", 1, 
                        "_area", a,
			"_opacity", Oi);
            }
            else{ // if both, neither, or just COLOR was selected, default to the bake_COLOR
		float a, opacity;
                a = area(P, "dicing"); // micropolygon area
                opacity = 0.333333 * (Oi[0] + Oi[1] + Oi[2]); // average opacity
                a *= opacity; // reduce area if non-opaque    
                color c=0;
                surface("Ci", c);

                bake3d( bake_file, "", 
                    P, N, 
                    "coordsystem", bake_coordsyst,
                    "_radiosity", c, 
                    "interpolate", 1,
		    "_area", a,
		    "_opacity", Oi);
            }
      }

	Ci *= 1;
	Oi *= 1;
    }