Solved How to access the ObjectPlugin child objects.

Hello,

I have ObjectPlugin that contain a sphere object with texture tag, and from the NodeData.Message() I want to run my "Texture Baker" CommandData plugin to bake the sphere object texture.
The Texture Baker work on default sphere object but on plugin object I don't know how to do to access the sphere object inside the plugin object cache.

BaseObject* MyObject::GetVirtualObjects(BaseObject* op, HierarchyHelp* hh)
{
	if (!op)
		return BaseObject::Alloc(Onull);

	Bool bIsDirty = op->CheckCache(hh) || op->IsDirty(DIRTYFLAGS_DATA);
	if (!bIsDirty)
		return op->GetCache(hh);

	BaseContainer* objectData = op->GetDataInstance();
	if (!objectData)
		return BaseObject::Alloc(Onull);

	BaseObject* container = BaseObject::Alloc(Onull);
	BaseObject* sphere = BaseObject::Alloc(Osphere);

	if (!container || !sphere)
		return BaseObject::Alloc(Onull);

	container->SetName("Container");
	sphere->SetName("BakerObject");

	Float rad = objectData->GetFloat(HDRISGBAKEROBJECT_RAD);
	sphere->SetParameter(PRIM_SPHERE_TYPE, 2, DESCFLAGS_SET_0);

	BaseTag* phongTag = sphere->MakeTag(Tphong);
	phongTag->SetParameter(PHONGTAG_PHONG_ANGLELIMIT, Bool(true), DESCFLAGS_SET_0);

	// create the texture tag
	TextureTag* const textureTag = static_cast<TextureTag*>(sphere->MakeTag(Ttexture));
	if (textureTag == nullptr)
		return container;

	// apply material
	BaseDocument* doc = hh->GetDocument();

	BaseMaterial* material = doc->SearchMaterial("My Material");

	if (!material)
		return container;

	textureTag->SetMaterial(material);

	sphere->InsertUnder(container);
	return container;
}

I found this Topic and I wanted to try the suggested solution, but this crashing the c4d application.

Here how I use it

Bool MyObject::Message(GeListNode* node, Int32 type, void* data)
{
	switch (type)
	{
	case MSG_DESCRIPTION_COMMAND:
	{
		DescriptionCommand* dc = (DescriptionCommand*)data;

		const Int32 id = dc->id[0].id;

		switch (id)
		{
			case MYOBJECT_TEXTURE_BAKER:
			{
				// allocate a temp doc  
				AutoAlloc<BaseDocument> tempDoc;
				if (!tempDoc)
					return false;

				const Filename path = GeGetStartupWritePath() + Filename("tex") + Filename("texture_baker");

				tempDoc->SetDocumentPath(path);

				// allocate a primitive sphere  
				BaseObject* primSphere = BaseObject::Alloc(Osphere);
				if (!primSphere)
					return false;

				// obtain the polygon representation  
				PolygonObject* polygonSphere = ToPoly(primSphere);

				// insert into the temp doc  
				tempDoc->InsertObject(polygonSphere, nullptr, nullptr);

				// allocate a texture tag  
				TextureTag* sphereTextureTag = TextureTag::Alloc();
				if (!sphereTextureTag)
					return false;

				// set the texture tag params  
				sphereTextureTag->SetParameter(DescID(TEXTURETAG_PROJECTION), TEXTURETAG_PROJECTION_CUBIC, DESCFLAGS_SET_0);

				// insert into the polygonSphere  
				polygonSphere->InsertTag(sphereTextureTag);

				// allocate a material  
				AutoAlloc<Material> sphereMaterial;
				if (!sphereMaterial)
					return false;

				// get the BaseContainer of the material  
				BaseContainer *sphereMaterialBC = sphereMaterial->GetDataInstance();
				if (!sphereMaterialBC)
					return false;

				// allocate the colorizer shader  
				AutoAlloc<BaseShader> colorizerShader(Xcolorizer);
				if (!colorizerShader)
					return false;

				// retrieve the BaseContainer of the colorizer   
				BaseContainer* colorizerShaderBC = colorizerShader->GetDataInstance();
				if (!colorizerShaderBC)
					return false;

				// allocate the bitmap shader  
				AutoAlloc<BaseShader> bitmapShader(Xbitmap);
				if (!bitmapShader)
					return false;

				// retrieve the BaseContainer of the bitmap  
				BaseContainer* bitmapShaderBC = bitmapShader->GetDataInstance();
				if (!bitmapShaderBC)
					return false;

				Filename bitmapFilename("bitmap.jpg");

				// set the filename of the bitmap shader  
				// NOTE: the file should reside in the application directory if the project files has not been   
				// saved on disk or inside the /tex folder where the project files resides  
				bitmapShaderBC->SetFilename(BITMAPSHADER_FILENAME, bitmapFilename);

				// set the texture link of the colorizer shader to the bitmapShader  
				colorizerShaderBC->SetLink(SLA_COLORIZER_TEXTURE, bitmapShader);
				colorizerShader->InsertShader(bitmapShader.Release());

				// set the color link of the material to the colorizer shader  
				sphereMaterialBC->SetLink(MATERIAL_COLOR_SHADER, colorizerShader);
				sphereMaterial->InsertShader(colorizerShader.Release());

				// update   
				sphereMaterial->Message(MSG_UPDATE);
				sphereMaterial->Update(true, true);

				// insert the material and set the texture tag to use this material  
				sphereTextureTag->SetMaterial(sphereMaterial);
				tempDoc->InsertMaterial(sphereMaterial.Release());

				// allocate a BaseContainer for the texture baking settings and set a few meaningful values  
				BaseContainer textureBakingBC;
				textureBakingBC.SetInt32(BAKE_TEX_WIDTH, 512);
				textureBakingBC.SetInt32(BAKE_TEX_HEIGHT, 512);
				textureBakingBC.SetBool(BAKE_TEX_COLOR, true);

				// get the UVW tag from the sphere - it's not required to run GenerateUVW() to get the proper  
				// UVW representation because it's done internally by the InitBakeTexture  
				UVWTag* sphereUVWTag = (UVWTag *)polygonSphere->GetTag(Tuvw);

				// proceed to bake the texture assigned in the color slot  
				BAKE_TEX_ERR initBakingRes = BAKE_TEX_ERR_NONE, bakingRes = BAKE_TEX_ERR_NONE;

				//  init the baking process  
				BaseDocument* bakingDoc = InitBakeTexture(tempDoc, sphereTextureTag, sphereUVWTag, NULL, textureBakingBC, &initBakingRes, NULL);
			
				if (initBakingRes != BAKE_TEX_ERR_NONE)
				{
					GePrint("Failed to init texture baking[" + String::IntToString(initBakingRes) + "]");
					BaseDocument::Free(bakingDoc);
					return false;
				}

				// allocate the bitmap used for storing and saving the baking computations  
				AutoAlloc<BaseBitmap> bakingBmp;
				if (!bakingBmp)
				{
					BaseDocument::Free(bakingDoc);
					return false;
				}

				// execute the texture baking 
				bakingRes = BakeTexture(bakingDoc, textureBakingBC, bakingBmp, NULL, NULL, NULL);

				if (bakingRes != BAKE_TEX_ERR_NONE)
				{
					GePrint("Failed to bake the texture[" + String::IntToString(bakingRes) + "]");
					BaseDocument::Free(bakingDoc);
					return false;
				}

				GePrint("Texture baking accomplished");

				// free the baking document because we're still owning it  
				BaseDocument::Free(bakingDoc);

				// save the bitmap on disk  
				Filename bakingBmpFilename("TextureBackingOutput.jpg");
				Filename bakingBmpFullFilename = tempDoc->GetDocumentPath() + bakingBmpFilename;
				IMAGERESULT bakingBmpRes = bakingBmp->Save(bakingBmpFullFilename, FILTER_JPG, nullptr, SAVEBIT_0);
				if (bakingBmpRes != IMAGERESULT_OK)
				{
					GePrint("Failed to save baked texture bitmap [" + String::IntToString(bakingBmpRes) + "]");
					return false;
				}

				GePrint("Texture baking saved on " + bakingBmpFullFilename.GetString());

				break;
			}
			}
			break;
		}
	}
	return true;
}

Hi,

  1. All NodeData instances have a GeListNode that represents them somewhere in the scene graph. For an ObjectData instance this is a BaseObject for example. It is crucial to understand that your NodeData type is not instantiated into in the scene graph, but is living its life happily as a BaseData somewhere else.
  2. To most methods of NodeData and its derived types this representing node is passed as an argument (with annoyingly inconsistent naming: node in NodeData methods, op in ObjectData methods, and the list goes on). You can also get this node with by invoking NodeData::Get()(really expressive method name, I know).
  3. As described above, your ObjectData plugin is represented by a BaseObjectin the scene graph. BaseObject has multiple methods to access its caches. Most importantly GetCache() and GetDeformCache(). You should always use the second one (the cache of your object after deformers have been applied) unless you are certain that you have to ignore deformers. Note that caches can be empty. In this case you have to fall back to lower caches or do nothing.

Cheers
zipit

MAXON SDK Specialist
developers.maxon.net

Hi,

  1. All NodeData instances have a GeListNode that represents them somewhere in the scene graph. For an ObjectData instance this is a BaseObject for example. It is crucial to understand that your NodeData type is not instantiated into in the scene graph, but is living its life happily as a BaseData somewhere else.
  2. To most methods of NodeData and its derived types this representing node is passed as an argument (with annoyingly inconsistent naming: node in NodeData methods, op in ObjectData methods, and the list goes on). You can also get this node with by invoking NodeData::Get()(really expressive method name, I know).
  3. As described above, your ObjectData plugin is represented by a BaseObjectin the scene graph. BaseObject has multiple methods to access its caches. Most importantly GetCache() and GetDeformCache(). You should always use the second one (the cache of your object after deformers have been applied) unless you are certain that you have to ignore deformers. Note that caches can be empty. In this case you have to fall back to lower caches or do nothing.

Cheers
zipit

MAXON SDK Specialist
developers.maxon.net

@zipit
Hi,
Thank you, and have a nice day.

Hi @mfersaoui in the future try to split as much as possible your topic in order to help other users to find relevant information.
I've forked all your discussion about baking in this post Bake Texture within ObjectData.

And please mark this topic as solved if your original question is answered (which I think is the case by the good answers from @zipit).

Cheers,
Maxime.