Alphablending textures as Sprites

Started by
6 comments, last by turnpast 18 years, 9 months ago
Hi all, I have a query about blending textures together. I have loaded a grayscaled background image:

private void RenderBackgroundLayer(Device device)
{
	// Not very efficient to create this here, 
	// but do so anyway if necessary
	if (backgroundTexture == null)
		backgroundTexture = TextureLoader.FromFile(
			device, ".\\staticbackdrop.png", 1280, 1024, 1,
			Usage.None, Format.X8R8G8B8, 
			Pool.Default, Filter.None, 
			Filter.None, Color.FromArgb(255, 0, 0, 0).ToArgb());

	if (backgroundSprite == null)
		backgroundSprite = new Sprite(device);

	backgroundSprite.Begin(SpriteFlags.None);

	// Blend colours towards green.
	System.Drawing.Color blendColour = System.Drawing.Color.FromArgb(0xFF, 0x00, 0xFF, 0x00);
				
	backgroundSprite.Draw(backgroundTexture, new Rectangle(0, 0, 1280,			1024), new Vector3(), new Vector3(), blendColour.ToArgb());

	backgroundSprite.End();
}

Additionally I need to blend over that some additional data from a dynamic texture ( a cut down version is shown below ):

private unsafe void RenderPlotLayer_Dynamic(Device device, bool useNewData)
{
   if (showPlotLayer)
   {
      if (plotTexture == null)
      {
         plotTexture = new Texture(device, 1000, 1000, 1,
            Usage.Dynamic, Format.X8R8G8B8, Pool.Default);
            
         // Set the texture to transparent black
         InitialiseTexture(plotTexture, 1000, 1000, 0xFF000000);
      }

      if (plotSprite == null)
         plotSprite = new Sprite(device);

      if (useNewData)
      {
         // Determine which page should be used.
         GraphicsStream gs = plotTexture.LockRectangle(0, LockFlags.None);
         uint* pdataStart = (uint*)gs.InternalData.ToPointer();

         SurfaceDescription surfaceDescription = plotTexture.GetLevelDescription(0);

         uint currentLineForUpdate = ((1000 - (uint)scrollOffset) * 1024);
         uint* pdata = pdataStart + (uint)currentLineForUpdate;
         
         // Set some data in the current line
         dataPlotCollection.WriteDataSetToMemory(pdata, 1024, 1000, 24, scrollOffset, 0x77);

         plotTexture.UnlockRectangle(0);

         if (scrollOffset == 1000)
            SwapBuffers();
      }

      System.Drawing.Color blendColour = System.Drawing.Color.FromArgb(0x77, 0x00, 0xFF, 0x00);

      plotSprite.Begin(SpriteFlags.AlphaBlend | SpriteFlags.SortTexture);
      plotSprite.Draw(plotTexture, new Rectangle(0,0,1000,1000), new Vector3(), new Vector3(12, 12, 0), blendColour.ToArgb());
      plotSprite.End();
   }
}

OK, onto my question. In the second function, my blend-colour has an Alpha of 0x77. This results in my background image being shown at half-brightness. If I change this to 0x00 I get no transparancy and to 0xFF I get nothing drawn. How do I blend these together? I'm using Managed DirectX in C# with the DX9 Framework (June 2005), but I'm more than comfortable in C++ if that's any help to anyone thinking of responding. I have discovered the following two lines in the device initialisation and wonder if some other Blend setting may be necessary for me. device.RenderState.SourceBlend = Blend.SourceAlpha; device.RenderState.DestinationBlend = Blend.InvSourceAlpha; I'd like to avoid getting the two textures and creating a third one manually, so if anyone can help, thanks! Regards, Ray [Edited by - rayhayes on July 4, 2005 10:25:28 AM]
Advertisement
Hi,

I might be tired, but what do you want to see in the end? Do you blend it with a plain black texture?

Anyway, please use the [ source ] and [ /source ] tags around your source, since like this, it is hard to see even the second function :)

kp
------------------------------------------------------------Neo, the Matrix should be 16-byte aligned for better performance!
Ok, firstly, I've fixed the source tags - first post here, sorry! I couldn't see anything on the form suggesting their use!

Right, what I want to see is the second texture placed directly over the first - but where I have nothing of interest I want the background unchanged. At the moment it is at half-brightness. I'm currently only using the green and alpha channels in the dynamic texture (the second of the two). When I first create the texture, it should be FF000000 (e.g. fully-transparent black).

My initialise-texture code is below if it helps:

unsafe private void InitialiseTexture(Texture texture, int width, int height, uint fillColour)		{	GraphicsStream gs = texture.LockRectangle(0, LockFlags.None);	uint* pdataStart = (uint*)gs.InternalData.ToPointer();	SurfaceDescription surfaceDescription = texture.GetLevelDescription(0);	// NOTE: need a way of calculating the difference between the texture size and	// the buffer MDX puts it into.	const int endOfLinePadding = 24;	uint* pdata = pdataStart;	for (int x = 0; x < surfaceDescription.Width; x++)	{		for (int y = 0; y < surfaceDescription.Height; y++)		{			*pdata = fillColour;			pdata++;		}		pdata += endOfLinePadding;	}	texture.UnlockRectangle(0);}


Regards,
Ray
Hey,

Now I see! Here is my code that is used for placing another layer onto the top of the first texture, controlled by the alpha channel in the second texture

// Color = (diffuse * tex0 * alphatex0) + (tex1 * alphatex1)    [second layer controlled by alpha channel, for adding rust, dirt, etc..]		guard.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);		guard.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);		guard.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);		guard.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA);		guard.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);		guard.SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);		guard.SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE);


I hope this is what you wanted!

kp


------------------------------------------------------------Neo, the Matrix should be 16-byte aligned for better performance!
Thanks so far,

I've converted that to the following, I'm not sure what your "guard" is, but the function was only available on the "device" (neither the sprite nor texture had anything similar). With a small restructuring, I have:

device.TextureState[0].ColorOperation = TextureOperation.Modulate;device.TextureState[0].AlphaArgument1 = TextureArgument.TextureColor;device.TextureState[0].AlphaArgument2 = TextureArgument.Current;device.TextureState[1].ColorOperation = TextureOperation.BlendTextureAlpha;device.TextureState[1].AlphaArgument1 = TextureArgument.TextureColor;device.TextureState[1].AlphaArgument2 = TextureArgument.Current;device.TextureState[2].ColorOperation = TextureOperation.Disable;


I'm not however seeing anything different. Should this work with Sprites? If so, when I "Begin" the sprite, what flags should I use (SpriteFlags.None and SpriteFlags.AlphaBlend respectively equate to just the new texture and just the original texture).

Perhaps I need to adjust the "color" property of the sprite.Draw function? I've tried with a solid colour and Color.Transparent to no effect

System.Drawing.Color blendColour = System.Drawing.Color.FromArgb(0x77,0,0xFF,0);sprite.Draw(sonarDataTexture_NewData, newDataRectangle, new Vector3(), new Vector3(12, 12, 0), blendColour.ToArgb());


Any clues?

Regards
Ray
When you call Sprite.Begin() it takes your texture and render states and clobbers the majority or importnat ones with its own (this is throughly documented in the C++ docs, but not in the managed). If you want to set up your own texture/render/sampler states you will have to use the DoNotModifyRenderState flag in you call to Begin(). If you do this you will manually have to set up all the render states that sprite usually sets up for you.

If you are rendering with alpha you should probably use the SortDepthBackToFront flag and not the SortTexture flag unless you are sure that your sprites will not overlap.

I am a little unclear on the effect you are trying to achieve, but you will get the best results if you use an alpha channel in the texture and don't try to fudge it with odd render states. Note that the X8R8G8B8 format does not have an alpha channel.
Oh, the X8R8G8B8 may be a problem then..

Which would be better?

Regards,
Ray
Try A8R8G8B8 or A1R5G5B5(if you only have one bit of alpha) or take a look at the supported formats in your caps viewer if those don't work.

This topic is closed to new replies.

Advertisement