From 15318301e09a9b45236aec0c47d7fdbd0123f4f5 Mon Sep 17 00:00:00 2001 From: Alex Nichol Date: Sun, 27 Aug 2023 13:02:49 -0700 Subject: [PATCH] whipped cream --- examples/usable/milkshake_ringholder/cream.go | 68 +++++++++++++++++++ examples/usable/milkshake_ringholder/cup.go | 17 ++++- examples/usable/milkshake_ringholder/main.go | 16 ++++- 3 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 examples/usable/milkshake_ringholder/cream.go diff --git a/examples/usable/milkshake_ringholder/cream.go b/examples/usable/milkshake_ringholder/cream.go new file mode 100644 index 0000000..cca483c --- /dev/null +++ b/examples/usable/milkshake_ringholder/cream.go @@ -0,0 +1,68 @@ +package main + +import ( + "math" + + "github.com/unixpickle/model3d/model2d" + "github.com/unixpickle/model3d/model3d" + "github.com/unixpickle/model3d/render3d" + "github.com/unixpickle/model3d/toolbox3d" +) + +const ( + CreamRadius = 0.15 + CreamHeight = 0.8 + CreamZOffset = 0.05 +) + +func CreamSolid() (model3d.Solid, toolbox3d.CoordColorFunc) { + mesh := CreamMesh() + return model3d.NewColliderSolid(model3d.MeshToCollider(mesh)), + toolbox3d.ConstantCoordColorFunc(render3d.NewColor(1.0)) +} + +func CreamMesh() *model3d.Mesh { + baseShape := model2d.CheckedFuncSolid( + model2d.Ones(-CreamRadius), + model2d.Ones(CreamRadius), + func(c model2d.Coord) bool { + norm := c.Norm() + if norm < 1e-8 { + return true + } + normed := c.Scale(1 / norm) + pow := 2.5 + r := math.Pow(math.Pow(math.Abs(normed.X), pow)+math.Pow(math.Abs(normed.Y), pow), pow) + return norm/CreamRadius < r + }, + ) + length := 10.0 + solid3d := model3d.ProfileSolid(baseShape, 0, length) + mesh3d := model3d.DualContour(solid3d, 0.03, true, false) + + // Deform along a curve. + return mesh3d.MapCoords(func(c model3d.Coord3D) model3d.Coord3D { + centerCoord := creamCurve(c.Z / length) + c2 := creamCurve(c.Z/length + 1e-5) + derivative := c2.Sub(centerCoord).Normalize() + x1 := model3d.Z(1).ProjectOut(derivative) + x2 := x1.Cross(derivative) + + // Apply a small twist along the curve. + rotation := c.Z / length * 25 + x1, x2 = x1.Scale(math.Cos(rotation)).Add(x2.Scale(math.Sin(rotation))), + x1.Scale(-math.Sin(rotation)).Add(x2.Scale(math.Cos(rotation))) + return centerCoord.Add(x1.Scale(c.Y)).Add(x2.Scale(c.X)) + }) +} + +func creamCurve(t float64) model3d.Coord3D { + theta := t * 30 + // We want the start to naturally "tuck into" the spiral. + radius := (CupTopRadius - CreamRadius) * (1 - math.Abs(t*1.1-0.1)) + return model3d.XYZ( + math.Cos(theta)*radius, + math.Sin(theta)*radius, + CupHeight+t*CreamHeight-CreamZOffset, + ) +} diff --git a/examples/usable/milkshake_ringholder/cup.go b/examples/usable/milkshake_ringholder/cup.go index 0e52905..204f762 100644 --- a/examples/usable/milkshake_ringholder/cup.go +++ b/examples/usable/milkshake_ringholder/cup.go @@ -17,6 +17,8 @@ const ( CupTopRadius = 0.9 CupHeight = 3 CupRimHeight = 0.4 + CupRimThickness = 0.1 + CupContentsDepth = 0.1 ) func CupSolid() (model3d.Solid, toolbox3d.CoordColorFunc) { @@ -39,9 +41,22 @@ func CupSolid() (model3d.Solid, toolbox3d.CoordColorFunc) { facetDepth := math.Sqrt(1 - r*r) radius -= facetDepth * CupFacetFlatten } + } else if c.Z > CupHeight-CupContentsDepth { + r := c.XY().Norm() + return r < radius && r > radius-CupRimThickness } return c.XY().Norm() < radius }, ) - return solid, toolbox3d.ConstantCoordColorFunc(render3d.NewColorRGB(0x65/255.0, 0xbc/255.0, 0xd4/255.0)) + colorFn := func(c model3d.Coord3D) render3d.Color { + fracTop := c.Z / CupHeight + radius := fracTop*CupTopRadius + (1-fracTop)*CupBottomRadius + r := c.XY().Norm() + if r <= radius-CupRimThickness && c.Z > CupHeight-CupRimHeight { + return render3d.NewColor(1.0) + } else { + return render3d.NewColorRGB(0x65/255.0, 0xbc/255.0, 0xd4/255.0) + } + } + return solid, colorFn } diff --git a/examples/usable/milkshake_ringholder/main.go b/examples/usable/milkshake_ringholder/main.go index eb71fee..a7dd8de 100644 --- a/examples/usable/milkshake_ringholder/main.go +++ b/examples/usable/milkshake_ringholder/main.go @@ -3,10 +3,20 @@ package main import ( "github.com/unixpickle/model3d/model3d" "github.com/unixpickle/model3d/render3d" + "github.com/unixpickle/model3d/toolbox3d" ) func main() { - cup, colorFn := CupSolid() - mesh := model3d.MarchingCubesSearch(cup, 0.02, 8) - render3d.SaveRandomGrid("rendering.png", mesh, 3, 3, 300, colorFn.RenderColor) + cup, cupColor := CupSolid() + cream, creamColor := CreamSolid() + joined := model3d.JoinedSolid{cup, cream} + + mesh, interior := model3d.MarchingCubesInterior(joined, 0.02, 8) + colorFunc := toolbox3d.JoinedSolidCoordColorFunc( + interior, + cup, cupColor, + cream, creamColor, + ) + + render3d.SaveRandomGrid("rendering.png", mesh, 3, 3, 300, colorFunc.RenderColor) }