**Update:** In versions 12.1+, we can use the directive `SurfaceAppearance["TextureShading", Texture[img]]` to texturize any surface with `img`:

    reg = TriangulateMesh[BoundaryDiscretizeRegion[Rectangle[]], MaxCellMeasure -> .02];

    disks = Graphics[{Red, MeshPrimitives[reg, 2] /. Polygon -> (Apply[Disk] @* Insphere)}];

     Graphics3D[{SurfaceAppearance["TextureShading", Texture[disks]], 
       KnotData["Trefoil", "ImageData"]}, 
      Boxed -> False, ImageSize -> Large] 

[![enter image description here][1]][1]

Using the functions `curve3`, `normal` and `binormal` from cvgmt's answer:


    ParametricPlot3D[curve3[t] + .6 (Cos[u] normal + Sin[u] binormal), 
     {u, 0, 2 π}, {t, 0, 2 π}, PlotPoints -> 80, Mesh -> None, 
     Boxed -> False, Axes -> False, 
     PlotStyle -> SurfaceAppearance["TextureShading", Texture[disks]], 
     ViewPoint -> {0.2, -0.3, 3.3}, Lighting->"Neutral"]

[![enter image description here][2]][2]

**Original answer:**


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 

[![enter image description here][3]][3]

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.}]

[![enter image description here][4]][4] 

Use `surfaceAppearance["Tiling" -> {15, 15}]` to get:

[![enter image description here][5]][5]

Use `surfaceAppearance["UseScreenSpace" -> 1, "StepCount" -> 2, "Tiling" -> {7, 7}]` to get:

[![enter image description here][6]][6]

Use `surfaceAppearance["Tiling" -> {15, 15}, "Shape"->"Triangle"]` to get:

[![enter image description here][7]][7]


Use  `surfaceAppearance["StepCount" -> 3,"Tiling" -> {10,10},"Shape" -> "Hexagon"]` to get:

[![enter image description here][8]][8]


  [1]: https://i.sstatic.net/TGyBI.png
  [2]: https://i.sstatic.net/hTc0Y.png
  [3]: https://i.sstatic.net/NvTo0.png
  [4]: https://i.sstatic.net/6s5iM.png
  [5]: https://i.sstatic.net/uQhsX.png
  [6]: https://i.sstatic.net/ZwZGn.png
  [7]: https://i.sstatic.net/OMD6B.png
  [8]: https://i.sstatic.net/azHpS.png