JiWindowBox_Examples.zip
// jiWindowBox - creates a fake "room" from a single plane
// jiWindowBox.osl, by Julius Ihle
// windowAspect wall distortion fix by David McDonnell
// UI overhaul to Qt, filenmae widget & Color grading integrated by Mads Drøschler
// External Grading function from the OSL CC base node
// Mads Drøschler
// Modified 4/15/21 by Saul Espinosa for Redshift 3d Support
// Added ACES output, Gamma, and new page/min/max metadata
color Grader (color Input, color InputMin, color InputMax, vector HSV, color OutputMax, color OutputMin, float MidTones, int Clamp)
{
color Out;
color col = (Input - InputMin) / InputMax;
color hsv = transformc("rgb", "hsv", col);
hsv[0] += HSV[0];
hsv[1] *= HSV[1];
hsv[2] *= HSV[2];
col = transformc("hsv", "rgb", hsv);
Out = mix(OutputMin, OutputMax, pow(col, 1.0/MidTones));
if (Clamp) Out = clamp(Out, 0.0, 1.0);
return Out;
}
// UI overhaul port to QT for 3dsmax custom User interface
// Mads Drøschler
shader jiWindowBox_Redshift
[[ string help = "Window Box Projection Shader",
string label = "Window Box" ]]
(
// Filename node is not needed with the string widget "filename" in max with this addition.
// User can load the texture directly into the shader.
// Mads Drøschler
string input_tex = ""
[[
string widget = "filename",
int connectable = 0,
string page = "0 : Texture",
]],
int zUpAxis = 0
[[
string widget = "checkBox",
int connectable = 0,
string page = "0 : Texture",
]],
int textureFlip = 0
[[
string widget = "checkBox",
int connectable = 0,
string page = "0 : Texture",
]],
int textureFlop = 0
[[
string widget = "checkBox",
int connectable = 0,
string page = "0 : Texture",
]],
float Hue = 0
[[
int connectable = 0,
string page = "1 : Color Correct",
float min = 0,
float max = 1
]],
float Saturation = 1
[[
int connectable = 0,
string page = "1 : Color Correct",
float min = 0,
float max = 1,
]],
float Value = 1
[[
int connectable = 0,
string page = "1 : Color Correct",
float min = 0,
float max = 100
]],
float ManualGamma = 2.2
[[
string label="Gamma",
string page = "1 : Color Correct",
float min = 0,
float max = 5
]],
color InputMin = 0.0
[[
string help = "The input value that maps to the darkest output. Incoming black level. ",
int connectable = 0,
string page = "2 : Color Clamp",
]],
color InputMax = 1.0
[[
string help = "The input value that maps to the brightst output. Incoming white level. ",
int connectable = 0,
string page = "2 : Color Clamp",
]],
float MidTones = 1.0
[[
string help = "Adjusts the MidTones/Gamma.",float min = 0.01, float max = 9.99,
int connectable = 0,
string page = "2 : Color Clamp",
]],
color OutputMin = 0.0
[[
string help = "The output black level.",
int connectable = 0,
string page = "2 : Color Clamp",
]],
color OutputMax = 1.0
[[
string help = "The output white level.",
int connectable = 0,
string page = "2 : Color Clamp",
]],
float windowAspect = 1
[[
int connectable = 0,
string page = "3 : Window Shape",
float min = 0,
float max = 10
]],
float roomDepth = 1
[[
float min = 0.1,
float max = 100,
int connectable = 0,
string page = "3 : Window Shape",
]],
float widthOverscan = 0
[[
float min = 0.0,
float max = 0.9,
int connectable = 0,
string page = "3 : Window Shape",
]],
float heightOverscan = 0
[[
float min = 0.0,
float max = 0.9,
int connectable = 0,
string page = "3 : Window Shape",
]],
int enableMidground = 0
[[
string widget = "checkBox",
int connectable = 0,
string page = "4 : Midground",
]],
float midgroundDepth = 0.5
[[
float min = 0.1,
float max = 100,
int connectable = 0,
string page = "4 : Midground"
]],
float midgroundOffsetX = 0
[[
int connectable = 0,
float min = -10.0,
float max = 10.0,
string page = "4 : Midground"
]],
float midgroundOffsetY = 0
[[
int connectable = 0,
float min = -10.0,
float max = 10.0,
string page = "4 : Midground"
]],
int enableCurtains = 0
[[
string widget = "boolean",
string page = "5 : Foreground",
int connectable = 0,
]],
int Clamp = 1
[[
string widget = "checkBox",
string help = "Clamp the output to the 0-1 range for each component",
string page = "6 : Extra",
int connectable = 0,
]],
int aces = 0
[[ string widget = "checkBox",
string page = "6 : Extra",
string label = "ACES",
int connectable = 0
]],
output color outColor = 0.0
)
{
// additional inits Mads Drøschler
vector HSV = vector(Hue,Saturation,Value);
//user controls remapping
float roomDepthMult = clamp(roomDepth,0.1,100);
float heightOverscanMult = 1 - clamp(heightOverscan,0,0.9);
float widthOverscanMult = 1 - clamp(widthOverscan,0,0.9);
float midgroundDepthMult = clamp(midgroundDepth,0.05,roomDepthMult-0.01);
float midgroundOffY = midgroundOffsetY * (textureFlip*2-1) * 0.1;
float midgroundOffX = midgroundOffsetX * (textureFlop*2-1) * 0.1;
//global variables & remapping
vector objI = transform("object", -I);
if (zUpAxis > 0){
objI = vector(-objI[0],-objI[1],-objI[2]) * color(widthOverscanMult*(1/windowAspect), heightOverscanMult, 1); //reorder to match UV for Y up axis
} else {
objI = vector(-objI[0],-objI[1],-objI[2]) * color(widthOverscanMult*(1/windowAspect), heightOverscanMult, 1); //reorder to match UV for Z up axis
}
color objPOrig = (color(u,v,0.5) * 2 - 1) * 0.5 + 0.5; //for curtains
color objP = (color(u,v,0.5) * 2 - 1) * color(widthOverscanMult, heightOverscanMult, 1) * 0.5 + 0.5; //UV seems to be the better approach
//bases for width/height/depth
vector sections = step(0, objI);
color baseDepth = (objP-sections)/(-objI * roomDepthMult);
color mgDepth = (objP-sections)/(-objI * midgroundDepthMult);
color baseBack = (objP-sections)/(-objI);
color baseWidth = baseDepth * roomDepthMult;
//depth and width ramps
color baseDepthX = (baseDepth[1]*objI+objP + 1);
color baseDepthY = (baseDepth[0]*objI+objP + 1);
color baseWidthX = (baseWidth[1]*objI+objP + 1);
color baseWidthY = (baseWidth[0]*objI+objP + 1);
float horizU = baseDepthY[2] - 0.5;
float vertU = baseWidthX[0] - 1;
float horizV = baseWidthY[1] - 1;
float vertV = baseDepthX[2] - 0.5;
//convert ramps to UV/ST... WIP - not very efficient
float sideWallsMask = step(0,horizU) * step(0,1-max(horizV, 1-horizV));
color sideWallsUV = color(horizU, horizV, 0) / 3;
color rWallUV = (sideWallsUV + color(2.0/3.0, 1.0/3.0, 0)) * sideWallsMask * sections[0];
color lWallUV = (sideWallsUV + color(0.0, 1.0/3.0, 0)) * sideWallsMask * (1-sections[0]);
lWallUV[0] = (1.0/3.0 - lWallUV[0]) * sideWallsMask * (1-sections[0]);
float FloorCeilMask = step(0,vertV) * step(0,1-max(vertU, 1-vertU));
color FloorCeilUV = color(vertU, vertV, 0) / 3;
color ceilUV = (FloorCeilUV + color(1.0/3.0, 2.0/3.0, 0)) * FloorCeilMask * sections[1];
color floorUV = (FloorCeilUV + color(1.0/3.0, 0, 0)) * FloorCeilMask * (1-sections[1]);
floorUV[1] = (1.0/3.0 - floorUV[1]) * FloorCeilMask * (1-sections[1]);
color backWallUV = ((baseBack[2]*objI + (objP/2)/(roomDepthMult)) * (roomDepthMult*2) / 3 + color(1.0/3.0, 1.0/3.0, 0) ) * (1 - max(step(0,horizU), step(0,vertV)));
color midgroundUV = (1.0/3.0 - (baseBack[2]*objI + (objP)/(midgroundDepthMult*2)) * (midgroundDepthMult*2) / 3);
float midgroundMask = step( 0, midgroundUV[1] * 3 * (1-midgroundUV[1]*3) ) * step( 0, midgroundUV[0] * (1.0/3.0-midgroundUV[0]) );
midgroundUV = (color(midgroundOffX, midgroundOffY, 0) + midgroundUV);
midgroundUV[1] = (1-midgroundUV[1]) - 2.0/3.0;
color curtainsUV = objPOrig * color(1.0/3.0, 1.0/3.0, 1);
curtainsUV[0] = 1.0/3.0 - curtainsUV[0];
curtainsUV[1] = 2.0/3.0 + curtainsUV[1]; //VRay specific
color finalUV = ceilUV + floorUV + rWallUV + lWallUV + backWallUV;
//flipping ctrl
if (textureFlop < 1){ //VRay specific
midgroundUV[0] = 1.0/3.0 - midgroundUV[0];
curtainsUV[0] = 1.0/3.0 - curtainsUV[0];
}else
finalUV[0] = 1-finalUV[0];
if (textureFlip > 0){
finalUV[1] = 1-finalUV[1];
midgroundUV[1] = 1.0/3.0 - midgroundUV[1]; // VRay specific
curtainsUV[1] = 1 - curtainsUV[1] + 2.0/3.0; // VRay specific
}
color roomRGB = texture(input_tex, finalUV[0], finalUV[1], "width" , 0);
color finalRGB;
//midground switch
if (enableMidground > 0){
float midgroundA;
color midgroundRGB = texture(input_tex, midgroundUV[0], midgroundUV[1], "alpha", midgroundA, "width" , 0);
finalRGB = mix(roomRGB,midgroundRGB,midgroundA * midgroundMask); //VRay specific
}
else{
finalRGB = roomRGB;
}
//curtains switch
if (enableCurtains > 0){
float curtainsA;
color curtainsRGB = texture(input_tex, curtainsUV[0], curtainsUV[1], "alpha", curtainsA, "width" , 0);
finalRGB = mix(finalRGB,curtainsRGB,curtainsA);
}
// ACES sRGB Transform
matrix aces_tm = matrix(
0.6131, 0.0701, 0.0206, 0,
0.3395, 0.9164, 0.1096, 0,
0.0474, 0.0135, 0.8698, 0,
0, 0, 0, 1);
// Fetch the color grade function
// Mads Drøschler
finalRGB = Grader(finalRGB,InputMin,InputMax,HSV,OutputMax,OutputMin,MidTones,Clamp);
color result = finalRGB;
// Gamma & ACES
{
if (ManualGamma != 1.0)
result = pow(finalRGB, ManualGamma);
}
float r = result[0], g = result[1], b = result[2];
// ACES Output
if (aces == 0)
outColor = result;
else
{
outColor = transform(aces_tm, vector(r,g,b));
}
}