Image sampling color from a flat mesh?

Creating gradients from curves using mesh coloring is very interesting, I’m looking for a way to sample them using Image Sampler or replicate that functionality.

Something akin to below, although I imagine even an automated method of exporting and importing images would be slow.

image

Alternatively if there is a better method than getting meshes involved I’m all ears. I appreciate any advice!

gradient crv test1.gh (629.6 KB)

I once did some similar test.


I think from the realistic aspect. we should use E=I/r²


I personally prefer something like this:


gradient.gh (12.4 KB)

3 Likes

Those are some beautiful methods, I imagine the hard edge of the first is useful in some scenarios.

What I’m still stuck on, is how to reference these mesh gradients as bitmaps for image sampling, or at least a better way than exporting/importing manually.

For my use I choose to use one or more array of double, it is more efficient than bitmap. Not sure it is very good programming but it works and helps me for BlueNoise (not published), Making an image with a single thread (not here),

public class ImageGreyScale
    {
        public double[,] image;
        public double[,] imageAlpha;

        int width;
        int height;

        double initialWidth;
        double initialHeight;


        Point3d LowerLeftPoint;
        double ScaleX;
        double ScaleY;

        /// <summary>
        /// Image with a gradiant
        /// </summary>
        /// <param name="curve"></param>
        /// <param name="dMax"></param>
        /// <param name="maxPixelWidth"></param>
        public ImageGreyScale(Curve curve, double dMax, int maxPixelWidth, double power)
        {
            power = Math.Min(10, Math.Max(0.1, power));

            PolylineCurve plCurve = curve.ToPolyline(dMax / 1000, 0.01, dMax / 1000, dMax);

            BoundingBox bb = curve.GetBoundingBox(true);

            width = maxPixelWidth;
            ScaleX = (double)(width - 1) / bb.Diagonal.X;
            LowerLeftPoint = bb.PointAt(0, 0, 0);
            height = (int)(bb.Diagonal.Y * ScaleX);
            ScaleY = (double)(height - 1) / bb.Diagonal.Y;


            image = new double[width, height];
            imageAlpha = new double[width, height];

            System.Threading.Tasks.Parallel.For(0, height, j =>
            {
                for (int i = 0; i < width; i++)
                {
                    Point3d pt = GetPoint(i, j);


                    //Pas la peine de passer en polyline on gagne rien !
                    PointContainment ptCt = curve.Contains(pt, Plane.WorldXY, 0.01);

                    double t = 0.0;
                    curve.ClosestPoint(pt, out t);
                    double distance = curve.PointAt(t).DistanceTo(pt);

                    if (ptCt == PointContainment.Outside)
                    {
                        image[i, j] = 1;
                        imageAlpha[i, j] = 0;
                    }
                    else
                    {
                        image[i, j] = Math.Pow(Math.Max(0, Math.Min(1, distance / dMax)), power);
                        imageAlpha[i, j] = 1;
                    }


                }
            });
        }


        public ImageGreyScale(string fileName)
        {
            Bitmap bitmap = new Bitmap(fileName);
            PrivateImageGreyScale(fileName, bitmap.Width);
            bitmap.Dispose();
        }

        public void Save(string fileName)
        {
            Image img = ToImage();
            img.Save(fileName);
        }

        public Image ToImage()
        {
            Bitmap bmp = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(bmp)) g.Clear(Color.White);
            for (int j = 0; j < bmp.Height; j++)
            {
                for (int i = 0; i < bmp.Width; i++)
                {
                    int alpha = (int)(Math.Max(0, Math.Min(imageAlpha[i, j], 1)) * 255);
                    int val = (int)(Math.Max(0, Math.Min(image[i, j], 1)) * 255);
                    bmp.SetPixel(i, j, Color.FromArgb(alpha, val, val, val));
                }
            }

            return (Bitmap)bmp;
        }

        public Mesh GetMesh()
        {
            Mesh mesh = new Mesh();
            for (int j = 0; j < height; j++)
            {
                for (int i = 0; i < width; i++)
                {

                    mesh.Vertices.Add(this.GetPoint(i, j));
                    int alpha = (int)(Math.Max(0, Math.Min(imageAlpha[i, j], 1)) * 255);
                    int val = (int)(Math.Max(0, Math.Min(image[i, j], 1)) * 255);
                    mesh.VertexColors.Add(Color.FromArgb(alpha, val, val, val));
                }
            }
            for (int j = 0; j < height - 1; j++)
            {
                for (int i = 0; i < width - 1; i++)
                {
                    mesh.Faces.AddFace(new MeshFace(i + j * width, i + 1 + j * width, i + 1 + (j + 1) * width, i + (j + 1) * width));
                }
            }
            mesh.RebuildNormals();

            return mesh;
        }
2 Likes

Thank you Laurent, through I am not quite sure how to interface with that, is that for a plugin or a gh script? If I am only meant to follow the logic I am grateful and will parse out what I can, but I tried to plug it into a component like a monkey trying to fit a square peg into a triangular hole and got similar results.

1 Like

It is more an example to show how to use image. It is not easy to use it with other component except if you output a mesh. Image could also be used like in some plugin but classical image type is not really defined in space. So if you need an image with a physical dimension like a rectangle it could surely be worth to develop a dll. But if no problem of speed mesh is the best candidate as it is an existing type of data in GH. So I think you could

  1. use mesh, perhaps some speed limit and also perhaps precision issue
  2. output an image file, its location and the rectangle that contains the image, your sampler will use the file location to read the file and the rectangle to put it at the good location and size.
  3. develop an image type derived from GH_GOO
    GH_Goo(T) Class
    You have example of implementation in Culebra and others plugin
    Culebra/Culebra_GH at master · elQuixote/Culebra · GitHub
    Core.Grasshopper/SurfaceGhData.cs at master · Paramdigma/Core.Grasshopper · GitHub
1 Like

Just wanted to thank you Laurent, still processing all of that. I appreciate the links, I’ll report back any headway.

1 Like