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

594 lines
15 KiB
Mathematica

(* ::Package:: *)
(* ::Title:: *)
(*Image*)
(* ::Subtitle:: *)
(*Image representation through slices, depth map, projection, and Image3D.*)
(* ::Text:: *)
(*Copyright Contributors to the OpenVDB Project*)
(*SPDX-License-Identifier: Apache-2.0*)
(* ::Section:: *)
(*Initialization & Usage*)
Package["OpenVDBLink`"]
PackageExport["OpenVDBImage3D"]
PackageExport["OpenVDBDepthImage"]
PackageExport["OpenVDBProjectionImage"]
PackageExport["OpenVDBSliceImage"]
PackageExport["OpenVDBDynamicSliceImage"]
OpenVDBImage3D::usage = "OpenVDBImage3D[expr] returns an Image3D representation of an OpenVDB grid.";
OpenVDBDepthImage::usage = "OpenVDBDepthImage[expr] returns a top view depth map image of an OpenVDB grid.";
OpenVDBProjectionImage::usage = "OpenVDBProjectionImage[expr] returns a top view projection image of an OpenVDB grid.";
OpenVDBSliceImage::usage = "OpenVDBSliceImage[expr, z] returns a slice image of an OpenVDB grid at height z.";
OpenVDBDynamicSliceImage::usage = "OpenVDBDynamicSliceImage[expr] returns a Dynamic z slice viewer of expr.";
(* ::Section:: *)
(*Image3D*)
(* ::Subsection::Closed:: *)
(*OpenVDBImage3D*)
(* ::Subsubsection::Closed:: *)
(*Main*)
Options[OpenVDBImage3D] = {Resampling -> Automatic, "ScalingFactor" -> 1.0};
OpenVDBImage3D[args___] /; !CheckArgs[OpenVDBImage3D[args], {1, 2}] = $Failed;
OpenVDBImage3D[args___] :=
With[{res = iOpenVDBImage3D[args]},
res /; res =!= $Failed
]
OpenVDBImage3D[args___] := mOpenVDBImage3D[args]
(* ::Subsubsection::Closed:: *)
(*iOpenVDBImage3D*)
Options[iOpenVDBImage3D] = Options[OpenVDBImage3D];
iOpenVDBImage3D[vdb_?carefulPixelGridQ, bds_?bounds3DQ -> regime_?regimeQ, OptionsPattern[]] :=
Block[{bdsindex, scaling, resampling, vdbscaled, im3d},
bdsindex = regimeConvert[vdb, bds, regime -> $indexregime];
scaling = parseImage3DScaling[OptionValue["ScalingFactor"], bdsindex];
resampling = OptionValue[Resampling];
(
bdsindex = regimeConvert[vdb, scaling * bds, regime -> $indexregime];
vdbscaled = scaleVDB[vdb, scaling, resampling];
(
im3d = vdbscaled["gridImage3D"[bdsindex]];
im3d /; ImageQ[im3d]
) /; OpenVDBGridQ[vdbscaled]
) /; scaling > 0
]
iOpenVDBImage3D[vdb_?carefulPixelGridQ, opts:OptionsPattern[]] := iOpenVDBImage3D[vdb, vdb["IndexBoundingBox"] -> $indexregime, opts]
iOpenVDBImage3D[vdb_?carefulPixelGridQ, Automatic, opts:OptionsPattern[]] := iOpenVDBImage3D[vdb, vdb["IndexBoundingBox"] -> $indexregime, opts]
iOpenVDBImage3D[vdb_, bspec_List, opts:OptionsPattern[]] /; bounds3DQ[bspec] || intervalQ[bspec] := iOpenVDBImage3D[vdb, bspec -> $indexregime, opts]
iOpenVDBImage3D[vdb_?carefulPixelGridQ, int_?intervalQ -> regime_?regimeQ, opts:OptionsPattern[]] :=
Block[{bds2d},
bds2d = regimeConvert[vdb, Most[vdb["IndexBoundingBox"]], $indexregime -> regime];
iOpenVDBImage3D[vdb, Append[bds2d, int] -> regime, opts] /; bounds2DQ[bds2d]
]
iOpenVDBImage3D[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*Argument conform & completion*)
registerForLevelSet[iOpenVDBImage3D, 1];
SyntaxInformation[OpenVDBImage3D] = {"ArgumentsPattern" -> {_, _., OptionsPattern[]}};
OpenVDBDefaultSpace[OpenVDBImage3D] = $indexregime;
(* ::Subsubsection::Closed:: *)
(*Utilities*)
parseImage3DScaling[x_?Positive, _] := x
parseImage3DScaling[Automatic, bds_] := Min[1.0, N[CubeRoot[$targetImage3DSize/indexVoxelCount[bds]]]]
parseImage3DScaling[___] = $Failed;
indexVoxelCount[bds_] := Times @@ (Abs[Subtract @@@ bds] + 1)
$targetImage3DSize = 1500000000;
scaleVDB[vdb_, s_ /; s == 1.0, _] := vdb
scaleVDB[vdb_, s_, resamp_] :=
Block[{vdbscaled},
vdbscaled = OpenVDBTransform[vdb, s, Resampling -> resamp];
vdbscaled /; OpenVDBGridQ[vdbscaled]
]
scaleVDB[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*Messages*)
Options[mOpenVDBImage3D] = Options[OpenVDBImage3D];
mOpenVDBImage3D[expr_, ___] /; messageGridQ[expr, OpenVDBImage3D] = $Failed;
mOpenVDBImage3D[expr_, ___] /; messagePixelGridQ[expr, OpenVDBImage3D] = $Failed;
mOpenVDBImage3D[_, bbox_, ___] /; message3DBBoxQ[bbox, OpenVDBImage3D] = $Failed;
mOpenVDBImage3D[__, OptionsPattern[]] :=
Block[{s},
s = parseImage3DScaling[OptionValue["ScalingFactor"], {{0,1},{0,1},{0,1}}];
(
Message[OpenVDBImage3D::scale];
$Failed
) /; s === $Failed
]
mOpenVDBImage3D[___] = $Failed;
OpenVDBImage3D::scale = "The setting for \"ScalingFactor\" should either be a positive number or Automatic.";
(* ::Section:: *)
(*Depth*)
(* ::Subsection::Closed:: *)
(*OpenVDBDepthImage*)
(* ::Subsubsection::Closed:: *)
(*Main*)
OpenVDBDepthImage[args___] /; !CheckArgs[OpenVDBDepthImage[args], {1, 4}] = $Failed;
OpenVDBDepthImage[args___] :=
With[{res = iOpenVDBDepthImage[args]},
res /; res =!= $Failed
]
OpenVDBDepthImage[args___] := mOpenVDBDepthImage[args]
(* ::Subsubsection::Closed:: *)
(*iOpenVDBDepthImage*)
iOpenVDBDepthImage[vdb_?carefulPixelGridQ, bds_?bounds3DQ -> regime_?regimeQ, \[Gamma]_?Positive, mnmx_] /; Length[mnmx] == 2 && VectorQ[mnmx, NumericQ] :=
Block[{bdsindex, im},
bdsindex = regimeConvert[vdb, bds, regime -> $indexregime];
im = vdb["depthMap"[bdsindex, \[Gamma], mnmx[[1]], mnmx[[2]]]];
im /; ImageQ[im]
]
iOpenVDBDepthImage[vdb_] := iOpenVDBDepthImage[vdb, Automatic]
iOpenVDBDepthImage[vdb_?carefulPixelGridQ, Automatic, args___] := iOpenVDBDepthImage[vdb, vdb["IndexBoundingBox"] -> $indexregime, args]
iOpenVDBDepthImage[vdb_, bspec_List, opts:OptionsPattern[]] /; bounds3DQ[bspec] || intervalQ[bspec] := iOpenVDBDepthImage[vdb, bspec -> $indexregime, opts]
iOpenVDBDepthImage[vdb_?carefulPixelGridQ, int_?intervalQ -> regime_?regimeQ, args___] :=
Block[{bds2d},
bds2d = regimeConvert[vdb, Most[vdb["IndexBoundingBox"]], $indexregime -> regime];
iOpenVDBDepthImage[vdb, Append[bds2d, int] -> regime, args] /; bounds2DQ[bds2d]
]
iOpenVDBDepthImage[vdb_, bdspec_] := iOpenVDBDepthImage[vdb, bdspec, 0.5]
iOpenVDBDepthImage[vdb_, bdspec_, \[Gamma]_] := iOpenVDBDepthImage[vdb, bdspec, \[Gamma], {0.2, 1.0}]
iOpenVDBDepthImage[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*Argument conform & completion*)
registerForLevelSet[iOpenVDBDepthImage, 1];
SyntaxInformation[OpenVDBDepthImage] = {"ArgumentsPattern" -> {_, _., _., _., OptionsPattern[]}};
OpenVDBDefaultSpace[OpenVDBDepthImage] = $indexregime;
(* ::Subsubsection::Closed:: *)
(*Messages*)
mOpenVDBDepthImage[expr_, ___] /; messageGridQ[expr, OpenVDBDepthImage] = $Failed;
mOpenVDBDepthImage[expr_, ___] /; messagePixelGridQ[expr, OpenVDBDepthImage] = $Failed;
mOpenVDBDepthImage[_, bbox_, ___] /; message3DBBoxQ[bbox, OpenVDBDepthImage] = $Failed;
mOpenVDBDepthImage[_, _, \[Gamma]_, ___] /; !TrueQ[\[Gamma] > 0] :=
(
Message[OpenVDBDepthImage::gamma, \[Gamma], 3];
$Failed
)
mOpenVDBDepthImage[_, _, _, mnmx_] /; !MatchQ[mnmx, {a_, b_} /; 0 <= a <= b] :=
(
Message[OpenVDBDepthImage::range, mnmx, 4];
$Failed
)
mOpenVDBDepthImage[___] = $Failed;
OpenVDBDepthImage::gamma = "`1` at position `2` should be a positive number.";
OpenVDBDepthImage::range = "`1` at position `2` should be a list of two increasing non\[Hyphen]negative numbers.";
(* ::Section:: *)
(*Projection*)
(* ::Subsection::Closed:: *)
(*OpenVDBProjectionImage*)
(* ::Subsubsection::Closed:: *)
(*Main*)
OpenVDBProjectionImage[args___] /; !CheckArgs[OpenVDBProjectionImage[args], {1, 2}] = $Failed;
OpenVDBProjectionImage[args___] :=
With[{res = iOpenVDBProjectionImage[args]},
res /; res =!= $Failed
]
OpenVDBProjectionImage[args___] := mOpenVDBProjectionImage[args]
(* ::Subsubsection::Closed:: *)
(*iOpenVDBProjectionImage*)
iOpenVDBProjectionImage[vdb_?carefulPixelGridQ, bds_?bounds3DQ -> regime_?regimeQ] :=
Block[{bdsindex, im},
bdsindex = regimeConvert[vdb, bds, regime -> $indexregime];
im = vdb["depthMap"[bdsindex, 1.0, 1.0, 1.0]];
(
If[fogVolumeQ[vdb],
Image[im, "Byte"],
Image[im, "Bit"]
]
) /; ImageQ[im]
]
iOpenVDBProjectionImage[vdb_] := iOpenVDBProjectionImage[vdb, Automatic]
iOpenVDBProjectionImage[vdb_?carefulPixelGridQ, Automatic] := iOpenVDBProjectionImage[vdb, vdb["IndexBoundingBox"] -> $indexregime]
iOpenVDBProjectionImage[vdb_, bspec_List, opts:OptionsPattern[]] /; bounds3DQ[bspec] || intervalQ[bspec] := iOpenVDBProjectionImage[vdb, bspec -> $indexregime, opts]
iOpenVDBProjectionImage[vdb_?carefulPixelGridQ, int_?intervalQ -> regime_?regimeQ] :=
Block[{bds2d},
bds2d = regimeConvert[vdb, Most[vdb["IndexBoundingBox"]], $indexregime -> regime];
iOpenVDBProjectionImage[vdb, Append[bds2d, int] -> regime] /; bounds2DQ[bds2d]
]
iOpenVDBProjectionImage[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*Argument conform & completion*)
registerForLevelSet[iOpenVDBProjectionImage, 1];
SyntaxInformation[OpenVDBProjectionImage] = {"ArgumentsPattern" -> {_, _., OptionsPattern[]}};
OpenVDBDefaultSpace[OpenVDBProjectionImage] = $indexregime;
(* ::Subsubsection::Closed:: *)
(*Messages*)
mOpenVDBProjectionImage[expr_, ___] /; messageGridQ[expr, OpenVDBProjectionImage] = $Failed;
mOpenVDBProjectionImage[expr_, ___] /; messagePixelGridQ[expr, OpenVDBProjectionImage] = $Failed;
mOpenVDBProjectionImage[_, bbox_] /; message3DBBoxQ[bbox, OpenVDBProjectionImage] = $Failed;
mOpenVDBProjectionImage[___] = $Failed;
(* ::Section:: *)
(*Slice*)
(* ::Subsection::Closed:: *)
(*OpenVDBSliceImage*)
(* ::Subsubsection::Closed:: *)
(*Main*)
Options[OpenVDBSliceImage] = {"MirrorSlice" -> False};
OpenVDBSliceImage[args___] /; !CheckArgs[OpenVDBSliceImage[args], {1, 3}] = $Failed;
OpenVDBSliceImage[args___] :=
With[{res = iOpenVDBSliceImage[args]},
res /; res =!= $Failed
]
OpenVDBSliceImage[args___] := mOpenVDBSliceImage[args]
(* ::Subsubsection::Closed:: *)
(*iOpenVDBSliceImage*)
Options[iOpenVDBSliceImage] = Options[OpenVDBSliceImage];
iOpenVDBSliceImage[vdb_?carefulPixelGridQ, z_?NumericQ -> regime_?regimeQ, bds_?bounds2DQ, OptionsPattern[]] :=
Block[{mirrorQ, threadedQ, zindex, bdsindex, im},
mirrorQ = TrueQ[OptionValue["MirrorSlice"]];
threadedQ = True;
zindex = regimeConvert[vdb, z, regime -> $indexregime];
bdsindex = regimeConvert[vdb, bds, regime -> $indexregime];
im = vdb["gridSliceImage"[zindex, bdsindex, mirrorQ, threadedQ]];
im /; ImageQ[im]
]
iOpenVDBSliceImage[vdb_, z_?NumericQ, args___] := iOpenVDBSliceImage[vdb, z -> $indexregime, args]
iOpenVDBSliceImage[vdb_?carefulPixelGridQ, z_ -> regime_, Automatic, opts___] :=
Block[{bbox},
bbox = If[worldRegimeQ[regime],
"WorldBoundingBox",
"IndexBoundingBox"
];
iOpenVDBSliceImage[vdb, z -> regime, Most[vdb[bbox]], opts]
]
iOpenVDBSliceImage[vdb_, z_, opts:OptionsPattern[]] := iOpenVDBSliceImage[vdb, z, Automatic, opts]
iOpenVDBSliceImage[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*Argument conform & completion*)
registerForLevelSet[iOpenVDBSliceImage, 1];
SyntaxInformation[OpenVDBSliceImage] = {"ArgumentsPattern" -> {_, _, _., OptionsPattern[]}};
OpenVDBDefaultSpace[OpenVDBSliceImage] = $indexregime;
(* ::Subsubsection::Closed:: *)
(*Messages*)
mOpenVDBSliceImage[expr_, ___] /; messageGridQ[expr, OpenVDBSliceImage] = $Failed;
mOpenVDBSliceImage[expr_, ___] /; messagePixelGridQ[expr, OpenVDBSliceImage] = $Failed;
mOpenVDBSliceImage[_, z_, ___] /; messageZSliceQ[z, OpenVDBSliceImage] = $Failed;
mOpenVDBSliceImage[_, _, bbox_, ___] /; message2DBBoxQ[bbox, OpenVDBSliceImage] = $Failed;
mOpenVDBSliceImage[___] = $Failed;
(* ::Subsection::Closed:: *)
(*OpenVDBDynamicSliceImage*)
(* ::Subsubsection::Closed:: *)
(*Main*)
Options[OpenVDBDynamicSliceImage] = {DisplayFunction -> Identity, ImageSize -> Automatic};
OpenVDBDynamicSliceImage[args___] /; !CheckArgs[OpenVDBDynamicSliceImage[args], 1] = $Failed;
OpenVDBDynamicSliceImage[args___] :=
With[{res = iOpenVDBDynamicSliceImage[args]},
res /; res =!= $Failed
]
OpenVDBDynamicSliceImage[args___] := mOpenVDBDynamicSliceImage[args]
(* ::Subsubsection::Closed:: *)
(*iOpenVDBDynamicSliceImage*)
Options[iOpenVDBDynamicSliceImage] = Options[OpenVDBDynamicSliceImage];
iOpenVDBDynamicSliceImage[vdb_?carefulPixelGridQ, OptionsPattern[]] /; !emptyVDBQ[vdb] :=
DynamicModule[{x1, x2, y1, y2, z1, z2, start, end, ox1, ox2, oy1, oy2, zs, func, imsz, pxmax},
{x1, x2, y1, y2, z1, z2} = Flatten[vdb["IndexBoundingBox"]];
{x1, x2, y1, y2} += {-3, 3, -3, 3};
{ox1, ox2, oy1, oy2} = {x1, x2, y1, y2};
zs = Round[(z1+z2)/2];
func = OptionValue[DisplayFunction];
imsz = OptionValue[ImageSize];
pxmax = If[OpenVDBBooleanGridQ[vdb] || OpenVDBMaskGridQ[vdb], 1, 255];
Manipulate[
If[TrueQ[OpenVDBGridQ[vdb]],
Graphics[
EventHandler[
{
Raster[Image`InternalImageData[func[OpenVDBSliceImage[vdb, Round[k], {{ox1, ox2}, {oy1, oy2}}]]], Automatic, {0, pxmax}],
Dynamic[If[ListQ[start], {EdgeForm[Directive[AbsoluteThickness[1], Red]], FaceForm[], Rectangle[start, MousePosition["Graphics"]]}, {}]]
},
{
"MouseDown" :> (
start = Round[MousePosition["Graphics"]]
),
"MouseUp" :> (
end = Round[MousePosition["Graphics"]];
If[start == end,
{ox1, ox2, oy1, oy2} = {x1, x2, y1, y2},
{ox1, ox2, oy1, oy2} = {ox1, ox1-1, oy2+1, oy2} + Flatten[Sort /@ ({1, -1}Transpose[{start, end}])]
];
start=.
)
}
],
Frame -> True,
FrameTicks -> None,
ImageMargins -> 0,
ImagePadding -> 25,
ImageSize -> imsz,
PlotRangePadding -> None
],
""
],
{{k, zs, "slice"}, z1, z2, 1},
FrameMargins -> 0
]
]
iOpenVDBDynamicSliceImage[___] = $Failed;
(* ::Subsubsection::Closed:: *)
(*Argument conform & completion*)
SyntaxInformation[OpenVDBDynamicSliceImage] = {"ArgumentsPattern" -> {_, OptionsPattern[]}};
(* ::Subsubsection::Closed:: *)
(*Messages*)
mOpenVDBDynamicSliceImage[expr_, ___] /; messageGridQ[expr, OpenVDBDynamicSliceImage] = $Failed;
mOpenVDBDynamicSliceImage[expr_, ___] /; messagePixelGridQ[expr, OpenVDBDynamicSliceImage] = $Failed;
mOpenVDBDynamicSliceImage[expr_, ___] /; messageNonEmptyGridQ[expr, OpenVDBDynamicSliceImage] = $Failed;
mOpenVDBDynamicSliceImage[___] = $Failed;