/*

Author:        Cameron Leger
Date:        1/4/2012
Version:    2.2
Title:        cl_ptc_light_uber

The rendered image will be the effect you've checked on top of the render.

Because this is a light shader, it obeys light linking. So, you can have many lights with this shader attached to different objects to get multiple effects in one run.

It is still used mainly the same way as my ptc_uber shader.

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

Also, for things like Reflection Occlusion when you only want the effect you should probably turn off your other lights so they don't interfere.

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_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_SSS - The subsurface scattering

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

1.8
    Fixed SSS for 3Delight 3.0.69
    Fixed all the coneangle parameters (hadn't converted them to radians)
    Added AOVs again

1.9
    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

2.0
    Added a rebaking and reusing section

2.1
    Fixed many things

2.2
    Added SSS presets
*/


##    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/filename;"
#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 filename "gadgettype=inputfile;label=PTC File;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."
#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_int;"
#pragma annotation AO_int "gadgettype=floadfield;label=Intensity;hint=Multiplied by the AO effect. Default is 1."
#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_int;"
#pragma annotation DO_int "gadgettype=floadfield;label=Intensity;hint=Multiplied by the DO effect. Default is 1."
#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_int;"
#pragma annotation RO_int "gadgettype=floadfield;label=Intensity;hint=Multiplied by the RO effect. Default is 1."
#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 .2"
#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_int;"
#pragma annotation GRefl_int "gadgettype=floadfield;label=Intensity;hint=Multiplied by the GRefl effect. Default is 1."
#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 in radians 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_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 in radians 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_int;"
#pragma annotation IBL_int "gadgettype=floadfield;label=Intensity;hint=Multiplied by the IBL effect. Default is 1."
#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_int;"
#pragma annotation GI_int "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 30 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"
## 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."

light cl_ptc_light_uber (
    string filename = "<project>/3delight/ptc/<scene>.#.ptc";
    string envmap = "";
    string coordsyst = "world";
    string envspace = "world";
    string AO_hitsides = "both";
    float composite = 0,
    AO_maxdist = 1e2,
    AO_int = .5,
    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_int = .5,
    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_int = 1,
    RO_falloff = 1,
    RO_falloffmode = 1,
    RO_bias = 0.01,
    RO_clamp = 1,
    RO_maxsolidangle = 0.05,
    RO_coneangle = 30,
    RO = 0;
    string GRefl_hitsides = "both";
    float GRefl_maxdist = 1e15,
    GRefl_int = 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 = 1e15,
    GI_falloff = 1,
    GI_falloffmode = 1,
    GI_bias = 0.045,
    GI_clamp = 1,
    GI_sort = 1,
    GI_coneangle = 180,
    GI_maxsolidangle = .2,
    GI_int = 1,
    GI = 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;
    float reuse = 0,
    rebake = 0;
    string rebaked_file = "<project>/3delight/ptc/<scene>.#.rebake.ptc",
    rebaked_coordsyst = "world";
    output varying color GI_Cl = 0;
    output varying color GRefl_Cl = 0;
    output varying color GRefr_Cl = 0;
    output varying color RO_Cl = 0;
    output varying color IBL_Cl = 0;
    output varying color AO_Cl = 1;
    output varying color DO_Cl = 1;
    output varying color SSS_Cl = 1;
    output varying color aov_envcolor = 1)
{
    normal shading_normal = normalize(Ns);

    if(AO == 1) {
        if (reuse != 1) {
            AO_Cl = AO_int*(1-occlusion( // performs occlusion with parameters from GUI, inverse AO and multiply by our intensity
                Ps, 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, Ps, shading_normal,
                "occlusion", AO_Cl,
                "coordsystem", rebaked_coordsyst);
        }
        outputchannel("aov_AO", AO_Cl);
        if(composite == 1) {
            Cl = AO_Cl;
        } else {
            Cl = Cl;
        }
        Ol = Ol;
        if(rebake == 1) {
            bake3d(rebaked_file, "", Ps, shading_normal,
                "occlusion", AO_Cl,
                "coordsystem", rebaked_coordsyst,
                "interpolate", 1);
        }
    }

    if(DO == 1) {
        if (reuse != 1) {
            DO_Cl = DO_int*(1-occlusion( // performs occlusion with parameters from GUI, inverse AO and multiply by our intensity
                Ps, 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, Ps, DO_dir,
                "occlusion", DO_Cl,
                "coordsystem", rebaked_coordsyst);
        }
        outputchannel("aov_DO", DO_Cl);
        if(composite == 1) {
            Cl = DO_Cl;
        } else {
            Cl = Cl;
        };
            Ol = Ol;
        if(rebake == 1) {
            bake3d(rebaked_file, "", Ps, DO_dir,
                "occlusion", DO_Cl,
                "coordsystem", rebaked_coordsyst,
                "interpolate", 1);
        }
    }

    if(RO == 1) {
        vector RO_refl = reflect(I, shading_normal); // Uses the reflected vector to compute occlusion, thus reflection occlusion
        if (reuse != 1) {
            RO_Cl = RO_int*(1-occlusion(Ps, 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, Ps, RO_refl,
                "occlusion", RO_Cl,
                "coordsystem", rebaked_coordsyst);
        }
        outputchannel("aov_RO", RO_Cl);
        if(composite == 1) {
            Cl = RO_Cl;
        } else {
            Cl = Cl;
        }
        Ol = Ol;
        if(rebake == 1) {
            bake3d(rebaked_file, "", Ps, RO_refl,
                "occlusion", RO_Cl,
                "coordsystem", rebaked_coordsyst,
                "interpolate", 1);
        }
    }

    if(GRefl == 1) {
        vector GRefl_refl = reflect(I, shading_normal); // Again, using a reflection vector for computation
        if (reuse != 1) {
            GRefl_Cl = GRefl_int*indirectdiffuse(Ps, 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, Ps, GRefl_refl,
                "reflection", GRefl_Cl,
                "coordsystem", rebaked_coordsyst);
        }
        outputchannel("aov_GRefl", GRefl_Cl);
        if(composite == 1) {
            Cl = GRefl_Cl;
        } else {
            Cl = Cl;
        }
        Ol = Ol;
        if(rebake == 1) {
            bake3d(rebaked_file, "", Ps, GRefl_refl,
                "reflection", GRefl_Cl,
                "coordsystem", rebaked_coordsyst,
                "interpolate", 1);
        }
    }

    if(GRefr == 1) {
        if (reuse != 1) {
            extern point Ps;
            extern normal N;
            extern vector I;
            // normalizing
            vector IN = normalize(I);
            // stores reflection and refraction vectors
            vector reflDir, refrDir;
            float eta = (IN.shading_normal < 0) ? 1/GRefr_ior : GRefr_ior;
            float kr, kt;
            // computes fresnel effect
            fresnel(IN, shading_normal, eta, kr, kt, reflDir, refrDir);
            kt = 1 - kr;

            vector RF = normalize(refrDir);
            GRefr_Cl = kt*GRefr_int*indirectdiffuse(Ps, 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);

        } else {
            texture3d(rebaked_file, Ps,  shading_normal,
                "refraction", GRefr_Cl,
                "coordsystem", rebaked_coordsyst);
        }
        outputchannel("aov_GRefr", GRefr_Cl);
        if(composite == 1) {
            Cl = GRefr_Cl;
        } else {
            Cl = Cl;
        }
        Ol = Ol;
        if(rebake == 1) {
            bake3d(rebaked_file, "", Ps, shading_normal,
                "refraction", GRefr_Cl,
                "coordsystem", rebaked_coordsyst,
                "interpolate", 1);
        }
    }

    if(IBL == 1) {
        if (reuse != 1) {
            color IBL_envcol = 0;
            vector IBL_envdir = 0;
            IBL_Cl = IBL_int*occlusion( // performs occlusion from HDRI with parameters from GUI
                Ps, 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,
                "environmentcolor", aov_envcolor);

        } else {
            texture3d(rebaked_file, Ps, shading_normal,
                "ibl", IBL_Cl,
                "coordsystem", rebaked_coordsyst);
        }
        outputchannel("aov_IBL", IBL_Cl);
        if(composite == 1) {
            Cl = IBL_Cl;
        } else {
            Cl = Cl;
        }
        Ol = Ol;
        if(rebake == 1) {
            bake3d(rebaked_file, "", Ps,  shading_normal,
                "ibl", IBL_Cl,
                "coordsystem", rebaked_coordsyst,
                "interpolate", 1);
        }
    }

    if(GI == 1) {
        if (reuse != 1) {
			float GI_AO = 0;
            GI_Cl = GI_int*indirectdiffuse(Ps,  // 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,
            "occlusion", GI_AO);

        } else {
            texture3d(rebaked_file, Ps, shading_normal,
                "indirectdiffuse", GI_Cl,
                "coordsystem", rebaked_coordsyst);
        }
        outputchannel("aov_GI", GI_Cl);
        outputchannel("aov_AO", AO_Cl);
        if(composite == 1) {
            Cl = GI_Cl * (1-AO_Cl);
        } else {
            Cl = Cl;
        }


        Ol = Ol;
        if(rebake == 1) {
            bake3d(rebaked_file, "", Ps,  shading_normal,
                "indirectdiffuse", GI_Cl,
                "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) {
            float SSS_mult = SSS_weight;
            SSS_mult = (SSS_mult - 1)*(-1); // SSS_weight should be 0 for SSS and 1 for diffuse.
            SSS_Cl = subsurface( // performs subsurface with ptc
                Ps, shading_normal,
                "coordsystem", coordsyst,
                "filename", filename,
                "scale", SSS_scale,
                "smooth", SSS_smooth,
                "scattering", SSS_scatter,
                "absorption", SSS_absorption,
                "ior", SSS_ior) * SSS_mult; // Multiply by the SSS_mult to control SSS intensity

        } else {
            texture3d(rebaked_file, Ps, shading_normal,
                "subsurface", SSS_Cl,
                "coordsystem", rebaked_coordsyst);
        }
        outputchannel("aov_SSS", SSS_Cl);
        if(composite == 1) {
            Cl = SSS_Cl;
        } else {
            Cl = Cl;
        }
        Ol = Ol;
        if(rebake == 1) {
            bake3d(rebaked_file, "", Ps,  shading_normal,
                "subsurface", SSS_Cl,
                "coordsystem", rebaked_coordsyst,
                "interpolate", 1);
        }
    }

}

