/*

Author:        Cameron Leger
Date:        1/10/2012
Version:    2.2
Title:        cl_ptc_uber

If you're using a point cloud, please only select one of the ways to use it per instance of the shader.

The rendered image will be the effect you've checked on top of the render. You should be ready to go with just that.
For more control, you can render out in passes, which is explained later. Since the scene is rendered along with the
effects, a seperate pass for the effects is not required in most cases.

For space and efficiency's sake, you can bake PTC files for static objects separately than the animated objects and combine them at rendertime.
Bake them out however you want, but when you use them, include them as following:

path/to/file.ptc;path/to/file2.ptc

Without spaces between the paths and a ";" to separate PTCs

Instructions:

Add these attributes to your PreWorldMEL whenever you want to bake data to ensure that you get the full geometry pointcloud
    RiAttribute -n "cull" -p "hidden" "integer" "0" -p "backfacing" "integer" "0";
    RiAttribute -n "dice" -p "rasterorient" "integer" "0";

Under all of your passes:
    1) Under advanced options enable Standard Atomosphere Shader
    2) Under advanced options make sure it's set to ALL AOVs

Because this shader is an atmosphere shader, you can:
    1) Make a shader collection with an atmosphere override so everything is included in a point cloud or effect
    2) Apply the atmosphere shader individually to objects to render individual point clouds or effects
    3) Keep the surface shaders on your objects so shaded point clouds work

You can use the results straight from the render, or use these passes for compositing.

This shader outputs AOVs for the passes. Each pass has at least one AOV, called by the name of the section.
"aov_<section>" will give you just the effect from that pass.
To use them, type color "aov_<section>" into the AOV box.
ie: "color aov_GI" without the quotes

Here is the list of AOVs and description:
    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_DO - The directional occlusion
    4) aov_RO - The reflection occlusion
    5) aov_GRefl - The blurred reflections
    6) aov_GRefr - The blurred refractions
    7) aov_envcolor - The environment color from the GI pass if you're using it for lighting from a texture
    8) aov_IBL - The lighting from the image in the IBL pass
    9) aov_SSS - The subsurface scattering

So, if you render AO, you can either use the render that's generated, or use aov_AO to get just the occlusion
and disable composite so so rgba is the rendered image and combine them in post.

This shader also supports rebaking and reusing of PTC generated effects for speeding up renders when a look is finalized.

This is done the same was as normally using the shader, with a few extra steps.
Bake the PTC like normal from a baking pass.
Read in the PTC like normal from a normal render pass. Once you have the look finalized and the animation isn't changing, you can rebake.
Check the checkbox for Rebaking. In the rebaking section, make sure a valid PTC path is specified, and not overwriting your current PTC file.
Make sure for the renderpass that you have the attributes set in the PreWorldMEL to get a full PTC and atmosphere options set correctly.
Render that pass. You will get another PTC file.
In the shader, uncheck Rebaking and check Reusing. This will use the same PTC just generated to lookup data instead of calculating it.

For more efficiency, you can also convert the 2nd PTC files to brickmaps and load those in the Rebaking section for Reusing.

NOTE:
The general concept and much of this code is based around:
http://www.cs.amherst.edu/~jer/cs32/RPS_15.0/pointbased.html

The follow links were very helpful towards compiling this shader:
http://www.3delight.com/en/modules/PunBB/viewtopic.php?id=1246&p=1
http://www.3delight.com/en/modules/PunBB/viewtopic.php?id=1847&p=1
http://www.3delight.com/en/modules/PunBB/viewtopic.php?id=1854&p=1

And of course, the lovely manual.

Changes:

1.4
    Added SSS functionality.
    Changed the baking section and normals to fix some materials rendering white
    Changed the way Glossy Reflections are applied. There's a control for mixing between purely diffuse and purely reflective

1.5
    Fixed SSS for 3Delight 3.0.69
    Fixed all the coneangle parameters (hadn't converted them to radians)

1.6
    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

1.7
    Added a rebaking and reusing section

1.9
    Added a texture mapping ability to all uses of the shader
    This texture map will act as an alpha, masking the shader
    Fixed a bug where you couldn't control the IBL Intensity
    Fixed transparency

2.0
    Fixed a few baking related things

2.1
    Added SSS presets

2.1
    Fixed a few math operations
*/


##    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."
##    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."
##    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."
##    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."
##    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/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 = 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 = 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 = 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 = 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));

        } 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));

        } 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,
                "environmentmap", envmap));

        } 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,
                "environmentmap", envmap));

            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,
                "environmentmap", envmap));

        } 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,
            "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) {
		float GI_AO_aov = 0;
        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,
                "occlusion", GI_AO_aov)*GI_intensity; // multiplied by GUI intensity controller

        } 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
            //GI_AO_aov = mix(white, GI_AO_aov, GI_AO_texture); // Mix between white and AO by the texture
        }
        aov_envcolor=Oi*aov_envcolor;
        if(composite==1) {
            Ci = (Ci + aov_GI) * (1-GI_AO_aov); // 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
            bake3d(bake_file, "",
                P, shading_normal,
                "coordsystem", bake_coordsyst,
                "interpolate", 1,
                "_opacity", Oi);
        } else { // if both, neither, or just COLOR was selected, default to the bake_COLOR
            color c=0;
            surface("Ci", c);
            bake3d( bake_file, "",
                P, shading_normal,
                "coordsystem", bake_coordsyst,
                "interpolate", 1,
                "_radiosity", c,
                "_opacity", Oi);
        }
    }

    Ci *= 1; // Fixes a bug in older versions of 3Delight where raytraced effects don't compute if Ci is not used
    Oi *= 1; // Fixes a bug in older versions of 3Delight where raytraced effects don't compute if Oi is not used
}

