[SOLVED][Q]What or how is the icon generated in the material list UI

Im would like to know if some one knows how the icon in the Material List is created. I want to add this for an external render engine, most is already working but when i change diffuse color it doesnt update this small icon.

Ive tried looking at template_lists and then at “MATERIAL_UL_matslots”. But it only states icon and im stuck at this point.

This is the code from the main source

class MATERIAL_UL_matslots(UIList):

    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        # assert(isinstance(item, bpy.types.MaterialSlot)
        # ob = data
        slot = item
        ma = slot.material
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            if ma:
                layout.prop(ma, "name", text="", emboss=False, icon_value=icon)
            else:
                layout.label(text="", icon_value=icon)
            if ma and not context.scene.render.use_shading_nodes:
                manode = ma.active_node_material
                if manode:
                    layout.label(text=iface_("Node %s") % manode.name, translate=False, icon_value=layout.icon(manode))
                elif ma.use_nodes:
                    layout.label(text="Node <none>")
        elif self.layout_type == 'GRID':
            layout.alignment = 'CENTER'
            layout.label(text="", icon_value=icon)

This is how cycles and blender internal show the preview icons. The engine i use simply shows the preview from cycles when i switch it but does not update to the changed color than. First i was always black. So i imported the classes for this part into the addon and adjust its names.

But that doesnt help me.

anyone with knowledge, please CC

How cycles show mat icon in the material list

How it looks in the engine i use with custom added the Materiallist and MATERIAL_UL_matslots

To be more clear, this is what im talking about

Cycles engine

My addon engine

To generate the small material preview icon, a regular material preview is started (renderengine instance with is_preview == True).
You can only recognize that it’s for the icon from the small render dimension size.

Thanks, the main preview is working. That one fires by it self, i still dont have that one figured out as well. I know when a scene is named “preview” it will render the preview window.

How can i add this “is_preview = True” tag ?

Code for preview render material

Preview scene works and updates. I dont know how it fires that action as well. I think the Panel is doing that.

I had a quick look in other files. I found this part in the freestyle script and the sequencer script.
Ill study these than and see what it does or how i can use this. Hope this works.

I also noticed it in Cycles init file. I dont see it in bledner internal code. The BI engine also does it.

Anyways, many thanks… I got something to work with now, lets hope this works for me :slight_smile:

You don’t set the is_preview attribute, you read it to check wether you are rendering a preview or final render.
https://docs.blender.org/api/2.79/bpy.types.RenderEngine.html?highlight=is_preview#bpy.types.RenderEngine.is_preview

If your material preview is already working, I don’t see why the icons shouldn’t work as well.
Did you write the whole addon yourself, or was it done by someone else?
Many external renderers don’t render the preview icons (e.g. my own LuxCore addon does not do this as well) because it can lead to serious lag when it’s done through the Pyton API (BI/Cycles have an advantage here).
For example, BlendLuxCore has this check: https://github.com/LuxCoreRender/BlendLuxCore/blob/master/engine/preview.py#L32
Try to search for such a condition in your addon.

But its not the main material preview right?

PS i just saw this tag " bl_use_preview

Should i add this as well than?

EDIT
ow i see its already there in the addon
Im getting confused now weither or not this is for the small icon or the standard preview render. The last one is working already

To be honest, I have no idea.
Most of the “bl_use_…” attributes are not documented and did nothing in my tests, but I did not dig into this further.

Not sure I understand what you mean, however there are three ways a renderengine is called by Blender for rendering:

  • update(), then render(), is_preview == True:
    This means a material preview should be rendered (can be the “big one” in the material properties or the small icons for the material list).
  • update(), then render(), is_preview == False:
    This means final render.
  • view_update(), then view_draw():
    This means viewport render.
1 Like

I think the is preview is for the Preview panel and not the icon in the material list ui.

I just quickly added the example engine from that page and also added the material UI panel
MATERIAL_PT_context_material

I changed the green and it doesnt update the small icon neither. So its not this is_preview i think

Unless im missing something here?

Ill try that update, see if it works

Do you know how i can call the function Def Render(self, context) from the update function?

I used part of cycles, i commented most out because i got errors with that. So thought first test it doing a preview render. But i cant seem to be able to call the render function from the update function

I tried self.render() but i get an error "‘RenderSettings’ object is not callable "

You can not call update() and render() yourself, they are called by Blender.
Your implementation of the RenderEngine class just defines them.

In cycles things are done with sessions and create. i see the update is working now when i added. But i dont understand how these are passed to really start something to preview.

As i cant call the render part it self. I have no idea how it actually starts than?

I think i sort of understand now. In this addon the preview is somehow hardcoded into the main render fucntion.

I added this part to render engine, its the part of the simple render from that api page.

def render_preview(self, scene):

		pixel_count = self.size_x * self.size_y

		# The framebuffer is defined as a list of pixels, each pixel
		# itself being a list of R,G,B,A values
		green_rect = [[1.0, 1.0, 0.0, 1.0]] * pixel_count
		#green_rect = [[bpy.data.materials[bpy.context.object.active_material.name].diffuse_color]] * pixel_count

		# Here we write the pixel values to the RenderResult
		result = self.begin_result(0, 0, self.size_x, self.size_y)
		layer = result.layers[0].passes["Combined"]
		layer.rect = green_rect
		self.end_result(result)

I noticed the preview show the green and than later was added as an icon. So im now gonna try to add the preview render part which is in the main render engine function.

See here is the top part of the main render funcion. I think the preview part should not be here but in the render_preview function. Its not there now but with the test i did, than the icon seems to be updating :slight_smile:

def render(self, scene):
		def testBreak(self):
			if self.test_break():
				thea_globals.log.debug("## KILL ENGINE")

		global exporter, tmpTheaRenderFile, imgTheaRenderFile, scn, outputImage, selectedObjects, dataPath, materialUpdated

		(exportPath, theaPath, theaDir, dataPath, currentBlendDir, currentBlendFile) = setPaths(scene)
		scale = scene.render.resolution_percentage / 100.0
		self.size_x = int(scene.render.resolution_x * scale)
		self.size_y = int(scene.render.resolution_y * scale)
		if self.is_preview:
			self.render_preview(scene)

		if scene.name != "preview":
			world = bpy.context.scene.world
			# CHECK IF PATH existS
			expPath = os.path.exists(exportPath)
			if expPath == False:
				self.report({'ERROR'}, "Please check export path, See Render>Output panel")
				return {'FINISHED'}
			if world is None:
				self.report({'ERROR'}, "Please add atleast 1 world in World tab. ")
				return {'FINISHED'}
			if not camCheck():
				self.report({'ERROR'}, "Please make sure scene camera is visible")
				return {'FINISHED'}
			if len(currentBlendFile) < 2:
				self.report({'ERROR'}, "Please save the scene before exporting!")
				return {'FINISHED'}
			if (checkTheaMaterials() == False):
				self.report({'ERROR'}, "Please set materials and lights to get proper render")
				# return {'FINISHED'}
			if (checkTheaExtMat() == False):
				self.report({'ERROR'}, "Please check linked materials")
				#            thea_globals.log.debug("*** CheckMaterials = %s ***" % checkTheaExtMat())
				return {'FINISHED'}
			if not os.path.isdir(exportPath):
				self.report({'ERROR'}, "Please set proper output path before exporting!")
				return {'FINISHED'}
			if scene.thea_Selected:
				obList = [ o for o in bpy.context.scene.objects if o.select ]
				if len(obList) == 0:
					self.report({'ERROR'}, "Selection Only needs atleast 1 object")
					return {'FINISHED'}


			checkTheaExtMat()
			valuesExt = checkTheaExtMat()

			if scene.thea_useExtMatCheck:
				if (valuesExt[0] == False):
					#            self.report({'ERROR'}, "Please link Material: %s > Object: %s" % (valuesExt[1], valuesExt[2]))
					missing_Mat = ""
					for mat in valuesExt[3]:
						missing_Mat = missing_Mat + "\n" + mat
					self.report({'ERROR'}, "Please link Material:%s" % missing_Mat)
					#            thea_globals.log.debug("*** CheckMaterials = %s ***" % valuesExt[1])
					return {'FINISHED'}

		calculatePreview = True
		previewGeneratorPort = 30001
		renderInProgress = False

		r = scene.render
		material = False
		# return

		# compute resolution
		x = int(r.resolution_x * r.resolution_percentage * 0.01)
		y = int(r.resolution_y * r.resolution_percentage * 0.01)

		if (x <= 80) or (y <= 80):
			return

		def update_image(image, layer, sx, sy, x, y):
			result = self.begin_result(sx, sy, x, y)
			lay = result.layers[layer]
			# time.sleep(0.1)
			try:
				lay.load_from_file(image)
			except:
				pass
			self.end_result(result)


I probably sound fuzzy… hope you understand what im trying to explain

i tried so many things now and was able to get the solid color from the diffuse channel. So i went on search how the get pixel values and convert these to RGB value so it could construct the thumbnail.

As i was about to give up for today suddenly i see the thumbnail appear from the render preview???

It give me an error but it works. Now i need to clean the code again because its one big mess now.

I wanted to thank for pointing out the “render_preview” part. Know i need to check if the external linked material also still work.

Im also thinking of using a simple scene for the icon which renders just a sphere