I am trying to implement a Wiremap project in Rhino/Grasshopper.
It is a take on volumetric projection where a 2D image is projected onto wires arranged in 3D space. Based on some of the sample material provided on the Instructables page, I have created the layout of the wires.
As a test, I sampled this image at appropriate intervals and simply assigned the pixel’s colour to the wire in that position. The seemingly random pattern of RGB lines sorts the wires into three groups.
How would I go about simulating it such that I could place a virtual ‘projector’ in rhinospace, feed it that (or any) image, and have the wires act as a screen for the projector?
And there are several cases where values are passed through text panels, which is not a good idea because in some cases (geometry?) it converts to text. Text panels are great for examining component outputs but should be wired so they can be deleted without affecting the end result.
Apologies, I’ve tried to clean up some of these errors. Reuploading the GH file along with the missing references. Also adding these to the original post.
The code appears to work fine but I’m puzzled about what it’s doing and what your objective is?
Using the ‘final_output128.txt’ file looks very odd? Did you create that file by hand?
I can see that the locations of the vertical lines comes from the intersection (Curve | Curve) of ‘U’ isocurves with a very selective list of ‘V’ isocurves driven by the ‘final_output128.txt’ file, but I don’t know enough about that selection process of ‘V’ isocurves
And don’t know why the ‘128 wires.png’ image is appropriate for colors? Was it also created by hand?
Finally, what you are trying to do is not clear to me at all
I guess with the above word “image” you mean “2D/3D shape”, don’t you?
just to better understand, I did a sort of stupid box that rotates on two axis in the center of the wires-array
let’s say I’d like to have that box somehow visualized on the wires only if any Face of the box is intersecting a wire, I would give a try to something like this:
I don’t know what sort of data format you were planning to use to link the Rhino geometry with the actual video frames that are going to be projected on the wires… my first thought would be for each “video frame” to have a separate list for each wire that indicates the height of the points to be projected on it (only Z value of each point, as x and y are already defined by the position of each wire)
I say “points” because in my file the output data are Curve-Brep intersection points… but they could also be Lines (…Points and Lines are indeed the only geometries you can use I guess )
if the Z value is useful “data” to process, then that is organized in a data-tree like {A:B} where:
A = frame number
B = wire number
and each {A;B} branch contains Z value of one or more point to be projected on that particular wire B at frame A
So the objective is to use those wires as a volume for volumetric projection.
The idea is to have a sandbox where I can place a solid, check which portions of which wires would have to be ‘illuminated’ by a 2d Projector for it to be the best approximation of the solid in the sandbox. Something like this:
The ‘final_output128.txt’ file was one created by the guy who made the project and the author of the Instructables page. The wire positions are essentially random- the only criterion was that no wire sit in front of another from the POV of the projector.
The ‘128 wires.png’ too is from a calibration program made by the original author. The intended use case was to calibrate the positions of the wires in a physical model.
I’ve updated the GH file to include the next portion of the program.
The Solid placed in the sandbox on the left is checked against the wires for intersections.
If I were to construct a physical model of this wire setup and feed this image to a projector placed at the correct position, it should light up the wires just right.
This simulation of a projector is what I am trying to achieve next - i.e. construct a virtual projector within Rhino/GH.
Thank you! Your approach is quite close to the one I’ve used. I have a tree with the wire numbers and the start and end positions of the pixels on my frame that are coloured. Something like this. I’m just saving a single static image at the moment.
What I am struggling with now is trying to simulate a ‘virtual’ projector within Rhino/GH now to work through this process backwards - i.e. give it this image I’ve saved and project it back on to the wires without ‘cheating’ by just sampling the pixel columns of the image and assigning colors to the wires that way. It should, for instance, be possible to create a somewhat striped pattern on the wires by tilting the virtual projector.
Hey @PeterFotiadis,
As an occasional lurker, I’ve seen you help a bunch of people with stuff! I’m stuck on trying to create this virtual projector in Rhino/GH. If you have a moment, I’d really appreciate any thoughts or tips you might have. Thanks in advance!
Well … that’s rather easy … but the bad news is: if I’ll provide an indicative solution (100% code driven ) that would be a black box for you (unless you know how to code or you have plans to walk that walk)
I hear you! Fortunately, I do know how to code, so I’m definitely up for diving into whatever solution you can provide. I’m down to break it apart and figure it out. Appreciate any help you can throw my way!
You are in the correct path. But I’m not in the rabbit hole (practice) right now. When back I’ll do something for you.
BTW: What is the - real life - purpose of this ? You want to “pixelate” (LOL) an image with a rather freaky way? (i.e. use a pixel RRG value to Color some prox to a given Ray3d wire segment )
Update: in a crap Laptop found a “similar” (so to speak) case - some client wants a thematic park with some big/ugly/pointless installation that … blah, blah. So the following could act as a start point (of some sort). It’s rather good to use a pull/push option (for the D) and a remap.
public Point3dList grid;
public Point3d gridOrig;
public Surface gridSurf;
public Vector3d gridZ;
public void GetGrid(Plane plane, double x, int xc, double y, int yc){
grid = new Point3dList();
gridOrig = plane.Origin;
gridZ = plane.ZAxis;
Vector3d vx = plane.XAxis * x / (double) xc;
Vector3d vy = plane.YAxis * y / (double) yc;
Point3d p1 = gridOrig;
Point3d p2 = p1 + vx * xc;
Point3d p3 = p2 + vy * yc;
Point3d p4 = p1 + vy * yc;
gridSurf = NurbsSurface.CreateFromCorners(p1, p2, p3, p4);
for (int i = 0; i < xc; i++){
for (int j = 0; j < yc; j++){
Point3d p = gridOrig + i * vx + j * vy;
grid.Add(p);
}
}
}
public List<RINFO> rInfo;
// 1M Q: what does this class? Why is used? Answers: The Lord, District 666, North Pole
public class RINFO {
public IndexPair PAIR {get;set;}
public Color COLOR {get;set;}
public Point3d CENT {get;set;}
public Ray3d RAY {get;set;}
public Point3d? HITPT {get;set;}
public double D {get;set;}
public RINFO (IndexPair pair, Color c, Point3d cent, Ray3d ray, Point3d hit){
this.PAIR = pair; this.COLOR = c; this.CENT = cent; this.RAY = ray; this.HITPT = hit;
if(hit != null) this.D = Math.Round(((Point3d) hit).DistanceTo(cent), 3);
}
}
public void GetRInfoList(string filePath, Rectangle3d frame, Point3d proj){
rInfo = new List<RINFO>();
Point3d orig = frame.Corner(0);
Plane plane = new Plane(orig, frame.Corner(1), frame.Corner(3));
Bitmap bmp = new Bitmap(filePath);
int height = bmp.Height;
int width = bmp.Width;
Vector3d vx = plane.XAxis / (double) width;
Vector3d vy = plane.YAxis / (double) height;
for (int i = 0; i < width; i++){
for (int j = 0; j < height; j++){
IndexPair pair = new IndexPair(i, j);
Color color = bmp.GetPixel(i, j);
Point3d cent = orig + i * vx + j * vy;
Ray3d ray = new Ray3d(proj, cent - proj);
Point3d? hit = GetHitOnGrid(ray);
RINFO info = new RINFO(pair, color, cent, ray, hit);
rInfo.Add(info);
}
}
// from this point apply/use whatever policy you want
// BTW: for the dist you may use a pull/push option
// BTW: get a proper Ducati, forget all that stuff
}
public Point3d? GetHitOnGrid(Ray3d ray){
Point3d[] ccx = Rhino.Geometry.Intersect.Intersection.RayShoot(ray, new Surface[1]{gridSurf}, 1);
if(ccx == null || ccx.Length < 1) return null;
else{
Point3d p = ccx[0];
return grid[grid.ClosestIndex(p)];
}
}
BTW: The whole thing is “more or less similar” to a classic Mesh Hightmap. Shown an immortal NCR New Blue Ducati: