Help with shader node preview exercise

I have been interested in finding my way around Blender’s source code and looking for a feature I could try to implement.
Recently I have been made aware of a add-on that adds preview to shader nodes (https://blendermarket.com/products/node-preview). I thought that sounds like something that could (should?) be built into Blender.

Compositor node tree already has functionality like this for “Image” node for example.

I started digging. I started off trying to get a shader node to have a preview image like this. Picked a Voronoi Noise one for proof of concept target.
First part was quite promising, just adding “NODE_PREVIEW” to flags when node is created:

sh_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE, NODE_PREVIEW);

That has gotten me much further than I thought, as that already added the clickable “expand preview” image, it already started allocating space for preview image inside the node.

The next step I had was to just populate preview image with “something” (just a full red image) the preview.
And that’s where I started getting lost in where I should be injecting things.
I tried looking at https://wiki.blender.org/wiki/Source, but I couldn’t find overview of how the nodes editor and node trees are working.

I found that “previews” (bNodePreview) are property of “node tree” as a whole, and not something associated with bNode itself.
So the ntree object has the node structure under it and separately it stores previews for those nodes.
I see that one must call BKE_node_preview_init_tree to create hash map for preview objects.

This is where I started getting lost. It looks like BKE_node_preview_init_tree is not called for shader node trees at all. And I can’t grasp where the shader node tree is constructed/allocated (as I was thinking call to BKE_node_preview_init_tree should be part of construction).

The other problem I hit is that I am not clear where “refresh of preview” should happen. Looking at drawnode.cc and node_draw.cc they don’t seem to handle refresh. When that code runs it seems to just copy over what already is in bNodePreview.
I can’t however find the place where bNodePreview buffer is filled.
I thought that node_shader_update_tex_voronoi would be the place to update the preview (it sounds like a function that gets called every time something about input to node changes).
The snag with this is that I can’t work out how to look up bNodePreview given bNode and bNodeTree.
There is BKE_node_instance_hash_lookup, but that takes a bNodeInstanceKey. This one seems to be something I could get by calling BKE_node_instance_key, but this one takes an unexpected (by me) argument “parent_key”, and I am not quite clear how I would work that one out. At least without, what seems like really inefficient way of doing it, recursing over bNodeTree looking for the specific bNode.

Please correct me if I got something wrong.

So with all this context I was hoping someone could help me with those questions:

  • is this even right forum to ask this sort of question?
  • where in code should I be looking at to add BKE_node_preview_init_tree to shader node trees?
  • where in code should I be looking at to update bNodePreview for shader nodes?
4 Likes

This is the right forum for these questions.

Before starting to implement this it’s important understand how shader nodes are actually executed in Cycles and Eevee. Both renderers translate the shader node graph into their own representation, which is then optimized and compiled.

The simplest implementation of previews most likely involves doing a bunch of small renders, one for each node, and for each compiling a shader for the relevant subset of the shader nodes. This is not the most efficient, but especially with larger shader graphs and many previews it will be rather slow. However the alternative would be to make deep changes to the shader code generation for Cycles and Eevee, which is a rather complex project.

It’s probably easiest to generate node previews from the drawing code, similar to how e.g. previews icons of materials are made. Something along the lines of:

  • Detect when a material changes in ED_render_id_flush_update and mark any existing previews as outdated.
  • When drawing the preview and it’s missing or outdated, launch a job to render it. ED_preview_icon_job is an example of how that works for preview icons, nodes could do something simpler.
  • In the job, render a plane with a special material assigned. The preview render code already has a mechanism for making a local copy of the shader node tree. This node tree can then be modified to link the current node’s output directly to the material output.

The instance key is there for distinguishing between the same nodes in different node groups. The parent_key is the key of the parent node group node, or NODE_INSTANCE_KEY_BASE if the node is not in a node group. The node editor drawing code should have access somehow to the list of group nodes that a particular node being draw is in.

1 Like

I have been trying to get a bit further using hints you gave, however the more I read the code the more it feels like I am trying to bite more than I can chew.
Even going with the simpler approach, I also realised conceptual problem. Nodes have many different outputs, and it is not clear to me which of the output the preview should be of.

I think I will have to pass on trying to implement this, at least at this point in time.
I might keep on looking for something smaller to dabble in (i.e. from Good First Issue list)