Files
UnrealEngine/Engine/Source/ThirdParty/OpenVDB/openvdb-12.0.0/openvdb_wolfram/OpenVDBLink/Render.m
2025-05-18 13:04:45 +08:00

1479 lines
48 KiB
Mathematica

(* ::Package:: *)
(* ::Title:: *)
(*Render*)
(* ::Subtitle:: *)
(*Various rendering techniques on grids.*)
(* ::Text:: *)
(*Copyright Contributors to the OpenVDB Project*)
(*SPDX-License-Identifier: Apache-2.0*)
(* ::Section:: *)
(*Initialization & Usage*)
Package["OpenVDBLink`"]
PackageExport["OpenVDBLevelSetRender"]
PackageExport["OpenVDBLevelSetViewer"]
OpenVDBLevelSetRender::usage = "OpenVDBLevelSetRender[expr] returns a 3D render Image of an OpenVDB level set grid.";
OpenVDBLevelSetViewer::usage = "OpenVDBLevelSetViewer[expr] returns a manipulatable 3D render Image of an OpenVDB level set grid.";
(* ::Section:: *)
(*Shader and theme names*)
(* ::Subsection::Closed:: *)
(*Shaders*)
$dielectricList = {"Rubber", "Plastic", "Diffuse", "Glazed", "Satin", "Clay", "Matte", "Foil"};
$metalList = {"Gold", "Aluminum", "Brass", "Bronze", "Copper", "Electrum", "Iron", "Pewter"};
$rainbowList = {"Normal", "Position"};
$depthList = {"Depth"};
(* ::Subsection::Closed:: *)
(*Themes*)
$renderColorThemes = <|
(* front face back face closed face background *)
"Default" -> {RGBColor["#4D94FF"], RGBColor["#FFA24E"], RGBColor["#4D94FF"], RGBColor[1, 1, 1]},
"Monochrome" -> {RGBColor[1, 1, 1], RGBColor[1, 1, 1], RGBColor[1, 1, 1], RGBColor[0, 0, 0]},
"Bold" -> {ColorData[106, 2], ColorData[106, 1], ColorData[106, 2], Lighter[ColorData[106, 4], 0.5]},
"Cool" -> {ColorData[107, 1], ColorData[107, 4], ColorData[107, 1], RGBColor["#E6EBFF"]},
"Neon" -> {ColorData[109, 8], ColorData[109, 2], ColorData[109, 8], ColorData[109, 3]},
"Pastel" -> {RGBColor["#D5B0F6"], RGBColor["#F5AE6F"], RGBColor["#D5B0F6"], RGBColor["#B9FFDB"]},
"Soft" -> {RGBColor["#CFCFE1"], RGBColor["#EBBBAC"], RGBColor["#CFCFE1"], RGBColor["#3C3C78"]},
"Vibrant" -> {ColorData[112, 2], ColorData[112, 1], ColorData[112, 2], RGBColor["#FFDC80"]},
"Warm" -> {ColorData[113, 1], ColorData[113, 2], ColorData[113, 1], RGBColor["#FFE7B7"]}
|>;
(* ::Section:: *)
(*OpenVDBLevelSetRender*)
(* ::Subsection::Closed:: *)
(*Main*)
Options[OpenVDBLevelSetRender] = Join[
{Background -> Automatic, "ClosedClipping" -> False, "FrameTranslation" -> Automatic, ImageResolution -> Automatic,
"IsoValue" -> 0.0, "OrthographicFrame" -> Automatic, PerformanceGoal :> $PerformanceGoal},
Options[Graphics3D, {ImageSize, ViewAngle, ViewCenter, ViewPoint, ViewProjection, ViewRange, ViewVertical}]
];
OpenVDBLevelSetRender[args___] /; !CheckArgs[OpenVDBLevelSetRender[args], {1, 2}] = $Failed;
OpenVDBLevelSetRender[args___] :=
With[{res = iLevelSetRender[args]},
res /; res =!= $Failed
]
OpenVDBLevelSetRender[args___] := mLevelSetRender[args]
(* ::Subsection::Closed:: *)
(*iLevelSetRender*)
Options[iLevelSetRender] = Options[OpenVDBLevelSetRender];
iLevelSetRender[vdb_?OpenVDBScalarGridQ, shading_, opts:OptionsPattern[]] /; levelSetQ[vdb] :=
Block[{ropts, res},
ropts = parseRenderOptions[vdb, shading, opts];
(
res = oLevelSetRender[vdb, ropts];
res /; res =!= $Failed
) /; AssociationQ[ropts]
]
iLevelSetRender[vdb_, opts:OptionsPattern[]] := iLevelSetRender[vdb, Automatic, opts]
iLevelSetRender[___] = $Failed;
(* ::Subsection::Closed:: *)
(*Argument conform & completion*)
registerForLevelSet[iLevelSetRender, 1];
SyntaxInformation[OpenVDBLevelSetRender] = {"ArgumentsPattern" -> {_, _., OptionsPattern[]}};
addCodeCompletion[OpenVDBLevelSetRender][None, Join[Keys[$renderColorThemes], $dielectricList, $metalList], None];
(* ::Subsection::Closed:: *)
(*oLevelSetRender*)
Options[oLevelSetRender] = Options[iLevelSetRender];
oLevelSetRender[vdb_, ropts_] /; emptyVDBQ[vdb] || (!fogVolume[vdb] && vdb["BackgroundValue"] <= ropts["IsoValue"]) :=
Block[{bg, res, ires},
bg = RGBColor @@ ropts["Background"];
res = ropts["Resolution"];
ires = ropts["ImageResolution"];
ConstantImage[bg, res, "Byte", ImageResolution -> ires]
]
oLevelSetRender[vdb_, ropts_] /; KeyExistsQ[materialParameters, ropts["Shader"]] :=
Block[{ires, pbrparams, args, im},
ires = ropts["ImageResolution"];
args = Lookup[ropts, $PBRrenderLevelSetArgumentKeys];
pbrparams = materialParameters[ropts["Shader"]];
(
im = vdb["renderGridPBR"[##]]& @@ Join[args, Values[pbrparams][[4 ;; -1]]];
Image[im, ImageResolution -> ires] /; ImageQ[im]
) /; AssociationQ[pbrparams]
]
oLevelSetRender[vdb_, ropts_] :=
Block[{ires, args, im},
ires = ropts["ImageResolution"];
args = Lookup[ropts, $renderLevelSetArgumentKeys];
im = vdb["renderGrid"[##]]& @@ args;
Image[im, ImageResolution -> ires] /; ImageQ[im]
]
oLevelSetRender[___] = $Failed;
(* ::Subsection::Closed:: *)
(*Messages*)
mLevelSetRender[args___] := messageRenderFunction[OpenVDBLevelSetRender, args]
(* ::Section:: *)
(*OpenVDBLevelSetViewer*)
(* ::Subsection::Closed:: *)
(*Main*)
Options[OpenVDBLevelSetViewer] = Options[OpenVDBLevelSetRender];
OpenVDBLevelSetViewer[args___] /; !CheckArgs[OpenVDBLevelSetViewer[args], {1, 2}] = $Failed;
OpenVDBLevelSetViewer[args___] :=
With[{res = iLevelSetViewer[args]},
res /; res =!= $Failed
]
OpenVDBLevelSetViewer[args___] := mLevelSetViewer[args]
(* ::Subsection::Closed:: *)
(*iLevelSetViewer*)
Options[iLevelSetViewer] = Options[OpenVDBLevelSetViewer];
iLevelSetViewer[vdb_?OpenVDBScalarGridQ, shading_, opts:OptionsPattern[]] /; levelSetQ[vdb] :=
Block[{ropts, args, im},
ropts = parseRenderOptions[vdb, shading, opts];
(
iDynamicRender[vdb, shading, ropts, opts]
) /; AssociationQ[ropts]
]
iLevelSetViewer[vdb_, opts:OptionsPattern[]] := iLevelSetViewer[vdb, Automatic, opts]
iLevelSetViewer[___] = $Failed;
(* ::Subsection::Closed:: *)
(*Argument conform & completion*)
registerForLevelSet[iLevelSetViewer, 1];
SyntaxInformation[OpenVDBLevelSetViewer] = {"ArgumentsPattern" -> {_, _., OptionsPattern[]}};
addCodeCompletion[OpenVDBLevelSetViewer][None, Join[Keys[$renderColorThemes], $dielectricList, $metalList], None];
(* ::Subsection::Closed:: *)
(*iDynamicRender*)
Options[iDynamicRender] = Options[OpenVDBLevelSetViewer];
iDynamicRender[vdb_, shading_, iropts_, opts:OptionsPattern[]] :=
DynamicModule[{t, l, b, vp, ovp, vv, ovv, va, ova, vc, vr, sz, dx = 0.0, dy = 0.0, dz = 0.0, origva, origvc, origvr, origvp, origvv, mem, iso, oiso, mniso, mxiso, ir,
td\[Delta], \[Delta], shader, oshader, vrng, ovrng, volQ, ivolQ, projection, oprojection, origprojection, oframe, ooframe, c1, oc1, c2, oc2, c3, oc3, bg, obg, clp, im, antialq, oantialq},
{t, l, b} = Lookup[iropts, {"Translate", "LookAt", "Bounds"}];
td\[Delta] = {0.005, 0.005, 0.1}*Max[Abs[Subtract @@@ b]];
{vp, vv} = OptionValue[{ViewPoint, ViewVertical}];
va = constructViewAngle[OptionValue[ViewAngle], t, l, b];
vc = parseRenderViewCenter[OptionValue[ViewCenter], t, l, {{0, 1}, {0, 1}, {0, 1}}];
origvc = vc;
origvp = ovp = vp;
origvv = ovv = vv;
origva = ova = va;
origvr = ovrng = initialViewRange[OptionValue[ViewRange], vp, vc, vv, va, b];
volQ = ivolQ = TrueQ[OptionValue["ClosedClipping"]];
ir = OptionValue[ImageResolution];
sz = initialImageSize[iropts["ImageSize"], OptionValue[ImageSize]];
oshader = canonicalizeShader[shading][[1]];
projection = Replace[OptionValue[ViewProjection], Automatic -> "Perspective", {0}];
origprojection = oprojection = projection;
oframe = orthographicSphericalFrame[b];
ooframe = oframe;
{c1, c2, c3, bg} = If[TrueQ[customColorQ[oshader]],
RGBColor @@@ Lookup[iropts, {"BaseColorFront", "BaseColorBack", "BaseColorClosed", "Background"}],
$renderColorThemes["Default"]
];
{oc1, oc2, oc3, obg} = {c1, c2, c3, bg};
oiso = iropts["IsoValue"];
{mniso, mxiso} = {-1, 1}Ramp[vdb["BackgroundValue"] - 1.5voxelSize[vdb]];
mem = Quotient[vdb["MemoryUsage"], Replace[$ProcessorCount, Except[_Integer?Positive] -> 1, {0}]];
oantialq = OptionValue[PerformanceGoal] =!= "Speed";
Manipulate[
Which[
dz != 0,
vp = zoomViewPoint[vp, vc, td\[Delta][[3]]dz, vv, va, b],
dx != 0 || dy != 0,
vc = translateViewCenter[vc, {td\[Delta][[1]]dx, td\[Delta][[2]]dy}]
];
Overlay[
{
Dynamic @ Image[im = iRender[
vdb, makeShader[shader, c1, c2, c3], "BoundingBox" -> b, ViewPoint -> vp, ViewVertical -> vv, ViewAngle -> va, ViewCenter -> vc,
ViewRange -> Scaled[vrng], ViewProjection -> projection, "OrthographicFrame" -> oframe, Background -> bg,
ImageSize -> dRenderImageSize[sz, \[Delta], OptionValue[PerformanceGoal], mem], "IsoValue" -> Clip[iso, .999{mniso, mxiso}],
PerformanceGoal -> If[antialq && !$ControlActiveSetting, "Quality", "Speed"], ImageResolution -> ir,
"ClosedClipping" -> volQ, opts
], ImageSize -> sz],
Graphics3D[{},
Boxed -> False, Method -> {}, ImageSize -> Dynamic[sz],
ViewPoint -> Dynamic[vp], ViewVertical -> Dynamic[vv], ViewAngle -> Dynamic[va], ViewCenter -> Dynamic[vc]
]
},
{1, 2},
2
],
OpenerView[{
Style["Appearance", Medium],
Column[{
Control[{{shader, oshader, "shading"},
KeyValueMap[#1 -> Row[{If[#2 === Automatic, Dynamic[c1], #2], ToLowerCase[#1]}, Spacer[2]]&, $dynamicRenderShaders],
ControlType -> PopupMenu
}],
Row[{
Control[{{antialq, oantialq, "anti aliasing"}, {True, False}}],
Control[{{volQ, ivolQ, "closed clipping"}, {True, False}}]
}, Spacer[2]],
Control[{{\[Delta], 1, "resolution"}, 0, 1}],
If[mxiso > 0, Control[{{iso, oiso, "iso\[Hyphen]value"}, mniso, mxiso}], Nothing],
Row[{
"themes",
Row[KeyValueMap[themeButton[ToLowerCase[#1], {c1, c2, c3, bg} = #2, Enabled -> Dynamic[customColorQ[shader]]]&, $renderColorThemes]]
}, Spacer[2]],
Dynamic @ Which[
!customColorQ[shader],
Row[{
Control[{{bg, obg, "background"}, obg, ControlType -> ColorSetter}]
}, Spacer[10]],
!volQ,
Row[{
Control[{{bg, obg, "background"}, obg, ControlType -> ColorSetter}],
Control[{{c1, oc1, "front face"}, oc1, ControlType -> ColorSetter}],
Control[{{c2, oc2, "back face"}, oc2, ControlType -> ColorSetter}], Spacer[3],
If[c1 =!= c2, themeButton["flip faces", If[c1 === c3, c3 = c2]; {c1, c2} = {c2, c1}], Nothing]
}, Spacer[1]],
c1 === c2 === c3,
Row[{
Control[{{bg, obg, "background"}, obg, ControlType -> ColorSetter}],
Control[{{c1, oc1, "front face"}, oc1, ControlType -> ColorSetter}],
Control[{{c2, oc2, "back face"}, oc2, ControlType -> ColorSetter}],
Control[{{c3, oc3, "closed face"}, oc3, ControlType -> ColorSetter}]
}, Spacer[1]],
True,
Grid[{{
Control[{{c1, oc1, "front face"}, oc1, ControlType -> ColorSetter}],
Control[{{c2, oc2, "back face"}, oc2, ControlType -> ColorSetter}], Spacer[3],
If[c1 =!= c2, Row[{themeButton["flip faces", If[c1 === c3, c3 = c2]; {c1, c2} = {c2, c1}], ""}], Nothing]
}, {
Control[{{bg, obg, "background"}, obg, ControlType -> ColorSetter}],
Control[{{c3, oc3, "closed face"}, oc3, ControlType -> ColorSetter}], Spacer[3],
If[c1 =!= c3, Row[{themeButton["set closed as front", c3 = c1], ""}], Nothing]
}},
Alignment -> {{Right, Right, Left, Left}, Automatic},
Spacings -> {1, Automatic}]
]
},
Spacings -> {Automatic, {Automatic, Automatic, Automatic, 1, 1}}]
}, Method -> "Active"],
OpenerView[{
Style["Orientation", Medium],
Column[{
Control[{{vv, ovv, "view vertical"}, {{0,0,1} -> "(0,0,1)", {0,0,-1} -> "(0,0,\[Hyphen]1)", {1,0,0} -> "(1,0,0)", {-1,0,0} -> "(\[Hyphen]1,0,0)", {0,1,0} -> "(0,1,0)", {0,-1,0} -> "(0,\[Hyphen]1,0)"}, ControlType -> Setter}],
Control[{{vp, ovp, "view point"}, {{1.3,-2.4,2} -> "default", {-3,0,0} -> "left", {3,0,0} -> "right", {0,-3,0} -> "front", {0,3,0} -> "back", {0,0,-3} -> "below", {0,0,3} -> "above"}, ControlType -> Setter}],
Row[{
"view point\[ThinSpace]&\[ThinSpace]center",
Framed[
Grid[{{
EventHandler[panSlider[Dynamic[dz, (dz = If[Abs[#] < .05, 0., #])&], Enabled -> Dynamic[projection =!= "Orthographic"]], {"MouseUp" :> (dz = 0)}, PassEventsDown -> True],
EventHandler[panSlider[Dynamic[dx, (dx = If[Abs[#] < .05, 0., #])&]], {"MouseUp" :> (dx = 0)}, PassEventsDown -> True],
EventHandler[panSlider[Dynamic[dy, (dy = If[Abs[#] < .05, 0., #])&]], {"MouseUp" :> (dy = 0)}, PassEventsDown -> True]
},
{"out\[ThinSpace]\[TwoWayRule]\[ThinSpace]in", "left\[ThinSpace]\[TwoWayRule]\[ThinSpace]right", "down\[ThinSpace]\[TwoWayRule]\[ThinSpace]up"}},
Spacings -> {1, 0.5}
],
ContentPadding -> True,
FrameStyle -> None,
ImageMargins -> {{0,0},{2,0}}
]
}, Spacer[2]]
}]
}, Method -> "Active"],
OpenerView[{
Style["Field of View", Medium],
Column[{
Row[{
Control[{{vrng, ovrng, "clipping"}, 0, 1, ControlType -> IntervalSlider, MinIntervalSize -> 0.01, Method -> "Stop"}],
Control[{{volQ, ivolQ, "closed"}, {True, False}}]
}, Spacer[3]],
Dynamic @ If[projection =!= "Orthographic",
Control[{{va, ova, "FOV (rad)"}, 0, 75*\[Pi]/180}],
Control[{{oframe, ooframe, "frame width"}, 0, ooframe}]
],
Control[{{projection, oprojection, "projection"}, {"Perspective" -> "perspective", "Orthographic" -> "orthographic"}}]
}]
}, Method -> "Active"],
OpenerView[{
Style["General", Medium],
Row[{
Button["Copy image",
CopyToClipboard[im]],
Button["Copy view settings",
CopyToClipboard[copyString @ {If[projection =!= "Orthographic", ViewAngle -> va, "OrthographicFrame" -> oframe], ViewCenter -> vc,
ViewRange -> unscaledViewRange[vrng, vp, vc, vv, va, b], ViewPoint -> vp, ViewProjection -> projection, ViewVertical -> vv}]],
Button["Reset view settings",
va = origva; vc = origvc; vrng = origvr; vp = origvp; vv = origvv; projection = origprojection; oframe = ooframe;]
}]
}, Method -> "Active"]
],
Initialization -> With[{args = Sequence @@ Append[vdb, $SessionID]}, iDynamicRenderTrack[args] = vdb],
Deinitialization :> With[{args = Sequence @@ Append[vdb, $SessionID]}, If[Head[iDynamicRenderTrack[args]] =!= iDynamicRenderTrack, iDynamicRenderTrack[args]=.]]
]
(* ::Subsection::Closed:: *)
(*iRender*)
Options[iRender] = Options[iLevelSetRender];
iRender[args__] :=
With[{res = Quiet[iLevelSetRender[args]]},
res /; ImageQ[res]
]
iRender[___] = Image[{{1}}];
(* ::Subsection::Closed:: *)
(*Utilities*)
Scan[(customColorQ[#] = True )&, $dielectricList];
Scan[(customColorQ[#] = False)&, $metalList];
Scan[(customColorQ[#] = False)&, $rainbowList];
Scan[(customColorQ[#] = True)&, $depthList];
$dynamicRenderShaders := $dynamicRenderShaders = Association @ Join[
# -> Automatic& /@ $dielectricList,
# -> materialParameters[#]["BaseColorFront"]& /@ $metalList,
# -> $rainbowSwatch& /@ $rainbowList,
# -> $depthSwatch& /@ $depthList
]
dynamicRenderShaders = $dynamicRenderShaders[If[ListQ[#], First[#, ""], #]]&;
$rainbowSwatch = Image[ImagePad[Image[Table[With[{r = Sqrt[x^2 + y^2], \[Theta] = ArcTan[.0000001-y, x]}, Hue[\[Theta]/(2\[Pi])+1/2., Clip[r,{0,1}],1]], {x, -1., 1., .1}, {y, -1., 1., .1}]], 1], "Byte", ImageSize -> 11];
$depthSwatch = Image[ImagePad[Image[Table[With[{r = Sqrt[x^2 + y^2], \[Theta] = ArcTan[.0000001-y, x]}, Hue[0, 0, Clip[1-r, {0,1}]^0.5]], {x, -1., 1., .1}, {y, -1., 1., .1}]], 1], "Byte", ImageSize -> 11];
makeShader[shader_, colors__] :=
If[TrueQ[customColorQ[shader]] || !KeyExistsQ[materialParameters, shader],
{shader, colors},
Prepend[Lookup[materialParameters[shader], {"BaseColorFront", "BaseColorBack", "BaseColorClosed"}], shader]
]
initialViewRange[{min_?NumericQ, max_?NumericQ}, vp_, vc_, vv_, va_, bds_] /; min <= max :=
Block[{t, l, vr},
t = parseRenderViewPoint[vp, bds];
l = parseRenderViewCenter[vc, t, vv, va, bds];
vr = parseRenderViewRange[Scaled[{0, 1}], t, l, bds];
Clip[Rescale[{min, max}, vr], {0, 1}]
]
initialViewRange[___] = {0, 1};
unscaledViewRange[vrng_, vp_, vc_, vv_, va_, bds_] :=
Block[{t, l},
t = parseRenderViewPoint[vp, bds];
l = parseRenderViewCenter[vc, t, vv, va, bds];
parseRenderViewRange[Scaled[vrng], t, l, bds]
]
copyString[expr_List] := StringTake[ToString[expr, InputForm], {2, -2}]
copyString[expr_] := ToString[expr, InputForm]
initialImageSize[{sx_, _}, Automatic] := {sx, sx}
initialImageSize[sz_, _] := sz
dRenderImageSize[sz_, \[Delta]_, pgoal_, mem_] :=
With[{s = sz*\[Delta]},
Clip[Round[dPGoalFactor[pgoal, s, mem]*s], {1, \[Infinity]}]
]
(* ::Text:: *)
(*TODO figure out when rotating becomes laggy. I think it's some function of image size, vdb memory footprint, and average depth of the first layer.*)
dPGoalFactor["Speed", sz_, mem_] :=
If[TrueQ[(Times @@ sz) > Min[450^2, Divide[500000000.*720^2, mem]] && $ControlActiveSetting],
0.5,
1.0
]
dPGoalFactor[__] = 1.0;
panSlider[var_, opts___] := Slider[var, {-1, 1}, opts, Appearance -> "UpArrow", ImageSize -> {75, 22}]
orthographicSphericalFrame[bds_] :=
With[{reg = BoundingRegion[Tuples[bds], "MinBall"]},
2reg[[2]] /; MatchQ[reg, Ball[_, _Real]]
]
orthographicSphericalFrame[___] = $Failed;
renderColor[__, "Normal"|"NormalClosed"|"Position"|"PositionClosed"] = White;
renderColor[c1_, c1_, _] := c1
renderColor[c1_, c2_, _] := FaceForm[c1, c2]
SetAttributes[themeButton, HoldRest];
themeButton[label_, action_, opts___] := Button[Style[label, Small], action, opts, Appearance -> "Palette"]
translateViewCenter[{vc_, {x_, y_}}, {dx_, dy_}] := {vc, {x+dx, y+dy}}
translateViewCenter[vc_, {dx_, dy_}] := {vc, {0.5+dx, 0.5+dy}}
zoomViewPoint[vp_, vc_, dz_, vv_, va_, bds_] :=
Block[{translate, lookat, dir, center, mx},
translate = parseRenderViewPoint[vp, bds];
lookat = parseRenderViewCenter[vc, translate, vv, va, bds];
dir = Min[.1dz*Power[Norm[Subtract[lookat, translate]], 1.25], 1.5]Normalize[Subtract[lookat, translate]];
translate += dir;
lookat += dir;
center = Mean /@ bds;
mx = Replace[Max[Abs[Subtract @@@ bds]], _?NonPositive -> 1.0, {0}];
Divide[Subtract[translate, center], mx]
]
(* ::Subsection::Closed:: *)
(*Messages*)
mLevelSetViewer[args___] := messageRenderFunction[OpenVDBLevelSetViewer, args]
(* ::Section:: *)
(*Utilities*)
(* ::Subsection::Closed:: *)
(*$renderLevelSetArgumentKeys*)
$renderLevelSetArgumentKeys = {"IsoValue", "BaseColorFront", "BaseColorBack", "BaseColorClosed", "Background", "Translate", "LookAt", "Up",
"Range", "FOV", "Shader", "Camera", "Samples", "Resolution", "Frame", "DepthParameters", "Lighting", "Step", "IsClosed"};
$PBRrenderLevelSetArgumentKeys = {"IsoValue", "Background", "Translate", "LookAt", "Up",
"Range", "FOV", "Camera", "Samples", "Resolution", "Frame", "IsClosed", "BaseColorFront", "BaseColorBack", "BaseColorClosed"};
(* ::Subsection::Closed:: *)
(*Option parsing utilities*)
(* ::Subsubsection::Closed:: *)
(*parseRenderOptions*)
Options[parseRenderOptions] = Join[Options[iLevelSetRender], {"BoundingBox" -> Automatic}];
parseRenderOptions[vdb_, shading_, opts:OptionsPattern[]] :=
Block[{res},
res = iparseRenderOptions[vdb, shading, opts];
res /; AssociationQ[res] && NoneTrue[res, FailureQ]
]
parseRenderOptions[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*iparseRenderOptions*)
Options[iparseRenderOptions] = Options[parseRenderOptions];
iparseRenderOptions[vdb_, shading_, OptionsPattern[]] :=
Block[{bds, translate, lookat1, \[Alpha], lookat, up, transdist, depthdata, imgresolution, shader, ropts},
bds = parseBoundingBox[vdb, OptionValue["BoundingBox"]];
translate = parseRenderViewPoint[OptionValue[ViewPoint], bds];
up = parseRenderViewVertical[OptionValue[ViewVertical], OptionValue[ViewPoint]];
lookat1 = parseRenderViewCenterNoOffset[OptionValue[ViewCenter], bds];
\[Alpha] = constructViewAngle[OptionValue[ViewAngle], translate, lookat1, bds];
lookat = parseRenderViewCenter[OptionValue[ViewCenter], translate, up, \[Alpha], bds];
shader = canonicalizeShader[shading];
depthdata = parseDepthParameters[shader];
imgresolution = parseRenderImageResolution[OptionValue[ImageResolution]];
<|
"Bounds" -> bds,
"IsoValue" -> parseIsoValue[OptionValue["IsoValue"]],
"Background" -> parseRenderBackgroundColor[OptionValue[Background], shader],
"Translate" -> translate,
"LookAt" -> lookat,
"Up" -> up,
"Range" -> parseRenderViewRange[OptionValue[ViewRange], translate, lookat, bds],
"FOV" -> parseRenderViewAngle[OptionValue[ViewAngle], translate, lookat, bds],
"Shader" -> parseRenderShader[First[shader, $Failed]],
"Camera" -> parseRenderViewProjection[OptionValue[ViewProjection], OptionValue[ViewPoint]],
"Samples" -> parseRenderPerformance[OptionValue[PerformanceGoal]],
"Resolution" -> parseRenderImageSize[OptionValue[ImageSize], imgresolution, translate, up, bds],
"ImageSize" -> parseRenderUnscaledImageSize[OptionValue[ImageSize], translate, up, bds],
"ImageResolution" -> imgresolution,
"Frame" -> parseOrthographicFrame[OptionValue[ViewProjection], OptionValue["OrthographicFrame"], translate, lookat, up, bds],
"DepthParameters" -> depthdata,
"Lighting" -> RotationTransform[0.25, {-1, 1, 1}][translate - lookat],
"Step" -> {1.0, 2.0},
"BaseColorFront" -> parseRenderColor[shader],
"BaseColorBack" -> parseRenderColor2[shader],
"BaseColorClosed" -> parseRenderColor3[shader],
"IsClosed" -> TrueQ[OptionValue["ClosedClipping"]]
|>
]
(* ::Subsubsection::Closed:: *)
(*renderFailureOption*)
renderFailureOption[assoc_] :=
(
If[FailureQ[assoc["Bounds"]], Return["BoundingBox"]];
If[FailureQ[assoc["IsoValue"]], Return["IsoValue"]];
If[FailureQ[assoc["Shader"]], Return["Shader"]];
If[FailureQ[assoc["Background"]], Return[Background]];
If[FailureQ[assoc["Translate"]], Return[ViewPoint]];
If[FailureQ[assoc["Up"]], Return[ViewVertical]];
If[FailureQ[assoc["FOV"]], Return[ViewAngle]];
If[FailureQ[assoc["LookAt"]], Return[ViewCenter]];
If[FailureQ[assoc["Range"]], Return[ViewRange]];
If[FailureQ[assoc["Camera"]], Return[ViewProjection]];
If[FailureQ[assoc["Samples"]], Return[PerformanceGoal]];
If[FailureQ[assoc["ImageResolution"]], Return[ImageResolution]];
If[FailureQ[assoc["ImageSize"]], Return[ImageSize]];
$Failed
)
(* ::Subsubsection::Closed:: *)
(*canonicalizeShader*)
$defaultShaderSpec = "Rubber";
$defaultColorSpec = "Default";
canonicalizeShader[shader_String] /; KeyExistsQ[materialParameters, shader] := Prepend[Lookup[materialParameters[shader], {"BaseColorFront", "BaseColorBack", "BaseColorClosed"}], shader]
canonicalizeShader[theme_String] /; KeyExistsQ[$renderColorThemes, theme] := {$defaultShaderSpec, theme}
canonicalizeShader[shader:("Depth"|{"Depth", _?NumericQ, __})] := {shader, RGBColor[1, 1, 1], RGBColor[1, 1, 1], RGBColor[1, 1, 1]}
canonicalizeShader[{shader_, theme_String}] := {shader, theme}
canonicalizeShader[{shader_, icolor_?ColorQ}] :=
With[{color = ColorConvert[icolor, "RGB"][[1 ;; 3]]},
{shader, color, color, color}
]
canonicalizeShader[{shader_, icolorf_?ColorQ, icolorb_?ColorQ}] :=
With[{
colorf = ColorConvert[icolorf, "RGB"][[1 ;; 3]],
colorb = ColorConvert[icolorb, "RGB"][[1 ;; 3]]
},
{shader, colorf, colorb, colorf}
]
canonicalizeShader[{shader_, colorf_?ColorQ, colorb_?ColorQ, colorc_?ColorQ}] :=
{shader, ColorConvert[colorf, "RGB"][[1 ;; 3]], ColorConvert[colorb, "RGB"][[1 ;; 3]], ColorConvert[colorc, "RGB"][[1 ;; 3]]}
canonicalizeShader[Automatic] = {$defaultShaderSpec, $defaultColorSpec};
canonicalizeShader[{colors__?ColorQ}] := canonicalizeShader[{$defaultShaderSpec, colors}]
canonicalizeShader[color_?ColorQ] := canonicalizeShader[{$defaultShaderSpec, color}]
canonicalizeShader[shader_] := {shader, $defaultColorSpec}
canonicalizeShader[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseBoundingBox*)
parseBoundingBox[vdb_, bds_] := If[bds === Automatic, vdb["WorldBoundingBox"], bds]
(* ::Subsubsection::Closed:: *)
(*parseIsoValue*)
parseIsoValue[Automatic] = 0.0;
parseIsoValue[x_?realQ] := x
parseIsoValue[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseRenderColor*)
parseRenderColor[{"Normal"|"NormalClosed"|"Position"|"PositionClosed", __}] = {1.0, 1.0, 1.0};
parseRenderColor[{_, theme_String}] :=
With[{color = $renderColorThemes[theme][[1]]},
List @@ color /; ColorQ[color]
]
parseRenderColor[{_, color_?ColorQ, _, _}] := List @@ color
parseRenderColor[___] = $Failed;
parseRenderColor2[{"Normal"|"NormalClosed"|"Position"|"PositionClosed", __}] = {1.0, 1.0, 1.0};
parseRenderColor2[{_, theme_String}] :=
With[{color = $renderColorThemes[theme][[2]]},
List @@ color /; ColorQ[color]
]
parseRenderColor2[{_, _, color_?ColorQ, _}] := List @@ color
parseRenderColor2[___] = $Failed;
parseRenderColor3[{"Normal"|"NormalClosed"|"Position"|"PositionClosed", __}] = {1.0, 1.0, 1.0};
parseRenderColor3[{_, theme_String}] :=
With[{color = $renderColorThemes[theme][[3]]},
List @@ color /; ColorQ[color]
]
parseRenderColor3[{_, _, _, color_?ColorQ}] := List @@ color
parseRenderColor3[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseRenderBackgroundColor*)
parseRenderBackgroundColor[None, shader_] := parseRenderBackgroundColor[White, shader]
parseRenderBackgroundColor[Automatic, shader:{"Depth"|{"Depth", ___}|"DepthClosed"|{"DepthClosed", ___}, __}] := parseRenderBackgroundColor[Black, shader]
parseRenderBackgroundColor[Automatic, shader_] := parseRenderBackgroundColor[White, shader]
parseRenderBackgroundColor[Automatic, {shader_, t_String}] /; KeyExistsQ[$renderColorThemes, t] := parseRenderBackgroundColor[$renderColorThemes[t][[4]], {shader, t}]
parseRenderBackgroundColor[color_?ColorQ, __] := List @@ ColorConvert[color, "RGB"][[1 ;; 3]]
parseRenderBackgroundColor[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseRenderViewPoint*)
canonicalizeViewPoint[Left] = {-2,0,0};
canonicalizeViewPoint[Right] = { 2,0,0};
canonicalizeViewPoint[Front] = {0,-2,0};
canonicalizeViewPoint[Back] = {0, 2,0};
canonicalizeViewPoint[Below] = {0,0,-2};
canonicalizeViewPoint[Above] = {0,0, 2};
canonicalizeViewPoint[vp_] := vp
parseRenderViewPoint[vp_List, bds_?bounds3DQ] /; VectorQ[vp, NumericQ] && Length[vp] === 3 :=
Block[{vpfinite, mx},
vpfinite = vp /. inf_DirectedInfinity :> Sign[inf]*1000;
mx = Replace[Max[Abs[Subtract @@@ bds]], _?NonPositive -> 1.0, {0}];
mx * vpfinite + (Mean /@ bds)
]
parseRenderViewPoint[dir:(Left|Right|Front|Back|Below|Above), bds_] := parseRenderViewPoint[canonicalizeViewPoint[dir], bds]
parseRenderViewPoint[dirs:{(Left|Right|Front|Back|Below|Above)..}, bds_] :=
Block[{canons, vps},
canons = canonicalizeViewPoint /@ dirs;
(
vps = GatherBy[canons, Unitize][[All, -1]];
Total[parseRenderViewPoint[canonicalizeViewPoint[#], bds]& /@ vps]
) /; MatrixQ[canons]
]
parseRenderViewPoint[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseRenderViewCenter*)
parseRenderViewCenter[{vc_List, {ox_?NumericQ, oy_?NumericQ}}, translate_, up_, \[Alpha]_, bds_?bounds3DQ] :=
Block[{lookat = parseRenderViewCenterNoOffset[vc, bds], v, cross, rot},
(
v = translate-lookat;
cross = Cross[v, up];
rot = RotationTransform[(oy-0.5)*\[Alpha], cross, translate] @* RotationTransform[(ox-0.5)*\[Alpha], up, translate];
rot[lookat]
) /; lookat =!= $Failed
]
parseRenderViewCenter[vc_, __, bds_] := parseRenderViewCenterNoOffset[vc, bds];
parseRenderViewCenterNoOffset[Automatic, bds_] := parseRenderViewCenterNoOffset[{0.5, 0.5, 0.5}, bds]
parseRenderViewCenterNoOffset[vc_List, bds_?bounds3DQ] /; VectorQ[vc, NumericQ] && Length[vc] === 3 := MapThread[Dot, {Transpose[{1-vc, vc}], bds}]
parseRenderViewCenterNoOffset[{vc_List, _}, bds_?bounds3DQ] := parseRenderViewCenterNoOffset[vc, bds]
parseRenderViewCenterNoOffset[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseRenderViewVertical*)
parseRenderViewVertical[vv_List, vp_] /; VectorQ[vp, NumericQ] && Length[vp] === 3 :=
If[degenerateViewVerticalQ[vv, vp],
fixDegenerateViewVertical[vp],
vv
]
parseRenderViewVertical[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseRenderViewRange*)
parseRenderViewRange[Automatic|All, vp_, vc_, bds_] :=
Block[{corners, inview, far},
corners = Tuples[bds];
inview = Pick[corners, RegionMember[HalfSpace[vp-vc, vp], corners]];
If[Length[inview] == 0,
parseRenderViewRange[{0.0, 0.0}, vp, vc, bds],
far = Sqrt[Max[Total[(Transpose[inview] - vp)^2]]];
parseRenderViewRange[{0.0, far}, vp, vc, bds]
]
]
parseRenderViewRange[{min_?NumericQ, max_?NumericQ}, ___] /; min <= max :=
Block[{clip},
clip = Clip[{min, max}, {.001, \[Infinity]}];
If[Equal @@ clip,
clip + {0, 0.001},
clip
]
]
parseRenderViewRange[Scaled[vrng:{min_?NumericQ, max_?NumericQ}], vp_, vc_, bds_] /; min <= max :=
Block[{padding, vrmin, vrmax},
padding = 0.02*Max[Abs[Subtract @@@ bds]];
vrmin = Clip[SignedRegionDistance[Cuboid @@ Transpose[bds], vp] - padding, {0.1, \[Infinity]}];
vrmax = Ramp[Sqrt[Max[Total[Subtract[Transpose[Tuples[bds]], vp]^2, {1}]]] + .11];
vrng*(vrmax-vrmin) + vrmin
]
parseRenderViewRange[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseRenderViewAngle*)
$renderFocalLength = 50.0;
parseRenderViewAngle[args__] :=
With[{aperture = viewAngleAperture[args]},
{aperture, $renderFocalLength} /; aperture =!= $Failed && NumericQ[$renderFocalLength]
]
parseRenderViewAngle[___] = $Failed;
viewAngleAperture[args__] :=
With[{\[Alpha] = constructViewAngle[args]},
2$renderFocalLength*Tan[Clip[\[Alpha], {.001, 3.14059}]/2] /; \[Alpha] =!= $Failed
];
viewAngleAperture[___] = $Failed;
constructViewAngle[All, translate_, lookat_, bds_] :=
With[{v = lookat - translate},
2.0*Max[VectorAngle[v, # - translate]& /@ Tuples[bds]]
];
constructViewAngle[Automatic, args__] :=
With[{\[Alpha] = constructViewAngle[All, args]},
Min[35.0*Degree, \[Alpha]] /; \[Alpha] =!= $Failed
];
constructViewAngle[\[Alpha]_?NumericQ, args__] /; 0 <= \[Alpha] <= \[Pi] := \[Alpha]
constructViewAngle[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseRenderShader*)
parseRenderShader["Diffuse"] = 0;
parseRenderShader["Matte"] = 1;
parseRenderShader["Normal"] = 2;
parseRenderShader["Position"] = 3;
parseRenderShader["Depth"] = 4;
parseRenderShader[{"Depth", ___}] = parseRenderShader["Depth"];
parseRenderShader[shader_String] /; KeyExistsQ[materialParameters, shader] := shader
parseRenderShader[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseRenderPerformance*)
parseRenderPerformance["Speed"] = 1;
parseRenderPerformance["Quality"] = 9;
parseRenderPerformance[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseDepthParameters*)
$imin = 0.0;
$imax = 1.0;
$gamma = 1.0;
parseDepthParameters[{{"Depth"|"DepthClosed", args___}, __}] := iParseDepthParameters[args]
parseDepthParameters[___] = {$imin, $imax, $gamma};
iParseDepthParameters[] = {$imin, $imax, $gamma};
iParseDepthParameters[gamma_?Positive] := {$imin, $imax, gamma}
iParseDepthParameters[gamma_?Positive, {imin_, imax_}] /; 0 <= imin <= imax <= 1 := {imin, imax, gamma}
iParseDepthParameters[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseRenderViewProjection*)
parseRenderViewProjection["Perspective", _] = 0;
parseRenderViewProjection["Orthographic", _] = 1;
parseRenderViewProjection[Automatic, vp_] :=
With[{p = If[FreeQ[vp, _DirectedInfinity], "Perspective", "Orthographic"]},
parseRenderViewProjection[p, vp]
]
parseRenderViewProjection[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*parseRenderImageResolution*)
parseRenderImageResolution[Automatic] := imageResolution[]
parseRenderImageResolution[x_?Positive] := x
parseRenderImageResolution[___] = $Failed;
imageResolution[] := Replace[Max[Quiet[CurrentValue[{"ConnectedDisplays", "Resolution"}]]], Except[_Real|_Integer] -> 72., {0}]
(* ::Subsubsection::Closed:: *)
(*parseRenderImageSize*)
parseRenderImageSize[x:(_Integer|Automatic), args__] := parseRenderImageSize[{x, Automatic}, args]
parseRenderImageSize[{x_Integer?Positive, y_Integer?Positive}, res_, __] := res/72*{x, y}
parseRenderImageSize[{x_, y_}, res_, vp_List, vv_List, bds_?bounds3DQ] :=
Block[{aspectratio, w, h},
aspectratio = 1.0;(*viewPointAspectRatio[bds, vp, vv];*)
w = Round[Replace[x, Automatic -> 360*res/72, {0}]];
h = Round[Replace[y, Automatic -> w*aspectratio, {0}]];
{w, h}
]
parseRenderImageSize[___] = $Failed
viewPointAspectRatio[bds_, vp_, vv_] :=
Block[{rot, proj1, up2d, proj2},
rot = RotationTransform[{vp-(Mean /@ bds), {0,0,1}}];
proj1 = rot[Tuples[bds]][[All, 1;;2]];
up2d = rot[vv][[1 ;; 2]];
proj2 = RotationTransform[{up2d, {0, 1}}][proj1];
Divide @@ Clip[Reverse[Abs[Subtract @@@ CoordinateBounds[proj2]]], {0.001, \[Infinity]}]
]
(* ::Subsubsection::Closed:: *)
(*parseRenderUnscaledImageSize*)
parseRenderUnscaledImageSize[x:(_Integer|Automatic), args__] := parseRenderUnscaledImageSize[{x, Automatic}, args]
parseRenderUnscaledImageSize[{x_Integer?Positive, y_Integer?Positive}, __] := {x, y}
parseRenderUnscaledImageSize[{x_, y_}, vp_List, vv_List, bds_?bounds3DQ] :=
Block[{aspectratio, w, h},
aspectratio = viewPointAspectRatio[bds, vp, vv];
w = Round[Replace[x, Automatic -> 360, {0}]];
h = Round[Replace[y, Automatic -> w*aspectratio, {0}]];
{w, h}
]
parseRenderUnscaledImageSize[___] = $Failed
viewPointAspectRatio[___] = 1.0;
(* ::Subsubsection::Closed:: *)
(*parseOrthographicFrame*)
parseOrthographicFrame["Orthographic", x_?NumericQ, __] := Clip[x, {0.001, \[Infinity]}]
parseOrthographicFrame["Orthographic", Automatic, vp_, vc_, vv_, bds_] :=
Block[{rot, proj1, up2d, proj2},
rot = RotationTransform[{vp-vc, {0,0,1}}];
proj1 = rot[Tuples[bds]][[All, 1;;2]];
up2d = rot[vv][[1 ;; 2]];
proj2 = RotationTransform[{up2d, {0, 1}}][proj1];
Clip[Abs[Subtract @@@ CoordinateBounds[proj2]][[1]], {0.001, \[Infinity]}]
]
parseOrthographicFrame["Perspective"|Automatic, __] = 1.0;
parseOrthographicFrame[___] = $Failed;
(* ::Subsection::Closed:: *)
(*Degenerate ViewVertical*)
degenerateViewVerticalQ[vv_, vp_] := Chop[Norm[Cross[vv, canonicalizeViewPoint[vp]]]] === 0
fixDegenerateViewVertical[vp_] := Normalize[RotateLeft[canonicalizeViewPoint[vp]]]
(* ::Subsection::Closed:: *)
(*MaterialShading parameters*)
(* ::Text:: *)
(*Found through ctrl-shift-e on MaterialShading[] outputs.*)
materialParameters = <||>;
(* ::Subsubsection::Closed:: *)
(*Aluminum*)
materialParameters["Aluminum"] = <|
"BaseColorFront" -> RGBColor[0.95, 0.95, 0.95],
"BaseColorBack" -> RGBColor[0.95, 0.95, 0.95],
"BaseColorClosed" -> RGBColor[0.95, 0.95, 0.95],
"MetallicCoefficient" -> 0.8,
"RoughnessCoefficient" -> 0.75,
"SpecularAnisotropyCoefficient" -> 0.6,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1.0,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Brass*)
materialParameters["Brass"] = <|
"BaseColorFront" -> RGBColor[0.9, 0.855, 0.45],
"BaseColorBack" -> RGBColor[0.9, 0.855, 0.45],
"BaseColorClosed" -> RGBColor[0.9, 0.855, 0.45],
"MetallicCoefficient" -> 0.8,
"RoughnessCoefficient" -> 0.65,
"SpecularAnisotropyCoefficient" -> 0.4,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Bronze*)
materialParameters["Bronze"] = <|
"BaseColorFront" -> RGBColor[0.9, 0.68625, 0.45],
"BaseColorBack" -> RGBColor[0.9, 0.68625, 0.45],
"BaseColorClosed" -> RGBColor[0.9, 0.68625, 0.45],
"MetallicCoefficient" -> 0.8,
"RoughnessCoefficient" -> 0.65,
"SpecularAnisotropyCoefficient" -> 0.3,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Copper*)
materialParameters["Copper"] = <|
"BaseColorFront" -> RGBColor[1.0, 0.65, 0.5],
"BaseColorBack" -> RGBColor[1.0, 0.65, 0.5],
"BaseColorClosed" -> RGBColor[1.0, 0.65, 0.5],
"MetallicCoefficient" -> 0.8,
"RoughnessCoefficient" -> 0.65,
"SpecularAnisotropyCoefficient" -> 0.3,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Electrum*)
materialParameters["Electrum"] = <|
"BaseColorFront" -> RGBColor[0.9, 0.774, 0.45],
"BaseColorBack" -> RGBColor[0.9, 0.774, 0.45],
"BaseColorClosed" -> RGBColor[0.9, 0.774, 0.45],
"MetallicCoefficient" -> 0.7,
"RoughnessCoefficient" -> 0.7,
"SpecularAnisotropyCoefficient" -> 0.3,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Gold*)
materialParameters["Gold"] = <|
"BaseColorFront" -> RGBColor[1.0, 0.75, 0.0],
"BaseColorBack" -> RGBColor[1.0, 0.75, 0.0],
"BaseColorClosed" -> RGBColor[1.0, 0.75, 0.0],
"MetallicCoefficient" -> 0.8,
"RoughnessCoefficient" -> 0.65,
"SpecularAnisotropyCoefficient" -> 0.3,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1.0,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Iron*)
materialParameters["Iron"] = <|
"BaseColorFront" -> RGBColor[0.6, 0.576, 0.54],
"BaseColorBack" -> RGBColor[0.6, 0.576, 0.54],
"BaseColorClosed" -> RGBColor[0.6, 0.576, 0.54],
"MetallicCoefficient" -> 0.7,
"RoughnessCoefficient" -> 0.6,
"SpecularAnisotropyCoefficient" -> 0.3,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Pewter*)
materialParameters["Pewter"] = <|
"BaseColorFront" -> RGBColor[0.9, 0.864, 0.81],
"BaseColorBack" -> RGBColor[0.9, 0.864, 0.81],
"BaseColorClosed" -> RGBColor[0.9, 0.864, 0.81],
"MetallicCoefficient" -> 1,
"RoughnessCoefficient" -> 0.75,
"SpecularAnisotropyCoefficient" -> 0.3,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Silver*)
materialParameters["Silver"] = <|
"BaseColorFront" -> RGBColor[1.0, 1.0, 1.0],
"BaseColorBack" -> RGBColor[1.0, 1.0, 1.0],
"BaseColorClosed" -> RGBColor[1.0, 1.0, 1.0],
"MetallicCoefficient" -> 1,
"RoughnessCoefficient" -> 0.75,
"SpecularAnisotropyCoefficient" -> 0.3,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Clay*)
materialParameters["Clay"] = <|
"BaseColorFront" -> RGBColor[0.8, 0.352, 0.16],
"BaseColorBack" -> RGBColor[0.8, 0.352, 0.16],
"BaseColorClosed" -> RGBColor[0.8, 0.352, 0.16],
"MetallicCoefficient" -> 0,
"RoughnessCoefficient" -> 0,
"SpecularAnisotropyCoefficient" -> 0.0,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 0.0,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Foil*)
materialParameters["Foil"] = <|
"BaseColorFront" -> RGBColor[0.5, 1.0, 0.0],
"BaseColorBack" -> RGBColor[0.5, 1.0, 0.0],
"BaseColorClosed" -> RGBColor[0.5, 1.0, 0.0],
"MetallicCoefficient" -> 0.5,
"RoughnessCoefficient" -> 0.6,
"SpecularAnisotropyCoefficient" -> 0.0,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.6,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.75
|>;
(* ::Subsubsection::Closed:: *)
(*Glazed*)
materialParameters["Glazed"] = <|
"BaseColorFront" -> RGBColor[1.0, 0.24, 0.0],
"BaseColorBack" -> RGBColor[1.0, 0.24, 0.0],
"BaseColorClosed" -> RGBColor[1.0, 0.24, 0.0],
"MetallicCoefficient" -> 0.5,
"RoughnessCoefficient" -> 0.6,
"SpecularAnisotropyCoefficient" -> 0.6,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.2,
"CoatAnisotropyCoefficient" -> 0.6,
"CoatReflectance" -> 0.6,
"SpecularColorMultiplier" -> 1.0,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.75
|>;
(* ::Subsubsection::Closed:: *)
(*Plastic*)
materialParameters["Plastic"] = <|
"BaseColorFront" -> RGBColor[0.3, 0.58, 1.0],
"BaseColorBack" -> RGBColor[0.3, 0.58, 1.0],
"BaseColorClosed" -> RGBColor[0.3, 0.58, 1.0],
"MetallicCoefficient" -> 0.0,
"RoughnessCoefficient" -> 1.0,
"SpecularAnisotropyCoefficient" -> 0.0,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.3,
"CoatAnisotropyCoefficient" -> 0.5,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1.0,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.75
|>;
(* ::Subsubsection::Closed:: *)
(*Rubber*)
materialParameters["Rubber"] = <|
"BaseColorFront" -> RGBColor[0.5, 0.5, 0.5],
"BaseColorBack" -> RGBColor[0.5, 0.5, 0.5],
"BaseColorClosed" -> RGBColor[0.5, 0.5, 0.5],
"MetallicCoefficient" -> 0.2,
"RoughnessCoefficient" -> 0.6,
"SpecularAnisotropyCoefficient" -> 0.0,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Satin*)
materialParameters["Satin"] = <|
"BaseColorFront" -> RGBColor[0.75, 0.5, 1.0],
"BaseColorBack" -> RGBColor[0.75, 0.5, 1.0],
"BaseColorClosed" -> RGBColor[0.75, 0.5, 1.0],
"MetallicCoefficient" -> 0.5,
"RoughnessCoefficient" -> 0.66,
"SpecularAnisotropyCoefficient" -> 0.8,
"Reflectance" -> 0.5,
"CoatColor" -> {1.0, 1.0, 1.0},
"CoatRoughnessCoefficient" -> 0.0,
"CoatAnisotropyCoefficient" -> 0.0,
"CoatReflectance" -> 0.5,
"SpecularColorMultiplier" -> 1.0,
"DiffuseColorMultiplier" -> 1.0,
"CoatColorMultiplier" -> 0.0
|>;
(* ::Subsubsection::Closed:: *)
(*Base materials*)
$baseMaterials = Keys[materialParameters];
(* ::Subsection::Closed:: *)
(*messageRenderFunction*)
Options[messageRenderFunction] = Options[OpenVDBLevelSetRender];
messageRenderFunction[head_, expr_, ___] /; messageScalarGridQ[expr, head] = $Failed;
messageRenderFunction[head_, expr_, ___] /; messageLevelSetGridQ[expr, head] = $Failed;
messageRenderFunction[head_, vdb_, opts:OptionsPattern[]] := messageRenderFunction[head, vdb, Automatic, opts]
messageRenderFunction[head_, vdb_, shading_, opts:OptionsPattern[]] /; !OptionQ[shading] :=
Block[{assoc, opt},
assoc = iparseRenderOptions[vdb, shading, opts];
(
opt = renderFailureOption[assoc];
(
If[opt === "Shader",
Message[head::shaderval, shading],
Message[head::renderval, opt -> OptionValue[opt]]
];
$Failed
) /; opt =!= $Failed
) /; AssociationQ[assoc]
]
messageRenderFunction[___] = $Failed
General::renderval = "`1` is an invalid render setting.";
General::shaderval = "`1` is an invalid shader setting.";