Sign in to follow this  

Pixel shader question... Texture blending

This topic is 3742 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi everyone. I've been trying to get my hands around pixel shaders for a while now. I'm not making the best progress, but I've come into a bit of an actual snag I can't seem to free myself from. What I'm essentially trying to do is use a mask image that contains 4 color elements (RGBA) and when passed through a pixel shader along with 4 other textures, will blend them together. This is what I've gotten thus far:
sampler2D grass_texture;
sampler2D rock_texture;
sampler2D stone_texture;
sampler2D moss_texture;
sampler2D texture_map;

float4 texture_scale;

struct PS_INPUT 
{
   float2 Texcoord : TEXCOORD0;   
};

float4 ps_main( PS_INPUT Input ) : COLOR0
{
   
   float4 colorvalue = tex2D(texture_map, Input.Texcoord);
   float4 coloradd = {0, 0, 0, 0};
      
   if (colorvalue.x) // Red
   {
      coloradd += tex2D(moss_texture, Input.Texcoord * texture_scale[0]) * colorvalue.x;
   }
   
   if (colorvalue.y) // Green
   {
      coloradd += tex2D(rock_texture, Input.Texcoord * texture_scale[1]) * colorvalue.y;
   }
   
   if (colorvalue.z) // Blue
   {
      coloradd += tex2D(grass_texture, Input.Texcoord * texture_scale[2]) * colorvalue.z;
   }
   
   //if (colorvalue.w < 0.99) // Alpha (we're looking for a lack of solid)
   //{
   //   coloradd += tex2D(stone_texture, Input.Texcoord * texture_scale[3]) * colorvalue.w;
   //}

   return coloradd;
}




Here is the texture map I'm using at the moment to blend the colors: Here is the result: However any attempts to utilize the alpha channel to use the last texture ends in failure (generally screws up the appearance of the rest of the surface). I'm probably doing something stupid or missing something obvious, but I really don't know where to go and what to do about this problem. Hopefully someone else has some insight? Perhaps there is a better way I can be doing this? [Edited by - Flimflam on September 19, 2007 12:56:22 AM]

Share this post


Link to post
Share on other sites
Just a little update:

With a little tinkering with the shader:
   if (colorvalue.w <= 0.99) // Alpha (we're looking for a lack of solid)
{
coloradd = tex2D(stone_texture, Input.Texcoord * texture_scale[3]) * colorvalue.w;
}


I was able to get this effect:


So I manage to get all 4 textures up, but as you can see, since I'm not adding the color values for the Alpha channel together, rather I'm specifically setting the color explicitly, it doesn't turn out too well... Adding the color to the rest seems to screw up pretty much everything else.

[Edited by - Flimflam on September 19, 2007 2:17:23 AM]

Share this post


Link to post
Share on other sites
The texture you're using is always selecting either R, G or B (i.e., one of your textures), not adding them. If the alpha adds, you're likely to saturate the values. You should have R+G+B+A = 1 to have things work well.

Share this post


Link to post
Share on other sites
Quote:
Original post by ET3D
The texture you're using is always selecting either R, G or B (i.e., one of your textures), not adding them. If the alpha adds, you're likely to saturate the values. You should have R+G+B+A = 1 to have things work well.


I hate to sound like an idiot here (I really am on this subject) but care to elaborate a little further?

Share this post


Link to post
Share on other sites
Quote:
Original post by Flimflam
I hate to sound like an idiot here (I really am on this subject) but care to elaborate a little further?


He means that in your code, you permit a fragment (pixel) to receive multiple layers at the same time (ie if the colorvalue is yellow (red AND green). The problem with that is that RED channel is 1.0 and GREEN channel is 1.0...

Now if the texture corresponding to red is (0.7,0.7,0.7) and the one corresponding to green is (0.9,0.9,0.9)

(0.7,0.7,0.7) * 1.0 + (0.9,0.9,0.9) * 1.0 = (1.6,1.6,1.6)

your resulting texture will be saturated, thus appear white !

You should thus be sure that your input colorvalue respects the following fact :

colorvalue.r + colorvalue.g + colorvalue.b + colorvalue.a = 1.0

(EDIT : as i understand, you don't permit colorvalue to be yellow, but take my explanation for RED and ALPHA, and the conclusion is the same)

Share this post


Link to post
Share on other sites
I see... I have to admit I'm a little stumped on how to prevent this from happening. (I'm still really new to pixel shaders in general)

I'm starting to wonder if I would be better off just sticking to 3 textures per object rather than 4, since 3 is working just fine.

Share this post


Link to post
Share on other sites
Why don't you do something like this :


float4 colorvalue = tex2D(texture_map, Input.Texcoord);
float4 coloradd = {0, 0, 0, 0};

colorvalue /= colorvalue.x + colorvalue.y + colorvalue.z + colorvalue.w;

coloradd += tex2D(moss_texture, Input.Texcoord * texture_scale[0]) * colorvalue.x;
coloradd += tex2D(rock_texture, Input.Texcoord * texture_scale[1]) * colorvalue.y;
coloradd += tex2D(grass_texture, Input.Texcoord * texture_scale[2]) * colorvalue.z;
coloradd += tex2D(stone_texture, Input.Texcoord * texture_scale[3]) * colorvalue.w;

return coloradd;


Share this post


Link to post
Share on other sites
Quote:
Original post by jfdegbo
Why don't you do something like this :

*** Source Snippet Removed ***


Thank you very much! This seems to have fixed all of my problems!

Share this post


Link to post
Share on other sites
Quote:
Original post by Namethatnobodyelsetook
If you calculate the 4 scaled texcoords in the VS and pass all 5 sets of coords to the pixel shader you'll likely increase your framerate. Right now they're all dependant reads, which are slow.


I went ahead and made that change:

struct VS_OUTPUT 
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
float2 TexCoord1 : TEXCOORD1;
float2 TexCoord2 : TEXCOORD2;
float2 TexCoord3 : TEXCOORD3;
float2 TexCoord4 : TEXCOORD4;
};

VS_OUTPUT vs_main( VS_INPUT Input )
{
VS_OUTPUT Output;

Output.Position = mul( Input.Position, matViewProjection );
Output.TexCoord = Input.Texcoord;

Output.TexCoord1 = Input.Texcoord * texture_scale[0];
Output.TexCoord2 = Input.Texcoord * texture_scale[1];
Output.TexCoord3 = Input.Texcoord * texture_scale[2];
Output.TexCoord4 = Input.Texcoord * texture_scale[3];

return( Output );
}



And I got about a 40-60fps increase in RenderMonkey. Thanks =D

Share this post


Link to post
Share on other sites

This topic is 3742 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this