PDA

View Full Version : Problem with getting material data


Guiniture
05-06-2008, 11:18 PM
Hi,

For some reason I am having a problem using an "if" statement to get an objects material data.
can anybody tell me why this does not work:


$box01.material.diffuse = (color 255 255 255)
a = $box01.material.diffuse

if a == (color 255 255 255) do (print "it works")


If i type this into the listerner it returns: undefined.
I dont understand why this does not work, it works fine if i try and access $.material.diffuse.r??

Anybody??

erilaz
05-06-2008, 11:39 PM
Did you actually apply a material to the box first? Doing that runs the code fine for me.

Guiniture
05-07-2008, 12:03 AM
yeh the object has a material on.

I started by using the openbitmap command to import a small bitmap image into the scene, the script just takes each pixel in the bitmap and creates a box in the scene and adds a standardmaterial too it that corasponds to the pixel colour.

Now all I want to do is get boxes with a certain color eg: (color 255 0 9) and do something to them.
So i am looping through all the boxes like this:


for i in allboxes do
(
if i.material.diffuse == (color 255 0 9) do (print "it works")
)



But this does seem to do anything!?? I have just tried opening a new scene and creating an object and assigning it a material from the material editor, if i do this i can select it and use:
if $.material.diffuse == (color 150 150 150) do (print "it works") and it does work!!

I dont think there is a problem with the boxes material as all I have done is loop though the boxes and assigned them a standardmaterial:



for w = 1 to aa_w do
(
pixelcol = pixel_line[w].r + pixel_line[w].g + pixel_line[w].b
newbox = box length:1 width:1 height:(pixelcol/50) pos: [w,-h,0]
newmat = standardmaterial diffuse: pixel_line[w]
newbox.material = newmat
)



any ideas?

JHaywood
05-07-2008, 12:27 AM
Maybe none of your boxes have that color in the diffuse. Just for debuging purposes, add a line to report what the code is doing outside of the if/do statement.


for i in allboxes do
(
format "% diffuse color: %\n" i i.material.diffuse
if i.material.diffuse == (color 255 0 9) do (print "it works")
)

erilaz
05-07-2008, 12:32 AM
yeh the object has a material on.

I started by using the openbitmap command to import a small bitmap image into the scene, the script just takes each pixel in the bitmap and creates a box in the scene and adds a standardmaterial too it that corasponds to the pixel colour.


You might want to check out this older challenge, as it was centered around exactly what you're doing:
http://forums.cgsociety.org/showthread.php?t=271753

As to the selection part i'm not sure why... I can have a go once i'm off work. :)

Bobo
05-07-2008, 02:26 AM
Something that is not very obvious - the colors in Max are internally floats in the 0.0-1.0 range. The 0-255 colors you see are a print time representation of the internal values. So if you read and assigned some bitmap pixel to some object, that value might APPEAR to be some 8-bit color, but internally to be slightly off (because of decimal point imprecisions when converting the floating points to 255 range and back. Thus, you should use the CloseEnough() function provided in Max 2008 and higher (or in the Avguard Extensions before that) and check each component of the color one by one with some error threshold, or write your own function that takes the .R, .G and .B and looks if the result of the subtraction of the pairs is less than, say, 0.01 or something.

erilaz
05-07-2008, 03:38 AM
Something that is not very obvious - the colors in Max are internally floats in the 0.0-1.0 range. The 0-255 colors you see are a print time representation of the internal values. So if you read and assigned some bitmap pixel to some object, that value might APPEAR to be some 8-bit color, but internally to be slightly off (because of decimal point imprecisions when converting the floating points to 255 range and back. Thus, you should use the CloseEnough() function provided in Max 2008 and higher (or in the Avguard Extensions before that) and check each component of the color one by one with some error threshold, or write your own function that takes the .R, .G and .B and looks if the result of the subtraction of the pairs is less than, say, 0.01 or something.

You know Bobo, sometimes I wish I didn't have to say "Wow, I never knew that!" every single time you post. :D

Guiniture
05-07-2008, 09:05 AM
That makes perfect sense! Thanks a lot for the help. Im using Max 7 at the moment so i dont have the closeenough() function but, I guess if i wanted to get round the problem i could tweek the colors of the boxes to make them whole numbers:


for i in allboxes do
(
new_r = ceil i.material.diffuse.r
new_g = ceil i.material.diffuse.g
new_b = ceil i.material.diffuse.b

i.material.diffuse.r = new_r
i.material.diffuse.g = new_g
i.material.diffuse.b = new_b
)


Il have a play with that. Cheers.

Bobo
05-07-2008, 02:02 PM
That makes perfect sense! Thanks a lot for the help. Im using Max 7 at the moment so i dont have the closeenough() function but, I guess if i wanted to get round the problem i could tweek the colors of the boxes to make them whole numbers:


for i in allboxes do
(
new_r = ceil i.material.diffuse.r
new_g = ceil i.material.diffuse.g
new_b = ceil i.material.diffuse.b

i.material.diffuse.r = new_r
i.material.diffuse.g = new_g
i.material.diffuse.b = new_b
)


Il have a play with that. Cheers.

This might not help. I would rather do the tweaking when comparing, not when assigning. As I mentioned, when you assign a color of, say, color 127 43 151, the values stored internally are actually 0.498039 0.168627 0.592157 (the range from 0 to 255 is converted to 0-1 by dividing by 255.0 internally). As you can see, these numbers could cause problems because of decimal precision - accrding to MAXScript,
0.168627*255 = 42.9999
but also according to MAXScript,
((color 127 43 151)/255.0)*255.0 = color 127 43 151
So the Green color is entered and shown as 43 in both cases, but the internal floating point value is ridiculously close to but not quite the same as 43...

So back to your example using the above "bad" number:

$box01.material.diffuse = (color 127 43 151)
(color 127 43 151)
a = $box01.material.diffuse
(color 127 43 151)
if a == (color 127 43 151) do (print "it works")
undefined
if a as string == (color 127 43 151) as string do (print "it works")
"it works"
"it works"
if abs(a.r-127.0)<0.001 AND abs(a.g-43.0)<0.001 AND abs(a.b-151.0)<0.001 do (print "it works")
"it works"
"it works"

So you can define a simple function like this:

fn closeEnoughColor colorA colorB precision:0.0001=
(
abs (colorA.r-colorB.r) < precision AND \
abs (colorA.g-colorB.g) < precision AND \
abs (colorA.b-colorB.b) < precision AND \
abs (colorA.a-colorB.a) < precision
)

if closeEnoughColor a (color 127 43 151) do (print "it works")

JHaywood
05-07-2008, 04:46 PM
The hacky way to do this without using the closeEnough function would be to do the comparison in a different space, as strings for example...


for i in allboxes do
(
if (i.material.diffuse as string) == ((color 255 0 9) as string) do (print "it works")
)

Bobo
05-07-2008, 09:28 PM
The hacky way to do this without using the closeEnough function would be to do the comparison in a different space, as strings for example...


for i in allboxes do
(
if (i.material.diffuse as string) == ((color 255 0 9) as string) do (print "it works")
)

Yep, if you look at my longer example above, I did that there, but did not comment on it because it is indeed a hack. But it works! :)

Guiniture
05-08-2008, 08:37 PM
Thanks guys! i will have a go at doing the 'proper' way and if that doesnt work il use the hacky way!!

Cheers.

CGTalk Moderation
05-08-2008, 08:37 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.