Gradually brighten Colors in MaxScript

I’m following a tutorial and trying to do something on my own to see if I’ve learned anything. What the script does is creates a line of spheres that grows larger and more dense as the numbers of spheres increases. What I wanted to add was a way for the spheres to get lighter as they go along as well without changing the starting color. MXS will be my first serious attempt to learn a scripting language (i don’t count actionscript for me) so if this seems like a noob question, that’s why. He’re my entire code so far. The part I’m having trouble with is at the very bottom. I’ve managed to make the spehres darker with division, but that’s not what I want to do.:

rollout SphereTool "Spheres Creator"
	(
		--these are the UI controls
		spinner count "Number: " type:#integer range:[1,100,10]
		spinner growth "Radius growth: " range:[1,100,10]
		colorpicker ballColor "Wireframe color:" color:[127,127,127]
		button create "Create Spheres"

	--what happens when the create button is pressed.
	on create pressed do
		for i in 1 to count.value do
			sphere radius:(i*growth.value) pos:[i^2*growth.value,0,0] segs:(i*4) wirecolor:(ballColor.color*((i*ballColor.color.value)/ballColor.color.value))
	)

Unfortunately I don’t have Max installed on any machine anymore, but you’re probably having a hard time because you’re doing too much too fast/succintly.

From the listener, type in ‘c = color 128 128 128’, and evaluate. Then make sure that your colorpicker’s color.value is the same format (color class with values between 0 and 255, Max is notorious for having multiple representations of a color).

If it is, then in the listener, figure out what math you need to do to brighten it. Simplest would be something like: c2 = color (c.r + 1) (c.g + 1) (c.b + 1). Obviously that’s lame. But then you can try stuff like c2 = c * 1.1, or whatever combination of math gives you what you want.

Breaking down a problem to its fundamentals, and working and iterating on that, and then implementing it in a more complex context, is an essential skill for a programmer.

Rob couldn’t say it any better, however here is a very crude way to do it but it should point you in the right direction.

rollout SphereTool "Spheres Creator"
(
	--these are the UI controls
	spinner count "Number: " type:#integer range:[1,100,10]
	spinner growth "Radius growth: " range:[1,100,10]
	colorpicker ballColor "Wireframe color:" color:[127,127,127]
	button create "Create Spheres"

	local ourColor = [10, 10, 10]
	--what happens when the create button is pressed.
	on create pressed do
		for i in 1 to count.value do
		(
			sphere radius:(i*growth.value) pos:[i^2*growth.value,0,0] segs:(i*4) wirecolor:(ballColor.color * (ourColor * i))
		)
)
	
mainDialog = NewRolloutFloater "Sphere Maker" 300 130
addRollout SphereTool mainDialog

A more elegant way to do this would be to figure out how many spheres are being created and then calculate how much we need to be adding to the RGB values of the wirecolor. This way we are sure that the values won’t exceed 255 as they will in the example above. We could always clamp the values, but that’s no fun!

@Rob: I didn’t think I was moving too fast because it seemed like something that would be simple, but I guess you’re right. I started thinking about more ways to do it after posting my questions and I did figure out that separating the RGB values would be a better approach, but I didn’t have time to try it out. But since you’re saying this is too complex for me right now, I’ll just leave it alone till I get more comfortable.

@Ryan: I think I get what you’re saying. The ourColor variable kinda lost me though. And I was thinking about clamping, but since I’m just beginning, I didn’t want to do that or think it was necessary. As of now, the most technical experience I have is the material editor in UDK, so I was starting to think along those lines. Thanks.

Let me clarify- I don’t think what you are doing is too complex. Actually I think what you’re doing is the perfect complexity. You just didn’t tackle things one at a time- you had a series of relatively simple components (basic syntax, programming concepts, understanding Max UI, getting familiar with max data structures, event handlers, colors)- the problem is just that you tried to tackle the last of them at the same time as tackling all the previous ones. If you tackle each individually and then string them together, you’ll have a much easier time. The same concept applies to if you had a complex algorithm that ran when you pressed a button on a nested UI- you wouldn’t want to iterate on and fix that algorithm having to go through the UI, you’d write it as a function you could run from code/interpreter to test and tweak it.

Speaking of which, it’d probably help you (and would definitely make your code clearer) if you made some functions for all the math you’re doing, rather than handling it inline.

If you’re feeling overwhelmed or feeling that this is to complex for you at the moment, a great place to look is the max script docs. However I too feel that a script like this is a good place to get your hands dirty with MXS.

Out of all the docs I’ve had to use, the max script docs are very complete feeling, IMO. This might help, it’s aimed at 2012 so you might want to open it through the help menu within max and navigate to this section instead:

http://docs.autodesk.com/3DSMAX/14/ENU/MAXScript%20Help%202012/index.html?url=files/GUID-676FB825-84C1-4708-A398-993266E4D2A-300.htm,topicNumber=d28e97490

Also, in my modification to your script I just declared a local vector those 3 values correspond to RGB just as ballColor.color does. I allowing me to multiply them together and get a overall brightness increase easily. As rob says, it’s probably best to split everything for clarity, good learnin’ to be done there as well. :slight_smile:

@ Rob: I did tackle my problems one by one and finally came up with the results I wanted. I opted for a gradient formula instead of just making it brighter. One wierd problem i kept running into is how max deals with parenthesis in a problem. Even though (x)(y) is the same thing as (x)*(y), max seems to prefer the latter.
Unfortunately, I don’t have a really good grasp on functions yet to try them out. I’m working on that since I seems them everywhere in other languages.

@Ryan: thanks. I did look at the MXS docs, otherwise i wouldn’t have even known how to add a color picker. One thing that had me stumped for a while thought is that MXS doesn’t like color_picker.red. It wanted me to put color_picker.color.red before it understood what I was trying to get. But thanks for the link. I will definitely one through those tutorials once I’m done with this set.

Here’s my script in it’s entirety if anyone wants to critique me. The comments are there for me so I don’t forget what I was doing. I’m just happy that I figured out a decent formula for creating gradients along the shapes. Just upset that it took longer to implement it than it did to figure out.

macroScript Macro4
	category:"DragAndDrop"
	toolTip:""
(
	rollout SphereTool "Spheres Creator"
		(
			--these are the UI controls
			spinner count "Number: " type:#integer range:[1,100,10] align:#left
			spinner growth "Radius growth: " range:[1,100,2] align:#left
			spinner revolution "Rotation: " type:#integer range:[0,360,0] align:#left
			colorpicker start_color "Starting Color:" color:[127,127,127] align:#left
			colorpicker end_color "Ending color:" color:[128,128,128] align:#left
			button create "Create Spheres"
			

		--what happens when the create button is pressed.
		on create pressed do
			for i in 1 to count.value do
				(	
					--did this so the first sphere appears at the pivot
					new_pos = (i^2*growth.value)-growth.value
					--turned the spheres into a variable so they'd be easier for me to mess with
					new_ball = sphere radius:(i*growth.value) segs:(i*4) pos:[new_pos,0,0]
					--Testing out gradient formulas. Doing the math on each channel individually seems to work best.
					--The equation get the difference between the two colors and divides it by it's count value so it'll spread evenly
					--before the difference is divided, it multiply it by the current loop number minus 1 so it'll avoid the first object.
					--I subtracted 1 from the count value so it'll disregard this first object in the loop
					gradR = ((i-1)*(end_color.color.r - start_color.color.r)/(count.value - 1)) + start_color.color.r
					gradG = ((i-1)*(end_color.color.g - start_color.color.g)/(count.value - 1)) + start_color.color.g
					gradB = ((i-1)*(end_color.color.b - start_color.color.b)/(count.value - 1)) + start_color.color.b
					--gave the balls a unique name so that they can each get their own material that wouldn't clash
					new_ball.name = uniquename "grad_balls"
					--the material generated for each abject in the loop
					new_material = standardmaterial diffuse:[gradR,gradG,gradB]
					--derived the name of the material from the ball
					new_material.name = new_ball.name
					--attached the material to the ball
					new_ball.material = new_material
					--gonna try something else from the tutorial
					new_ring = torus radius1:(i^2*growth.value) radius2:(i*0.5) segs:(i*4) sides:(i*3)
					new_ring.material = new_material
					--this links the balls to the rings
					new_ball.parent = new_ring
					--rotates the rings by a value. the balls will rotate too since they're linked.
					rotate new_ring (i*revolution.value) z_axis
					--print (i-1)
				)
		)

		createDialog SphereTool width:200 --opens dialog
)

edit Is there a way I can preview my results before I submit to them like with array of some of the editable poly feature?