ScriptSpot

Forum topic · General Scripting

bitmap switcher

By ste · 2014-07-03

Description

Another script...another newbie problem!

I'm trying to develop a script that let me change diffuse texture of a certain material.
I started studying Joe Gunn old script "face switcher": this script change material ID (but first we need to create a multiamterial with a lot of submaterials with different textures), while I think it's faster to have only one material and change its texture.
The script let you choose a directory to sort bitmap from, create thumbnails and...nothing.
The scope is to change material texture clicking on the corresponding thumbnail and to create a keyframe for material diffuse slot.

This is my result:


try(destroyDialog ::texchange)catch()
rollout texchange"TEXTURE CHANGE"

(	
--interface
	button btnSetD "Set Dir:" pos:[5,5] width:50 height:20 toolTip:"directory immagini"  
	edittext Fdir "" pos:[55,5] width:100 height:20
	button btn01 "01" pos:[5,30] width:30 height:30  
	button btn02 "02" offset:[-30,-35] width:30 height:30
	button btn03 "03" offset:[0,-35] width:30 height:30  
	button btn04 "04" offset:[30,-35] width:30 height:30
	button btn05 "05" offset:[60,-35] width:30 height:30
--choose bitmap path
	on btnSetD pressed do
	(
		local curpath = Fdir.text 
		local newPath = getSavePath initialDir:(curpath) caption:"Select the path where your Face Images are located" 
		if newPath != undefined then	
--create thumbnails
		(
			Fdir.text = newpath
			btn01.images = #(Fdir.text + "\01.png", Fdir.text + "\01.png", 1, 1, 1, 1, 1)
			btn02.images = #(Fdir.text + "\02.png", Fdir.text + "\02.png", 1, 1, 1, 1, 1)
			btn03.images = #(Fdir.text + "\03.png", Fdir.text + "\03.png", 1, 1, 1, 1, 1)
			btn04.images = #(Fdir.text + "\04.png", Fdir.text + "\04.png", 1, 1, 1, 1, 1)
			btn05.images = #(Fdir.text + "\05.png", Fdir.text + "\05.png", 1, 1, 1, 1, 1)
		)
	)
--actions
	on btn01 pressed do
	(	
--and here the problem... load 1st thumbnail image to object material
	)
	on btn02 pressed do
	(	
--same, and so on...
	)	
)
createdialog texchange 160 200 10 110 style:#(#style_titlebar, #style_sysmenu, #style_toolwindow)

I hope to have been clear enought... any idea?

Comments (27)

dalmirobu · 2014-10-06

This work fine for me!!! THANKS!!!

You are Awasome!

Great job!!!

dalmirobu · 2014-09-29

Could you please share this script? I would be very useful.

thank you very much

Thanks!

ste · 2014-09-30

It could be a good tool, but I really need some help to finish it because it's full of bugs!!

Here the complete and commented code (I forget something... but some time has passed, sorry).

I have attacherd a zip file containing the script, a simple scene (max 2010) and 2 textures just to speed up testing process.


----- FACE SWITCHER V.0.1
----- This is a scripted modifier
----- It allows you to change object texture editing bitmap cropping and placement

----- INSTALLATION:
----- put this file in ...maxfolder\stdplugs\stdscripts\ before to open max

----- USE:
----- Create your bitmap with aspect ratio 10:1. This must contain 10 square images side to side
----- Put it in diffuse channel of your material (that must be a VrayMtl, and must be ID#1 of a Multi/Sub-Object material)
----- Set bitmap cropping to W:0.1 H:1.0 (so only the first image is used)
----- Assign Multi/Sub-Object material to your object
----- Add "Face switcher DEV" modifier to your object
----- Click on "Pick Obj": bitmap name should appear in text box and thumbnails in numbered boxes (in this step the script create a lowres version of your bitmap to use in UI, same folder, same format, same name with suffix "_lowres")
----- Done! Now you can change your texture clicking on each thumbnail
----- If you move the time slider and change the texture, keyframes are created automatically (stepped)

----- PROBLEMS/BUGS:
----- Works only with multisubmat
----- Material with bitmap to switch must have ID#1
----- If you use a bitmap with alpha the small one created for UI is terrible (tried jpg, bmp, tiff, png... no way, but this is a max problem I think)
----- If you use it on more than one object with different materials (and bitmap of course) UI icons are always the same, even if texture name displayed is right
----- Something that I forgot for sure...

----- Probably there are errors and inaccuracies in this script, but this is one of my first tries and I know I miss the basics


plugin modifier Face_switcher_DEV
name:"Face switcher DEV"
classID:#(0x133078, 0x54409)
version:1


--- CREATE UI
(	
	parameters main rollout:test
	(
		obj type: #string  ui:obj animatable:false
	)
	
	rollout test "FACE SWITCHER" width:162

	(	
	button pickObj "Pick Obj" pos:[5,5] width:50 height:20
	edittext obj "" pos:[55,5] width:100 height:20
	
	button btn01 "01" pos:[5,30] width:50 height:50  
	button btn02 "02" offset:[-1,-55] width:50 height:50
	button btn03 "03" offset:[49,-55] width:50 height:50  
	button btn04 "04" offset:[-51,-5] width:50 height:50
	button btn05 "05" offset:[-1,-55] width:50 height:50
	button btn06 "06" offset:[49,-55] width:50 height:50
	button btn07 "07" offset:[-51,-5] width:50 height:50
	button btn08 "08" offset:[-1,-55] width:50 height:50
	button btn09 "09" offset:[49,-55] width:50 height:50  
	button btn10 "10" offset:[-51,-5] width:50 height:50

		
--- PICK OBJECT TEXTURE, CREATE LOWRES VERSION, SAVE IT AND PUT IT IN UI
	on pickObj pressed do
	(
		--- GET MATERIAL TEXTURE
		local TEXTURE_NAME = $.material[1].TEXMAP_diffuse.filename
		
		--- FUNCTION TO OPEN TEXTURE
		local TEXTURE = openbitmap $.material[1].TEXMAP_diffuse.filename
		
		--- CANT'T REMEMBER SORRY
		local TEXMAP = bitmaptexture bitmap:(openBitmap TEXTURE_NAME)
		
		--- TEXTURE WIDTH, HEIGHT AND ASPECT RATIO
		w = TEXTURE.width
		h = TEXTURE.height
		c = w/h
		
		--- THUMBNAIL SIZE, BASED ON ORIGINAL TEXTURE ASPECT RATIO
		local THUMB_SIZE = [c*50, 50]
		
		--- GENERATE THUMBNAIL
		local THUMBNAIL = renderMap TEXMAP size:THUMB_SIZE filter:on
		THUMBNAIL.filename = (getFilenamePath TEXTURE_NAME + getFilenameFile TEXTURE_NAME + "_lowres" + getFilenameType TEXTURE_NAME)   
		
		--- SAVE THUMBNAIL
		save THUMBNAIL
		
		--- CLOSE THUMBNAIL
		close THUMBNAIL
				
		--- CANT'T REMEMBER SORRY AGAIN
		filename = filterstring TEXTURE_NAME "\\"
		filename = filename[filename.count]
		
		--- SUBDIVIDE THUMBNAIL OVER 10 UI BUTTONS
		btn01.images = #(THUMBNAIL, THUMBNAIL, c, 1, 1, 1, 1)
		btn02.images = #(THUMBNAIL, THUMBNAIL, c, 2, 2, 1, 1)
		btn03.images = #(THUMBNAIL, THUMBNAIL, c, 3, 3, 1, 1)
		btn04.images = #(THUMBNAIL, THUMBNAIL, c, 4, 4, 1, 1)
		btn05.images = #(THUMBNAIL, THUMBNAIL, c, 5, 5, 1, 1)
		btn06.images = #(THUMBNAIL, THUMBNAIL, c, 6, 6, 1, 1)
		btn07.images = #(THUMBNAIL, THUMBNAIL, c, 7, 7, 1, 1)
		btn08.images = #(THUMBNAIL, THUMBNAIL, c, 8, 8, 1, 1)
		btn09.images = #(THUMBNAIL, THUMBNAIL, c, 9, 9, 1, 1)
		btn10.images = #(THUMBNAIL, THUMBNAIL, c, 10, 10, 1, 1)
		obj.text = filename
	)

	
--- ACTION ON BUTTON PRESSED, SAME FOR ALL
	on btn01 pressed do if selection.count != 0 do
	(
		if (mtl = selection[1].mat) != undefined do
		(
			mtl = getClassInstances VRayMtl target:mtl
			if mtl.count != 0 do if isKindOf (map = mtl[1].TEXMAP_diffuse) bitmaptex do
			(
				
				--- SET AUTOKEY ON AND DEFINE BITMAP PLACEMENT
				with animate on (map.clipu = 0)
				
				--- CREATE KEYFRAME - SET IN & OUT TANGENT TO STEP
				map.clipu.controller.keys.inTangentType = map.clipu.controller.keys.outTangentType = #step
			)
		)
	)
	
	on btn02 pressed do if selection.count != 0 do
	(
		if (mtl = selection[1].mat) != undefined do
		(
			mtl = getClassInstances VRayMtl target:mtl
			if mtl.count != 0 do if isKindOf (map = mtl[1].TEXMAP_diffuse) bitmaptex do
			(
				with animate on (map.clipu = 0.1)
				map.clipu.controller.keys.inTangentType = map.clipu.controller.keys.outTangentType = #step
			)
		)
	)
	
	on btn03 pressed do if selection.count != 0 do
	(
		if (mtl = selection[1].mat) != undefined do
		(
			mtl = getClassInstances VRayMtl target:mtl
			if mtl.count != 0 do if isKindOf (map = mtl[1].TEXMAP_diffuse) bitmaptex do
			(
				with animate on (map.clipu = 0.2)
				map.clipu.controller.keys.inTangentType = map.clipu.controller.keys.outTangentType = #step
			)
		)
	)
	
	on btn04 pressed do if selection.count != 0 do
	(
		if (mtl = selection[1].mat) != undefined do
		(
			mtl = getClassInstances VRayMtl target:mtl
			if mtl.count != 0 do if isKindOf (map = mtl[1].TEXMAP_diffuse) bitmaptex do
			(
				with animate on (map.clipu = 0.3)
				map.clipu.controller.keys.inTangentType = map.clipu.controller.keys.outTangentType = #step
			)
		)
	)
	
	on btn05 pressed do if selection.count != 0 do
	(
		if (mtl = selection[1].mat) != undefined do
		(
			mtl = getClassInstances VRayMtl target:mtl
			if mtl.count != 0 do if isKindOf (map = mtl[1].TEXMAP_diffuse) bitmaptex do
			(
				with animate on (map.clipu = 0.4)
				map.clipu.controller.keys.inTangentType = map.clipu.controller.keys.outTangentType = #step
			)
		)
	)
	
	on btn06 pressed do if selection.count != 0 do
	(
		if (mtl = selection[1].mat) != undefined do
		(
			mtl = getClassInstances VRayMtl target:mtl
			if mtl.count != 0 do if isKindOf (map = mtl[1].TEXMAP_diffuse) bitmaptex do
			(
				with animate on (map.clipu = 0.5)
				map.clipu.controller.keys.inTangentType = map.clipu.controller.keys.outTangentType = #step
			)
		)
	)
	
	on btn07 pressed do if selection.count != 0 do
	(
		if (mtl = selection[1].mat) != undefined do
		(
			mtl = getClassInstances VRayMtl target:mtl
			if mtl.count != 0 do if isKindOf (map = mtl[1].TEXMAP_diffuse) bitmaptex do
			(
				with animate on (map.clipu = 0.6)
				map.clipu.controller.keys.inTangentType = map.clipu.controller.keys.outTangentType = #step
			)
		)
	)	
	
	on btn08 pressed do if selection.count != 0 do
	(
		if (mtl = selection[1].mat) != undefined do
		(
			mtl = getClassInstances VRayMtl target:mtl
			if mtl.count != 0 do if isKindOf (map = mtl[1].TEXMAP_diffuse) bitmaptex do
			(
				with animate on (map.clipu = 0.7)
				map.clipu.controller.keys.inTangentType = map.clipu.controller.keys.outTangentType = #step
			)
		)
	)	
	
	on btn09 pressed do if selection.count != 0 do
	(
		if (mtl = selection[1].mat) != undefined do
		(
			mtl = getClassInstances VRayMtl target:mtl
			if mtl.count != 0 do if isKindOf (map = mtl[1].TEXMAP_diffuse) bitmaptex do
			(
				with animate on (map.clipu = 0.8)
				map.clipu.controller.keys.inTangentType = map.clipu.controller.keys.outTangentType = #step
			)
		)
	)	
	
	on btn10 pressed do if selection.count != 0 do
	(
		if (mtl = selection[1].mat) != undefined do
		(
			mtl = getClassInstances VRayMtl target:mtl
			if mtl.count != 0 do if isKindOf (map = mtl[1].TEXMAP_diffuse) bitmaptex do
			(
				with animate on (map.clipu = 0.9)
				map.clipu.controller.keys.inTangentType = map.clipu.controller.keys.outTangentType = #step
			)
		)
	)

	)
)
Attachments

EUREKA!

ste · 2014-07-04

It works!
...with my stupid $ and vraymaterial, but it works!!


...
btn01.images = #(Fdir.text + "\lowres.jpg", undefined, 5, 1, 1, 1, 1)
btn02.images = #(Fdir.text + "\lowres.jpg", undefined, 5, 2, 1, 1, 1)
btn03.images = #(Fdir.text + "\lowres.jpg", undefined, 5, 3, 1, 1, 1)
btn04.images = #(Fdir.text + "\lowres.jpg", undefined, 5, 4, 1, 1, 1)
btn05.images = #(Fdir.text + "\lowres.jpg", undefined, 5, 5, 1, 1, 1)
...
on btn01 pressed do 
( $.material.texmap_diffuse.clipu = 0 )
on btn02 pressed do 
( $.material.texmap_diffuse.clipu = 0.2 )
on btn03 pressed do 
( $.material.texmap_diffuse.clipu = 0.4 )
on btn04 pressed do 
( $.material.texmap_diffuse.clipu = 0.6 )
on btn05 pressed do 
( $.material.texmap_diffuse.clipu = 0.8 )
...

Now I have to make it works with multimaterial and create keyframe automatically :)

barigazy · 2014-07-04

Just try

with animate on (selection[1].material.texmap_diffuse.clipu = 0.4)

.

ste · 2014-07-04

Perfect on vraymtl, but does not work on multisub material :(

barigazy · 2014-07-04

I already post example how to manage nested VRayMtl inside any material (Multimaterial, Blend, VRayBlend, VRayLight etc.)

.

ste · 2014-07-04

Yup,
and your advice have produced good results :)


on btn03 pressed do if selection.count != 0 do
 (
  if (mtl = selection[1].mat) != undefined do
   (
    mtl = getClassInstances VRayMtl target:mtl
     if mtl.count != 0 do 
      if isKindOf  (map = mtl[1].texmap_diffuse) bitmaptex do with animate on (map.clipu = 0.4)
   )
  )

Did I worked well?
:)

barigazy · 2014-07-04

Yep. I will explain line by line

-- on button is pressed check first if selection exists
on btn03 pressed do if selection.count != 0 do
(
-- check if first item in selection have assigned material
if (mtl = selection[1].mat) != undefined do
(
-- collect all VRayMtl instance in targeted object material
-- this material can be multimaterial or any other that have VRayMtl nested inside
-- in this case I overide "mtl" variable
-- at first this variable is selection material and then array of VRayMtl's
mtl = getClassInstances VRayMtl target:mtl
-- check if array is not empty
if mtl.count != 0 do
-- check if first material in array have texturemap in diffuse slot
if isKindOf (map = mtl[1].texmap_diffuse) bitmaptex do with animate on (map.clipu = 0.4)
-- the rest you get it already ;)
)
)

.

ste · 2014-07-04

Wow, something I understood, something I missed :)

Last step is to set created keyframes to step with some


.inTangentType = #step
.outTangentType = #step

but all my attempts are failed.

barigazy · 2014-07-04

Try this

on btn03 pressed do if selection.count != 0 do
(
if (mtl = selection[1].mat) != undefined do
(
mtl = getClassInstances VRayMtl target:mtl
if mtl.count != 0 do if isKindOf (map = mtl[1].texmap_diffuse) bitmaptex do
(
with animate on (map.clipu = 0.4)
map.clipu.controller.keys[1].inTangentType = map.clipu.controller.keys[1].outTangentType = #step
)
)
)

.

ste · 2014-07-04

Almost right, with your code the 1st keyframe is stepped, while the others are not.

With


map.clipu.controller.keys.inTangentType = map.clipu.controller.keys.outTangentType = #step

works well!

barigazy · 2014-07-04

Yep.
In this example I used first object in selection, first material in array and
of course first key

:)

.

ste · 2014-07-05

One problem solved, another discovered (::disappointed::)

As a dialog works fine.
Converted into a scripted plugin works too.

But I will have more than one character in my scene and I prefer to use this tool as a modifier: if I apply it to two objects with 2 different material it works, but button thumbnails are the same even if I pick 2 different directories (with different images).

Is a local variable (path) problem?

.

ste · 2014-07-07

Path names in EditText disappered also...

Now I fix it with:


 parameters main rollout:test (
  Fdir type: #string ui:Fdir animatable:false
)

they are also saved with scene and restored on open....
but no way to fix thumbnails problem :(

Any idea?

barigazy · 2014-07-04

By using below method you can avoid any error.
I hope that you understand what i wrote.
If not then just read mxs help.

.

ste · 2014-07-04

If I wrote:


	on btn01 pressed do
	(
--texmap_diffuse because of vray material
		$.material.texmap_diffuse.filename = "C:\\test\\01.png"
	)

it works, but obviously is not what I need... it should be something like this:


	on btn02 pressed do
	(
		$.material.texmap_diffuse.filename = btn02.images
	)

but my knowledge stops here...

YEP!

ste · 2014-07-04

I find a solution... is it the right one?


 on btn01 pressed do
  (
   $.material.texmap_diffuse.filename = (Fdir.text + "\01.png")
  )

barigazy · 2014-07-04

Better use "selection[1]" then "$" sign ei

on btn01 pressed do if selection.count != 0 do
(
if isKindOf (mtl = selection[1].mat) VRayMtl do
mtl.texmap_diffuse.filename = (Fdir.text + "\01.png")
)

.

ste · 2014-07-04

You rock!

Thanks, I'm learning a lot from you in these days.

It works fine with a vraymaterial, but does not work (nor mine do) if vraymtl is a submat of a multimaterial...

barigazy · 2014-07-04

It's easy to implement this to works with any material that include VRayMtl but
you need to decide which VRayMtl must be changed.
Let say you have multimaterial with 10 sub-materials that is assigned to one object. Which sub-mat you want to have switch operation?

.

ste · 2014-07-04

It's the same.. let's say submat 1

barigazy · 2014-07-04


on btn01 pressed do if selection.count != 0 do
(
if (mtl = selection[1].mat) != undefined do
(
mtl = getClassInstances VRayMtl target:mtl
if mtl.count != 0 do
if isKindOf (map = mtl[1].texmap_diffuse) bitmaptex do map.filename = (Fdir.text + "\01.png")
)
)

.

ste · 2014-07-04

Yes, You are the man!

And now the nice part, I need to keyframe my bitmap change, but I'm not sure it is possible...I just realized that, right?

barigazy · 2014-07-04

It's not posible but...
You can use "Mix" procedural map. Put two maps and use mix amount to switch between these. Also this parameter can be animated for sure

.

ste · 2014-07-04

Uff...I know!

With mix map I can only mix up two maps.. I need more, at least 10.

I have the idea, but I need help to develop it.

1. We have a folder with 2 textures, each with 5 images side by side

2. First texture is lowres, to use for buttons thumbnail (to sort with .images array, and this is done)

3. Second texture is highres: now I put this texture in diffuse slot of my material, and then with buttons from 1 to 5 I will change its cropping and placement (btn01->place 0 crop 0.2, btn02->place 0.2 crop 0.2, btn03->place 0.4 crop 0.2, btn04->place 0.6 crop 0.2, btn05->place 0.8 crop 0.2), crating keyframes.

Is it a good idea?

barigazy · 2014-07-04

I think that this is not possible with mxs, but not sure.