PDA

View Full Version : Selecting Colors in an array - Please Help!



Ian_
March 30th, 2009, 07:24
Hello, I'm pretty new to mental ray shader writing and compiling, and I'm trying to find examples and tutorials, where ever I can. Unfortunately, I can't find any examples on how to make a shader that switches between colors in an array, with an integer, like the Comp_color_select shader from mental mill. I tried making a shader for 3dsmax, that I thought would work, It seemed to compile correctly, and it loaded without any errors, but 3dsmax crashes whenever I change any parameters on the shader.

Here's the cpp file-

#include <math.h>
#include "shader.h"

typedef struct
{
miInteger select;
int i_list;
int n_list;
miColor colors[1];
}color_select_t;

extern "C"
{
DLLEXPORT int color_select_version(void) {return(1);}

DLLEXPORT miBoolean color_select(miColor *result, miState *state, color_select_t *paras)
{
miInteger select = *mi_eval_integer(&paras->select);
int i_list = *mi_eval_integer(&paras->i_list);
int n_list = *mi_eval_integer(&paras->n_list);
int i;
miColor *color;
for (i = 0; i < n_list; i++) {
if (i>=select) {
color = mi_eval_color(&paras->colors[i_list + i]);
break;
}
result->r += color->r;
result->g += color->g;
result->b += color->b;
result->a = 1.0;
}
return(miTRUE);
}
}

And the mi file-

declare shader
color "color_select" (
integer "select", #: min 0 default 0,
array color "colors"
)
version 1
apply material
end declare

declare phenomenon
color "color_select_2" (
integer "select", #: min 0 default 0 max 1,
color "color1",
color "color2"
)
shader "select"
"color_select" (
"select" = interface "select",
"colors"
[ = interface "color1",
= interface "color2"
]
)
root = "select"
version 1
apply texture, material
gui "gui_color_select_2" {
control "Global" "Global" (
"uiName" "Color Select 2",
"category" "Texture"
)
control "select" "integer" ("uiName" "Select", "value" 0)
control "color1" "color" ("uiName" "Color 1", "value" 1.0 1.0 1.0)
control "color2" "color" ("uiName" "Color 2", "value" 1.0 1.0 1.0)
}
end declare

Hopefully, I'm pretty close to doing this kind of shader the right way. Once I get a working shader, then it should be fairly easy to create a shader for scalars,vectors,etc. Any help would be greatly appreciated. :)

bart
March 30th, 2009, 17:48
I moved this because it didn't seem to be about the book writing mental ray shaders, but rather somewhat of a follow up on the sticky post in this forum on color array inputs.

Did you verify that you get all the colors you want by adding an mi_info() statement into your shader for testing purposes?

If all you have is the application, and no standalone, then that might be the easiest way to debug this. However, note that if you do get the book, it includes a copy of standalone, which makes for easier shader debugging before using it in an application.

For example, we use the book scenes and shaders to isolate and debug when consulting. It makes a great sandbox of scenes for isolating features.

Ian_
March 30th, 2009, 19:39
Hello, thanks for responding. I did try to learn from the color array input sticky, but that example added the colors together, and I tried to figure out how this would work, from other websites. I mainly just know how to write in msl and somewhat in hlsl, writing in c is pretty foreign to me. I didn't know that there was a mi_info statement, and I'm not sure how you would use it. Also right now I really can't afford the book, so I'm trying to learn what I can from online examples. Since I only work from one computer right now, I don't really need the standalone version of mental ray.

If you were to write a shader that selects colors from an array, using an integer, what would write differently? Also, one other thing I tried that seemed to work. is by replacing-

for (i = 0; i < n_list; i++) {
if (i>=select) {
color = mi_eval_color(&paras->colors[i_list + i]);
break;
}

with-

for (i = 0; i < n_list; i++) {
color = mi_eval_color(&paras->colors[select]);

It does switch the colors but, when you put the select number higher than ther amount of colors in the phenomenon, then mental ray encounters a problem, and 3dsmax crashes.

If we could solve this problem, then having this kind of example would definitely be helpful for everyone. Again, I appreciate your help. :)

bart
March 31st, 2009, 21:01
The point of standalone isn't about how many machine resources you have. It is a suggestion for more efficient, streamlined shader development.

Currently, it is much easier to debug your edits of a Phenomenon, for example, using standalone. The code, compile, render, debug loop is much faster.

A well placed mi_info() or even mi_fatal() using standalone works very well for fast debugging.

I really can't emphasize enough how much value the book has, giving you the examples, and more importantly explaining them, for your understanding. Then, including a copy of standalone to complete your hands-on experience.

Besides, if you only want C shader examples, you can go to the book's website, http://www.writingshaders.com

bart
March 31st, 2009, 21:10
Now, to address your issues specifically, I personally like to code according to what I hear is needed. What I mean is that you say you want to check the elect number against the number of array elements. So I use mi_warning or mi_fatal to do just that.

Here is the snippet that I think you were looking for:

if (select >= n_colors)
mi_warning("Your select value of %i exceeds the 0-based number of (%i) colors input", select, n_colors);
else {
color = mi_eval_color(&params->colors[select + i_colors]);
...}

Or for the full shader source:


#include "shader.h"

struct select_color {
miInteger select;
int i_colors;
int n_colors;
miColor colors[1];
};


DLLEXPORT
int select_color_version(void) { return 1; }

DLLEXPORT
miBoolean select_color(
miColor *result, miState *state, struct select_color *params)
{
miInteger select = *mi_eval_integer(&params->select);
int n_colors = *mi_eval_integer(&params->n_colors);
int i_colors = *mi_eval_integer(&params->i_colors);
miColor *color;

if (select >= n_colors)
mi_fatal("Your select value of %i exceeds the 0-based number of (%i) colors input", select, n_colors);
else {
color = mi_eval_color(&params->colors[select + i_colors]);

result->r = color->r;
result->g = color->g;
result->b = color->b;
result->a = 1.0;
}
return miTRUE;
}

bart
March 31st, 2009, 21:12
You can also specify a shader input range in most applications. In 3ds max, you add a "range" min max, line.

Here's the full declaration that matches the above code:


declare shader
color "select_color" (
integer "select",
array color "colors"
)
apply material
version 1
end declare

declare phenomenon
color "select_color_2" (
integer "select", #: min 0 default 0 max 1,
color "color1",
color "color2"
)
shader "selected_color"
"select_color" (
"select" = interface "select",
"colors"
[ = interface "color1",
= interface "color2"
]
)
root = "selected_color"
version 1
apply texture, material
gui "gui_select_color_2" {
control "Global" "Global" (
"uiName" "Select Color 2",
"category" "Texture"
)
control "select" "integer" (
"uiName" "Select",
"range" 0 1,
"value" 0)
control "color1" "color" (
"uiName" "Color 1",
"value" 1.0 1.0 1.0)
control "color2" "color" (
"uiName" "Color 2",
"value" 1.0 1.0 1.0)
}
end declare

Ian_
April 24th, 2009, 07:33
Hello, sorry for a late reply, but thank you so very much for all of your help bart. The way that I've been learning how to write shaders so far, is by trial and error, and learning from other source code examples.

Your revisions seem to work perfectly, except when you put select to 2, which would make sense, since the warning says "Your select value of %i exceeds the 0-based number of (%i) colors input", and there is only 2 colors declared, and the first color starts at 0. I compiled your full source code, including having the warning text. I'm still confused on what to change, in order to fix this. without having to limit the UI number, and I'm still confused on how those warning and fatal statements work, do you put mi_fatal next to a line of code, with brackets around that code, and if there is an error, it puts the error message into your cpp file? Or did you copy and past that code from somewhere else? Sorry if this is a dumb question.

Pretty much, I'm trying to make the equivalent of the "SelectColor" shader from drUtilShaders which clamps the the selected colors to the first and last color the the array, even when you have the select integer way above the number of colors, which is what I'd like to achieve. Unfortunately, the only source code that comes with those shaders is for the illumination shaders.

Anyways, thanks again for all of your input on this. :)

bart
April 24th, 2009, 21:43
Well, that should be simple enough,...
if select >= n_colors, set select = n_colors -1.

Use that instead of the if .. else code.

if (select >= n_colors) select = n_colors - 1;

color = mi_eval_color(&params->colors[select + i_colors]);
result->r = color->r;
result->g = color->g;
result->b = color->b;
result->a = 1.0;

However, if I were managing this development, I would prefer not to hide issues. I'd rather prevent them.

So you can reduce confusion and be more preventative by using the UI limiting approach. Is there something that prevents you from doing that?

Ian_
April 26th, 2009, 13:13
I haven't yet tried your new if else code but, I have found a way to get what I needed, and it seems to work good so far-

if (select <= 0)
select = select * 0;
select = (select < 0 ? 0 : (select > (n_colors - 1) ? (n_colors - 1) : select));
if (select >= n_colors)
color = mi_eval_color(&paras->colors[n_colors]);
else {
color = mi_eval_color(&paras->colors[select + i_colors]);
result->r = color->r;
result->g = color->g;
result->b = color->b;
result->a = 1.0;
This pretty much limits the select value from going below 0 and not going higher than the amount of colors in the array, but I alsoI limited the UI. However it it has another shader mapped to the select value it can go above and below the UI limits, but the actual integer value will be clamped. I mainly wanted the select value to be able to go outside the min and max values for when the select value is mapped. For example, having blinn lighting multiplied by a certain amount and converted to an integer and mapped to the select value to have multiple steps of cell shading. Of course there are probably many other uses for mapping the select value.I'll include the source file and library with mi file.

Thanks again bart for your help man. Let me know if you have any other ideas for this.

bart
April 26th, 2009, 18:07
To clarify, there is no else clause in my last example.

I see that you added an adjustment to below 0 as well. But your code does things multiple times, which makes it confusing. It also multiplies select by 0, when you could just be setting it.

I would suggest that you make it simpler, so that it is easier to figure out when you or someone else looks at it in the future. Eg.


/* constrain select to range */
if (select < 0) select = 0;
if (select >= n_colors) select = n_colors - 1;

/* select color */
color = mi_eval_color(&paras->colors[select + i_colors]);
result->r = color->r;
result->g = color->g;
result->b = color->b;
result->a = 1.0;

Ian_
April 26th, 2009, 20:19
Thanks man, that is a lot simpler. It definitely helps with rendering large scenes, when shaders are optimized. :) Maybe this thread should also be a sticky, or maybe have the information added to the color array inputs sticky, since as you said earlier, that this is pretty much a follow up on it.