Creating and populating a node group from C

I try to create a material node group from within C.

So far i am able to generate the node hierarchy and add links to the nodes. But now i have a problem to convert this to a node group. My first thought was to simply use the function node_group_make_from_selected() in this way:

// ntree: ma->nodetree where i have setup the nodes
void bc_make_material_group(bContext *C, bNodeTree *ntree)
    bNode * gnode = node_group_make_from_selected(
    // i am not sure if the following calls are necessary.

    nodeSetActive(ntree, gnode);
    bNodeTree *ngroup = (bNodeTree *)gnode->id;
    ntreeUpdateTree(bmain, ngroup);
    Main *bmain = CTX_data_main(C);

However this approach has 2 nasty issues:

  1. The function node_group_make_from_selected() is not public. (So i made it public for experimenting)

  2. Good news: the node group is actually created and the node editor shows what i expect to see.
    Bad news: When i try to open the Material properties editor, then i get a crash in line 314:

    BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) == 0); 

Hence i believe my approach is totally wrong. So maybe someone can give me a hint how to proceed and get a material node group created properly from within C. I bet that its actually super easy, i just do not know how to do it.


I’m not sure if it’s helpful to make a node group when importing materials, many other importers don’t do this either. As material exporters don’t support looking into node groups it can give problems too.

If you want to implement this you’ll need to refactor the code to move the node group creation into blenkernel/intern/node.c, and make it reusable.

It’s not immediately clear why you are getting that error, perhaps you are editing a depsgraph evaluated material instead of the original material? Though I’m not sure how that could happen in an importer. It’s also unclear what the error is without seeing the full backtrace.

I thought i have to use the material node system because we have no “simple” material setup any longer. So my very first attempt was to just create a principled PBR and a material output node. But then one thing lead to the next and i ended up with the idea to generate a collada_material_group during import.

Right. I had a shimmer of an idea to also use some sort of collada_export_group here as a general interface for the exporter so that it has something that it can reliably ask for data.

blender.exe!issue_debug_notification(const wchar_t * const message) Line 28	C++
blender.exe!__acrt_report_runtime_error(const wchar_t * message) Line 154	C++
blender.exe!abort() Line 61	C++
blender.exe!DEG::Depsgraph::add_id_node(ID * id, ID * id_cow_hint) Line 314	C++
blender.exe!DEG::DepsgraphNodeBuilder::add_id_node(ID * id) Line 177	C++
blender.exe!DEG::DepsgraphNodeBuilder::build_nodetree(bNodeTree * ntree) Line 1401	C++
blender.exe!DEG::DepsgraphNodeBuilder::build_nodetree(bNodeTree * ntree) Line 1457	C++
blender.exe!DEG::DepsgraphNodeBuilder::build_material(Material * material) Line 1485	C++
blender.exe!DEG::DepsgraphNodeBuilder::build_object_data_geometry(Object * object, bool is_object_visible) Line 1212	C++
blender.exe!DEG::DepsgraphNodeBuilder::build_object_data(Object * object, bool is_object_visible) Line 686	C++
blender.exe!DEG::DepsgraphNodeBuilder::build_object(int base_index, Object * object, DEG::eDepsNode_LinkedState_Type linked_state, bool is_visible) Line 613	C++
blender.exe!DEG::DepsgraphNodeBuilder::build_view_layer(Scene * scene, ViewLayer * view_layer, DEG::eDepsNode_LinkedState_Type linked_state) Line 113	C++
blender.exe!DEG_graph_build_from_view_layer(Depsgraph * graph, Main * bmain, Scene * scene, ViewLayer * view_layer) Line 220	C++
blender.exe!DEG_graph_relations_update(Depsgraph * graph, Main * bmain, Scene * scene, ViewLayer * view_layer) Line 291	C++
blender.exe!BKE_scene_graph_update_for_newframe(Depsgraph * depsgraph, Main * bmain) Line 1461	C
blender.exe!engine_depsgraph_init(RenderEngine * engine, ViewLayer * view_layer) Line 501	C
blender.exe!RE_engine_render(Render * re, int do_all) Line 731	C
blender.exe!do_render_3d(Render * re) Line 1103	C
blender.exe!RE_PreviewRender(Render * re, Main * bmain, Scene * sce) Line 2623	C
blender.exe!shader_preview_render(ShaderPreview * sp, ID * id, int split, int first) Line 865	C
blender.exe!shader_preview_startjob(void * customdata, short * stop, short * do_update) Line 902	C
blender.exe!icon_preview_startjob(void * customdata, short * stop, short * do_update) Line 1103	C
blender.exe!common_preview_startjob(void * customdata, short * stop, short * do_update, float * UNUSED_progress) Line 1118	C
blender.exe!icon_preview_startjob_all_sizes(void * customdata, short * stop, short * do_update, float * progress) Line 1197	C
blender.exe!do_job_thread(void * job_v) Line 338	C
blender.exe!tslot_thread_start(void * tslot_p) Line 254	C

Maybe it is intersting to know that the add_node_id() function is called also while the group is created. But only later when i am back in the blender user interface and navigate to the material properties, then the add_node_id() function is called again and fails this time.

Ok, i can live with not using node groups for now as they might just be nice to have eye candy :slight_smile:

But then i still have to decide:

  • Either create a simple material setup (principled bsdf + material output) and only import diffuse colors/textures
  • or create a more complex material node system to also allow importing of emission and transparency.

I got both ready to go now. I could make it an Import option…