[C#] Vertex color from bitmap in uv space [Solved]

Hi Guys,

i was wondering is there a possibility to read vertex color through rhinocommon from applied texture from uv space ( if im writing this correctly ). I’d like to make a point/pointcloud representation of render mesh where points/verticies receives colors from texture corresponding to mapping. Im attaching overlayed image in ps for the explanation :slight_smile:
UV_VERTEX_COLOR

@dale, could you say a word about this in free time?

@andy @nathanletwory It is easy to get access to the texture coordinates from the object. What would be the way to evaluate the texture at that coordinate? I can imagine a workflow for a bitmap texture (find the bitmap, sample at the texture coordinates), but for a procedural, like wave texture, I’m not sure how to go about it.

I’m not sure about v5, but you’d be using the GetColor on the TextureEvaluator of a texture. Just set up Point3d uvw to be the UV coordinates, the third can be just 0.0 since we’re not doing 3d sampling. I unfortunately don’t know how to further get to the stage of doing that in v5.

1 Like

Thx. It seems to be there (undocumented) in v5. Textures don’t seem to have this TextureEvaluator. Are there any examples of its use?

TextureEvaluators are created dor RenderTextures: CreateEvaluator

1 Like

Hmm quite confusing for me when those evaluators are created and i cant call new evaluator on my own cause its constructor is protected. Simple example here would be nice :slight_smile:

I’ll have to try write some sample on Monday. I haven’t used v5, so it will take some time.

But essentially you’ll have to create a RenderMaterial from a Material like in this example, then query the RenderMaterial for the RenderTexture in the slot you’re interested in. On that RenderTexture instance you call CreateEvaluator - you can’t instantiate one directly.

I’ll know more next week, but maybe the above can get you started…

/Nathan

1 Like

Thanks @nathanletwory, here are some examples in gh. To use, reference a mesh object with a material w/ texture applied. This just looks at the diffuse channel.

Note: I set the Vector3d duvwdx, Vector3d duvwdy to Vector3d.Unset. What are these useful for? I don’t hangout in that corner of the namespace too often. :stuck_out_tongue:

Rhino 5: v5_SampleTexture.gh (4.7 KB)

MeshObject mo = RhinoDocument.Objects.Find(id) as MeshObject;
string name = mo.RenderMaterial.TextureChildSlotName(Rhino.Render.RenderMaterial.StandardChildSlots.Diffuse);
Rhino.Render.RenderTexture r_texture = mo.RenderMaterial.FindChild(name) as Rhino.Render.RenderTexture;
var textureEval = r_texture.CreateEvaluator();
var colorList = new List<Color>();
foreach(Point2f coo in mo.MeshGeometry.TextureCoordinates)
{
  var color = textureEval.GetColor(new Point3d(coo.X, coo.Y, 0), Vector3d.Unset, Vector3d.Unset).AsSystemColor();
  colorList.Add(color);
}

//Colors = colorList;
//Vertices = mo.MeshGeometry.Vertices;

RhinoWIP/6: v6_SampleTexture.gh (10.5 KB)

var mo = RhinoDocument.Objects.FindId(id) as MeshObject;
var r_texture = mo.RenderMaterial.GetTextureFromUsage(Rhino.Render.RenderMaterial.StandardChildSlots.Diffuse);
var textureEval = r_texture.CreateEvaluator();
var colorList = new List<Color>();
foreach(Point2f coo in mo.MeshGeometry.TextureCoordinates)
{
  var color = textureEval.GetColor(new Point3d(coo.X, coo.Y, 0), Vector3d.Unset, Vector3d.Unset).AsSystemColor();
  colorList.Add(color);
}

//Colors = colorList;
//Vertices = mo.MeshGeometry.Vertices;
2 Likes

@fraguada those are coefficients that help give better sampling when using i.e. procedurals, or when up- or downsampling. The halfpixel is put in these. This is how I use them in RhinoCycles: code. Note that I use zero vectors instead of unset.

@D-W, does this help?

@fraguada Nice example! I was trying to reach the texture directly instead of querying it via slot name - but as i suppose theres no way to reach it that way? I wanted to keep it simple outside referring in my method to the selected object.

@fraguada Sure it helps a lot! Now im struggling with getting render mesh via GetMeshes(MeshType enum) but i probably use it now in wrong context cause enum 1 shows that cannot convert int to MeshType - im still new to all that stuff but your help guys is very apprecited!

I think you are looking for the MeshType enum, which should be MeshType.Render: http://developer.rhino3d.com/api/RhinoCommonWin/html/T_Rhino_Geometry_MeshType.htm

1 Like

Thanks a lot! Its bit funny that sometimes enum is int and sometimes need to call like u said :slight_smile: Heres another thing - we’re considering here mesh that exist in the document as an object and what if i create mesh on the fly as type Mesh ? Should i push it to object first? As far as i understand Mesh type, in this case, is only geometry representation and as a MeshObject it receives rest of properties in this case material? Am i right?

EDIT: I dug here and there and all seems to be clear now :wink: Thank you very much guys!

@fraguada @nathanletwory Guys last question here. Im trying to cast material from Doc to RenderMaterial and im using CreateBasicMaterial(mat); to use evaluator but this way it looks like this isnt working cause im getting always black dots. Is there any way to cast RhinoDoc texture directly to RenderTexture ?

Material mat = instance.GetMaterial(true);
Rhino.Render.RenderMaterial renMat = Rhino.Render.RenderMaterial.CreateBasicMaterial(mat);
string nname = renMat.TextureChildSlotName(Rhino.Render.RenderMaterial.StandardChildSlots.Diffuse);
Rhino.Render.RenderTexture renTex = renMat.FindChild(nname) as Rhino.Render.RenderTexture;
var texEval = renTex.CreateEvaluator();

I don’t have a clue why material don’t have texture cause it inherits for eg. name. Due to use of different rendering plugins material defs are different but every of them exposes diffuse for preview purposes so diffuse should be “catchable”. So i tried with standard rhinorender mat and i get also 0,0,0 eval on all points.

Edit: It is bit weird cause if i force to open renTex in modal editor everything is ok even when reading bitmap from external render plugin. @fraguada any clue whats going on?

Edit2: I tried to comitchanges/push material to doc etc. It is weird cause even if material is created and then i assign new material manually (rhino internal mat of course) i still get 0,0,0 from evaluator … created material looks ok it has diffuse in slot as it should, so i dont know what could be wrong here… renTex.OpenInModalEditor(); shows proper texture so i dont know where to look further :frowning: @dale @pascal Maybe You Guys have some idea on this?

Edit3: So far i found that this is probably bug cause when i call rendertexture using renMat i get always black points.

int material_index = instance.Attributes.MaterialIndex;
material_index = Rhino.RhinoDoc.ActiveDoc.Materials.Add();
Rhino.DocObjects.Material xmat = Rhino.RhinoDoc.ActiveDoc.Materials[material_index];
xmat.Default();
xmat.SetBitmapTexture(diff.FileName);
xmat.CommitChanges();

Rhino.Render.RenderTexture renTex = instance.RenderMaterial.FindChild(nname) as Rhino.Render.RenderTexture;

renTex retuns null in this case - i really ran out of ideas.

Edit4: Even when i created completely new mat and assigned texture and updated object and then returned to original state as @fraguada showed in example - i’ve ended up again with new material in material tab which looks ok and has diffuse slot loaded with proper texture but from this material evaluator i get 0,0,0 again. So far i understand texture evaluator only works with materials created by hand?

@andy ? :frowning:

Today im blown away:

How this can be that im creating new material and i set path but instead of that i get unnamed material with orange diffuse color ?

Edit: I looked into Locals on breakpoints and it looks like there is no way to assign texture this way cause it is never assigned to doc and it never inherits LocalMappingTransform so probably due to this parameters evaluator cant pick colors when i try to cast materials to native ones. Is there someone who can say that this can be caused by this?

@D-W, I’m looking into this, but it takes me some learning time, as I’m finding my way through V5 (I’ve pretty much only used V6).

1 Like

@D-W the following code seems to work for me in v5:

	int index = doc.Materials.Add();
	Rhino.DocObjects.Material mat = doc.Materials[index];
	mat.SetBitmapTexture("C:\\colgrid.png");
	mat.Name = "Testing";
	mat.DiffuseColor = System.Drawing.Color.Chocolate;
	mat.SpecularColor = System.Drawing.Color.CadetBlue;
	mat.CommitChanges();

	Rhino.DocObjects.ObjRef pob;
	if(Rhino.Input.RhinoGet.GetOneObject("Pick ob", false, Rhino.DocObjects.ObjectType.AnyObject, out pob)!=Result.Success)
	{
			RhinoApp.WriteLine(":/");
	}

	var ob = pob.Object();
	ob.CreateMeshes(MeshType.Render, MeshingParameters.Smooth, false);
	Rhino.DocObjects.ObjectAttributes attr = ob.Attributes.Duplicate();
	attr.MaterialIndex = index;
	attr.MaterialSource = Rhino.DocObjects.ObjectMaterialSource.MaterialFromObject;
	ob.Attributes = attr;
	ob.CommitChanges();

	doc.Views.Redraw();

	var rm = Rhino.Render.RenderMaterial.CreateBasicMaterial(mat);
					
	if(rm == null)
	{
			RhinoApp.WriteLine("no rendermaterial");
			return Result.Failure;
	}

	var diffslot = rm.TextureChildSlotName(Rhino.Render.RenderMaterial.StandardChildSlots.Diffuse);
	var rt = rm.FindChild(diffslot) as Rhino.Render.RenderTexture;
	int w;
	int h;
	object wo = rt.GetParameter("pixel-width");
	object ho = rt.GetParameter("pixel-height");
					
	w = Convert.ToInt32(wo);
	h = Convert.ToInt32(ho);

	RhinoApp.WriteLine($"--: {wo} _ {w}");
	RhinoApp.WriteLine($"--: {ho} _ {h}");

	using (var eval = rt.CreateEvaluator())
	{
			var zp = new Vector3d(0.0, 0.0, 0.0);
			for (int y = 0; y < w; y++)
			{
					for (int x = 0; x < h; x++)
					{
							var p = new Point3d(x / 100.0, y / 100.0, 0.0);

							var c = eval.GetColor(p, zp, zp);

							if (y < 10 && x < 10) RhinoApp.WriteLine($"{p.X},{p.Y},{p.Z} - {c.R} {c.G} {c.B}");
					}
			}
	}
1 Like

I just realized one doesn’t need an object to get to the texture evaluator, so here is a stripped version:

int index = doc.Materials.Add();
Rhino.DocObjects.Material mat = doc.Materials[index];
mat.SetBitmapTexture("C:\\colgrid.png");
mat.Name = "Testing";
mat.DiffuseColor = System.Drawing.Color.Chocolate;
mat.SpecularColor = System.Drawing.Color.CadetBlue;
mat.CommitChanges();

var rm = Rhino.Render.RenderMaterial.CreateBasicMaterial(mat);

if(rm == null)
{
RhinoApp.WriteLine("no rendermaterial");
return Result.Failure;
}

var diffslot = rm.TextureChildSlotName(Rhino.Render.RenderMaterial.StandardChildSlots.Diffuse);
var rt = rm.FindChild(diffslot) as Rhino.Render.RenderTexture;

using (var eval = rt.CreateEvaluator())
{
	var zp = new Vector3d(0.0, 0.0, 0.0);
	for (int y = 0; y < 15; y++)
	{
		for (int x = 0; x < 15; x++)
		{
			var p = new Point3d(x / 15.0, y / 15.0, 0.0); // create a UV coordinate

			var c = eval.GetColor(p, zp, zp);

			if (y < 10 && x < 10) RhinoApp.WriteLine($"{p.X},{p.Y},{p.Z} - {c.R} {c.G} {c.B}");
		}
	}
}

While typing this code I also ran into the situation where the evaluator would return just black color. It turned out I had typoed the path to the image. So make sure you have correct path to the image you want, and that you have read access to it.

I hope this helps.

/Nathan

2 Likes