We can use the new-in-12.1 directive HalfToneShading:
Graphics3D[{HalftoneShading[#, Red], KnotData["Trefoil", "ImageData"]},
Lighting -> "Neutral", ImageSize -> 250, Boxed -> False,
ViewPoint -> {1.5, -1.5, 4.}] & /@ {.3, .5, .7} // Row
Needless to say, this approach is not match for cvgmt's approach in terms of flexibility and beauty of the pictures produced.
To get some flexibility in controlling the density of shapes, we can use the options of SurfaceAppearance to define a directive with options:
Options[surfaceAppearance] = {"StepCount" -> 1, "Tiling" -> {5, 5},
"FeatureColor" -> Red, "UseScreenSpace" -> 0, "IsTwoTone" -> 1,
"LuminanceModifier" -> 0.0, "Shape" -> "Disk"};
surfaceAppearance[opts : OptionsPattern[surfaceAppearance]] :=
SurfaceAppearance["RampShading",
Sequence @@ FilterRules[{opts, Options[surfaceAppearance]}, Except["Shape"]],
"Arguments" -> {"HalftoneShading", 0.5, Red, OptionValue["Shape"]},
EdgeForm[], Texture["HalftoneShading" <> OptionValue["Shape"]]]
Examples:
Graphics3D[{surfaceAppearance[], KnotData["Trefoil", "ImageData"]},
Lighting -> "Accent", Boxed -> False, ViewPoint -> {1.5, -1.5, 4.}]
Use surfaceAppearance["Tiling" -> {15, 15}] to get:
Use surfaceAppearance["UseScreenSpace" -> 1, "StepCount" -> 2, "Tiling" -> {7, 7}] to get:
Use surfaceAppearance["Tiling" -> {15, 15}, "Shape"->"Triangle"] to get:
Use surfaceAppearance["StepCount" -> 3,"Tiling" -> {10,10},"Shape" -> "Hexagon"] to get:





