Texture mapping

Hi @dale,

I have managed to read/write materials and textures. I would like to extend the functionality further. I have never understood correctly, the concept of mapping channel. Please do post an example to iterate through the render materials including the mapping channels.

Also, an example v6 file with materials with mapped channels. Are there many users using this functionality?

Hi @rajeev,

Does this help?

– Dale

I had read through the document…

As far as my limited knowledge of Rhino rendering… there can be only one mapping channel per texture…

For eg. color can have a texture on a mapping channel. … likewise for bump and transparency. Why do you need multiple channel numbers.

the document says “An object can have any number of channels and therefore can hold any number of texture mapping types.”

still confused… is it “any different type of texture mapping types” rather than any number?

A texture can reference a single mapping channel. Objects have any number of mapping channels, each of which defines a way of calculating texture coordinates from either the object itself (it’s paramter space), a primitive mapping or another object.

A texture can reference a single mapping channel.

Thank you, that was the confusion…

Hi @andy,
I am trying to implement what I have understood… I am able to iterate through the materials, but unable to reference Texture mapping info …But I think I am not casting the ON_TextureMapping correctly? Please find the code below

ONx_Model model= ..
	ONX_ModelComponentIterator it(model, ON_ModelComponent::Type::RenderMaterial);
	const ON_ModelComponent* model_component = nullptr;
	for (model_component = it.FirstComponent(); nullptr != model_component; model_component = it.NextComponent())
	{
		
		const ON_Material* material = ON_Material::Cast(model_component);
		if (nullptr != material)
		{
			//color, transparency, shininess, etc.. working ok
			
			//trying to get texture mappings
			const int tex_count = material->m_textures.Count();
			for (int i = 0; i < tex_count; i++)
			{
				const ON_Texture tex = material->m_textures[i];
				const ON_ModelComponentReference texmap_ref = model.ComponentFromId(ON_ModelComponent::Type::TextureMapping, tex.m_texture_id);
				const ON_TextureMapping* texmap = ON_TextureMapping::Cast(texmap_ref.ModelComponent());
				//texmap always returns nullptr
				if (nullptr != texmap)
				{
					switch (tex.m_type)
					{
					default:
						break;
					case ON_Texture::TYPE::bitmap_texture:
					{
						switch (texmap->m_type) 
							
							case ON_TextureMapping::TYPE::srfp_mapping: todo
							..
							..
							
					}
					..
					..
				}
			}
		}
	}

Rajeev

Yup - you can’t do it like that. Texture mapping is on an object, so you can’t get directly from the material to the texture mapping. You first have to pick an object, and then find the material that’s on it…and the texture mappings that are on it…and match them up.

  • Andy
1 Like
ONX_Model model;
model.Read("c:\\users\\andy\\desktop\\test.3dm");

const ON_ModelComponent* model_component = nullptr;

ON_SimpleArray<const ON_Material*> material_table;

ONX_ModelComponentIterator itMaterials(model, ON_ModelComponent::Type::RenderMaterial);
for (model_component = itMaterials.FirstComponent(); nullptr != model_component; model_component = itMaterials.NextComponent())
{
	material_table.Append(ON_Material::Cast(model_component));
}

ONX_ModelComponentIterator it(model, ON_ModelComponent::Type::ModelGeometry);
for (model_component = it.FirstComponent(); nullptr != model_component; model_component = it.NextComponent())
{
	const auto* pGeometry = ON_ModelGeometryComponent::Cast(model_component);
	if (nullptr != pGeometry)
	{
		const auto* pAttrs = pGeometry->Attributes(nullptr);
		if (pAttrs)
		{
			const ON_Material* pMaterial = nullptr;

			const auto* pMatRef = pAttrs->m_rendering_attributes.MaterialRef(ON_nil_uuid);
			if (pMatRef)
			{
				pMaterial = ON_Material::Cast(model.ComponentFromId(ON_ModelComponent::Type::RenderMaterial, pMatRef->m_material_id).ModelComponent());
			}
			else
			{
				if (-1 != pAttrs->m_material_index)
				{
					pMaterial = material_table[pAttrs->m_material_index];
				}
			}

			if (pMaterial)
			{
				const auto& textures = pMaterial->m_textures;

				for (int i = 0; i < textures.Count(); i++)
				{
					const auto& texture = textures[i];

					//See docs for MAPPING_CHANNEL for more information about this
					if (texture.m_mapping_channel_id > 0 && texture.m_mapping_channel_id < (unsigned int)ON_Texture::MAPPING_CHANNEL::screen_based_channel)
					{
						const auto* pMappingRef = pAttrs->m_rendering_attributes.MappingRef(ON_nil_uuid);

						if (pMappingRef)
						{
							const auto* pMappingChannel = pMappingRef->MappingChannel(texture.m_mapping_channel_id);

							if (pMappingChannel)
							{
								const auto* pMapping = ON_TextureMapping::Cast(model.ComponentFromId(ON_ModelComponent::Type::TextureMapping, pMappingChannel->m_mapping_id).ModelComponent());

								if (pMapping)
								{
									//Let the fun begin
									Sleep(1);
								}
							}
						}
					}
				}
			}
		}
	}
}
1 Like

And here is the file I was using

test.3dm (652.9 KB)

@andy … That helped! Thank you very much…

1 Like

Hi @andy,
I ran into problems trying to read the attached v5 file. Upon closer inspection, I realised that the mapping_channel_id was returning a value of 0.
Read the documentation… found that

// A value of zero means no mapping is supplied
// and the texture coordinates on the mesh are
// used.

Used the condition ( ON_Texture::IsBuiltinMappingChannel(texture.m_mapping_channel_id) ) to directly map the texture to the surface UV… Results are consistent with the original mapping in the v5 file…
Is it the correct way?

v5_extrusions.3dm (192.3 KB)

And the texture file compressed …
AtoZ.zip (6.7 KB)