Cycle through option for selfIllumAmount in Standard material


#1

Hi,

I want a button to cycle through these options for my material:
.selfIllumAmount = 20
.selfIllumAmount = 100
.selfIllumAmount = 0

How can I do it?


#2
(
	myMat = selection[1].material
	selfIllumVal = myMat.selfIllumAmount
	
	format "Before: %\n" myMat.selfIllumAmount
	
	case selfIllumVal of
	(
		0: myMat.selfIllumAmount = 20
		20: myMat.selfIllumAmount = 100
		100: myMat.selfIllumAmount = 0
		default: 0
	)
	
	--	"check"
	format "After: %\n" myMat.selfIllumAmount
)

#3

thank you, but it actually stuck at 20 and never proceed to the next case


#4
(
	rollout RO_BUTTON_CYCLE "" width:110 height:48
	(
		button bt_cycle "Cycle" pos:[8,8] width:96 height:32
		
		local list = #(0, 20, 100)
		local current = 1
		local mat
		
		on bt_cycle pressed do
		(
			current = if current == list.count then 1 else current+=1
			mat.selfillumamount = list[current]
		)
	)
	createdialog RO_BUTTON_CYCLE
	
	delete objects
	RO_BUTTON_CYCLE.mat = (converttomesh (sphere material:(standard diffuse:red selfillumamount:0))).mat
)

You can also keep track of the variable “current” in an item of the array (list) if you don’t want to keep track of two variables.

(
	rollout RO_BUTTON_CYCLE "" width:110 height:48
	(
		button bt_cycle "Cycle" pos:[8,8] width:96 height:32
		
		local list = #(2, 0, 20, 100)
		local mat
		
		on bt_cycle pressed do
		(
			mat.selfillumamount = list[ if list[1] == list.count then list[1]=2 else list[1]+=1 ]
		)
	)
	createdialog RO_BUTTON_CYCLE
	
	delete objects
	RO_BUTTON_CYCLE.mat = (converttomesh (sphere material:(standard diffuse:red selfillumamount:0))).mat
)

#5

Max2020 - no stuck. Check this video:

https://drive.google.com/file/d/1kWvRwsxVuhbGo1MjIk58qEjmIfHPfTTc/view


#6
StdMatAdvCA = attributes StdMatAdvCA attribid:#(0x3F981131, 0x7431DD17)
(
	fn getOwner = 
	(
		custAttributes.getOwner this
	)
	
	parameters params rollout:params
	(
		undoable type:#boolean default:off ui:undoable_ch
	)
	rollout params "Advanced Controls" 
	(
		checkbox undoable_ch "Undoable" across:2 
		button illum_loop_bt "Loop Self Illum" width:172 align:#right offset:[0,-3]
		
		on illum_loop_bt pressed do undo "Change Illum" undoable
		(
			if iskindof (mat = getOwner()) Standard do
			(
				si = mat.selfIllumAmount
				if keyboard.shiftPressed then
					mat.selfIllumAmount = if si <= 0 then 100 else if si <= 20 then 0 else 20 	
				else
					mat.selfIllumAmount = if si >= 100 then 0 else if si >= 20 then 100 else 20 	
			)
		)
		on illum_loop_bt rightclick do undo "Change Illum" undoable
		(
			if iskindof (mat = getOwner()) Standard do
			(
				mat.selfIllumAmount = 0
			)
		)
	)
)

-- custattributes.add meditmaterials[1] StdMatAdvCA

#7

These are all very clever solutions. Thank you.

@miauu, unfortunately, I need it to work down to 2016 version at least

@PolyTools3D, thanks it’s easy to take and adapt :slight_smile:

@denisT, unfortunately, I couldn’t run it on 2016 version. It’s just nothing happen


#8

@PolyTools3D, when I apply it to multimaterial I get different illum value for every material. I’m using this code:

local mat = $.material
for m in mat do
(
	current = if current == illum_arr.count then 1 else current+=1
	m.selfIllumAmount = illum_arr[current]
)

I illustrated illum values here:
image


#9

What do you have with this:



local mat = $.material

current = if current == illum_arr.count then 1 else current+=1

for m in mat do
(	
	m.selfIllumAmount = illum_arr[current]
)

#10

this works great.

p.s.: realized how stupid I am including multiplier inside the loop for multimaterial


#11

unfortunately you don’t want to try to understand the code which of course works in any version.


#12

@PolyTools3D, unfortunately, it returns random result if I applied it to several objects, any way to adjust the code?

@denisT, you’re right, params and attributes are too complicated for me. My task right now is not to learn maxscript, but to sort out the materials. However, I learn something every time I ask for help.


#13

If you want to see how CA works in this case, uncomment the last line in my code and run the whole code.

Expecting the first material in the material editor is the Standard material, you will get a user interface created by applying CA to the material. This user interface will be available through both the Compact and Slate Mat editors. You should see an additional “Advanced Controls” rollout with a “Loop” button.


#14

From a usability point of view, a solution with a single button that sets one of the predefined values in a loop is inconvenient. It’s easier in all respects to make N buttons with a specific value for each.
In our case, it’s better to make three buttons “0”, “20”, and “100”…
It is easier to implement from the code side, it is clearer from the point of view of the user interface, it is easier to change and expand it functionally.


#15

Play with this:

StdMatAdvCA = attributes StdMatAdvCA attribid:#(0x3F981131, 0x7431DD17)
(
	fn getOwner = 
	(
		custAttributes.getOwner this
	)
	
	parameters params rollout:params
	(
		undoable type:#boolean default:on ui:undoable_ch
		illumAmounts type:#inttab tabSize:5 tabSizeVariable:false
		
		on illumAmounts set val i do
		(
			this.params.updateIllumButtons()
		)
		
	)
	rollout params "Advanced Controls" 
	(
		local btw = 26
		
		checkbox undoable_ch "Undoable" across:2
		button illum_loop_bt "Loop Self Illum" width:(5*(btw + 2) - 2) align:#left offset:[16,-3]
		button illum_bt0 "" width:btw pos:(illum_loop_bt.pos + [0*(btw + 2),24])
		button illum_bt1 "" width:btw pos:(illum_loop_bt.pos + [1*(btw + 2),24])
		button illum_bt2 "" width:btw pos:(illum_loop_bt.pos + [2*(btw + 2),24])
		button illum_bt3 "" width:btw pos:(illum_loop_bt.pos + [3*(btw + 2),24])
		button illum_bt4 "" width:btw pos:(illum_loop_bt.pos + [4*(btw + 2),24])
		
		local illum_bts = #(illum_bt0, illum_bt1, illum_bt2, illum_bt3, illum_bt4)
		
		fn updateIllumButtons = 
		(
			for k=1 to illumAmounts.count do
			(
				illum_bts[k].text = illumAmounts[k] as string
			)
		)
		
		fn setIllumAmount index:1 = undo "Change Illum" undoable 
		(
			if iskindof (mat = getOwner()) Standard do
			(
				mat.selfIllumAmount = illumAmounts[index]
			)
		)
		fn getIllumAmount index:1 = undo "Store Illum" on 
		(
			if iskindof (mat = getOwner()) Standard do
			(
				illumAmounts[index] = mat.selfIllumAmount
			)
		)
		
		on illum_bt0 pressed do setIllumAmount index:1
		on illum_bt1 pressed do setIllumAmount index:2
		on illum_bt2 pressed do setIllumAmount index:3
		on illum_bt3 pressed do setIllumAmount index:4
		on illum_bt4 pressed do setIllumAmount index:5

		on illum_bt0 rightclick do getIllumAmount index:1
		on illum_bt1 rightclick do getIllumAmount index:2
		on illum_bt2 rightclick do getIllumAmount index:3
		on illum_bt3 rightclick do getIllumAmount index:4
		on illum_bt4 rightclick do getIllumAmount index:5
		
		on illum_loop_bt pressed do undo "Change Illum" undoable
		(
			if iskindof (mat = getOwner()) Standard do
			(
				si = mat.selfIllumAmount
				if keyboard.shiftPressed then
					mat.selfIllumAmount = if si <= 0 then 100 else if si <= 20 then 0 else 20 	
				else
					mat.selfIllumAmount = if si >= 100 then 0 else if si >= 20 then 100 else 20 	
			)
		)
		on illum_loop_bt rightclick do undo "Change Illum" undoable
		(
			if iskindof (mat = getOwner()) Standard do
			(
				mat.selfIllumAmount = 0
			)
		)
		
		on params open do
		(
			updateIllumButtons()
		)
	)
	
	on postcreate do
	(
		illumAmounts = #(0,20,50,80,100)
	)
	on update do
	(
		illumAmounts = #(0,20,50,80,100)
	)
)

--custattributes.add meditmaterials[1] StdMatAdvCA

:wink:


#16

Yes, the code can be modified, but you need to be very specific about what you are trying to achieve.


#17

@PolyTools3D, thanks for your work : -0 I have many different models. All of them are built with Standard materials. Some models have multimaterials built with a list of Standard materials. Initial Illumination amount for all the models set to 0.

I want to select the model or group of models and cycle the Illumination value for every material of the selected model(s) between 0, 20 and 100.

@denisT, thanks for the script, :slight_smile: I’m building quick tools for myself most of the time and want to keep the work with the UI as focus as possible in a particular area of the screen. The more buttons I make, the less efficient I became. I don’t like this, that’s why I just put a tooltip to a button if it’s really needed. I will try the script now :wink:


#18

This script will cycle the materials illumination amount on the selected objects.

Notes:
The script does not track individual materials values, so all the materials on the selected objects will be set to the same illumination amount, and the “current” value will keep cycling over and over.

If what you need is to keep track of each individual illumination amount, and cycle them individually to the next value, things will get a bit more complex.

(
	-- TEST SCENE FUNCTIONS -------------------------------------------------------------------------------
	fn GetRandomColor =
	(
		clr = random black white
		clr.s = 100
		clr.v = 255
		return clr
	)
	
	fn CreateMultiMaterial =
	(
		mm = multimaterial numsubs:9
		for j = 1 to 9 do
		(
			mm[j].diffusecolor = GetRandomColor()
			mm[j].selfillumamount = 0
		)
		return mm
	)
	
	fn CreateNodes =
	(
		for j = -2 to 2 do
		(
			for k = -2 to 2 do
			(
				obj = converttopoly (plane pos:[j*30, k*30, 10] lengthsegs:3 widthsegs:3 wirecolor:black)
				
				if (random 1 3) == 1 then
				(
					for i = 1 to 9 do polyop.setfacematid obj i i
					obj.mat = CreateMultiMaterial()
				)else(
					clr = GetRandomColor()
					obj.mat = standard diffuse:clr selfillumamount:0
				)
			)
		)
	)
	-- TEST SCENE FUNCTIONS -------------------------------------------------------------------------------
	
	try (destroydialog ::RO_BUTTON_CYCLE) catch()
	
	rollout RO_BUTTON_CYCLE "" width:110 height:48
	(
		button bt_cycle "Cycle" pos:[8,8] width:96 height:32
		
		local list = #(0, 20, 100)
		local current = 1
		
		on bt_cycle pressed do
		(
			if selection.count == 0 do return (print "No objects selected")
			
			current = if current == list.count then 1 else current+=1
			illumVal = list[current]
			
			for j in selection do
			(
				mat = j.mat
				
				if iskindof mat multimaterial then
				(
					for k in mat do k.selfillumamount = illumVal
				)
				else if iskindof mat standardmaterial then
				(
					mat.selfillumamount = illumVal
				)
				else
				(
					format "Invalid Material: node:% material:%\n" j.name mat
				)
			)
		)
	)
	createdialog RO_BUTTON_CYCLE
	
	-- CREATE TEST SCENE
	delete objects
	CreateNodes()
	gc()
)

#19

I think this is the solution, it’s clear and working great, thank you :slight_smile: