# Parametric Volume

How can one write a function VolumeParametricPlot achieving the effect of a ParametricPlot3D with three parametrising variables, so as to create a plot of a volume rather than a surface?

As a simple example:

VolumeParametricPlot[
{x,y,(x^2+y^2-1/6 y^3)+h},
{x,-5,5},
{y,-5,5},
{h,-0.2,0.2}
]


RegionPlot3D won't work for the general problem, and is also quite slow because of its implementation. I am looking for something to behave in the same way as ParametricPlot3D, except with three parametrising variables instead of only two.

• What about ParametricPlot3D[{x, y, (x^2 + y^2 - 1/6 y^3)}, {x, -5, 5}, {y, -5, 5}, BoxRatios -> {1, 1, 0.6}, PlotStyle -> Thickness[0.2]]? Commented May 6, 2020 at 12:02
• and ParametricPlot3D[{x, y, (x^2 + y^2 - 1/6 y^3)}, {x, -5, 5}, {y, -5, 5}, BoxRatios -> 1, Extrusion -> .4]?
– kglr
Commented May 6, 2020 at 12:31
• I am looking for something to behave in the same way as ParametricPlot3D. Commented May 6, 2020 at 12:56
• if speed is not an issue you can use ParametricRegion + DiscretizeRegion. E.g., parreg = ParametricRegion[{x, y, h + (x^2 + y^2 - 1/6 y^3)}, {{x, -5, 5}, {y, -5, 5}, {h, -1, 1}}]; DiscretizeRegion[parreg, Method -> {"MarchingCubes", PlotPoints -> 150}]
– kglr
Commented May 6, 2020 at 13:52
• @kglr - I can't get your example to run to completion. It crashes Mathematica. Commented May 19, 2020 at 6:00

You can post-process polygon primitives into polyhedra with the desired height:

ClearAll[toPolyhedron]
toPolyhedron[h_][p : Polygon[coords_, VertexColors -> colors_, ___]] :=
Module[{prt = Partition[coords, 2, 1, 1], assoc = AssociationThread[coords, colors]},
Join[Translate[p, {0, 0, # h/2}] & /@ {-1, 1},
Polygon[Join @@ MapIndexed[TranslationTransform[{0, 0, (-1)^#2[[1]] h/2}] /@ # &,
{#, Reverse@#}], VertexColors -> assoc /@ Join[# , Reverse[#]]] & /@ prt]]


Examples:

pplt = ParametricPlot3D[{x, y, (x^2 + y^2 - 1/6 y^3)}, {x, -5, 5}, {y, -5, 5},
Mesh -> None, BoxRatios -> 1,
ColorFunction -> "Rainbow", Lighting -> "Neutral",
ImageSize -> 400, PlotRangePadding -> Scaled[.05]];

Row[{pplt, Normal[pplt] /. p_Polygon :> toPolyhedron[10][p]}, Spacer[10]]


Show[Normal[pplt] /. p_Polygon :> toPolyhedron[30][p],
ParametricPlot3D[{x, y, (x^2 + y^2 - 1/6 y^3)}, {x, -5, 5}, {y, -5, 5},
Mesh -> None, ColorFunction -> "Rainbow",
BoundaryStyle -> Directive[Thick, Black]],
Lighting -> "Neutral", ImageSize -> Large, BoxRatios -> 1]


Update: As an alternative to post-processing, you can use the option DisplayFunction to get the desired result in a single step:

ParametricPlot3D[{x, y, (x^2 + y^2 - 1/6 y^3)}, {x, -5, 5}, {y, -5, 5},
Mesh -> None, BoxRatios -> 1, ColorFunction -> "Rainbow",
Lighting -> "Neutral", ImageSize -> Large,
BoundaryStyle -> Directive[Thick, Black],
DisplayFunction -> (Normal[#] /. p_Polygon :> toPolyhedron[30][p] &)]


I used this for the point cloud to Image3D conversion: https://www.wolfram.com/language/gallery/make-a-3d-image-from-a-point-cloud We generate a million points from the domain {x,y,h}, apply f and voxelize the point cloud by bin-counting. I've used a more complicated function to showcase the general problem. I don't know how to get axes on the Image3D however:

PointCloudToImage3D[points_, thresh_, slices_] :=
Block[{ranges, bins, binCounts, transposedBinCounts},
ranges = Round[{Min[#], Max[#]} & /@ Transpose[points]];
bins = Append[#, ((#[[2]] - #[[1]])/slices)] & /@ ranges;
binCounts = BinCounts[points, Sequence @@ bins];
transposedBinCounts =
Map[UnitStep[# - thresh] &,
Reverse[Transpose[binCounts, {3, 2, 1}], {1, 2}], {3}];

• "I don't know how to get axes on the Image3D however" - use Raster3D[] instead so you can put it in Graphics3D[]. Commented May 23, 2020 at 4:54