Grabbing The Material Preview


#1

Hey All,

I just wrote a new post detailing my method for capturing the preview from the material editor. I thought I’d share as it’s something I’ve wanted to do for years but have not been able to figure out until now. What it does is allow high-res thumbnails to be generated to file from the material editor window. It’s also disgustingly hacky, so avert your eyes if you are of a nervous scripting disposition. :surprised

I wrote it so that I can begin writing a shader database system for work, but since I wrote this part in my spare time, I can share it with you peeps. Hopefully it will be useful for any similar material based asset tracking scripts you might want to write.

http://lonerobot.net/?p=1918


#2

I’ve got another slightly hacky way of doing it.

Install Kees’s Helium plugin, and you can use the function to get the shader ball as a bitmap value. It’s not quite as good as the real preview but it’s a lot less lines of code than yours :stuck_out_tongue:


#3

Wow, great! I don’t know why Autodesk doesn’t give access to this part directly. It would be really great to have the option to have our own material preview window inside our scripts/plugins…

Thank you!


#4

Ha, that’s because someone else did the hard work for you, Dave :smiley:

Good to know that helium can do this too though - thanks.


#5

this will do it

//********************************************************************************************
  // MtlPreviewToBitmap
  
  def_visible_primitive(MtlPreviewToBitmap, "MtlPreviewToBitmap");
  
  Value* MtlPreviewToBitmap_cf(Value** arg_list, int count)
{
	check_arg_count(MtlPreviewToBitmap, 2, count);

	MtlBase* mb = arg_list[0]->to_mtlbase();
	int sz = arg_list[1]->to_int();

	PStamp *ps = mb->CreatePStamp(sz,1);
	if(ps)
	{
		int d = PSDIM(sz);
		int scanw = ByteWidth(d);
		int nb = scanw*d;

		UBYTE *buf = new UBYTE[nb + sizeof(BITMAPINFOHEADER)];
		if(!buf)
			 &undefined;

// get the image data

		ps->GetImage(&buf[sizeof(BITMAPINFOHEADER)]);
		
// and create the header info		
		
		BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)buf;
		bih->biSize = sizeof(BITMAPINFOHEADER);
		bih->biWidth = d; 
		bih->biHeight = d; 
		bih->biPlanes = 1; 
		bih->biBitCount = 24;
		bih->biCompression = BI_RGB;
		bih->biSizeImage = 0;
		
		Bitmap *map = TheManager->Create((PBITMAPINFO)buf);
		delete [] buf;

		if(map)
		{
			one_typed_value_local(MAXBitMap* mbm);
			vl.mbm = new MAXBitMap();
			vl.mbm->bi.CopyImageInfo(&map->Storage()->bi);
			vl.mbm->bi.SetFirstFrame(0);
			vl.mbm->bi.SetLastFrame(0);
			vl.mbm->bi.SetName("");
			vl.mbm->bi.SetDevice("");
			if(vl.mbm->bi.Type() > BMM_TRUE_64)
				vl.mbm->bi.SetType(BMM_TRUE_64);
			vl.mbm->bm = map;
			return_value(vl.mbm);
		}
	}
	return &undefined;
}

sz = 0 -> 3232
sz = 1-> 88
88
sz > 1 -> 24*24

display (MtlPreviewToBitmap (getMeditMaterial 1) 0)	

edited to remove memcpy


#6

Is it possible to do the other way around?
Meaning - sending in a custom bitmap as a ‘material preview’?

The reason why I ask is because in a exporter I’ve been working on for a long time has it’s own ‘preview tab’ in the material, which then shows the external rendered preview image.
It would be very nice to send that image back into the material slot directly instead.

The exporter calls on a external renderer, that’s why it works with the current setup - we render a preview scene externally, save to a file named the same as material, then when you open that material in the editor it just shows that image.


#7

yes but I think it would need a custom mtl plugin which overides the mtlbase pstamp routines.

it might be possible without the use of a custom mtl, as the PStamp object has a setimage method.


#8

very nice! could you post it on “useful mxs extensions” thread, please?


#9

Thank you guys for sharing this.

@Pete:
There is a action that opens the preview (“Magnify”) window. Perhaps you may want to check it out and see if that could replace the double click hack?

actionMan.executeAction 2 "40296"

#10

Hi Chaps,

thanks for all your input.

Klunk - For those of us not clear about how to approach the SDK, is this method easily usable? My limit is that I’ve built an SDK maxscript extension before, is this a case of adding this and re-compiling? Many thanks for your solution

PolyTools3d - Thanks a million, anything to remove some of my hacky steps is awesome, I’ll change the code and update the article, I’m sure that will work much better.


#11

the easiest way is to copy and paste into the any of the files of the mxsagni project in the samples and recompile (as release) it and replace the mxsagni.dlx in stdplugins with the newly compiled version.


#12

Klvnk. could you make a tutorial how to do this please? When I look to Useful mxs sdk extension functions I understand that for some people it is useful, but unfortunately not for me, because I don’t know how to use them :frowning:

Or, at least, point us to a “short” tutorial.


#13

Yes please Klunk, that would be an awesome tutorial. I’d love to use that function.


#14

guys! using MAX sdk is the power. (Klunk can confirm it :))


#15

almost all functions in the “useful maxscript extentions” thread are really-really useful.


#16

thanks Klvnk, would it be possible to add “cleaan way” or if possible on the fly compile like in C# code ?


#17

I’m sure it’s possible but I’m probably not the man for that sort of thing c# is not my bag ! :slight_smile:


#18

Can anyone verify if this works? I’ve tried this call in 2013, 2014 and 2015 and it returns false with no material window magnified.

I’d +1 for a SDK heads up if anyone was kind enough to do it.


#19

Ack, my bad - its just a focus issue, you need to call MatEditor.Open() before you run the actionman item.


#20

it’s a Material Editor action. it means the editor has to be in focus when you execute this action.

edited

oops. you already answered your question