Sign in to follow this  
hand

Shader Question - Alpha Blending or Colour from Background

Recommended Posts

Hi, I have a shader question and I hope that somebody has an answer to it. My scene consists of an plane background object with a texture and a moving object with a texture (plane/or 3D). Slide 1a What I want to achieve is that the moving object gets coloured like the background texture at the given position of the moving object. Slide 2a Slide 3a I want to do this with a shader, because if it comes the colour pixels, it's the right place to go. My prefered shader language is CG but if you familial with any other I'll be able to adapt it. What I do know is the position of the moving object the position and the dimension of the background texture. Maybe I'm trying to do something very simple because I can't find anything in the web, or I'm using the wrong buzz words. This is actually a workaround for my original problem that I have: I'm using a particle system where the particle is a plane object and has a translucent circle with a white border as texture, so you can see the background through it. And the more particle there are the brighter the white will get. Slide 1b That behavior is right but not realy wanted. Because when the number of the particle went through the roof, I end up with an opaque white and the particles form a spongy mass and you can't see any more details in it. Slide 2b Is there an apha blending mode that I missed that will do the job? I'm using "add color" right now ... One way to solve this problem is to make the center of particle texture opaque, but I'm using the background texture as static light source so the particle gets brighter at the top of the scene and darker at the bottom. Thank you for your help. If you need more details please ask.

Share this post


Link to post
Share on other sites
Set up your particle texture so that the white border has an alpha of 255, and the rest of the texture has an alpha of 0. Then in your shader do:

Pixel.rgb = (ParticleTexture.rgb * ParticleTexture.a) + (BackgroundTexture.rgb * (1.0 - ParticleTexture.a))

This makes the particle completely see-through, except for the border. Hopefully I understood your post correctly and this is what you are looking for [smile]

Share this post


Link to post
Share on other sites
Thank you for the quick answer,
I've got it almost the way I want it to. The particle changes the color corresponding to its position in the background but a simple study shows a weird result.

See the pictures...

Slide 1
Slide 2
Slide 3
Slide 4
Slide 5

If the particle moves horizontal the color changes in the moving
direction, that is correct, but if the particle moves vertical, the
color change is contrary to the direction.


My setup:

The background, in this example the checkerboard (green, blue, yellow, red), has a dimension of
500x500 and its centered in the origin of the scene (x=0,y=0,z=0).
The left bottom corner is in (x=-250, y=-250).
The top right corner is in (x=250, y=250).
The particle's dimension is 30x30 and its moving clock wise.

The application updates the position of the particle every frame, so the shader knows can
calculate the relative position in the background texture.

Shader (Cg):


//// UN-TWEAKABLES - AUTOMATICALLY-TRACKED TRANSFORMS ////////////////
float4x4 WorldViewProj : WorldViewProjection;

texture ObjectTexture <
string UIName = "ObjectTexture";
string ResourceName = "../media/particle.png";
string ResourceType = "2D";
>;
sampler2D ObjectT : register(s0) = sampler_state {
Texture = <ObjectTexture>;
};

texture BackgroundTexture <
string UIName = "BackgroundTexture";
string ResourceName = "../media/background.png";
string ResourceType = "2D";
>;
sampler2D BackgroundT : register(s1) = sampler_state {
Texture = <BackgroundTexture>;
};

/* data from application vertex buffer */
struct appdata {
float3 Position : POSITION;
float4 UV : TEXCOORD0;
};

struct vertexOutput {
float4 HPosition : POSITION;
float4 UV : TEXCOORD0;
};

vertexOutput mainVS(appdata IN)
{
vertexOutput OUT;
float4 Po = float4(IN.Position.xyz,1);
OUT.HPosition = mul(WorldViewProj, Po);
OUT.UV = IN.UV;
return OUT;
}

float4 mainPS( vertexOutput IN,
uniform float3 position,
uniform float2 dimension) : COLOR
{
float2 pos = 0;
float2 size = 30;

float2 originPos = position.xy - size*0.5;


pos.x = (originPos.x + IN.UV.x * size.x) / dimension.x;
pos.y = (originPos.y + IN.UV.y * size.y) / dimension.y;

float4 particleColor = tex2D(ObjectT, IN.UV.xy);
float4 backgroundColor = tex2D(BackgroundT, pos);

float3 Color = (particleColor.rgb * particleColor.a) + (backgroundColor.rgb * (1.0 - particleColor.a));

float4 oColor = 0;
oColor.rgb = Color.rgb;
oColor.a = particleColor.a;

return oColor;
}

technique technique1 {
pass p0 {
CullFaceEnable = false;
VertexProgram = compile vp30 mainVS();
FragmentProgram = compile fp30 mainPS(position, dimension);
}
}





Do you have any idea why this behaves like this?

Share this post


Link to post
Share on other sites
I suspect you're being bitten by different interpretations of texture space origin. DirectX and OpenGL (and by extension various 3d packages/ image file formats) use two different mappings for UV texture space. In DirectX, the origin is at the top left of the texture, U is to the right and V is down, whereas in OpenGL the origin is at the bottom left of the texture so U is still to the right, but V is up. Inverting your V coordinate ( v = 1.0 - v ); either in you vertex shader or before passing it to the card should fix your problem.

N.B this is probably wrong for your circle texture too, but reflections can be pretty tricky to spot in circles and spheres ;)

Share this post


Link to post
Share on other sites
Many thanks to you both berkbig and Zipster!!

You made my day.

I've never ever thought about the difference of the two texture space origin
in DX and OpenGL, because I assumed by using Nvidia Cg the library would do the job for me. Guess that isn't the case in this example.

It really is a pitfall ...

What I've changed in the shader code:

float v = 1.0 - IN.UV.y;
pos.x = (originPos.x + IN.UV.x * size.x) / dimension.x;
pos.y = (originPos.y + v * size.y) / dimension.y;


float4 mainPS( vertexOutput IN,
uniform float3 position,
uniform float2 dimension) : COLOR
{
float2 pos = 0;
float2 size = 30;

float2 originPos = position.xy - size*0.5;

float v = 1.0 - IN.UV.y;

pos.x = (originPos.x + IN.UV.x * size.x) / dimension.x;
pos.y = (originPos.y + v * size.y) / dimension.y;

float4 particleColor = tex2D(ObjectT, IN.UV.xy);
float4 backgroundColor = tex2D(BackgroundT, pos);

float3 Color = (particleColor.rgb * particleColor.a) + (backgroundColor.rgb * (1.0 - particleColor.a));

float4 oColor = 0;
oColor.rgb = Color.rgb;
oColor.a = particleColor.a;

return oColor;
}




I hope this thread will help others if they have a similar problem!


Share this post


Link to post
Share on other sites
You are very welcome :)

By way of a piece of bonus advice and because it wasn't entirely clear in my previous post DirectX and OpenGL aren't the only things that affect which way up your texture is - in fact the problem here may lie in your choice of image format. Depending on if your texture is stored in PNG or BMP that may also invert the V axis of your texture, and in fact in TGA I believe you can choose which way up the image is in the header of the texture...

Just FYI - it might save you going mad when you get some textures in a different format and your whole program stops working again ;)

Share this post


Link to post
Share on other sites

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